diff options
| author | The Miri Conjob Bot <miri@cron.bot> | 2023-10-28 05:19:39 +0000 |
|---|---|---|
| committer | The Miri Conjob Bot <miri@cron.bot> | 2023-10-28 05:19:39 +0000 |
| commit | d7e49c03f63e40b9ce3b051c557a676c20f2431b (patch) | |
| tree | 3ff517fb8358703f78789fe7e84d47c1e3167b08 | |
| parent | e29845311d004d77750b62f3d5d2223124aa4e7f (diff) | |
| parent | 20952db40d5220e8a15c2e569ae480877bbc8417 (diff) | |
| download | rust-d7e49c03f63e40b9ce3b051c557a676c20f2431b.tar.gz rust-d7e49c03f63e40b9ce3b051c557a676c20f2431b.zip | |
Merge from rustc
572 files changed, 9692 insertions, 4598 deletions
diff --git a/Cargo.lock b/Cargo.lock index ff21d5f8c08..e1b0de6c7a4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4557,9 +4557,7 @@ dependencies = [ "rustc-demangle", "rustc_data_structures", "rustc_errors", - "rustc_fluent_macro", "rustc_hir", - "rustc_macros", "rustc_middle", "rustc_session", "rustc_span", @@ -4694,6 +4692,7 @@ dependencies = [ "arrayvec", "askama", "expect-test", + "indexmap 2.0.0", "itertools", "minifier", "once_cell", diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs index 54274f15356..a53fd4ae95a 100644 --- a/compiler/rustc_arena/src/lib.rs +++ b/compiler/rustc_arena/src/lib.rs @@ -18,7 +18,6 @@ #![feature(new_uninit)] #![feature(maybe_uninit_slice)] #![feature(decl_macro)] -#![feature(pointer_byte_offsets)] #![feature(rustc_attrs)] #![cfg_attr(test, feature(test))] #![feature(strict_provenance)] diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index e94e26a63bc..e09ba03d881 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -734,6 +734,8 @@ pub enum RangeSyntax { } /// All the different flavors of pattern that Rust recognizes. +// +// Adding a new variant? Please update `test_pat` in `tests/ui/macros/stringify.rs`. #[derive(Clone, Encodable, Decodable, Debug)] pub enum PatKind { /// Represents a wildcard pattern (`_`). @@ -967,6 +969,7 @@ impl Stmt { } } +// Adding a new variant? Please update `test_stmt` in `tests/ui/macros/stringify.rs`. #[derive(Clone, Encodable, Decodable, Debug)] pub enum StmtKind { /// A local (let) binding. @@ -1345,6 +1348,7 @@ pub struct StructExpr { pub rest: StructRest, } +// Adding a new variant? Please update `test_expr` in `tests/ui/macros/stringify.rs`. #[derive(Clone, Encodable, Decodable, Debug)] pub enum ExprKind { /// An array (`[a, b, c, d]`) @@ -2015,6 +2019,8 @@ pub struct BareFnTy { } /// The various kinds of type recognized by the compiler. +// +// Adding a new variant? Please update `test_ty` in `tests/ui/macros/stringify.rs`. #[derive(Clone, Encodable, Decodable, Debug)] pub enum TyKind { /// A variable-length slice (`[T]`). @@ -2880,6 +2886,7 @@ pub struct ConstItem { pub expr: Option<P<Expr>>, } +// Adding a new variant? Please update `test_item` in `tests/ui/macros/stringify.rs`. #[derive(Clone, Encodable, Decodable, Debug)] pub enum ItemKind { /// An `extern crate` item, with the optional *original* crate name if the crate was renamed. 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_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 1e51449e70c..04a8e2b134a 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1217,7 +1217,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { hir_id: this.lower_node_id(node_id), body: this.lower_const_body(path_expr.span, Some(&path_expr)), }); - return GenericArg::Const(ConstArg { value: ct, span }); + return GenericArg::Const(ConstArg { + value: ct, + span, + is_desugared_from_effects: false, + }); } } } @@ -1228,6 +1232,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ast::GenericArg::Const(ct) => GenericArg::Const(ConstArg { value: self.lower_anon_const(&ct), span: self.lower_span(ct.value.span), + is_desugared_from_effects: false, }), } } @@ -2525,6 +2530,7 @@ impl<'hir> GenericArgsCtor<'hir> { self.args.push(hir::GenericArg::Const(hir::ConstArg { value: hir::AnonConst { def_id, hir_id, body }, span, + is_desugared_from_effects: true, })) } diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index 44ba495721d..363ba0d4a81 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -13,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}; @@ -23,10 +24,7 @@ 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 fn rust_version_symbol() -> Symbol { - let version = option_env!("CFG_RELEASE").unwrap_or("<current>"); - Symbol::intern(&version) -} +pub const CURRENT_RUSTC_VERSION: &str = env!("CFG_RELEASE"); pub fn is_builtin_attr(attr: &Attribute) -> bool { attr.is_doc_comment() || attr.ident().is_some_and(|ident| is_builtin_attr_name(ident.name)) @@ -144,13 +142,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 { .. }) @@ -372,22 +381,24 @@ fn parse_stability(sess: &Session, attr: &Attribute) -> Option<(Symbol, Stabilit let since = if let Some(since) = since { if since.as_str() == VERSION_PLACEHOLDER { - Ok(rust_version_symbol()) - } else if parse_version(since.as_str(), false).is_some() { - Ok(since) + Since::Current + } else if let Some(version) = parse_version(since.as_str(), false) { + Since::Version(version) } else { - Err(sess.emit_err(session_diagnostics::InvalidSince { span: attr.span })) + sess.emit_err(session_diagnostics::InvalidSince { span: attr.span }); + Since::Err } } else { - Err(sess.emit_err(session_diagnostics::MissingSince { span: attr.span })) + sess.emit_err(session_diagnostics::MissingSince { span: attr.span }); + Since::Err }; - match (feature, since) { - (Ok(feature), Ok(since)) => { + match feature { + Ok(feature) => { let level = StabilityLevel::Stable { since, allowed_through_unstable_modules: false }; Some((feature, level)) } - (Err(ErrorGuaranteed { .. }), _) | (_, Err(ErrorGuaranteed { .. })) => None, + Err(ErrorGuaranteed { .. }) => None, } } @@ -556,11 +567,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> { @@ -576,6 +588,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( @@ -609,7 +627,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_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/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs index f22851d76b3..c84256f8ff3 100644 --- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs +++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs @@ -8,7 +8,7 @@ use rustc_infer::infer::InferCtxt; use rustc_middle::mir::ConstraintCategory; use rustc_middle::traits::query::OutlivesBound; use rustc_middle::ty::{self, RegionVid, Ty}; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::{ErrorGuaranteed, Span, DUMMY_SP}; use rustc_trait_selection::traits::query::type_op::{self, TypeOp}; use std::rc::Rc; use type_op::TypeOpOutput; @@ -318,7 +318,8 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { .param_env .and(type_op::implied_outlives_bounds::ImpliedOutlivesBounds { ty }) .fully_perform(self.infcx, DUMMY_SP) - .unwrap_or_else(|_| bug!("failed to compute implied bounds {:?}", ty)); + .map_err(|_: ErrorGuaranteed| debug!("failed to compute implied bounds {:?}", ty)) + .ok()?; debug!(?bounds, ?constraints); self.add_outlives_bounds(bounds); constraints 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_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs index 9e834b83df4..6e3a4cae2f6 100644 --- a/compiler/rustc_codegen_llvm/src/abi.rs +++ b/compiler/rustc_codegen_llvm/src/abi.rs @@ -362,9 +362,14 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { // currently use this mode so we have to allow it -- but we absolutely // shouldn't let any more targets do that. // (Also see <https://github.com/rust-lang/rust/issues/115666>.) + // + // The unstable abi `PtxKernel` also uses Direct for now. + // It needs to switch to something else before stabilization can happen. + // (See issue: https://github.com/rust-lang/rust/issues/117271) assert!( - matches!(&*cx.tcx.sess.target.arch, "wasm32" | "wasm64"), - "`PassMode::Direct` for aggregates only allowed on wasm targets\nProblematic type: {:#?}", + matches!(&*cx.tcx.sess.target.arch, "wasm32" | "wasm64") + || self.conv == Conv::PtxKernel, + "`PassMode::Direct` for aggregates only allowed on wasm and `extern \"ptx-kernel\"` fns\nProblematic type: {:#?}", arg.layout, ); } diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index f16fe372a92..d8c89f5947f 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -22,7 +22,9 @@ use rustc_session::utils::NativeLibKind; /// need out of the shared crate context before we get rid of it. use rustc_session::{filesearch, Session}; use rustc_span::symbol::Symbol; -use rustc_target::spec::crt_objects::{CrtObjects, LinkSelfContainedDefault}; +use rustc_target::spec::crt_objects::CrtObjects; +use rustc_target::spec::LinkSelfContainedComponents; +use rustc_target::spec::LinkSelfContainedDefault; use rustc_target::spec::{Cc, LinkOutputKind, LinkerFlavor, Lld, PanicStrategy}; use rustc_target::spec::{RelocModel, RelroLevel, SanitizerSet, SplitDebuginfo}; @@ -728,6 +730,7 @@ fn link_natively<'a>( ) -> Result<(), ErrorGuaranteed> { info!("preparing {:?} to {:?}", crate_type, out_filename); let (linker_path, flavor) = linker_and_flavor(sess); + let self_contained_components = self_contained_components(sess, crate_type); let mut cmd = linker_with_args( &linker_path, flavor, @@ -737,6 +740,7 @@ fn link_natively<'a>( tmpdir, out_filename, codegen_results, + self_contained_components, )?; linker::disable_localization(&mut cmd); @@ -812,14 +816,14 @@ fn link_natively<'a>( "Linker does not support -static-pie command line option. Retrying with -static instead." ); // Mirror `add_(pre,post)_link_objects` to replace CRT objects. - let self_contained = self_contained(sess, crate_type); + let self_contained_crt_objects = self_contained_components.is_crt_objects_enabled(); let opts = &sess.target; - let pre_objects = if self_contained { + let pre_objects = if self_contained_crt_objects { &opts.pre_link_objects_self_contained } else { &opts.pre_link_objects }; - let post_objects = if self_contained { + let post_objects = if self_contained_crt_objects { &opts.post_link_objects_self_contained } else { &opts.post_link_objects @@ -830,7 +834,9 @@ fn link_natively<'a>( .iter() .copied() .flatten() - .map(|obj| get_object_file_path(sess, obj, self_contained).into_os_string()) + .map(|obj| { + get_object_file_path(sess, obj, self_contained_crt_objects).into_os_string() + }) .collect::<Vec<_>>() }; let pre_objects_static_pie = get_objects(pre_objects, LinkOutputKind::StaticPicExe); @@ -1710,26 +1716,43 @@ fn detect_self_contained_mingw(sess: &Session) -> bool { /// Various toolchain components used during linking are used from rustc distribution /// instead of being found somewhere on the host system. /// We only provide such support for a very limited number of targets. -fn self_contained(sess: &Session, crate_type: CrateType) -> bool { - if let Some(self_contained) = sess.opts.cg.link_self_contained.explicitly_set { - if sess.target.link_self_contained == LinkSelfContainedDefault::False { - sess.emit_err(errors::UnsupportedLinkSelfContained); - } - return self_contained; - } +fn self_contained_components(sess: &Session, crate_type: CrateType) -> LinkSelfContainedComponents { + // Turn the backwards compatible bool values for `self_contained` into fully inferred + // `LinkSelfContainedComponents`. + let self_contained = + if let Some(self_contained) = sess.opts.cg.link_self_contained.explicitly_set { + // Emit an error if the user requested self-contained mode on the CLI but the target + // explicitly refuses it. + if sess.target.link_self_contained.is_disabled() { + sess.emit_err(errors::UnsupportedLinkSelfContained); + } + self_contained + } else { + match sess.target.link_self_contained { + LinkSelfContainedDefault::False => false, + LinkSelfContainedDefault::True => true, + + LinkSelfContainedDefault::WithComponents(components) => { + // For target specs with explicitly enabled components, we can return them + // directly. + return components; + } - match sess.target.link_self_contained { - LinkSelfContainedDefault::False => false, - LinkSelfContainedDefault::True => true, - // FIXME: Find a better heuristic for "native musl toolchain is available", - // based on host and linker path, for example. - // (https://github.com/rust-lang/rust/pull/71769#issuecomment-626330237). - LinkSelfContainedDefault::Musl => sess.crt_static(Some(crate_type)), - LinkSelfContainedDefault::Mingw => { - sess.host == sess.target - && sess.target.vendor != "uwp" - && detect_self_contained_mingw(&sess) - } + // FIXME: Find a better heuristic for "native musl toolchain is available", + // based on host and linker path, for example. + // (https://github.com/rust-lang/rust/pull/71769#issuecomment-626330237). + LinkSelfContainedDefault::InferredForMusl => sess.crt_static(Some(crate_type)), + LinkSelfContainedDefault::InferredForMingw => { + sess.host == sess.target + && sess.target.vendor != "uwp" + && detect_self_contained_mingw(&sess) + } + } + }; + if self_contained { + LinkSelfContainedComponents::all() + } else { + LinkSelfContainedComponents::empty() } } @@ -1889,37 +1912,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() { @@ -2053,13 +2053,14 @@ fn linker_with_args<'a>( tmpdir: &Path, out_filename: &Path, codegen_results: &CodegenResults, + self_contained_components: LinkSelfContainedComponents, ) -> Result<Command, ErrorGuaranteed> { - let self_contained = self_contained(sess, crate_type); + let self_contained_crt_objects = self_contained_components.is_crt_objects_enabled(); let cmd = &mut *super::linker::get_linker( sess, path, flavor, - self_contained, + self_contained_components.are_any_components_enabled(), &codegen_results.crate_info.target_cpu, ); let link_output_kind = link_output_kind(sess, crate_type); @@ -2086,7 +2087,7 @@ fn linker_with_args<'a>( // ------------ Object code and libraries, order-dependent ------------ // Pre-link CRT objects. - add_pre_link_objects(cmd, sess, flavor, link_output_kind, self_contained); + add_pre_link_objects(cmd, sess, flavor, link_output_kind, self_contained_crt_objects); add_linked_symbol_object( cmd, @@ -2229,7 +2230,7 @@ fn linker_with_args<'a>( cmd, sess, link_output_kind, - self_contained, + self_contained_components, flavor, crate_type, codegen_results, @@ -2245,7 +2246,7 @@ fn linker_with_args<'a>( // ------------ Object code and libraries, order-dependent ------------ // Post-link CRT objects. - add_post_link_objects(cmd, sess, link_output_kind, self_contained); + add_post_link_objects(cmd, sess, link_output_kind, self_contained_crt_objects); // ------------ Late order-dependent options ------------ @@ -2262,7 +2263,7 @@ fn add_order_independent_options( cmd: &mut dyn Linker, sess: &Session, link_output_kind: LinkOutputKind, - self_contained: bool, + self_contained_components: LinkSelfContainedComponents, flavor: LinkerFlavor, crate_type: CrateType, codegen_results: &CodegenResults, @@ -2270,7 +2271,7 @@ fn add_order_independent_options( tmpdir: &Path, ) { // Take care of the flavors and CLI options requesting the `lld` linker. - add_lld_args(cmd, sess, flavor); + add_lld_args(cmd, sess, flavor, self_contained_components); add_apple_sdk(cmd, sess, flavor); @@ -2295,7 +2296,7 @@ fn add_order_independent_options( // Make the binary compatible with data execution prevention schemes. cmd.add_no_exec(); - if self_contained { + if self_contained_components.is_crt_objects_enabled() { cmd.no_crt_objects(); } @@ -2326,7 +2327,7 @@ fn add_order_independent_options( cmd.linker_plugin_lto(); - add_library_search_dirs(cmd, sess, self_contained); + add_library_search_dirs(cmd, sess, self_contained_components.are_any_components_enabled()); cmd.output_filename(out_filename); @@ -2976,8 +2977,16 @@ fn get_apple_sdk_root(sdk_name: &str) -> Result<String, errors::AppleSdkRootErro /// invoke it: /// - when the self-contained linker flag is active: the build of `lld` distributed with rustc, /// - or any `lld` available to `cc`. -fn add_lld_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) { - debug!("add_lld_args requested, flavor: '{flavor:?}'"); +fn add_lld_args( + cmd: &mut dyn Linker, + sess: &Session, + flavor: LinkerFlavor, + self_contained_components: LinkSelfContainedComponents, +) { + debug!( + "add_lld_args requested, flavor: '{:?}', target self-contained components: {:?}", + flavor, self_contained_components, + ); // If the flavor doesn't use a C/C++ compiler to invoke the linker, or doesn't opt in to `lld`, // we don't need to do anything. @@ -2986,9 +2995,32 @@ fn add_lld_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) { } // 1. Implement the "self-contained" part of this feature by adding rustc distribution - // directories to the tool's search path: - // - if the self-contained linker is enabled on the CLI. - if sess.opts.cg.link_self_contained.is_linker_enabled() { + // directories to the tool's search path, depending on a mix between what users can specify on + // the CLI, and what the target spec enables (as it can't disable components): + // - if the self-contained linker is enabled on the CLI or by the target spec, + // - and if the self-contained linker is not disabled on the CLI. + let self_contained_cli = sess.opts.cg.link_self_contained.is_linker_enabled(); + let self_contained_target = self_contained_components.is_linker_enabled(); + + // FIXME: in the future, codegen backends may need to have more control over this process: they + // don't always support all the features the linker expects here, and vice versa. For example, + // at the time of writing this, lld expects a newer style of aarch64 TLS relocations that + // cranelift doesn't implement yet. That in turn can impact whether linking would succeed on + // such a target when using the `cg_clif` backend and lld. + // + // Until interactions between backends and linker features are expressible, we limit target + // specs to opt-in to lld only when we're on the llvm backend, where it's expected to work and + // tested on CI. As usual, the CLI still has precedence over this, so that users and developers + // can still override this default when needed (e.g. for tests). + let uses_llvm_backend = + matches!(sess.opts.unstable_opts.codegen_backend.as_deref(), None | Some("llvm")); + if !uses_llvm_backend && !self_contained_cli && sess.opts.cg.linker_flavor.is_none() { + // We bail if we're not using llvm and lld was not explicitly requested on the CLI. + return; + } + + let self_contained_linker = self_contained_cli || self_contained_target; + if self_contained_linker && !sess.opts.cg.link_self_contained.is_linker_disabled() { for path in sess.get_tools_search_paths(false) { cmd.arg({ let mut arg = OsString::from("-B"); 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_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..c6c8fd22f4e 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; @@ -136,7 +136,6 @@ pub static DEFAULT_LOCALE_RESOURCES: &[&str] = &[ rustc_query_system::DEFAULT_LOCALE_RESOURCE, rustc_resolve::DEFAULT_LOCALE_RESOURCE, rustc_session::DEFAULT_LOCALE_RESOURCE, - rustc_symbol_mangling::DEFAULT_LOCALE_RESOURCE, rustc_trait_selection::DEFAULT_LOCALE_RESOURCE, rustc_ty_utils::DEFAULT_LOCALE_RESOURCE, // tidy-alphabetical-end @@ -223,11 +222,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 +265,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 +292,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 +337,7 @@ fn run_compiler( override_queries: None, make_codegen_backend, registry: diagnostics_registry(), + using_internal_features, expanded_args: args, }; @@ -1333,8 +1355,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 +1371,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 +1422,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 +1435,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 +1457,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 +1545,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 +1555,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_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index da74ee6391a..5e3fdf170bc 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -508,6 +508,8 @@ pub enum StashKey { TraitMissingMethod, OpaqueHiddenTypeMismatch, MaybeForgetReturn, + /// Query cycle detected, stashing in favor of a better error. + Cycle, } fn default_track_diagnostic(d: &mut Diagnostic, f: &mut dyn FnMut(&mut Diagnostic)) { 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_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index f8d55192a37..17c6352ce24 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -246,6 +246,8 @@ impl<'hir> PathSegment<'hir> { pub struct ConstArg { pub value: AnonConst, pub span: Span, + /// Indicates whether this comes from a `~const` desugaring. + pub is_desugared_from_effects: bool, } #[derive(Clone, Copy, Debug, HashStable_Generic)] @@ -400,7 +402,14 @@ impl<'hir> GenericArgs<'hir> { /// This function returns the number of type and const generic params. /// It should only be used for diagnostics. pub fn num_generic_params(&self) -> usize { - self.args.iter().filter(|arg| !matches!(arg, GenericArg::Lifetime(_))).count() + self.args + .iter() + .filter(|arg| match arg { + GenericArg::Lifetime(_) + | GenericArg::Const(ConstArg { is_desugared_from_effects: true, .. }) => false, + _ => true, + }) + .count() } /// The span encompassing the text inside the surrounding brackets. @@ -1511,7 +1520,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 +1529,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 +3779,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/src/astconv/generics.rs b/compiler/rustc_hir_analysis/src/astconv/generics.rs index 7f0c0b961e4..d29a27eced0 100644 --- a/compiler/rustc_hir_analysis/src/astconv/generics.rs +++ b/compiler/rustc_hir_analysis/src/astconv/generics.rs @@ -429,6 +429,14 @@ pub(crate) fn check_generic_arg_count( .filter(|param| matches!(param.kind, ty::GenericParamDefKind::Type { synthetic: true, .. })) .count(); let named_type_param_count = param_counts.types - has_self as usize - synth_type_param_count; + let synth_const_param_count = gen_params + .params + .iter() + .filter(|param| { + matches!(param.kind, ty::GenericParamDefKind::Const { is_host_effect: true, .. }) + }) + .count(); + let named_const_param_count = param_counts.consts - synth_const_param_count; let infer_lifetimes = (gen_pos != GenericArgPosition::Type || infer_args) && !gen_args.has_lifetime_params(); @@ -573,11 +581,13 @@ pub(crate) fn check_generic_arg_count( debug!(?expected_min); debug!(arg_counts.lifetimes=?gen_args.num_lifetime_params()); + let provided = gen_args.num_generic_params(); + check_types_and_consts( expected_min, - param_counts.consts + named_type_param_count, - param_counts.consts + named_type_param_count + synth_type_param_count, - gen_args.num_generic_params(), + named_const_param_count + named_type_param_count, + named_const_param_count + named_type_param_count + synth_type_param_count, + provided, param_counts.lifetimes + has_self as usize, gen_args.num_lifetime_params(), ) 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/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 f379e8477e3..abb83228030 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -962,38 +962,29 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected: Ty<'tcx>, found: Ty<'tcx>, ) -> bool { - let ty::Adt(e, args_e) = expected.kind() else { - return false; - }; - let ty::Adt(f, args_f) = found.kind() else { - return false; - }; - if e.did() != f.did() { - return false; - } - if Some(e.did()) != self.tcx.get_diagnostic_item(sym::Result) { - return false; - } let map = self.tcx.hir(); - if let Some(hir::Node::Expr(expr)) = map.find_parent(expr.hir_id) - && let hir::ExprKind::Ret(_) = expr.kind - { - // `return foo;` - } else if map.get_return_block(expr.hir_id).is_some() { - // Function's tail expression. - } else { - return false; - } - let e = args_e.type_at(1); - let f = args_f.type_at(1); - if self - .infcx - .type_implements_trait( - self.tcx.get_diagnostic_item(sym::Into).unwrap(), - [f, e], - self.param_env, - ) - .must_apply_modulo_regions() + let returned = matches!( + map.find_parent(expr.hir_id), + Some(hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Ret(_), .. })) + ) || map.get_return_block(expr.hir_id).is_some(); + if returned + && let ty::Adt(e, args_e) = expected.kind() + && let ty::Adt(f, args_f) = found.kind() + && e.did() == f.did() + && Some(e.did()) == self.tcx.get_diagnostic_item(sym::Result) + && let e_ok = args_e.type_at(0) + && let f_ok = args_f.type_at(0) + && self.infcx.can_eq(self.param_env, f_ok, e_ok) + && let e_err = args_e.type_at(1) + && let f_err = args_f.type_at(1) + && self + .infcx + .type_implements_trait( + self.tcx.get_diagnostic_item(sym::Into).unwrap(), + [f_err, e_err], + self.param_env, + ) + .must_apply_modulo_regions() { err.multipart_suggestion( "use `?` to coerce and return an appropriate `Err`, and wrap the resulting value \ 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 13aa6454bc3..ca7dc298de6 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -10,8 +10,8 @@ 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}; @@ -536,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 @@ -1747,19 +1747,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected: Ty<'tcx>, found: Ty<'tcx>, ) -> bool { - let ty::Adt(adt, args) = found.kind() else { return false }; + let ty::Adt(adt, args) = found.kind() else { + return false; + }; let ret_ty_matches = |diagnostic_item| { - if let Some(ret_ty) = self - .ret_coercion - .as_ref() - .map(|c| self.resolve_vars_if_possible(c.borrow().expected_ty())) - && let ty::Adt(kind, _) = ret_ty.kind() - && self.tcx.get_diagnostic_item(diagnostic_item) == Some(kind.did()) - { - true - } else { - false - } + 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()`, diff --git a/compiler/rustc_incremental/src/lib.rs b/compiler/rustc_incremental/src/lib.rs index bdae07a3946..dde138973b9 100644 --- a/compiler/rustc_incremental/src/lib.rs +++ b/compiler/rustc_incremental/src/lib.rs @@ -5,7 +5,6 @@ #![cfg_attr(not(bootstrap), doc(rust_logo))] #![cfg_attr(not(bootstrap), feature(rustdoc_internals))] #![cfg_attr(not(bootstrap), allow(internal_features))] -#![feature(never_type)] #![recursion_limit = "256"] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] @@ -19,15 +18,11 @@ mod assert_dep_graph; mod errors; mod persist; -use assert_dep_graph::assert_dep_graph; pub use persist::copy_cgu_workproduct_to_incr_comp_cache_dir; -pub use persist::delete_workproduct_files; pub use persist::finalize_session_directory; -pub use persist::garbage_collect_session_directories; pub use persist::in_incr_comp_dir; pub use persist::in_incr_comp_dir_sess; pub use persist::load_query_result_cache; -pub use persist::prepare_session_directory; pub use persist::save_dep_graph; pub use persist::save_work_product_index; pub use persist::setup_dep_graph; diff --git a/compiler/rustc_incremental/src/persist/fs.rs b/compiler/rustc_incremental/src/persist/fs.rs index db8ea2bfe48..f56fb0d0534 100644 --- a/compiler/rustc_incremental/src/persist/fs.rs +++ b/compiler/rustc_incremental/src/persist/fs.rs @@ -53,7 +53,7 @@ //! ## Synchronization //! //! There is some synchronization needed in order for the compiler to be able to -//! determine whether a given private session directory is not in used any more. +//! determine whether a given private session directory is not in use any more. //! This is done by creating a lock file for each session directory and //! locking it while the directory is still being used. Since file locks have //! operating system support, we can rely on the lock being released if the @@ -136,26 +136,29 @@ const QUERY_CACHE_FILENAME: &str = "query-cache.bin"; const INT_ENCODE_BASE: usize = base_n::CASE_INSENSITIVE; /// Returns the path to a session's dependency graph. -pub fn dep_graph_path(sess: &Session) -> PathBuf { +pub(crate) fn dep_graph_path(sess: &Session) -> PathBuf { in_incr_comp_dir_sess(sess, DEP_GRAPH_FILENAME) } + /// Returns the path to a session's staging dependency graph. /// /// On the difference between dep-graph and staging dep-graph, /// see `build_dep_graph`. -pub fn staging_dep_graph_path(sess: &Session) -> PathBuf { +pub(crate) fn staging_dep_graph_path(sess: &Session) -> PathBuf { in_incr_comp_dir_sess(sess, STAGING_DEP_GRAPH_FILENAME) } -pub fn work_products_path(sess: &Session) -> PathBuf { + +pub(crate) fn work_products_path(sess: &Session) -> PathBuf { in_incr_comp_dir_sess(sess, WORK_PRODUCTS_FILENAME) } + /// Returns the path to a session's query cache. pub fn query_cache_path(sess: &Session) -> PathBuf { in_incr_comp_dir_sess(sess, QUERY_CACHE_FILENAME) } /// Locks a given session directory. -pub fn lock_file_path(session_dir: &Path) -> PathBuf { +fn lock_file_path(session_dir: &Path) -> PathBuf { let crate_dir = session_dir.parent().unwrap(); let directory_name = session_dir.file_name().unwrap().to_string_lossy(); @@ -202,7 +205,7 @@ pub fn in_incr_comp_dir(incr_comp_session_dir: &Path, file_name: &str) -> PathBu /// The garbage collection will take care of it. /// /// [`rustc_interface::queries::dep_graph`]: ../../rustc_interface/struct.Queries.html#structfield.dep_graph -pub fn prepare_session_directory( +pub(crate) fn prepare_session_directory( sess: &Session, crate_name: Symbol, stable_crate_id: StableCrateId, @@ -373,7 +376,7 @@ pub fn finalize_session_directory(sess: &Session, svh: Option<Svh>) { let _ = garbage_collect_session_directories(sess); } -pub fn delete_all_session_dir_contents(sess: &Session) -> io::Result<()> { +pub(crate) fn delete_all_session_dir_contents(sess: &Session) -> io::Result<()> { let sess_dir_iterator = sess.incr_comp_session_dir().read_dir()?; for entry in sess_dir_iterator { let entry = entry?; @@ -621,7 +624,7 @@ fn is_old_enough_to_be_collected(timestamp: SystemTime) -> bool { } /// Runs garbage collection for the current session. -pub fn garbage_collect_session_directories(sess: &Session) -> io::Result<()> { +pub(crate) fn garbage_collect_session_directories(sess: &Session) -> io::Result<()> { debug!("garbage_collect_session_directories() - begin"); let session_directory = sess.incr_comp_session_dir(); diff --git a/compiler/rustc_incremental/src/persist/load.rs b/compiler/rustc_incremental/src/persist/load.rs index 2310d0b12ef..cbd55fe4205 100644 --- a/compiler/rustc_incremental/src/persist/load.rs +++ b/compiler/rustc_incremental/src/persist/load.rs @@ -1,4 +1,4 @@ -//! Code to save/load the dep-graph from files. +//! Code to load the dep-graph from files. use crate::errors; use rustc_data_structures::memmap::Mmap; diff --git a/compiler/rustc_incremental/src/persist/mod.rs b/compiler/rustc_incremental/src/persist/mod.rs index fdecaca5a2d..94c05f4a2c8 100644 --- a/compiler/rustc_incremental/src/persist/mod.rs +++ b/compiler/rustc_incremental/src/persist/mod.rs @@ -11,14 +11,11 @@ mod save; mod work_product; pub use fs::finalize_session_directory; -pub use fs::garbage_collect_session_directories; pub use fs::in_incr_comp_dir; pub use fs::in_incr_comp_dir_sess; -pub use fs::prepare_session_directory; pub use load::load_query_result_cache; pub use load::setup_dep_graph; pub use load::LoadResult; pub use save::save_dep_graph; pub use save::save_work_product_index; pub use work_product::copy_cgu_workproduct_to_incr_comp_cache_dir; -pub use work_product::delete_workproduct_files; diff --git a/compiler/rustc_incremental/src/persist/save.rs b/compiler/rustc_incremental/src/persist/save.rs index 210da751d95..fa21320be26 100644 --- a/compiler/rustc_incremental/src/persist/save.rs +++ b/compiler/rustc_incremental/src/persist/save.rs @@ -1,3 +1,4 @@ +use crate::assert_dep_graph::assert_dep_graph; use crate::errors; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::sync::join; @@ -39,7 +40,7 @@ pub fn save_dep_graph(tcx: TyCtxt<'_>) { let dep_graph_path = dep_graph_path(sess); let staging_dep_graph_path = staging_dep_graph_path(sess); - sess.time("assert_dep_graph", || crate::assert_dep_graph(tcx)); + sess.time("assert_dep_graph", || assert_dep_graph(tcx)); sess.time("check_dirty_clean", || dirty_clean::check_dirty_clean_annotations(tcx)); if sess.opts.unstable_opts.incremental_info { diff --git a/compiler/rustc_incremental/src/persist/work_product.rs b/compiler/rustc_incremental/src/persist/work_product.rs index bce5ca1e16b..fb96bed5a71 100644 --- a/compiler/rustc_incremental/src/persist/work_product.rs +++ b/compiler/rustc_incremental/src/persist/work_product.rs @@ -11,7 +11,8 @@ use rustc_session::Session; use std::fs as std_fs; use std::path::Path; -/// Copies a CGU work product to the incremental compilation directory, so next compilation can find and reuse it. +/// Copies a CGU work product to the incremental compilation directory, so next compilation can +/// find and reuse it. pub fn copy_cgu_workproduct_to_incr_comp_cache_dir( sess: &Session, cgu_name: &str, @@ -45,7 +46,7 @@ pub fn copy_cgu_workproduct_to_incr_comp_cache_dir( } /// Removes files for a given work product. -pub fn delete_workproduct_files(sess: &Session, work_product: &WorkProduct) { +pub(crate) fn delete_workproduct_files(sess: &Session, work_product: &WorkProduct) { for (_, path) in work_product.saved_files.items().into_sorted_stable_ord() { let path = in_incr_comp_dir_sess(sess, path); if let Err(err) = std_fs::remove_file(&path) { 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/error_reporting/note_and_explain.rs b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs index 00289f9bfb4..a8ae43d5297 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs @@ -54,13 +54,17 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } (ty::Param(expected), ty::Param(found)) => { let generics = tcx.generics_of(body_owner_def_id); - let e_span = tcx.def_span(generics.type_param(expected, tcx).def_id); - if !sp.contains(e_span) { - diag.span_label(e_span, "expected type parameter"); + if let Some(param) = generics.opt_type_param(expected, tcx) { + let e_span = tcx.def_span(param.def_id); + if !sp.contains(e_span) { + diag.span_label(e_span, "expected type parameter"); + } } - let f_span = tcx.def_span(generics.type_param(found, tcx).def_id); - if !sp.contains(f_span) { - diag.span_label(f_span, "found type parameter"); + if let Some(param) = generics.opt_type_param(found, tcx) { + let f_span = tcx.def_span(param.def_id); + if !sp.contains(f_span) { + diag.span_label(f_span, "found type parameter"); + } } diag.note( "a type parameter was expected, but a different one was found; \ @@ -83,23 +87,29 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { | (ty::Alias(ty::Projection, proj), ty::Param(p)) if !tcx.is_impl_trait_in_trait(proj.def_id) => { - let p_def_id = tcx.generics_of(body_owner_def_id).type_param(p, tcx).def_id; - let p_span = tcx.def_span(p_def_id); - let expected = match (values.expected.kind(), values.found.kind()) { - (ty::Param(_), _) => "expected ", - (_, ty::Param(_)) => "found ", - _ => "", - }; - if !sp.contains(p_span) { - diag.span_label(p_span, format!("{expected}this type parameter")); - } - let hir = tcx.hir(); + let parent = tcx.generics_of(body_owner_def_id) + .opt_type_param(p, tcx) + .and_then(|param| { + let p_def_id = param.def_id; + let p_span = tcx.def_span(p_def_id); + let expected = match (values.expected.kind(), values.found.kind()) { + (ty::Param(_), _) => "expected ", + (_, ty::Param(_)) => "found ", + _ => "", + }; + if !sp.contains(p_span) { + diag.span_label( + p_span, + format!("{expected}this type parameter"), + ); + } + p_def_id.as_local().and_then(|id| { + let local_id = tcx.hir().local_def_id_to_hir_id(id); + let generics = tcx.hir().find_parent(local_id)?.generics()?; + Some((id, generics)) + }) + }); let mut note = true; - let parent = p_def_id.as_local().and_then(|id| { - let local_id = hir.local_def_id_to_hir_id(id); - let generics = tcx.hir().find_parent(local_id)?.generics()?; - Some((id, generics)) - }); if let Some((local_id, generics)) = parent { // Synthesize the associated type restriction `Add<Output = Expected>`. // FIXME: extract this logic for use in other diagnostics. @@ -172,14 +182,16 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { (ty::Param(p), ty::Dynamic(..) | ty::Alias(ty::Opaque, ..)) | (ty::Dynamic(..) | ty::Alias(ty::Opaque, ..), ty::Param(p)) => { let generics = tcx.generics_of(body_owner_def_id); - let p_span = tcx.def_span(generics.type_param(p, tcx).def_id); - let expected = match (values.expected.kind(), values.found.kind()) { - (ty::Param(_), _) => "expected ", - (_, ty::Param(_)) => "found ", - _ => "", - }; - if !sp.contains(p_span) { - diag.span_label(p_span, format!("{expected}this type parameter")); + if let Some(param) = generics.opt_type_param(p, tcx) { + let p_span = tcx.def_span(param.def_id); + let expected = match (values.expected.kind(), values.found.kind()) { + (ty::Param(_), _) => "expected ", + (_, ty::Param(_)) => "found ", + _ => "", + }; + if !sp.contains(p_span) { + diag.span_label(p_span, format!("{expected}this type parameter")); + } } diag.help("type parameters must be constrained to match other types"); if tcx.sess.teach(&diag.get_code().unwrap()) { @@ -217,9 +229,11 @@ impl<T> Trait<T> for X { } (ty::Param(p), ty::Closure(..) | ty::Coroutine(..)) => { let generics = tcx.generics_of(body_owner_def_id); - let p_span = tcx.def_span(generics.type_param(p, tcx).def_id); - if !sp.contains(p_span) { - diag.span_label(p_span, "expected this type parameter"); + if let Some(param) = generics.opt_type_param(p, tcx) { + let p_span = tcx.def_span(param.def_id); + if !sp.contains(p_span) { + diag.span_label(p_span, "expected this type parameter"); + } } diag.help(format!( "every closure has a distinct type and so could not always match the \ @@ -228,14 +242,16 @@ impl<T> Trait<T> for X { } (ty::Param(p), _) | (_, ty::Param(p)) => { let generics = tcx.generics_of(body_owner_def_id); - let p_span = tcx.def_span(generics.type_param(p, tcx).def_id); - let expected = match (values.expected.kind(), values.found.kind()) { - (ty::Param(_), _) => "expected ", - (_, ty::Param(_)) => "found ", - _ => "", - }; - if !sp.contains(p_span) { - diag.span_label(p_span, format!("{expected}this type parameter")); + if let Some(param) = generics.opt_type_param(p, tcx) { + let p_span = tcx.def_span(param.def_id); + let expected = match (values.expected.kind(), values.found.kind()) { + (ty::Param(_), _) => "expected ", + (_, ty::Param(_)) => "found ", + _ => "", + }; + if !sp.contains(p_span) { + diag.span_label(p_span, format!("{expected}this type parameter")); + } } } (ty::Alias(ty::Projection | ty::Inherent, proj_ty), _) @@ -364,13 +380,14 @@ impl<T> Trait<T> for X { }; // Get the `DefId` for the type parameter corresponding to `A` in `<A as T>::Foo`. // This will also work for `impl Trait`. - let def_id = if let ty::Param(param_ty) = proj_ty.self_ty().kind() { - let generics = tcx.generics_of(body_owner_def_id); - generics.type_param(param_ty, tcx).def_id - } else { + let ty::Param(param_ty) = proj_ty.self_ty().kind() else { return false; }; - let Some(def_id) = def_id.as_local() else { + let generics = tcx.generics_of(body_owner_def_id); + let Some(param) = generics.opt_type_param(param_ty, tcx) else { + return false; + }; + let Some(def_id) = param.def_id.as_local() else { return false; }; @@ -390,6 +407,10 @@ impl<T> Trait<T> for X { return true; } } + if (param_ty.index as usize) >= generics.parent_count { + // The param comes from the current item, do not look at the parent. (#117209) + return false; + } // If associated item, look to constrain the params of the trait/impl. let hir_id = match item { hir::Node::ImplItem(item) => item.hir_id(), 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 998e2686005..884afae23d8 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -856,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..3d191669b1a 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) @@ -612,7 +614,7 @@ fn test_codegen_options_tracking_hash() { tracked!(force_frame_pointers, Some(false)); tracked!(force_unwind_tables, Some(true)); tracked!(inline_threshold, Some(0xf007ba11)); - tracked!(instrument_coverage, Some(InstrumentCoverage::All)); + tracked!(instrument_coverage, InstrumentCoverage::All); tracked!(link_dead_code, Some(true)); tracked!(linker_plugin_lto, LinkerPluginLto::LinkerPluginAuto); tracked!(llvm_args, vec![String::from("1"), String::from("2")]); @@ -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_macros/src/lib.rs b/compiler/rustc_macros/src/lib.rs index 85829906f4e..776ba8f9ca1 100644 --- a/compiler/rustc_macros/src/lib.rs +++ b/compiler/rustc_macros/src/lib.rs @@ -4,6 +4,7 @@ #![feature(never_type)] #![feature(proc_macro_diagnostic)] #![feature(proc_macro_span)] +#![feature(proc_macro_tracked_env)] #![allow(rustc::default_hash_types)] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs index d8a695b131b..ad1980136f3 100644 --- a/compiler/rustc_macros/src/query.rs +++ b/compiler/rustc_macros/src/query.rs @@ -97,6 +97,9 @@ struct QueryModifiers { /// A cycle error results in a delay_bug call cycle_delay_bug: Option<Ident>, + /// A cycle error results in a stashed cycle error that can be unstashed and canceled later + cycle_stash: Option<Ident>, + /// Don't hash the result, instead just mark a query red if it runs no_hash: Option<Ident>, @@ -127,6 +130,7 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result<QueryModifiers> { let mut desc = None; let mut fatal_cycle = None; let mut cycle_delay_bug = None; + let mut cycle_stash = None; let mut no_hash = None; let mut anon = None; let mut eval_always = None; @@ -181,6 +185,8 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result<QueryModifiers> { try_insert!(fatal_cycle = modifier); } else if modifier == "cycle_delay_bug" { try_insert!(cycle_delay_bug = modifier); + } else if modifier == "cycle_stash" { + try_insert!(cycle_stash = modifier); } else if modifier == "no_hash" { try_insert!(no_hash = modifier); } else if modifier == "anon" { @@ -208,6 +214,7 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result<QueryModifiers> { desc, fatal_cycle, cycle_delay_bug, + cycle_stash, no_hash, anon, eval_always, @@ -329,6 +336,7 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream { fatal_cycle, arena_cache, cycle_delay_bug, + cycle_stash, no_hash, anon, eval_always, diff --git a/compiler/rustc_macros/src/symbols.rs b/compiler/rustc_macros/src/symbols.rs index 04facbf657d..4129712a6b2 100644 --- a/compiler/rustc_macros/src/symbols.rs +++ b/compiler/rustc_macros/src/symbols.rs @@ -26,7 +26,7 @@ use proc_macro2::{Span, TokenStream}; use quote::quote; use std::collections::HashMap; use syn::parse::{Parse, ParseStream, Result}; -use syn::{braced, punctuated::Punctuated, Ident, LitStr, Token}; +use syn::{braced, punctuated::Punctuated, Expr, Ident, Lit, LitStr, Macro, Token}; #[cfg(test)] mod tests; @@ -53,21 +53,46 @@ impl Parse for Keyword { struct Symbol { name: Ident, - value: Option<LitStr>, + value: Value, +} + +enum Value { + SameAsName, + String(LitStr), + Env(LitStr, Macro), + Unsupported(Expr), } impl Parse for Symbol { fn parse(input: ParseStream<'_>) -> Result<Self> { let name = input.parse()?; - let value = match input.parse::<Token![:]>() { - Ok(_) => Some(input.parse()?), - Err(_) => None, - }; + let colon_token: Option<Token![:]> = input.parse()?; + let value = if colon_token.is_some() { input.parse()? } else { Value::SameAsName }; Ok(Symbol { name, value }) } } +impl Parse for Value { + fn parse(input: ParseStream<'_>) -> Result<Self> { + let expr: Expr = input.parse()?; + match &expr { + Expr::Lit(expr) => { + if let Lit::Str(lit) = &expr.lit { + return Ok(Value::String(lit.clone())); + } + } + Expr::Macro(expr) => { + if expr.mac.path.is_ident("env") && let Ok(lit) = expr.mac.parse_body() { + return Ok(Value::Env(lit, expr.mac.clone())); + } + } + _ => {} + } + Ok(Value::Unsupported(expr)) + } +} + struct Input { keywords: Punctuated<Keyword, Token![,]>, symbols: Punctuated<Symbol, Token![,]>, @@ -111,6 +136,37 @@ pub fn symbols(input: TokenStream) -> TokenStream { output } +struct Preinterned { + idx: u32, + span_of_name: Span, +} + +struct Entries { + map: HashMap<String, Preinterned>, +} + +impl Entries { + fn with_capacity(capacity: usize) -> Self { + Entries { map: HashMap::with_capacity(capacity) } + } + + fn insert(&mut self, span: Span, str: &str, errors: &mut Errors) -> u32 { + if let Some(prev) = self.map.get(str) { + errors.error(span, format!("Symbol `{str}` is duplicated")); + errors.error(prev.span_of_name, "location of previous definition".to_string()); + prev.idx + } else { + let idx = self.len(); + self.map.insert(str.to_string(), Preinterned { idx, span_of_name: span }); + idx + } + } + + fn len(&self) -> u32 { + u32::try_from(self.map.len()).expect("way too many symbols") + } +} + fn symbols_with_errors(input: TokenStream) -> (TokenStream, Vec<syn::Error>) { let mut errors = Errors::default(); @@ -127,20 +183,9 @@ fn symbols_with_errors(input: TokenStream) -> (TokenStream, Vec<syn::Error>) { let mut keyword_stream = quote! {}; let mut symbols_stream = quote! {}; let mut prefill_stream = quote! {}; - let mut counter = 0u32; - let mut keys = - HashMap::<String, Span>::with_capacity(input.keywords.len() + input.symbols.len() + 10); + let mut entries = Entries::with_capacity(input.keywords.len() + input.symbols.len() + 10); let mut prev_key: Option<(Span, String)> = None; - let mut check_dup = |span: Span, str: &str, errors: &mut Errors| { - if let Some(prev_span) = keys.get(str) { - errors.error(span, format!("Symbol `{str}` is duplicated")); - errors.error(*prev_span, "location of previous definition".to_string()); - } else { - keys.insert(str.to_string(), span); - } - }; - let mut check_order = |span: Span, str: &str, errors: &mut Errors| { if let Some((prev_span, ref prev_str)) = prev_key { if str < prev_str { @@ -156,49 +201,98 @@ fn symbols_with_errors(input: TokenStream) -> (TokenStream, Vec<syn::Error>) { let name = &keyword.name; let value = &keyword.value; let value_string = value.value(); - check_dup(keyword.name.span(), &value_string, &mut errors); + let idx = entries.insert(keyword.name.span(), &value_string, &mut errors); prefill_stream.extend(quote! { #value, }); keyword_stream.extend(quote! { - pub const #name: Symbol = Symbol::new(#counter); + pub const #name: Symbol = Symbol::new(#idx); }); - counter += 1; } // Generate the listed symbols. for symbol in input.symbols.iter() { let name = &symbol.name; + check_order(symbol.name.span(), &name.to_string(), &mut errors); + let value = match &symbol.value { - Some(value) => value.value(), - None => name.to_string(), + Value::SameAsName => name.to_string(), + Value::String(lit) => lit.value(), + Value::Env(..) => continue, // in another loop below + Value::Unsupported(expr) => { + errors.list.push(syn::Error::new_spanned( + expr, + concat!( + "unsupported expression for symbol value; implement support for this in ", + file!(), + ), + )); + continue; + } }; - check_dup(symbol.name.span(), &value, &mut errors); - check_order(symbol.name.span(), &name.to_string(), &mut errors); + let idx = entries.insert(symbol.name.span(), &value, &mut errors); prefill_stream.extend(quote! { #value, }); symbols_stream.extend(quote! { - pub const #name: Symbol = Symbol::new(#counter); + pub const #name: Symbol = Symbol::new(#idx); }); - counter += 1; } // Generate symbols for the strings "0", "1", ..., "9". - let digits_base = counter; - counter += 10; for n in 0..10 { let n = n.to_string(); - check_dup(Span::call_site(), &n, &mut errors); + entries.insert(Span::call_site(), &n, &mut errors); prefill_stream.extend(quote! { #n, }); } + // Symbols whose value comes from an environment variable. It's allowed for + // these to have the same value as another symbol. + for symbol in &input.symbols { + let (env_var, expr) = match &symbol.value { + Value::Env(lit, expr) => (lit, expr), + Value::SameAsName | Value::String(_) | Value::Unsupported(_) => continue, + }; + + if !proc_macro::is_available() { + errors.error( + Span::call_site(), + "proc_macro::tracked_env is not available in unit test".to_owned(), + ); + break; + } + + let value = match proc_macro::tracked_env::var(env_var.value()) { + Ok(value) => value, + Err(err) => { + errors.list.push(syn::Error::new_spanned(expr, err)); + continue; + } + }; + + let idx = if let Some(prev) = entries.map.get(&value) { + prev.idx + } else { + prefill_stream.extend(quote! { + #value, + }); + entries.insert(symbol.name.span(), &value, &mut errors) + }; + + let name = &symbol.name; + symbols_stream.extend(quote! { + pub const #name: Symbol = Symbol::new(#idx); + }); + } + + let symbol_digits_base = entries.map["0"].idx; + let preinterned_symbols_count = entries.len(); let output = quote! { - const SYMBOL_DIGITS_BASE: u32 = #digits_base; - const PREINTERNED_SYMBOLS_COUNT: u32 = #counter; + const SYMBOL_DIGITS_BASE: u32 = #symbol_digits_base; + const PREINTERNED_SYMBOLS_COUNT: u32 = #preinterned_symbols_count; #[doc(hidden)] #[allow(non_upper_case_globals)] diff --git a/compiler/rustc_macros/src/symbols/tests.rs b/compiler/rustc_macros/src/symbols/tests.rs index bd0c08a53c4..9c53453df5b 100644 --- a/compiler/rustc_macros/src/symbols/tests.rs +++ b/compiler/rustc_macros/src/symbols/tests.rs @@ -27,7 +27,7 @@ fn test_symbols() { let body_tokens = m.mac.tokens.clone(); - test_symbols_macro(body_tokens, &[]); + test_symbols_macro(body_tokens, &["proc_macro::tracked_env is not available in unit test"]); } fn test_symbols_macro(input: TokenStream, expected_errors: &[&str]) { 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/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 23d77a1ebe4..062b03e71fd 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -251,6 +251,7 @@ rustc_queries! { "computing type of opaque `{path}`", path = tcx.def_path_str(key), } + cycle_stash } query type_alias_is_lazy(key: DefId) -> bool { @@ -341,7 +342,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/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/context.rs b/compiler/rustc_middle/src/ty/context.rs index 3c8bac2a9d3..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,10 +97,12 @@ 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; type AliasConst = ty::UnevaluatedConst<'tcx>; @@ -107,6 +111,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> { 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/flags.rs b/compiler/rustc_middle/src/ty/flags.rs index d75315b7ac9..a348e9f608a 100644 --- a/compiler/rustc_middle/src/ty/flags.rs +++ b/compiler/rustc_middle/src/ty/flags.rs @@ -134,7 +134,7 @@ impl FlagComputation { if should_remove_further_specializable { self.flags -= TypeFlags::STILL_FURTHER_SPECIALIZABLE; } - self.add_flags(TypeFlags::HAS_TY_GENERATOR); + self.add_flags(TypeFlags::HAS_TY_COROUTINE); } &ty::Closure(_, args) => { diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs index 44e88d3e230..888ee1d237a 100644 --- a/compiler/rustc_middle/src/ty/generics.rs +++ b/compiler/rustc_middle/src/ty/generics.rs @@ -237,6 +237,20 @@ impl<'tcx> Generics { } } + /// Returns the `GenericParamDef` with the given index if available. + pub fn opt_param_at( + &'tcx self, + param_index: usize, + tcx: TyCtxt<'tcx>, + ) -> Option<&'tcx GenericParamDef> { + if let Some(index) = param_index.checked_sub(self.parent_count) { + self.params.get(index) + } else { + tcx.generics_of(self.parent.expect("parent_count > 0 but no parent?")) + .opt_param_at(param_index, tcx) + } + } + pub fn params_to(&'tcx self, param_index: usize, tcx: TyCtxt<'tcx>) -> &'tcx [GenericParamDef] { if let Some(index) = param_index.checked_sub(self.parent_count) { &self.params[..index] @@ -268,6 +282,20 @@ impl<'tcx> Generics { } } + /// Returns the `GenericParamDef` associated with this `ParamTy` if it belongs to this + /// `Generics`. + pub fn opt_type_param( + &'tcx self, + param: &ParamTy, + tcx: TyCtxt<'tcx>, + ) -> Option<&'tcx GenericParamDef> { + let param = self.opt_param_at(param.index as usize, tcx)?; + match param.kind { + GenericParamDefKind::Type { .. } => Some(param), + _ => None, + } + } + /// Returns the `GenericParamDef` associated with this `ParamConst`. pub fn const_param(&'tcx self, param: &ParamConst, tcx: TyCtxt<'tcx>) -> &GenericParamDef { let param = self.param_at(param.index as usize, tcx); diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 769b374c793..739d4fa886e 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -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 diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 22648d853f4..433ac33f1b8 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -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 967f62cdbca..6af68bc5dba 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -185,43 +185,6 @@ 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 { WithInfcx::with_no_infcx(self).fmt(f) @@ -486,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, @@ -503,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, diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 53260a3996c..44592b10d55 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -32,10 +32,12 @@ use std::fmt; 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::*; @@ -47,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)] 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_middle/src/ty/visit.rs b/compiler/rustc_middle/src/ty/visit.rs index 15de9948644..ab0999b3f19 100644 --- a/compiler/rustc_middle/src/ty/visit.rs +++ b/compiler/rustc_middle/src/ty/visit.rs @@ -48,7 +48,7 @@ pub trait TypeVisitableExt<'tcx>: TypeVisitable<TyCtxt<'tcx>> { self.has_type_flags(TypeFlags::HAS_TY_OPAQUE) } fn has_coroutines(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_TY_GENERATOR) + self.has_type_flags(TypeFlags::HAS_TY_COROUTINE) } fn references_error(&self) -> bool { self.has_type_flags(TypeFlags::HAS_ERROR) 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 1cf8c202ea4..681e311a017 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -157,7 +157,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// [ 0. Pre-match ] /// | /// [ 1. Evaluate Scrutinee (expression being matched on) ] - /// [ (fake read of scrutinee) ] + /// [ (PlaceMention of scrutinee) ] /// | /// [ 2. Decision tree -- check discriminants ] <--------+ /// | | @@ -184,7 +184,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// /// We generate MIR in the following steps: /// - /// 1. Evaluate the scrutinee and add the fake read of it ([Builder::lower_scrutinee]). + /// 1. Evaluate the scrutinee and add the PlaceMention of it ([Builder::lower_scrutinee]). /// 2. Create the decision tree ([Builder::lower_match_tree]). /// 3. Determine the fake borrows that are needed from the places that were /// matched against and create the required temporaries for them @@ -223,6 +223,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let fake_borrow_temps = self.lower_match_tree( block, scrutinee_span, + &scrutinee_place, match_start_span, match_has_guard, &mut candidates, @@ -238,7 +239,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ) } - /// Evaluate the scrutinee and add the fake read of it. + /// Evaluate the scrutinee and add the PlaceMention for it. fn lower_scrutinee( &mut self, mut block: BasicBlock, @@ -246,26 +247,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { scrutinee_span: Span, ) -> BlockAnd<PlaceBuilder<'tcx>> { let scrutinee_place_builder = unpack!(block = self.as_place_builder(block, scrutinee)); - // Matching on a `scrutinee_place` with an uninhabited type doesn't - // generate any memory reads by itself, and so if the place "expression" - // contains unsafe operations like raw pointer dereferences or union - // field projections, we wouldn't know to require an `unsafe` block - // around a `match` equivalent to `std::intrinsics::unreachable()`. - // See issue #47412 for this hole being discovered in the wild. - // - // HACK(eddyb) Work around the above issue by adding a dummy inspection - // of `scrutinee_place`, specifically by applying `ReadForMatch`. - // - // NOTE: ReadForMatch also checks that the scrutinee is initialized. - // This is currently needed to not allow matching on an uninitialized, - // uninhabited value. If we get never patterns, those will check that - // the place is initialized, and so this read would only be used to - // check safety. - let cause_matched_place = FakeReadCause::ForMatchedPlace(None); - let source_info = self.source_info(scrutinee_span); - if let Some(scrutinee_place) = scrutinee_place_builder.try_to_place(self) { - self.cfg.push_fake_read(block, source_info, cause_matched_place, scrutinee_place); + let source_info = self.source_info(scrutinee_span); + self.cfg.push_place_mention(block, source_info, scrutinee_place); } block.and(scrutinee_place_builder) @@ -304,6 +288,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &mut self, block: BasicBlock, scrutinee_span: Span, + scrutinee_place_builder: &PlaceBuilder<'tcx>, match_start_span: Span, match_has_guard: bool, candidates: &mut [&mut Candidate<'pat, 'tcx>], @@ -331,6 +316,33 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // otherwise block. Match checking will ensure this is actually // unreachable. let source_info = self.source_info(scrutinee_span); + + // Matching on a `scrutinee_place` with an uninhabited type doesn't + // generate any memory reads by itself, and so if the place "expression" + // contains unsafe operations like raw pointer dereferences or union + // field projections, we wouldn't know to require an `unsafe` block + // around a `match` equivalent to `std::intrinsics::unreachable()`. + // See issue #47412 for this hole being discovered in the wild. + // + // HACK(eddyb) Work around the above issue by adding a dummy inspection + // of `scrutinee_place`, specifically by applying `ReadForMatch`. + // + // NOTE: ReadForMatch also checks that the scrutinee is initialized. + // This is currently needed to not allow matching on an uninitialized, + // uninhabited value. If we get never patterns, those will check that + // the place is initialized, and so this read would only be used to + // check safety. + let cause_matched_place = FakeReadCause::ForMatchedPlace(None); + + if let Some(scrutinee_place) = scrutinee_place_builder.try_to_place(self) { + self.cfg.push_fake_read( + otherwise_block, + source_info, + cause_matched_place, + scrutinee_place, + ); + } + self.cfg.terminate(otherwise_block, source_info, TerminatorKind::Unreachable); } @@ -599,13 +611,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } _ => { - let place_builder = unpack!(block = self.as_place_builder(block, initializer)); - - if let Some(place) = place_builder.try_to_place(self) { - let source_info = self.source_info(initializer.span); - self.cfg.push_place_mention(block, source_info, place); - } - + let place_builder = + unpack!(block = self.lower_scrutinee(block, initializer, initializer.span)); self.place_into_pattern(block, &irrefutable_pat, place_builder, true) } } @@ -622,6 +629,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let fake_borrow_temps = self.lower_match_tree( block, irrefutable_pat.span, + &initializer, irrefutable_pat.span, false, &mut [&mut candidate], @@ -1841,6 +1849,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let fake_borrow_temps = self.lower_match_tree( block, pat.span, + &expr_place_builder, pat.span, false, &mut [&mut guard_candidate, &mut otherwise_candidate], @@ -2342,6 +2351,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let fake_borrow_temps = this.lower_match_tree( block, initializer_span, + &scrutinee, pattern.span, false, &mut [&mut candidate, &mut wildcard], diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index 3265f92e514..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. @@ -128,7 +129,14 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> { 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; @@ -195,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), ); } @@ -481,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)] @@ -803,27 +811,37 @@ pub fn thir_check_unsafety(tcx: TyCtxt<'_>, def: LocalDefId) { } 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 2255220808e..186c77795e4 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs @@ -53,14 +53,13 @@ use smallvec::{smallvec, SmallVec}; use rustc_apfloat::ieee::{DoubleS, IeeeFloat, SingleS}; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxHashSet; -use rustc_hir::{HirId, RangeEnd}; +use rustc_hir::RangeEnd; use rustc_index::Idx; use rustc_middle::middle::stability::EvalResult; use rustc_middle::mir; use rustc_middle::thir::{FieldPat, Pat, PatKind, PatRange}; use rustc_middle::ty::layout::IntegerExt; use rustc_middle::ty::{self, Ty, TyCtxt, VariantDef}; -use rustc_session::lint; use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::{FieldIdx, Integer, VariantIdx, FIRST_VARIANT}; @@ -68,7 +67,6 @@ use self::Constructor::*; use self::SliceKind::*; use super::usefulness::{MatchCheckCtxt, PatCtxt}; -use crate::errors::{Overlap, OverlappingRangeEndpoints}; /// Recursively expand this pattern into its subpatterns. Only useful for or-patterns. fn expand_or_pat<'p, 'tcx>(pat: &'p Pat<'tcx>) -> Vec<&'p Pat<'tcx>> { @@ -111,15 +109,15 @@ pub(crate) struct IntRange { impl IntRange { #[inline] - fn is_integral(ty: Ty<'_>) -> bool { + pub(super) fn is_integral(ty: Ty<'_>) -> bool { matches!(ty.kind(), ty::Char | ty::Int(_) | ty::Uint(_) | ty::Bool) } - fn is_singleton(&self) -> bool { + pub(super) fn is_singleton(&self) -> bool { self.range.start() == self.range.end() } - fn boundaries(&self) -> (u128, u128) { + pub(super) fn boundaries(&self) -> (u128, u128) { (*self.range.start(), *self.range.end()) } @@ -177,23 +175,6 @@ impl IntRange { } } - fn suspicious_intersection(&self, other: &Self) -> bool { - // `false` in the following cases: - // 1 ---- // 1 ---------- // 1 ---- // 1 ---- - // 2 ---------- // 2 ---- // 2 ---- // 2 ---- - // - // The following are currently `false`, but could be `true` in the future (#64007): - // 1 --------- // 1 --------- - // 2 ---------- // 2 ---------- - // - // `true` in the following cases: - // 1 ------- // 1 ------- - // 2 -------- // 2 ------- - let (lo, hi) = self.boundaries(); - let (other_lo, other_hi) = other.boundaries(); - (lo == other_hi || hi == other_lo) && !self.is_singleton() && !other.is_singleton() - } - /// Partition a range of integers into disjoint subranges. This does constructor splitting for /// integer ranges as explained at the top of the file. /// @@ -293,7 +274,7 @@ impl IntRange { } /// Only used for displaying the range. - fn to_pat<'tcx>(&self, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Pat<'tcx> { + pub(super) fn to_pat<'tcx>(&self, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Pat<'tcx> { let (lo, hi) = self.boundaries(); let bias = IntRange::signed_bias(tcx, ty); @@ -315,51 +296,6 @@ impl IntRange { Pat { ty, span: DUMMY_SP, kind } } - - /// Lint on likely incorrect range patterns (#63987) - pub(super) fn lint_overlapping_range_endpoints<'a, 'p: 'a, 'tcx: 'a>( - &self, - pcx: &PatCtxt<'_, 'p, 'tcx>, - pats: impl Iterator<Item = &'a DeconstructedPat<'p, 'tcx>>, - column_count: usize, - lint_root: HirId, - ) { - if self.is_singleton() { - return; - } - - if column_count != 1 { - // FIXME: for now, only check for overlapping ranges on simple range - // patterns. Otherwise with the current logic the following is detected - // as overlapping: - // ``` - // match (0u8, true) { - // (0 ..= 125, false) => {} - // (125 ..= 255, true) => {} - // _ => {} - // } - // ``` - return; - } - - let overlap: Vec<_> = pats - .filter_map(|pat| Some((pat.ctor().as_int_range()?, pat.span()))) - .filter(|(range, _)| self.suspicious_intersection(range)) - .map(|(range, span)| Overlap { - range: self.intersection(&range).unwrap().to_pat(pcx.cx.tcx, pcx.ty), - span, - }) - .collect(); - - if !overlap.is_empty() { - pcx.cx.tcx.emit_spanned_lint( - lint::builtin::OVERLAPPING_RANGE_ENDPOINTS, - lint_root, - pcx.span, - OverlappingRangeEndpoints { overlap, range: pcx.span }, - ); - } - } } /// Note: this is often not what we want: e.g. `false` is converted into the range `0..=0` and @@ -644,7 +580,7 @@ impl<'tcx> Constructor<'tcx> { _ => None, } } - fn as_int_range(&self) -> Option<&IntRange> { + pub(super) fn as_int_range(&self) -> Option<&IntRange> { match self { IntRange(range) => Some(range), _ => None, diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs index 5218f772484..25e0f3ceaa4 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs @@ -307,8 +307,10 @@ use self::ArmType::*; use self::Usefulness::*; -use super::deconstruct_pat::{Constructor, ConstructorSet, DeconstructedPat, WitnessPat}; -use crate::errors::{NonExhaustiveOmittedPattern, Uncovered}; +use super::deconstruct_pat::{ + Constructor, ConstructorSet, DeconstructedPat, IntRange, SplitConstructorSet, WitnessPat, +}; +use crate::errors::{NonExhaustiveOmittedPattern, Overlap, OverlappingRangeEndpoints, Uncovered}; use rustc_data_structures::captures::Captures; @@ -317,6 +319,7 @@ use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir::def_id::DefId; use rustc_hir::HirId; use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_session::lint; use rustc_session::lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS; use rustc_span::{Span, DUMMY_SP}; @@ -473,11 +476,6 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> { Matrix { patterns: vec![] } } - /// Number of columns of this matrix. `None` is the matrix is empty. - pub(super) fn column_count(&self) -> Option<usize> { - self.patterns.get(0).map(|r| r.len()) - } - /// Pushes a new row to the matrix. If the row starts with an or-pattern, this recursively /// expands it. fn push(&mut self, row: PatStack<'p, 'tcx>) { @@ -833,15 +831,6 @@ fn is_useful<'p, 'tcx>( let v_ctor = v.head().ctor(); debug!(?v_ctor); - if let Constructor::IntRange(ctor_range) = &v_ctor { - // Lint on likely incorrect range patterns (#63987) - ctor_range.lint_overlapping_range_endpoints( - pcx, - matrix.heads(), - matrix.column_count().unwrap_or(0), - lint_root, - ) - } // We split the head constructor of `v`. let split_ctors = v_ctor.split(pcx, matrix.heads().map(DeconstructedPat::ctor)); // For each constructor, we compute whether there's a value that starts with it that would @@ -875,22 +864,102 @@ fn is_useful<'p, 'tcx>( ret } +/// A column of patterns in the matrix, where a column is the intuitive notion of "subpatterns that +/// inspect the same subvalue". +/// This is used to traverse patterns column-by-column for lints. Despite similarities with +/// `is_useful`, this is a different traversal. Notably this is linear in the depth of patterns, +/// whereas `is_useful` is worst-case exponential (exhaustiveness is NP-complete). +#[derive(Debug)] +struct PatternColumn<'p, 'tcx> { + patterns: Vec<&'p DeconstructedPat<'p, 'tcx>>, +} + +impl<'p, 'tcx> PatternColumn<'p, 'tcx> { + fn new(patterns: Vec<&'p DeconstructedPat<'p, 'tcx>>) -> Self { + Self { patterns } + } + + fn is_empty(&self) -> bool { + self.patterns.is_empty() + } + fn head_ty(&self) -> Option<Ty<'tcx>> { + if self.patterns.len() == 0 { + return None; + } + // If the type is opaque and it is revealed anywhere in the column, we take the revealed + // version. Otherwise we could encounter constructors for the revealed type and crash. + let is_opaque = |ty: Ty<'tcx>| matches!(ty.kind(), ty::Alias(ty::Opaque, ..)); + let first_ty = self.patterns[0].ty(); + if is_opaque(first_ty) { + for pat in &self.patterns { + let ty = pat.ty(); + if !is_opaque(ty) { + return Some(ty); + } + } + } + Some(first_ty) + } + + fn analyze_ctors(&self, pcx: &PatCtxt<'_, 'p, 'tcx>) -> SplitConstructorSet<'tcx> { + let column_ctors = self.patterns.iter().map(|p| p.ctor()); + ConstructorSet::for_ty(pcx.cx, pcx.ty).split(pcx, column_ctors) + } + fn iter<'a>(&'a self) -> impl Iterator<Item = &'p DeconstructedPat<'p, 'tcx>> + Captures<'a> { + self.patterns.iter().copied() + } + + /// Does specialization: given a constructor, this takes the patterns from the column that match + /// the constructor, and outputs their fields. + /// This returns one column per field of the constructor. The normally all have the same length + /// (the number of patterns in `self` that matched `ctor`), except that we expand or-patterns + /// which may change the lengths. + fn specialize(&self, pcx: &PatCtxt<'_, 'p, 'tcx>, ctor: &Constructor<'tcx>) -> Vec<Self> { + let arity = ctor.arity(pcx); + if arity == 0 { + return Vec::new(); + } + + // We specialize the column by `ctor`. This gives us `arity`-many columns of patterns. These + // columns may have different lengths in the presence of or-patterns (this is why we can't + // reuse `Matrix`). + let mut specialized_columns: Vec<_> = + (0..arity).map(|_| Self { patterns: Vec::new() }).collect(); + let relevant_patterns = + self.patterns.iter().filter(|pat| ctor.is_covered_by(pcx, pat.ctor())); + for pat in relevant_patterns { + let specialized = pat.specialize(pcx, &ctor); + for (subpat, column) in specialized.iter().zip(&mut specialized_columns) { + if subpat.is_or_pat() { + column.patterns.extend(subpat.iter_fields()) + } else { + column.patterns.push(subpat) + } + } + } + + assert!( + !specialized_columns[0].is_empty(), + "ctor {ctor:?} was listed as present but isn't; + there is an inconsistency between `Constructor::is_covered_by` and `ConstructorSet::split`" + ); + specialized_columns + } +} + /// Traverse the patterns to collect any variants of a non_exhaustive enum that fail to be mentioned -/// in a given column. This traverses patterns column-by-column, where a column is the intuitive -/// notion of "subpatterns that inspect the same subvalue". -/// Despite similarities with `is_useful`, this traversal is different. Notably this is linear in the -/// depth of patterns, whereas `is_useful` is worst-case exponential (exhaustiveness is NP-complete). +/// in a given column. +#[instrument(level = "debug", skip(cx), ret)] fn collect_nonexhaustive_missing_variants<'p, 'tcx>( cx: &MatchCheckCtxt<'p, 'tcx>, - column: &[&DeconstructedPat<'p, 'tcx>], + column: &PatternColumn<'p, 'tcx>, ) -> Vec<WitnessPat<'tcx>> { - if column.is_empty() { + let Some(ty) = column.head_ty() else { return Vec::new(); - } - let ty = column[0].ty(); + }; let pcx = &PatCtxt { cx, ty, span: DUMMY_SP, is_top_level: false }; - let set = ConstructorSet::for_ty(pcx.cx, pcx.ty).split(pcx, column.iter().map(|p| p.ctor())); + let set = column.analyze_ctors(pcx); if set.present.is_empty() { // We can't consistently handle the case where no constructors are present (since this would // require digging deep through any type in case there's a non_exhaustive enum somewhere), @@ -911,35 +980,11 @@ fn collect_nonexhaustive_missing_variants<'p, 'tcx>( // Recurse into the fields. for ctor in set.present { - let arity = ctor.arity(pcx); - if arity == 0 { - continue; - } - - // We specialize the column by `ctor`. This gives us `arity`-many columns of patterns. These - // columns may have different lengths in the presence of or-patterns (this is why we can't - // reuse `Matrix`). - let mut specialized_columns: Vec<Vec<_>> = (0..arity).map(|_| Vec::new()).collect(); - let relevant_patterns = column.iter().filter(|pat| ctor.is_covered_by(pcx, pat.ctor())); - for pat in relevant_patterns { - let specialized = pat.specialize(pcx, &ctor); - for (subpat, sub_column) in specialized.iter().zip(&mut specialized_columns) { - if subpat.is_or_pat() { - sub_column.extend(subpat.iter_fields()) - } else { - sub_column.push(subpat) - } - } - } - debug_assert!( - !specialized_columns[0].is_empty(), - "ctor {ctor:?} was listed as present but isn't" - ); - + let specialized_columns = column.specialize(pcx, &ctor); let wild_pat = WitnessPat::wild_from_ctor(pcx, ctor); for (i, col_i) in specialized_columns.iter().enumerate() { // Compute witnesses for each column. - let wits_for_col_i = collect_nonexhaustive_missing_variants(cx, col_i.as_slice()); + let wits_for_col_i = collect_nonexhaustive_missing_variants(cx, col_i); // For each witness, we build a new pattern in the shape of `ctor(_, _, wit, _, _)`, // adding enough wildcards to match `arity`. for wit in wits_for_col_i { @@ -952,6 +997,81 @@ fn collect_nonexhaustive_missing_variants<'p, 'tcx>( witnesses } +/// Traverse the patterns to warn the user about ranges that overlap on their endpoints. +#[instrument(level = "debug", skip(cx, lint_root))] +fn lint_overlapping_range_endpoints<'p, 'tcx>( + cx: &MatchCheckCtxt<'p, 'tcx>, + column: &PatternColumn<'p, 'tcx>, + lint_root: HirId, +) { + let Some(ty) = column.head_ty() else { + return; + }; + let pcx = &PatCtxt { cx, ty, span: DUMMY_SP, is_top_level: false }; + + let set = column.analyze_ctors(pcx); + + if IntRange::is_integral(ty) { + let emit_lint = |overlap: &IntRange, this_span: Span, overlapped_spans: &[Span]| { + let overlap_as_pat = overlap.to_pat(cx.tcx, ty); + let overlaps: Vec<_> = overlapped_spans + .iter() + .copied() + .map(|span| Overlap { range: overlap_as_pat.clone(), span }) + .collect(); + cx.tcx.emit_spanned_lint( + lint::builtin::OVERLAPPING_RANGE_ENDPOINTS, + lint_root, + this_span, + OverlappingRangeEndpoints { overlap: overlaps, range: this_span }, + ); + }; + + // If two ranges overlapped, the split set will contain their intersection as a singleton. + let split_int_ranges = set.present.iter().filter_map(|c| c.as_int_range()); + for overlap_range in split_int_ranges.clone() { + if overlap_range.is_singleton() { + let overlap: u128 = overlap_range.boundaries().0; + // Spans of ranges that start or end with the overlap. + let mut prefixes: SmallVec<[_; 1]> = Default::default(); + let mut suffixes: SmallVec<[_; 1]> = Default::default(); + // Iterate on patterns that contained `overlap`. + for pat in column.iter() { + let this_span = pat.span(); + let Constructor::IntRange(this_range) = pat.ctor() else { continue }; + if this_range.is_singleton() { + // Don't lint when one of the ranges is a singleton. + continue; + } + let (start, end) = this_range.boundaries(); + if start == overlap { + // `this_range` looks like `overlap..=end`; it overlaps with any ranges that + // look like `start..=overlap`. + if !prefixes.is_empty() { + emit_lint(overlap_range, this_span, &prefixes); + } + suffixes.push(this_span) + } else if end == overlap { + // `this_range` looks like `start..=overlap`; it overlaps with any ranges + // that look like `overlap..=end`. + if !suffixes.is_empty() { + emit_lint(overlap_range, this_span, &suffixes); + } + prefixes.push(this_span) + } + } + } + } + } else { + // Recurse into the fields. + for ctor in set.present { + for col in column.specialize(pcx, &ctor) { + lint_overlapping_range_endpoints(cx, &col, lint_root); + } + } + } +} + /// The arm of a match expression. #[derive(Clone, Copy, Debug)] pub(crate) struct MatchArm<'p, 'tcx> { @@ -1022,6 +1142,10 @@ pub(crate) fn compute_match_usefulness<'p, 'tcx>( NoWitnesses { .. } => bug!(), }; + let pat_column = arms.iter().flat_map(|arm| arm.pat.flatten_or_pat()).collect::<Vec<_>>(); + let pat_column = PatternColumn::new(pat_column); + lint_overlapping_range_endpoints(cx, &pat_column, lint_root); + // Run the non_exhaustive_omitted_patterns lint. Only run on refutable patterns to avoid hitting // `if let`s. Only run if the match is exhaustive otherwise the error is redundant. if cx.refutable @@ -1031,9 +1155,7 @@ pub(crate) fn compute_match_usefulness<'p, 'tcx>( rustc_session::lint::Level::Allow ) { - let pat_column = arms.iter().flat_map(|arm| arm.pat.flatten_or_pat()).collect::<Vec<_>>(); let witnesses = collect_nonexhaustive_missing_variants(cx, &pat_column); - if !witnesses.is_empty() { // Report that a match of a `non_exhaustive` enum marked with `non_exhaustive_omitted_patterns` // is not exhaustive enough. 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_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 9aaa54110bd..68b8911824c 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -20,6 +20,7 @@ extern crate tracing; #[macro_use] extern crate rustc_middle; +use hir::ConstContext; use required_consts::RequiredConstsVisitor; use rustc_const_eval::util; use rustc_data_structures::fx::FxIndexSet; @@ -251,8 +252,13 @@ fn mir_const_qualif(tcx: TyCtxt<'_>, def: LocalDefId) -> ConstQualifs { let const_kind = tcx.hir().body_const_context(def); // No need to const-check a non-const `fn`. - if const_kind.is_none() { - return Default::default(); + match const_kind { + Some(ConstContext::Const { .. } | ConstContext::Static(_)) + | Some(ConstContext::ConstFn) => {} + None => span_bug!( + tcx.def_span(def), + "`mir_const_qualif` should only be called on const fns and const items" + ), } // N.B., this `borrow()` is guaranteed to be valid (i.e., the value @@ -317,7 +323,21 @@ fn mir_promoted( // Ensure that we compute the `mir_const_qualif` for constants at // this point, before we steal the mir-const result. // Also this means promotion can rely on all const checks having been done. - let const_qualifs = tcx.mir_const_qualif(def); + + let const_qualifs = match tcx.def_kind(def) { + DefKind::Fn | DefKind::AssocFn | DefKind::Closure + if tcx.constness(def) == hir::Constness::Const + || tcx.is_const_default_method(def.to_def_id()) => + { + tcx.mir_const_qualif(def) + } + DefKind::AssocConst + | DefKind::Const + | DefKind::Static(_) + | DefKind::InlineConst + | DefKind::AnonConst => tcx.mir_const_qualif(def), + _ => ConstQualifs::default(), + }; let mut body = tcx.mir_const(def).steal(); if let Some(error_reported) = const_qualifs.tainted_by_errors { body.tainted_by_errors = Some(error_reported); diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 9f8361a4b1e..7b5bb319ed8 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -504,8 +504,10 @@ impl<'a> Parser<'a> { // Special-case "expected `;`" errors if expected.contains(&TokenType::Token(token::Semi)) { - if self.prev_token == token::Question && self.maybe_recover_from_ternary_operator() { - return Ok(true); + // If the user is trying to write a ternary expression, recover it and + // return an Err to prevent a cascade of irrelevant diagnostics + if self.prev_token == token::Question && let Err(e) = self.maybe_recover_from_ternary_operator() { + return Err(e); } if self.token.span == DUMMY_SP || self.prev_token.span == DUMMY_SP { @@ -1428,10 +1430,10 @@ impl<'a> Parser<'a> { /// Rust has no ternary operator (`cond ? then : else`). Parse it and try /// to recover from it if `then` and `else` are valid expressions. Returns - /// whether it was a ternary operator. - pub(super) fn maybe_recover_from_ternary_operator(&mut self) -> bool { + /// an err if this appears to be a ternary expression. + pub(super) fn maybe_recover_from_ternary_operator(&mut self) -> PResult<'a, ()> { if self.prev_token != token::Question { - return false; + return PResult::Ok(()); } let lo = self.prev_token.span.lo(); @@ -1449,20 +1451,18 @@ impl<'a> Parser<'a> { if self.eat_noexpect(&token::Colon) { match self.parse_expr() { Ok(_) => { - self.sess.emit_err(TernaryOperator { span: self.token.span.with_lo(lo) }); - return true; + return Err(self + .sess + .create_err(TernaryOperator { span: self.token.span.with_lo(lo) })); } Err(err) => { err.cancel(); - self.restore_snapshot(snapshot); } }; } - } else { - self.restore_snapshot(snapshot); - }; - - false + } + self.restore_snapshot(snapshot); + Ok(()) } pub(super) fn maybe_recover_from_bad_type_plus(&mut self, ty: &Ty) -> PResult<'a, ()> { diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 597303cae73..41b19ecb63a 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -159,8 +159,9 @@ pub struct Parser<'a> { /// appropriately. /// /// See the comments in the `parse_path_segment` function for more details. - unmatched_angle_bracket_count: u32, - max_angle_bracket_count: u32, + unmatched_angle_bracket_count: u16, + max_angle_bracket_count: u16, + angle_bracket_nesting: u16, last_unexpected_token_span: Option<Span>, /// If present, this `Parser` is not parsing Rust code but rather a macro call. @@ -394,6 +395,7 @@ impl<'a> Parser<'a> { break_last_token: false, unmatched_angle_bracket_count: 0, max_angle_bracket_count: 0, + angle_bracket_nesting: 0, last_unexpected_token_span: None, subparser_name, capture_state: CaptureState { diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 2fcb9a78cfd..4969e672a72 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -487,10 +487,24 @@ impl<'a> Parser<'a> { // Take a snapshot before attempting to parse - we can restore this later. let snapshot = is_first_invocation.then(|| self.clone()); + self.angle_bracket_nesting += 1; debug!("parse_generic_args_with_leading_angle_bracket_recovery: (snapshotting)"); match self.parse_angle_args(ty_generics) { - Ok(args) => Ok(args), + Ok(args) => { + self.angle_bracket_nesting -= 1; + Ok(args) + } + Err(mut e) if self.angle_bracket_nesting > 10 => { + self.angle_bracket_nesting -= 1; + // When encountering severely malformed code where there are several levels of + // nested unclosed angle args (`f::<f::<f::<f::<...`), we avoid severe O(n^2) + // behavior by bailing out earlier (#117080). + e.emit(); + rustc_errors::FatalError.raise(); + } Err(e) if is_first_invocation && self.unmatched_angle_bracket_count > 0 => { + self.angle_bracket_nesting -= 1; + // Swap `self` with our backup of the parser state before attempting to parse // generic arguments. let snapshot = mem::replace(self, snapshot.unwrap()); @@ -520,8 +534,8 @@ impl<'a> Parser<'a> { // Make a span over ${unmatched angle bracket count} characters. // This is safe because `all_angle_brackets` ensures that there are only `<`s, // i.e. no multibyte characters, in this range. - let span = - lo.with_hi(lo.lo() + BytePos(snapshot.unmatched_angle_bracket_count)); + let span = lo + .with_hi(lo.lo() + BytePos(snapshot.unmatched_angle_bracket_count.into())); self.sess.emit_err(errors::UnmatchedAngle { span, plural: snapshot.unmatched_angle_bracket_count > 1, @@ -531,7 +545,10 @@ impl<'a> Parser<'a> { self.parse_angle_args(ty_generics) } } - Err(e) => Err(e), + Err(e) => { + self.angle_bracket_nesting -= 1; + Err(e) + } } } diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 25ef5245cf1..026186cbe6c 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -393,6 +393,9 @@ passes_invalid_attr_at_crate_level = `{$name}` attribute cannot be used at crate level .suggestion = perhaps you meant to use an outer attribute +passes_invalid_attr_at_crate_level_item = + the inner attribute doesn't annotate this {$kind} + passes_invalid_deprecation_version = invalid deprecation version found .label = invalid deprecation version @@ -402,11 +405,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/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index dfe75ea5e8e..a8a27e761cb 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -2534,10 +2534,30 @@ fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) { if attr.style == AttrStyle::Inner { for attr_to_check in ATTRS_TO_CHECK { if attr.has_name(*attr_to_check) { + let item = tcx + .hir() + .items() + .map(|id| tcx.hir().item(id)) + .find(|item| !item.span.is_dummy()) // Skip prelude `use`s + .map(|item| errors::ItemFollowingInnerAttr { + span: item.ident.span, + kind: item.kind.descr(), + }); tcx.sess.emit_err(errors::InvalidAttrAtCrateLevel { span: attr.span, - snippet: tcx.sess.source_map().span_to_snippet(attr.span).ok(), + sugg_span: tcx + .sess + .source_map() + .span_to_snippet(attr.span) + .ok() + .filter(|src| src.starts_with("#![")) + .map(|_| { + attr.span + .with_lo(attr.span.lo() + BytePos(1)) + .with_hi(attr.span.lo() + BytePos(2)) + }), name: *attr_to_check, + item, }); } } diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 6f87b56c636..eca0fb7748b 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -856,8 +856,15 @@ pub struct UnknownLangItem { pub struct InvalidAttrAtCrateLevel { pub span: Span, - pub snippet: Option<String>, + pub sugg_span: Option<Span>, pub name: Symbol, + pub item: Option<ItemFollowingInnerAttr>, +} + +#[derive(Clone, Copy)] +pub struct ItemFollowingInnerAttr { + pub span: Span, + pub kind: &'static str, } impl IntoDiagnostic<'_> for InvalidAttrAtCrateLevel { @@ -871,15 +878,18 @@ impl IntoDiagnostic<'_> for InvalidAttrAtCrateLevel { diag.set_arg("name", self.name); // Only emit an error with a suggestion if we can create a string out // of the attribute span - if let Some(src) = self.snippet { - let replacement = src.replace("#!", "#"); + if let Some(span) = self.sugg_span { diag.span_suggestion_verbose( - self.span, + span, fluent::passes_suggestion, - replacement, + String::new(), rustc_errors::Applicability::MachineApplicable, ); } + if let Some(item) = self.item { + diag.set_arg("kind", item.kind); + diag.span_label(item.span, fluent::passes_invalid_attr_at_crate_level_item); + } diag } } @@ -1505,16 +1515,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/lib_features.rs b/compiler/rustc_passes/src/lib_features.rs index ceb8f58cac0..0daa273db67 100644 --- a/compiler/rustc_passes/src/lib_features.rs +++ b/compiler/rustc_passes/src/lib_features.rs @@ -5,7 +5,7 @@ //! collect them instead. use rustc_ast::Attribute; -use rustc_attr::{rust_version_symbol, VERSION_PLACEHOLDER}; +use rustc_attr::VERSION_PLACEHOLDER; use rustc_hir::intravisit::Visitor; use rustc_middle::hir::nested_filter; use rustc_middle::middle::lib_features::LibFeatures; @@ -59,7 +59,7 @@ impl<'tcx> LibFeatureCollector<'tcx> { if let Some(s) = since && s.as_str() == VERSION_PLACEHOLDER { - since = Some(rust_version_symbol()); + since = Some(sym::env_CFG_RELEASE); } if let Some(feature) = feature { diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index bb23dc257d7..7bfb0742b8b 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -3,8 +3,8 @@ use crate::errors; use rustc_attr::{ - self as attr, rust_version_symbol, ConstStability, Stability, StabilityLevel, Unstable, - UnstableReason, VERSION_PLACEHOLDER, + self as attr, ConstStability, Since, Stability, StabilityLevel, Unstable, UnstableReason, + VERSION_PLACEHOLDER, }; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; use rustc_hir as hir; @@ -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. } } } @@ -1109,7 +1115,7 @@ fn unnecessary_stable_feature_lint( mut since: Symbol, ) { if since.as_str() == VERSION_PLACEHOLDER { - since = rust_version_symbol(); + since = sym::env_CFG_RELEASE; } tcx.emit_spanned_lint( lint::builtin::STABLE_FEATURES, 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_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index 4516708ce17..536c0a20e2a 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -197,6 +197,9 @@ macro_rules! handle_cycle_error { ([(fatal_cycle) $($rest:tt)*]) => {{ rustc_query_system::HandleCycleError::Fatal }}; + ([(cycle_stash) $($rest:tt)*]) => {{ + rustc_query_system::HandleCycleError::Stash + }}; ([(cycle_delay_bug) $($rest:tt)*]) => {{ rustc_query_system::HandleCycleError::DelayBug }}; diff --git a/compiler/rustc_query_system/src/error.rs b/compiler/rustc_query_system/src/error.rs index e49e78cc7c4..5829e17ec16 100644 --- a/compiler/rustc_query_system/src/error.rs +++ b/compiler/rustc_query_system/src/error.rs @@ -15,6 +15,7 @@ pub enum HandleCycleError { Error, Fatal, DelayBug, + Stash, } #[derive(Subdiagnostic)] diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs index 69a9c0eb95a..1f3403d09be 100644 --- a/compiler/rustc_query_system/src/query/plumbing.rs +++ b/compiler/rustc_query_system/src/query/plumbing.rs @@ -19,7 +19,7 @@ use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::sync::Lock; #[cfg(parallel_compiler)] use rustc_data_structures::{outline, sync}; -use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed, FatalError}; +use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed, FatalError, StashKey}; use rustc_span::{Span, DUMMY_SP}; use std::cell::Cell; use std::collections::hash_map::Entry; @@ -133,6 +133,17 @@ where let guar = error.delay_as_bug(); query.value_from_cycle_error(*qcx.dep_context(), &cycle_error.cycle, guar) } + Stash => { + let guar = if let Some(root) = cycle_error.cycle.first() + && let Some(span) = root.query.span + { + error.stash(span, StashKey::Cycle); + qcx.dep_context().sess().delay_span_bug(span, "delayed cycle error") + } else { + error.emit() + }; + query.value_from_cycle_error(*qcx.dep_context(), &cycle_error.cycle, guar) + } } } 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_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index a5f8f61f3db..fd5d6fabf02 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -1570,7 +1570,26 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { err.set_primary_message( "cannot initialize a tuple struct which contains private fields", ); - + if !def_id.is_local() + && self + .r + .tcx + .inherent_impls(def_id) + .iter() + .flat_map(|impl_def_id| { + self.r.tcx.provided_trait_methods(*impl_def_id) + }) + .any(|assoc| !assoc.fn_has_self_parameter && assoc.name == sym::new) + { + // FIXME: look for associated functions with Self return type, + // instead of relying only on the name and lack of self receiver. + err.span_suggestion_verbose( + span.shrink_to_hi(), + "you might have meant to use the `new` associated function", + "::new".to_string(), + Applicability::MaybeIncorrect, + ); + } // Use spans of the tuple struct definition. self.r.field_def_ids(def_id).map(|field_ids| { field_ids diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 84933588f17..7aced414ed6 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -2739,32 +2739,25 @@ 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=branch` and `-C instrument-coverage=except-*` \ - require `-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: + InstrumentCoverage::All | InstrumentCoverage::Off => {} + // Unstable values: + 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) { + if cg.instrument_coverage != InstrumentCoverage::Off { if cg.profile_generate.enabled() || cg.profile_use.is_some() { handler.early_error( "option `-C instrument-coverage` is not compatible with either `-C profile-use` \ diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 77aaf951f0d..fd473acbd3c 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -294,7 +294,7 @@ impl CodegenOptions { // JUSTIFICATION: defn of the suggested wrapper fn #[allow(rustc::bad_opt_access)] pub fn instrument_coverage(&self) -> InstrumentCoverage { - self.instrument_coverage.unwrap_or(InstrumentCoverage::Off) + self.instrument_coverage } } @@ -913,23 +913,23 @@ mod parse { } pub(crate) fn parse_instrument_coverage( - slot: &mut Option<InstrumentCoverage>, + slot: &mut InstrumentCoverage, v: Option<&str>, ) -> bool { if v.is_some() { - let mut bool_arg = None; - if parse_opt_bool(&mut bool_arg, v) { - *slot = bool_arg.unwrap().then_some(InstrumentCoverage::All); + let mut bool_arg = false; + if parse_bool(&mut bool_arg, v) { + *slot = if bool_arg { InstrumentCoverage::All } else { InstrumentCoverage::Off }; return true; } } let Some(v) = v else { - *slot = Some(InstrumentCoverage::All); + *slot = InstrumentCoverage::All; return true; }; - *slot = Some(match v { + *slot = match v { "all" => InstrumentCoverage::All, "branch" => InstrumentCoverage::Branch, "except-unused-generics" | "except_unused_generics" => { @@ -940,7 +940,7 @@ mod parse { } "off" | "no" | "n" | "false" | "0" => InstrumentCoverage::Off, _ => return false, - }); + }; true } @@ -1352,7 +1352,7 @@ options! { inline_threshold: Option<u32> = (None, parse_opt_number, [TRACKED], "set the threshold for inlining a function"), #[rustc_lint_opt_deny_field_access("use `Session::instrument_coverage` instead of this field")] - instrument_coverage: Option<InstrumentCoverage> = (None, parse_instrument_coverage, [TRACKED], + instrument_coverage: InstrumentCoverage = (InstrumentCoverage::Off, 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: @@ -1593,16 +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) - `=branch` - `=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 94fe38b72ad..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 @@ -1389,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 @@ -1525,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/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 d3ea8cdc699..4d2a518226d 100644 --- a/compiler/rustc_smir/src/rustc_internal/mod.rs +++ b/compiler/rustc_smir/src/rustc_internal/mod.rs @@ -167,8 +167,9 @@ pub fn run(tcx: TyCtxt<'_>, f: impl FnOnce()) { def_ids: IndexMap::default(), alloc_ids: IndexMap::default(), spans: IndexMap::default(), - types: vec![], + types: IndexMap::default(), instances: IndexMap::default(), + constants: IndexMap::default(), })); stable_mir::run(&tables, || init(&tables, f)); } diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs index d5a5f800a40..eb868913017 100644 --- a/compiler/rustc_smir/src/rustc_smir/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/mod.rs @@ -20,7 +20,8 @@ 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; @@ -147,14 +148,7 @@ impl<'tcx> Context for TablesWrapper<'tcx> { fn ty_kind(&self, ty: stable_mir::ty::Ty) -> TyKind { let mut tables = self.0.borrow_mut(); - tables.types[ty.0].clone().stable(&mut *tables) - } - - fn mk_ty(&self, kind: TyKind) -> stable_mir::ty::Ty { - let mut tables = self.0.borrow_mut(); - let n = tables.types.len(); - tables.types.push(MaybeStable::Stable(kind)); - stable_mir::ty::Ty(n) + tables.types[ty].kind().stable(&mut *tables) } fn generics_of(&self, def_id: stable_mir::DefId) -> stable_mir::ty::Generics { @@ -213,8 +207,7 @@ impl<'tcx> Context for TablesWrapper<'tcx> { fn instance_ty(&self, def: InstanceDef) -> stable_mir::ty::Ty { let mut tables = self.0.borrow_mut(); let instance = tables.instances[def]; - let ty = instance.ty(tables.tcx, ParamEnv::empty()); - tables.intern_ty(ty) + instance.ty(tables.tcx, ParamEnv::empty()).stable(&mut *tables) } fn instance_def_id(&self, def: InstanceDef) -> stable_mir::DefId { @@ -252,33 +245,6 @@ impl<'tcx> Context for TablesWrapper<'tcx> { } } -#[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> { @@ -286,18 +252,18 @@ pub struct Tables<'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: Vec<MaybeStable<TyKind, Ty<'tcx>>>, + 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) } } @@ -321,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), @@ -334,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, + ) } } @@ -436,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), @@ -449,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)) @@ -460,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)), } @@ -604,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) @@ -885,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) => { @@ -917,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) } @@ -1053,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)), } } @@ -1099,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 { @@ -1241,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))), @@ -1256,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) => { @@ -1291,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)) } @@ -1312,32 +1280,36 @@ 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)); + let kind = match self.kind() { + ty::Value(val) => { + let const_val = tables.tcx.valtree_to_const_val((self.ty(), val)); + if matches!(const_val, mir::ConstValue::ZeroSized) { + ConstantKind::ZeroSized + } else { 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()), - } + } + 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) } } @@ -1422,22 +1394,28 @@ 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) if matches!(val, mir::ConstValue::ZeroSized) => { + let ty = ty.stable(tables); + let id = tables.intern_const(*self); + Const::new(ConstantKind::ZeroSized, 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) + } } } } @@ -1551,30 +1529,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)) } } @@ -1599,7 +1579,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) } } } @@ -1608,7 +1588,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 d3205f8eca1..88d9dab2ba5 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -713,6 +713,7 @@ symbols! { encode, end, env, + env_CFG_RELEASE: env!("CFG_RELEASE"), eprint_macro, eprintln_macro, eq, @@ -910,6 +911,7 @@ symbols! { iter, iter_mut, iter_repeat, + iterator, iterator_collect_fn, kcfi, keyword, diff --git a/compiler/rustc_symbol_mangling/Cargo.toml b/compiler/rustc_symbol_mangling/Cargo.toml index 052ef8bb94c..d53bc5b6a8e 100644 --- a/compiler/rustc_symbol_mangling/Cargo.toml +++ b/compiler/rustc_symbol_mangling/Cargo.toml @@ -15,9 +15,7 @@ twox-hash = "1.6.3" rustc_span = { path = "../rustc_span" } rustc_middle = { path = "../rustc_middle" } rustc_hir = { path = "../rustc_hir" } -rustc_fluent_macro = { path = "../rustc_fluent_macro" } rustc_target = { path = "../rustc_target" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_session = { path = "../rustc_session" } -rustc_macros = { path = "../rustc_macros" } rustc_errors = { path = "../rustc_errors" } diff --git a/compiler/rustc_symbol_mangling/messages.ftl b/compiler/rustc_symbol_mangling/messages.ftl deleted file mode 100644 index b7d48280f46..00000000000 --- a/compiler/rustc_symbol_mangling/messages.ftl +++ /dev/null @@ -1 +0,0 @@ -symbol_mangling_test_output = {$kind}({$content}) diff --git a/compiler/rustc_symbol_mangling/src/errors.rs b/compiler/rustc_symbol_mangling/src/errors.rs index f4d0751f753..2e081e55531 100644 --- a/compiler/rustc_symbol_mangling/src/errors.rs +++ b/compiler/rustc_symbol_mangling/src/errors.rs @@ -1,18 +1,32 @@ //! Errors emitted by symbol_mangling. -use rustc_errors::{DiagnosticArgValue, IntoDiagnosticArg}; -use rustc_macros::Diagnostic; +use rustc_errors::{ErrorGuaranteed, IntoDiagnostic}; use rustc_span::Span; +use std::fmt; -#[derive(Diagnostic)] -#[diag(symbol_mangling_test_output)] pub struct TestOutput { - #[primary_span] pub span: Span, pub kind: Kind, pub content: String, } +// This diagnostic doesn't need translation because (a) it doesn't contain any +// natural language, and (b) it's only used in tests. So we construct it +// manually and avoid the fluent machinery. +impl IntoDiagnostic<'_> for TestOutput { + fn into_diagnostic( + self, + handler: &'_ rustc_errors::Handler, + ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> { + let TestOutput { span, kind, content } = self; + + #[allow(rustc::untranslatable_diagnostic)] + let mut diag = handler.struct_err(format!("{kind}({content})")); + diag.set_span(span); + diag + } +} + pub enum Kind { SymbolName, Demangling, @@ -20,15 +34,13 @@ pub enum Kind { DefPath, } -impl IntoDiagnosticArg for Kind { - fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { - let kind = match self { - Kind::SymbolName => "symbol-name", - Kind::Demangling => "demangling", - Kind::DemanglingAlt => "demangling-alt", - Kind::DefPath => "def-path", +impl fmt::Display for Kind { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Kind::SymbolName => write!(f, "symbol-name"), + Kind::Demangling => write!(f, "demangling"), + Kind::DemanglingAlt => write!(f, "demangling-alt"), + Kind::DefPath => write!(f, "def-path"), } - .into(); - DiagnosticArgValue::Str(kind) } } diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs index 7b4ab67a24d..14dd8b4e56f 100644 --- a/compiler/rustc_symbol_mangling/src/lib.rs +++ b/compiler/rustc_symbol_mangling/src/lib.rs @@ -103,8 +103,6 @@ extern crate rustc_middle; #[macro_use] extern crate tracing; -use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; -use rustc_fluent_macro::fluent_messages; use rustc_hir::def::DefKind; use rustc_hir::def_id::{CrateNum, LOCAL_CRATE}; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; @@ -121,8 +119,6 @@ pub mod errors; pub mod test; pub mod typeid; -fluent_messages! { "../messages.ftl" } - /// This function computes the symbol name for the given `instance` and the /// given instantiating crate. That is, if you know that instance X is /// instantiated in crate Y, this is the symbol name this instance would have. 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_target/src/spec/crt_objects.rs b/compiler/rustc_target/src/spec/crt_objects.rs index c126390f5a9..53f710b8f9e 100644 --- a/compiler/rustc_target/src/spec/crt_objects.rs +++ b/compiler/rustc_target/src/spec/crt_objects.rs @@ -40,11 +40,9 @@ //! but not gcc's. As a result rustc cannot link with C++ static libraries (#36710) //! when linking in self-contained mode. -use crate::json::{Json, ToJson}; use crate::spec::LinkOutputKind; use std::borrow::Cow; use std::collections::BTreeMap; -use std::str::FromStr; pub type CrtObjects = BTreeMap<LinkOutputKind, Vec<Cow<'static, str>>>; @@ -123,39 +121,3 @@ pub(super) fn pre_wasi_self_contained() -> CrtObjects { pub(super) fn post_wasi_self_contained() -> CrtObjects { new(&[]) } - -/// Which logic to use to determine whether to use self-contained linking mode -/// if `-Clink-self-contained` is not specified explicitly. -#[derive(Clone, Copy, PartialEq, Hash, Debug)] -pub enum LinkSelfContainedDefault { - False, - True, - Musl, - Mingw, -} - -impl FromStr for LinkSelfContainedDefault { - type Err = (); - - fn from_str(s: &str) -> Result<LinkSelfContainedDefault, ()> { - Ok(match s { - "false" => LinkSelfContainedDefault::False, - "true" | "wasm" => LinkSelfContainedDefault::True, - "musl" => LinkSelfContainedDefault::Musl, - "mingw" => LinkSelfContainedDefault::Mingw, - _ => return Err(()), - }) - } -} - -impl ToJson for LinkSelfContainedDefault { - fn to_json(&self) -> Json { - match *self { - LinkSelfContainedDefault::False => "false", - LinkSelfContainedDefault::True => "true", - LinkSelfContainedDefault::Musl => "musl", - LinkSelfContainedDefault::Mingw => "mingw", - } - .to_json() - } -} diff --git a/compiler/rustc_target/src/spec/linux_musl_base.rs b/compiler/rustc_target/src/spec/linux_musl_base.rs index 61553e71b45..b698bcbcef6 100644 --- a/compiler/rustc_target/src/spec/linux_musl_base.rs +++ b/compiler/rustc_target/src/spec/linux_musl_base.rs @@ -1,5 +1,5 @@ -use crate::spec::crt_objects::{self, LinkSelfContainedDefault}; -use crate::spec::TargetOptions; +use crate::spec::crt_objects; +use crate::spec::{LinkSelfContainedDefault, TargetOptions}; pub fn opts() -> TargetOptions { let mut base = super::linux_base::opts(); @@ -7,7 +7,7 @@ pub fn opts() -> TargetOptions { base.env = "musl".into(); base.pre_link_objects_self_contained = crt_objects::pre_musl_self_contained(); base.post_link_objects_self_contained = crt_objects::post_musl_self_contained(); - base.link_self_contained = LinkSelfContainedDefault::Musl; + base.link_self_contained = LinkSelfContainedDefault::InferredForMusl; // These targets statically link libc by default base.crt_static_default = true; diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index f1c7513d885..3541810d437 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -38,7 +38,7 @@ use crate::abi::call::Conv; use crate::abi::{Endian, Integer, Size, TargetDataLayout, TargetDataLayoutErrors}; use crate::json::{Json, ToJson}; use crate::spec::abi::{lookup as lookup_abi, Abi}; -use crate::spec::crt_objects::{CrtObjects, LinkSelfContainedDefault}; +use crate::spec::crt_objects::CrtObjects; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_fs_util::try_canonicalize; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; @@ -278,6 +278,7 @@ impl LinkerFlavor { } } + /// Returns the corresponding backwards-compatible CLI flavor. fn to_cli(self) -> LinkerFlavorCli { match self { LinkerFlavor::Gnu(Cc::Yes, _) @@ -298,6 +299,20 @@ impl LinkerFlavor { } } + /// Returns the modern CLI flavor that is the counterpart of this flavor. + fn to_cli_counterpart(self) -> LinkerFlavorCli { + match self { + LinkerFlavor::Gnu(cc, lld) => LinkerFlavorCli::Gnu(cc, lld), + LinkerFlavor::Darwin(cc, lld) => LinkerFlavorCli::Darwin(cc, lld), + LinkerFlavor::WasmLld(cc) => LinkerFlavorCli::WasmLld(cc), + LinkerFlavor::Unix(cc) => LinkerFlavorCli::Unix(cc), + LinkerFlavor::Msvc(lld) => LinkerFlavorCli::Msvc(lld), + LinkerFlavor::EmCc => LinkerFlavorCli::EmCc, + LinkerFlavor::Bpf => LinkerFlavorCli::Bpf, + LinkerFlavor::Ptx => LinkerFlavorCli::Ptx, + } + } + fn infer_cli_hints(cli: LinkerFlavorCli) -> (Option<Cc>, Option<Lld>) { match cli { LinkerFlavorCli::Gnu(cc, lld) | LinkerFlavorCli::Darwin(cc, lld) => { @@ -520,6 +535,98 @@ impl ToJson for LinkerFlavorCli { } } +/// The different `-Clink-self-contained` options that can be specified in a target spec: +/// - enabling or disabling in bulk +/// - some target-specific pieces of inference to determine whether to use self-contained linking +/// if `-Clink-self-contained` is not specified explicitly (e.g. on musl/mingw) +/// - explicitly enabling some of the self-contained linking components, e.g. the linker component +/// to use `rust-lld` +#[derive(Clone, Copy, PartialEq, Debug)] +pub enum LinkSelfContainedDefault { + /// The target spec explicitly enables self-contained linking. + True, + + /// The target spec explicitly disables self-contained linking. + False, + + /// The target spec requests that the self-contained mode is inferred, in the context of musl. + InferredForMusl, + + /// The target spec requests that the self-contained mode is inferred, in the context of mingw. + InferredForMingw, + + /// The target spec explicitly enables a list of self-contained linking components: e.g. for + /// targets opting into a subset of components like the CLI's `-C link-self-contained=+linker`. + WithComponents(LinkSelfContainedComponents), +} + +/// Parses a backwards-compatible `-Clink-self-contained` option string, without components. +impl FromStr for LinkSelfContainedDefault { + type Err = (); + + fn from_str(s: &str) -> Result<LinkSelfContainedDefault, ()> { + Ok(match s { + "false" => LinkSelfContainedDefault::False, + "true" | "wasm" => LinkSelfContainedDefault::True, + "musl" => LinkSelfContainedDefault::InferredForMusl, + "mingw" => LinkSelfContainedDefault::InferredForMingw, + _ => return Err(()), + }) + } +} + +impl ToJson for LinkSelfContainedDefault { + fn to_json(&self) -> Json { + match *self { + LinkSelfContainedDefault::WithComponents(components) => { + // Serialize the components in a json object's `components` field, to prepare for a + // future where `crt-objects-fallback` is removed from the json specs and + // incorporated as a field here. + let mut map = BTreeMap::new(); + map.insert("components", components); + map.to_json() + } + + // Stable backwards-compatible values + LinkSelfContainedDefault::True => "true".to_json(), + LinkSelfContainedDefault::False => "false".to_json(), + LinkSelfContainedDefault::InferredForMusl => "musl".to_json(), + LinkSelfContainedDefault::InferredForMingw => "mingw".to_json(), + } + } +} + +impl LinkSelfContainedDefault { + /// Returns whether the target spec has self-contained linking explicitly disabled. Used to emit + /// errors if the user then enables it on the CLI. + pub fn is_disabled(self) -> bool { + self == LinkSelfContainedDefault::False + } + + /// Returns whether the target spec explictly requests self-contained linking, i.e. not via + /// inference. + pub fn is_linker_enabled(self) -> bool { + match self { + LinkSelfContainedDefault::True => true, + LinkSelfContainedDefault::False => false, + LinkSelfContainedDefault::WithComponents(c) => { + c.contains(LinkSelfContainedComponents::LINKER) + } + _ => false, + } + } + + /// Returns the key to use when serializing the setting to json: + /// - individual components in a `link-self-contained` object value + /// - the other variants as a backwards-compatible `crt-objects-fallback` string + fn json_key(self) -> &'static str { + match self { + LinkSelfContainedDefault::WithComponents(_) => "link-self-contained", + _ => "crt-objects-fallback", + } + } +} + bitflags::bitflags! { #[derive(Default)] /// The `-C link-self-contained` components that can individually be enabled or disabled. @@ -579,6 +686,21 @@ impl LinkSelfContainedComponents { LinkSelfContainedComponents::MINGW, ] } + + /// Returns whether at least a component is enabled. + pub fn are_any_components_enabled(self) -> bool { + !self.is_empty() + } + + /// Returns whether `LinkSelfContainedComponents::LINKER` is enabled. + pub fn is_linker_enabled(self) -> bool { + self.contains(LinkSelfContainedComponents::LINKER) + } + + /// Returns whether `LinkSelfContainedComponents::CRT_OBJECTS` is enabled. + pub fn is_crt_objects_enabled(self) -> bool { + self.contains(LinkSelfContainedComponents::CRT_OBJECTS) + } } impl IntoIterator for LinkSelfContainedComponents { @@ -594,6 +716,22 @@ impl IntoIterator for LinkSelfContainedComponents { } } +impl ToJson for LinkSelfContainedComponents { + fn to_json(&self) -> Json { + let components: Vec<_> = Self::all_components() + .into_iter() + .filter(|c| self.contains(*c)) + .map(|c| { + // We can unwrap because we're iterating over all the known singular components, + // not an actual set of flags where `as_str` can fail. + c.as_str().unwrap().to_owned() + }) + .collect(); + + components.to_json() + } +} + #[derive(Clone, Copy, Debug, PartialEq, Hash, Encodable, Decodable, HashStable_Generic)] pub enum PanicStrategy { Unwind, @@ -1770,6 +1908,8 @@ pub struct TargetOptions { /// Same as `(pre|post)_link_objects`, but when self-contained linking mode is enabled. pub pre_link_objects_self_contained: CrtObjects, pub post_link_objects_self_contained: CrtObjects, + /// Behavior for the self-contained linking mode: inferred for some targets, or explicitly + /// enabled (in bulk, or with individual components). pub link_self_contained: LinkSelfContainedDefault, /// Linker arguments that are passed *before* any user-defined libraries. @@ -2170,7 +2310,7 @@ impl TargetOptions { } fn update_to_cli(&mut self) { - self.linker_flavor_json = self.linker_flavor.to_cli(); + self.linker_flavor_json = self.linker_flavor.to_cli_counterpart(); self.lld_flavor_json = self.linker_flavor.lld_flavor(); self.linker_is_gnu_json = self.linker_flavor.is_gnu(); for (args, args_json) in [ @@ -2180,8 +2320,10 @@ impl TargetOptions { (&self.late_link_args_static, &mut self.late_link_args_static_json), (&self.post_link_args, &mut self.post_link_args_json), ] { - *args_json = - args.iter().map(|(flavor, args)| (flavor.to_cli(), args.clone())).collect(); + *args_json = args + .iter() + .map(|(flavor, args)| (flavor.to_cli_counterpart(), args.clone())) + .collect(); } } } @@ -2724,8 +2866,43 @@ impl Target { } Ok::<(), String>(()) } ); - - ($key_name:ident = $json_name:expr, link_self_contained) => ( { + ($key_name:ident, link_self_contained_components) => ( { + // Skeleton of what needs to be parsed: + // + // ``` + // $name: { + // "components": [ + // <array of strings> + // ] + // } + // ``` + let name = (stringify!($key_name)).replace("_", "-"); + if let Some(o) = obj.remove(&name) { + if let Some(o) = o.as_object() { + let component_array = o.get("components") + .ok_or_else(|| format!("{name}: expected a \ + JSON object with a `components` field."))?; + let component_array = component_array.as_array() + .ok_or_else(|| format!("{name}.components: expected a JSON array"))?; + let mut components = LinkSelfContainedComponents::empty(); + for s in component_array { + components |= match s.as_str() { + Some(s) => { + LinkSelfContainedComponents::from_str(s) + .ok_or_else(|| format!("unknown \ + `-Clink-self-contained` component: {s}"))? + }, + _ => return Err(format!("not a string: {:?}", s)), + }; + } + base.$key_name = LinkSelfContainedDefault::WithComponents(components); + } else { + incorrect_type.push(name) + } + } + Ok::<(), String>(()) + } ); + ($key_name:ident = $json_name:expr, link_self_contained_backwards_compatible) => ( { let name = $json_name; obj.remove(name).and_then(|o| o.as_str().and_then(|s| { match s.parse::<LinkSelfContainedDefault>() { @@ -2878,7 +3055,13 @@ impl Target { key!(post_link_objects = "post-link-objects", link_objects); key!(pre_link_objects_self_contained = "pre-link-objects-fallback", link_objects); key!(post_link_objects_self_contained = "post-link-objects-fallback", link_objects); - key!(link_self_contained = "crt-objects-fallback", link_self_contained)?; + // Deserializes the backwards-compatible variants of `-Clink-self-contained` + key!( + link_self_contained = "crt-objects-fallback", + link_self_contained_backwards_compatible + )?; + // Deserializes the components variant of `-Clink-self-contained` + key!(link_self_contained, link_self_contained_components)?; key!(pre_link_args_json = "pre-link-args", link_args); key!(late_link_args_json = "late-link-args", link_args); key!(late_link_args_dynamic_json = "late-link-args-dynamic", link_args); @@ -3134,7 +3317,6 @@ impl ToJson for Target { target_option_val!(post_link_objects); target_option_val!(pre_link_objects_self_contained, "pre-link-objects-fallback"); target_option_val!(post_link_objects_self_contained, "post-link-objects-fallback"); - target_option_val!(link_self_contained, "crt-objects-fallback"); target_option_val!(link_args - pre_link_args_json, "pre-link-args"); target_option_val!(link_args - late_link_args_json, "late-link-args"); target_option_val!(link_args - late_link_args_dynamic_json, "late-link-args-dynamic"); @@ -3231,6 +3413,10 @@ impl ToJson for Target { d.insert("default-adjusted-cabi".into(), Abi::name(abi).to_json()); } + // Serializing `-Clink-self-contained` needs a dynamic key to support the + // backwards-compatible variants. + d.insert(self.link_self_contained.json_key().into(), self.link_self_contained.to_json()); + Json::Object(d) } } diff --git a/compiler/rustc_target/src/spec/tests/tests_impl.rs b/compiler/rustc_target/src/spec/tests/tests_impl.rs index e0ecf8037c3..257867b1b80 100644 --- a/compiler/rustc_target/src/spec/tests/tests_impl.rs +++ b/compiler/rustc_target/src/spec/tests/tests_impl.rs @@ -97,7 +97,7 @@ impl Target { ); } - if self.link_self_contained == LinkSelfContainedDefault::False { + if self.link_self_contained.is_disabled() { assert!( self.pre_link_objects_self_contained.is_empty() && self.post_link_objects_self_contained.is_empty() diff --git a/compiler/rustc_target/src/spec/wasm32_wasi.rs b/compiler/rustc_target/src/spec/wasm32_wasi.rs index a0476d542e6..23fabcdc90d 100644 --- a/compiler/rustc_target/src/spec/wasm32_wasi.rs +++ b/compiler/rustc_target/src/spec/wasm32_wasi.rs @@ -72,7 +72,8 @@ //! best we can with this target. Don't start relying on too much here unless //! you know what you're getting in to! -use super::crt_objects::{self, LinkSelfContainedDefault}; +use super::crt_objects; +use super::LinkSelfContainedDefault; use super::{wasm_base, Cc, LinkerFlavor, Target}; pub fn target() -> Target { diff --git a/compiler/rustc_target/src/spec/wasm32_wasi_preview1_threads.rs b/compiler/rustc_target/src/spec/wasm32_wasi_preview1_threads.rs index c567155fee6..ba9a99ae380 100644 --- a/compiler/rustc_target/src/spec/wasm32_wasi_preview1_threads.rs +++ b/compiler/rustc_target/src/spec/wasm32_wasi_preview1_threads.rs @@ -72,8 +72,8 @@ //! best we can with this target. Don't start relying on too much here unless //! you know what you're getting in to! -use super::crt_objects::{self, LinkSelfContainedDefault}; -use super::{wasm_base, Cc, LinkerFlavor, Target}; +use super::{crt_objects, wasm_base}; +use super::{Cc, LinkSelfContainedDefault, LinkerFlavor, Target}; pub fn target() -> Target { let mut options = wasm_base::options(); diff --git a/compiler/rustc_target/src/spec/wasm_base.rs b/compiler/rustc_target/src/spec/wasm_base.rs index 341763aadba..82a3afeae31 100644 --- a/compiler/rustc_target/src/spec/wasm_base.rs +++ b/compiler/rustc_target/src/spec/wasm_base.rs @@ -1,4 +1,4 @@ -use super::crt_objects::LinkSelfContainedDefault; +use super::LinkSelfContainedDefault; use super::{cvs, Cc, LinkerFlavor, PanicStrategy, RelocModel, TargetOptions, TlsModel}; pub fn options() -> TargetOptions { diff --git a/compiler/rustc_target/src/spec/windows_gnu_base.rs b/compiler/rustc_target/src/spec/windows_gnu_base.rs index 2231983f071..b84e0fc0783 100644 --- a/compiler/rustc_target/src/spec/windows_gnu_base.rs +++ b/compiler/rustc_target/src/spec/windows_gnu_base.rs @@ -1,4 +1,5 @@ -use crate::spec::crt_objects::{self, LinkSelfContainedDefault}; +use crate::spec::crt_objects; +use crate::spec::LinkSelfContainedDefault; use crate::spec::{cvs, Cc, DebuginfoKind, LinkerFlavor, Lld, SplitDebuginfo, TargetOptions}; use std::borrow::Cow; @@ -90,7 +91,7 @@ pub fn opts() -> TargetOptions { post_link_objects: crt_objects::post_mingw(), pre_link_objects_self_contained: crt_objects::pre_mingw_self_contained(), post_link_objects_self_contained: crt_objects::post_mingw_self_contained(), - link_self_contained: LinkSelfContainedDefault::Mingw, + link_self_contained: LinkSelfContainedDefault::InferredForMingw, late_link_args, late_link_args_dynamic, late_link_args_static, 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..947ea3eece3 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:#}", )), ) } @@ -3465,11 +3465,11 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { if let Some(Node::Expr(expr)) = hir.find(arg_hir_id) && let Some(typeck_results) = &self.typeck_results { - if let hir::Expr { kind: hir::ExprKind::Block(..), .. } = expr { - let expr = expr.peel_blocks(); - let ty = - typeck_results.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(tcx)); - let span = expr.span; + if let hir::Expr { kind: hir::ExprKind::Block(block, _), .. } = expr { + let inner_expr = expr.peel_blocks(); + let ty = typeck_results.expr_ty_adjusted_opt(inner_expr) + .unwrap_or(Ty::new_misc_error(tcx)); + let span = inner_expr.span; if Some(span) != err.span.primary_span() { err.span_label( span, @@ -3480,6 +3480,49 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { format!("this tail expression is of type `{ty}`") }, ); + if let ty::PredicateKind::Clause(clause) = failed_pred.kind().skip_binder() + && let ty::ClauseKind::Trait(pred) = clause + && [ + tcx.lang_items().fn_once_trait(), + tcx.lang_items().fn_mut_trait(), + tcx.lang_items().fn_trait(), + ].contains(&Some(pred.def_id())) + { + if let [stmt, ..] = block.stmts + && let hir::StmtKind::Semi(value) = stmt.kind + && let hir::ExprKind::Closure(hir::Closure { + body, + fn_decl_span, + .. + }) = value.kind + && let body = hir.body(*body) + && !matches!(body.value.kind, hir::ExprKind::Block(..)) + { + // Check if the failed predicate was an expectation of a closure type + // and if there might have been a `{ |args|` typo instead of `|args| {`. + err.multipart_suggestion( + "you might have meant to open the closure body instead of placing \ + a closure within a block", + vec![ + (expr.span.with_hi(value.span.lo()), String::new()), + (fn_decl_span.shrink_to_hi(), " {".to_string()), + ], + Applicability::MaybeIncorrect, + ); + } else { + // Maybe the bare block was meant to be a closure. + err.span_suggestion_verbose( + expr.span.shrink_to_lo(), + "you might have meant to create the closure instead of a block", + format!( + "|{}| ", + (0..pred.trait_ref.args.len() - 1).map(|_| "_") + .collect::<Vec<_>>() + .join(", ")), + Applicability::MaybeIncorrect, + ); + } + } } } 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..7d6aa657104 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 @@ -98,6 +98,8 @@ pub trait TypeErrCtxtExt<'tcx> { error: &SelectionError<'tcx>, ); + fn fn_arg_obligation(&self, obligation: &PredicateObligation<'tcx>) -> bool; + fn report_const_param_not_wf( &self, ty: Ty<'tcx>, @@ -157,12 +159,6 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { predicate: error.obligation.predicate, index: Some(index), }); - - self.reported_trait_errors - .borrow_mut() - .entry(span) - .or_default() - .push(error.obligation.predicate); } // We do this in 2 passes because we want to display errors in order, though @@ -200,6 +196,18 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { for (error, suppressed) in iter::zip(&errors, &is_suppressed) { if !suppressed && error.obligation.cause.span.from_expansion() == from_expansion { self.report_fulfillment_error(error); + // We want to ignore desugarings here: spans are equivalent even + // if one is the result of a desugaring and the other is not. + let mut span = error.obligation.cause.span; + let expn_data = span.ctxt().outer_expn_data(); + if let ExpnKind::Desugaring(_) = expn_data.kind { + span = expn_data.call_site; + } + self.reported_trait_errors + .borrow_mut() + .entry(span) + .or_default() + .push(error.obligation.predicate); } } } @@ -412,6 +420,11 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { { return; } + if self.fn_arg_obligation(&obligation) { + // Silence redundant errors on binding acccess that are already + // reported on the binding definition (#56607). + return; + } let trait_ref = trait_predicate.to_poly_trait_ref(); let (post_message, pre_message, type_def) = self @@ -908,6 +921,26 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { err.emit(); } + fn fn_arg_obligation(&self, obligation: &PredicateObligation<'tcx>) -> bool { + if let ObligationCauseCode::FunctionArgumentObligation { + arg_hir_id, + .. + } = obligation.cause.code() + && let Some(Node::Expr(arg)) = self.tcx.hir().find(*arg_hir_id) + && let arg = arg.peel_borrows() + && let hir::ExprKind::Path(hir::QPath::Resolved( + None, + hir::Path { res: hir::def::Res::Local(hir_id), .. }, + )) = arg.kind + && let Some(Node::Pat(pat)) = self.tcx.hir().find(*hir_id) + && let Some(preds) = self.reported_trait_errors.borrow().get(&pat.span) + && preds.contains(&obligation.predicate) + { + return true; + } + false + } + fn report_const_param_not_wf( &self, ty: Ty<'tcx>, @@ -1611,9 +1644,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", }) } @@ -3071,6 +3104,13 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ); } }; + + if let Some(diag) = + self.tcx.sess.diagnostic().steal_diagnostic(self.tcx.def_span(def_id), StashKey::Cycle) + { + diag.cancel(); + } + err } 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 fbd403c82c6..a40c41583af 100644 --- a/compiler/rustc_type_ir/src/const_kind.rs +++ b/compiler/rustc_type_ir/src/const_kind.rs @@ -1,4 +1,5 @@ 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; @@ -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), diff --git a/compiler/rustc_type_ir/src/flags.rs b/compiler/rustc_type_ir/src/flags.rs index 2acb903c217..d5cadd4e83a 100644 --- a/compiler/rustc_type_ir/src/flags.rs +++ b/compiler/rustc_type_ir/src/flags.rs @@ -113,7 +113,7 @@ bitflags! { /// Does this value have `InferConst::Fresh`? const HAS_CT_FRESH = 1 << 22; - /// Does this have `Generator` or `GeneratorWitness`? - const HAS_TY_GENERATOR = 1 << 23; + /// Does this have `Coroutine` or `CoroutineWitness`? + const HAS_TY_COROUTINE = 1 << 23; } } 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 1ff220f3ed6..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, 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 23e575cbc37..19576ea58f1 100644 --- a/compiler/rustc_type_ir/src/region_kind.rs +++ b/compiler/rustc_type_ir/src/region_kind.rs @@ -1,4 +1,5 @@ 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; @@ -306,7 +307,7 @@ impl<I: Interner> fmt::Debug for RegionKind<I> { } // 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 9c719d2d978..b542547589a 100644 --- a/compiler/rustc_type_ir/src/ty_kind.rs +++ b/compiler/rustc_type_ir/src/ty_kind.rs @@ -622,7 +622,7 @@ impl<I: Interner> fmt::Debug for TyKind<I> { } // 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 => {} 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 8cacbdbda48..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; @@ -215,9 +214,6 @@ pub trait Context { /// Obtain the representation of a type. fn ty_kind(&self, ty: Ty) -> TyKind; - /// Create a new `Ty` from scratch without information from rustc. - fn mk_ty(&self, kind: TyKind) -> Ty; - /// Get the body of an Instance. /// FIXME: Monomorphize the body. fn instance_body(&self, instance: InstanceDef) -> Body; 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..e7440cc439b 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), @@ -434,6 +444,9 @@ pub enum ConstantKind { Allocated(Allocation), Unevaluated(UnevaluatedConst), Param(ParamConst), + /// Store ZST constants. + /// We have to special handle these constants since its type might be generic. + ZeroSized, } #[derive(Clone, Debug)] @@ -603,3 +616,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..05e0b9b4d78 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(_) => {} + super::ty::ConstantKind::Param(_) | super::ty::ConstantKind::ZeroSized => {} } - self.ty.visit(visitor) + self.ty().visit(visitor) } } diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index f28ae9a07b4..4f0a02da440 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -141,7 +141,6 @@ #![feature(maybe_uninit_uninit_array)] #![feature(maybe_uninit_uninit_array_transpose)] #![feature(pattern)] -#![feature(pointer_byte_offsets)] #![feature(ptr_addr_eq)] #![feature(ptr_internals)] #![feature(ptr_metadata)] diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs index 4ac956e7b76..7ce33bdd411 100644 --- a/library/core/src/char/methods.rs +++ b/library/core/src/char/methods.rs @@ -1450,7 +1450,7 @@ impl char { #[rustc_const_stable(feature = "const_ascii_ctype_on_intrinsics", since = "1.47.0")] #[inline] pub const fn is_ascii_alphanumeric(&self) -> bool { - matches!(*self, '0'..='9' | 'A'..='Z' | 'a'..='z') + matches!(*self, '0'..='9') | matches!(*self, 'A'..='Z') | matches!(*self, 'a'..='z') } /// Checks if the value is an ASCII decimal digit: @@ -1553,7 +1553,7 @@ impl char { #[rustc_const_stable(feature = "const_ascii_ctype_on_intrinsics", since = "1.47.0")] #[inline] pub const fn is_ascii_hexdigit(&self) -> bool { - matches!(*self, '0'..='9' | 'A'..='F' | 'a'..='f') + matches!(*self, '0'..='9') | matches!(*self, 'A'..='F') | matches!(*self, 'a'..='f') } /// Checks if the value is an ASCII punctuation character: @@ -1591,7 +1591,10 @@ impl char { #[rustc_const_stable(feature = "const_ascii_ctype_on_intrinsics", since = "1.47.0")] #[inline] pub const fn is_ascii_punctuation(&self) -> bool { - matches!(*self, '!'..='/' | ':'..='@' | '['..='`' | '{'..='~') + matches!(*self, '!'..='/') + | matches!(*self, ':'..='@') + | matches!(*self, '['..='`') + | matches!(*self, '{'..='~') } /// Checks if the value is an ASCII graphic character: diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index c7ace58afa8..6adea444214 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 { @@ -2141,7 +2142,7 @@ pub trait Iterator { /// passed collection. The collection is then returned, so the call chain /// can be continued. /// - /// This is useful when you already have a collection and wants to add + /// This is useful when you already have a collection and want to add /// the iterator items to it. /// /// This method is a convenience method to call [Extend::extend](trait.Extend.html), diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 03243e31348..0d00899c4de 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -148,7 +148,6 @@ #![feature(const_option)] #![feature(const_option_ext)] #![feature(const_pin)] -#![feature(const_pointer_byte_offsets)] #![feature(const_pointer_is_aligned)] #![feature(const_ptr_as_ref)] #![feature(const_ptr_is_null)] @@ -253,6 +252,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/mem/mod.rs b/library/core/src/mem/mod.rs index a79a204e2c6..7ef84b0f5b5 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -909,6 +909,10 @@ pub fn take<T: Default>(dest: &mut T) -> T { #[rustc_const_unstable(feature = "const_replace", issue = "83164")] #[cfg_attr(not(test), rustc_diagnostic_item = "mem_replace")] pub const fn replace<T>(dest: &mut T, src: T) -> T { + // It may be tempting to use `swap` to avoid `unsafe` here. Don't! + // The compiler optimizes the implementation below to two `memcpy`s + // while `swap` would require at least three. See PR#83022 for details. + // SAFETY: We read from `dest` but directly write `src` into it afterwards, // such that the old value is not duplicated. Nothing is dropped and // nothing here can panic. diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index a6c1adfac65..2a0b31404f0 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -791,7 +791,7 @@ impl u8 { #[rustc_const_stable(feature = "const_ascii_ctype_on_intrinsics", since = "1.47.0")] #[inline] pub const fn is_ascii_alphanumeric(&self) -> bool { - matches!(*self, b'0'..=b'9' | b'A'..=b'Z' | b'a'..=b'z') + matches!(*self, b'0'..=b'9') | matches!(*self, b'A'..=b'Z') | matches!(*self, b'a'..=b'z') } /// Checks if the value is an ASCII decimal digit: @@ -894,7 +894,7 @@ impl u8 { #[rustc_const_stable(feature = "const_ascii_ctype_on_intrinsics", since = "1.47.0")] #[inline] pub const fn is_ascii_hexdigit(&self) -> bool { - matches!(*self, b'0'..=b'9' | b'A'..=b'F' | b'a'..=b'f') + matches!(*self, b'0'..=b'9') | matches!(*self, b'A'..=b'F') | matches!(*self, b'a'..=b'f') } /// Checks if the value is an ASCII punctuation character: @@ -932,7 +932,10 @@ impl u8 { #[rustc_const_stable(feature = "const_ascii_ctype_on_intrinsics", since = "1.47.0")] #[inline] pub const fn is_ascii_punctuation(&self) -> bool { - matches!(*self, b'!'..=b'/' | b':'..=b'@' | b'['..=b'`' | b'{'..=b'~') + matches!(*self, b'!'..=b'/') + | matches!(*self, b':'..=b'@') + | matches!(*self, b'['..=b'`') + | matches!(*self, b'{'..=b'~') } /// Checks if the value is an ASCII graphic character: 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/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index a3e4f0fb90a..97f936fbd9e 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -480,8 +480,9 @@ impl<T: ?Sized> *const T { /// leaving the metadata untouched. #[must_use] #[inline(always)] - #[unstable(feature = "pointer_byte_offsets", issue = "96283")] - #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "96283")] + #[stable(feature = "pointer_byte_offsets", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "CURRENT_RUSTC_VERSION")] + #[rustc_allow_const_fn_unstable(set_ptr_value)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn byte_offset(self, count: isize) -> Self { // SAFETY: the caller must uphold the safety contract for `offset`. @@ -560,8 +561,9 @@ impl<T: ?Sized> *const T { /// leaving the metadata untouched. #[must_use] #[inline(always)] - #[unstable(feature = "pointer_byte_offsets", issue = "96283")] - #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "96283")] + #[stable(feature = "pointer_byte_offsets", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "CURRENT_RUSTC_VERSION")] + #[rustc_allow_const_fn_unstable(set_ptr_value)] pub const fn wrapping_byte_offset(self, count: isize) -> Self { self.cast::<u8>().wrapping_offset(count).with_metadata_of(self) } @@ -726,8 +728,9 @@ impl<T: ?Sized> *const T { /// For non-`Sized` pointees this operation considers only the data pointers, /// ignoring the metadata. #[inline(always)] - #[unstable(feature = "pointer_byte_offsets", issue = "96283")] - #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "96283")] + #[stable(feature = "pointer_byte_offsets", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "CURRENT_RUSTC_VERSION")] + #[rustc_allow_const_fn_unstable(set_ptr_value)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn byte_offset_from<U: ?Sized>(self, origin: *const U) -> isize { // SAFETY: the caller must uphold the safety contract for `offset_from`. @@ -952,8 +955,9 @@ impl<T: ?Sized> *const T { /// leaving the metadata untouched. #[must_use] #[inline(always)] - #[unstable(feature = "pointer_byte_offsets", issue = "96283")] - #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "96283")] + #[stable(feature = "pointer_byte_offsets", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "CURRENT_RUSTC_VERSION")] + #[rustc_allow_const_fn_unstable(set_ptr_value)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn byte_add(self, count: usize) -> Self { // SAFETY: the caller must uphold the safety contract for `add`. @@ -1045,8 +1049,9 @@ impl<T: ?Sized> *const T { /// leaving the metadata untouched. #[must_use] #[inline(always)] - #[unstable(feature = "pointer_byte_offsets", issue = "96283")] - #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "96283")] + #[stable(feature = "pointer_byte_offsets", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "CURRENT_RUSTC_VERSION")] + #[rustc_allow_const_fn_unstable(set_ptr_value)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn byte_sub(self, count: usize) -> Self { // SAFETY: the caller must uphold the safety contract for `sub`. @@ -1125,8 +1130,9 @@ impl<T: ?Sized> *const T { /// leaving the metadata untouched. #[must_use] #[inline(always)] - #[unstable(feature = "pointer_byte_offsets", issue = "96283")] - #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "96283")] + #[stable(feature = "pointer_byte_offsets", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "CURRENT_RUSTC_VERSION")] + #[rustc_allow_const_fn_unstable(set_ptr_value)] pub const fn wrapping_byte_add(self, count: usize) -> Self { self.cast::<u8>().wrapping_add(count).with_metadata_of(self) } @@ -1203,8 +1209,9 @@ impl<T: ?Sized> *const T { /// leaving the metadata untouched. #[must_use] #[inline(always)] - #[unstable(feature = "pointer_byte_offsets", issue = "96283")] - #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "96283")] + #[stable(feature = "pointer_byte_offsets", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "CURRENT_RUSTC_VERSION")] + #[rustc_allow_const_fn_unstable(set_ptr_value)] pub const fn wrapping_byte_sub(self, count: usize) -> Self { self.cast::<u8>().wrapping_sub(count).with_metadata_of(self) } @@ -1372,7 +1379,6 @@ impl<T: ?Sized> *const T { /// /// ``` /// #![feature(pointer_is_aligned)] - /// #![feature(pointer_byte_offsets)] /// /// // On some platforms, the alignment of i32 is less than 4. /// #[repr(align(4))] @@ -1494,7 +1500,6 @@ impl<T: ?Sized> *const T { /// /// ``` /// #![feature(pointer_is_aligned)] - /// #![feature(pointer_byte_offsets)] /// /// // On some platforms, the alignment of i32 is less than 4. /// #[repr(align(4))] diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 109c286929b..64695d63f0c 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -495,8 +495,9 @@ impl<T: ?Sized> *mut T { /// leaving the metadata untouched. #[must_use] #[inline(always)] - #[unstable(feature = "pointer_byte_offsets", issue = "96283")] - #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "96283")] + #[stable(feature = "pointer_byte_offsets", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "CURRENT_RUSTC_VERSION")] + #[rustc_allow_const_fn_unstable(set_ptr_value)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn byte_offset(self, count: isize) -> Self { // SAFETY: the caller must uphold the safety contract for `offset`. @@ -574,8 +575,9 @@ impl<T: ?Sized> *mut T { /// leaving the metadata untouched. #[must_use] #[inline(always)] - #[unstable(feature = "pointer_byte_offsets", issue = "96283")] - #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "96283")] + #[stable(feature = "pointer_byte_offsets", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "CURRENT_RUSTC_VERSION")] + #[rustc_allow_const_fn_unstable(set_ptr_value)] pub const fn wrapping_byte_offset(self, count: isize) -> Self { self.cast::<u8>().wrapping_offset(count).with_metadata_of(self) } @@ -898,8 +900,9 @@ impl<T: ?Sized> *mut T { /// For non-`Sized` pointees this operation considers only the data pointers, /// ignoring the metadata. #[inline(always)] - #[unstable(feature = "pointer_byte_offsets", issue = "96283")] - #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "96283")] + #[stable(feature = "pointer_byte_offsets", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "CURRENT_RUSTC_VERSION")] + #[rustc_allow_const_fn_unstable(set_ptr_value)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn byte_offset_from<U: ?Sized>(self, origin: *const U) -> isize { // SAFETY: the caller must uphold the safety contract for `offset_from`. @@ -1053,8 +1056,9 @@ impl<T: ?Sized> *mut T { /// leaving the metadata untouched. #[must_use] #[inline(always)] - #[unstable(feature = "pointer_byte_offsets", issue = "96283")] - #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "96283")] + #[stable(feature = "pointer_byte_offsets", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "CURRENT_RUSTC_VERSION")] + #[rustc_allow_const_fn_unstable(set_ptr_value)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn byte_add(self, count: usize) -> Self { // SAFETY: the caller must uphold the safety contract for `add`. @@ -1146,8 +1150,9 @@ impl<T: ?Sized> *mut T { /// leaving the metadata untouched. #[must_use] #[inline(always)] - #[unstable(feature = "pointer_byte_offsets", issue = "96283")] - #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "96283")] + #[stable(feature = "pointer_byte_offsets", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "CURRENT_RUSTC_VERSION")] + #[rustc_allow_const_fn_unstable(set_ptr_value)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn byte_sub(self, count: usize) -> Self { // SAFETY: the caller must uphold the safety contract for `sub`. @@ -1226,8 +1231,9 @@ impl<T: ?Sized> *mut T { /// leaving the metadata untouched. #[must_use] #[inline(always)] - #[unstable(feature = "pointer_byte_offsets", issue = "96283")] - #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "96283")] + #[stable(feature = "pointer_byte_offsets", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "CURRENT_RUSTC_VERSION")] + #[rustc_allow_const_fn_unstable(set_ptr_value)] pub const fn wrapping_byte_add(self, count: usize) -> Self { self.cast::<u8>().wrapping_add(count).with_metadata_of(self) } @@ -1304,8 +1310,9 @@ impl<T: ?Sized> *mut T { /// leaving the metadata untouched. #[must_use] #[inline(always)] - #[unstable(feature = "pointer_byte_offsets", issue = "96283")] - #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "96283")] + #[stable(feature = "pointer_byte_offsets", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "CURRENT_RUSTC_VERSION")] + #[rustc_allow_const_fn_unstable(set_ptr_value)] pub const fn wrapping_byte_sub(self, count: usize) -> Self { self.cast::<u8>().wrapping_sub(count).with_metadata_of(self) } @@ -1639,7 +1646,6 @@ impl<T: ?Sized> *mut T { /// /// ``` /// #![feature(pointer_is_aligned)] - /// #![feature(pointer_byte_offsets)] /// /// // On some platforms, the alignment of i32 is less than 4. /// #[repr(align(4))] @@ -1763,7 +1769,6 @@ impl<T: ?Sized> *mut T { /// /// ``` /// #![feature(pointer_is_aligned)] - /// #![feature(pointer_byte_offsets)] /// /// // On some platforms, the alignment of i32 is less than 4. /// #[repr(align(4))] diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 280d2219b9e..df7b34ce73b 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -16,7 +16,6 @@ #![feature(const_heap)] #![feature(const_maybe_uninit_as_mut_ptr)] #![feature(const_nonnull_new)] -#![feature(const_pointer_byte_offsets)] #![feature(const_pointer_is_aligned)] #![feature(const_ptr_as_ref)] #![feature(const_ptr_write)] @@ -87,7 +86,6 @@ #![feature(const_waker)] #![feature(never_type)] #![feature(unwrap_infallible)] -#![feature(pointer_byte_offsets)] #![feature(pointer_is_aligned)] #![feature(portable_simd)] #![feature(ptr_metadata)] diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index bca5d859b66..aa9a2482d2d 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -317,6 +317,7 @@ pub use self::stdio::set_output_capture; #[stable(feature = "is_terminal", since = "1.70.0")] pub use self::stdio::IsTerminal; #[unstable(feature = "print_internals", issue = "none")] +#[doc(hidden)] pub use self::stdio::{_eprint, _print}; #[stable(feature = "rust1", since = "1.0.0")] pub use self::{ diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index aaf20875129..f57c8d4e7e2 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -331,7 +331,6 @@ #![feature(panic_can_unwind)] #![feature(panic_info_message)] #![feature(panic_internals)] -#![feature(pointer_byte_offsets)] #![feature(pointer_is_aligned)] #![feature(portable_simd)] #![feature(prelude_2024)] 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/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index 7b26068c294..4097eb5549e 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -545,6 +545,15 @@ impl Builder { scope_data.increment_num_running_threads(); } + let main = Box::new(main); + // SAFETY: dynamic size and alignment of the Box remain the same. See below for why the + // lifetime change is justified. + #[cfg(bootstrap)] + let main = + unsafe { mem::transmute::<Box<dyn FnOnce() + 'a>, Box<dyn FnOnce() + 'static>>(main) }; + #[cfg(not(bootstrap))] + let main = unsafe { Box::from_raw(Box::into_raw(main) as *mut (dyn FnOnce() + 'static)) }; + Ok(JoinInner { // SAFETY: // @@ -559,14 +568,7 @@ impl Builder { // Similarly, the `sys` implementation must guarantee that no references to the closure // exist after the thread has terminated, which is signaled by `Thread::join` // returning. - native: unsafe { - imp::Thread::new( - stack_size, - mem::transmute::<Box<dyn FnOnce() + 'a>, Box<dyn FnOnce() + 'static>>( - Box::new(main), - ), - )? - }, + native: unsafe { imp::Thread::new(stack_size, main)? }, thread: my_thread, packet: my_packet, }) 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/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/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 831a86940fb..7fb67eea551 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -27,6 +27,7 @@ use crate::core::config::flags::Subcommand; use crate::core::config::TargetSelection; use crate::utils; use crate::utils::cache::{Interned, INTERNER}; +use crate::utils::exec::BootstrapCommand; use crate::utils::helpers::{ self, add_link_lib_path, dylib_path, dylib_path_var, output, t, up_to_date, }; @@ -629,7 +630,7 @@ impl Step for Miri { SourceType::InTree, &[], ); - let _guard = builder.msg_sysroot_tool(Kind::Test, compiler.stage, "miri", host, host); + let _guard = builder.msg_sysroot_tool(Kind::Test, compiler.stage, "miri", host, target); cargo.add_rustc_lib_path(builder, compiler); @@ -808,8 +809,8 @@ impl Step for Clippy { let _guard = builder.msg_sysroot_tool(Kind::Test, compiler.stage, "clippy", host, host); - #[allow(deprecated)] // Clippy reports errors if it blessed the outputs - if builder.config.try_run(&mut cargo).is_ok() { + // Clippy reports errors if it blessed the outputs + if builder.run_cmd(BootstrapCommand::from(&mut cargo).allow_failure()) { // The tests succeeded; nothing to do. return; } @@ -1566,10 +1567,12 @@ note: if you're sure you want to do this, please open an issue as to why. In the cmd.arg("--coverage-dump-path").arg(coverage_dump); } - if mode == "run-make" || mode == "run-coverage" { + if mode == "run-coverage" { + // The demangler doesn't need the current compiler, so we can avoid + // unnecessary rebuilds by using the bootstrap compiler instead. let rust_demangler = builder .ensure(tool::RustDemangler { - compiler, + compiler: compiler.with_stage(0), target: compiler.host, extra_features: Vec::new(), }) @@ -2999,7 +3002,10 @@ impl Step for CodegenCranelift { let triple = run.target.triple; let target_supported = if triple.contains("linux") { - triple.contains("x86_64") || triple.contains("aarch64") || triple.contains("s390x") + triple.contains("x86_64") + || triple.contains("aarch64") + || triple.contains("s390x") + || triple.contains("riscv64gc") } else if triple.contains("darwin") || triple.contains("windows") { triple.contains("x86_64") } else { @@ -3094,7 +3100,7 @@ impl Step for CodegenCranelift { .arg("testsuite.extended_sysroot"); cargo.args(builder.config.test_args()); - #[allow(deprecated)] - builder.config.try_run(&mut cargo.into()).unwrap(); + let mut cmd: Command = cargo.into(); + builder.run_cmd(BootstrapCommand::from(&mut cmd).fail_fast()); } } diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index 5702fa62d7c..d5f759ea159 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -8,6 +8,7 @@ use crate::core::build_steps::toolstate::ToolState; use crate::core::builder::{Builder, Cargo as CargoCommand, RunConfig, ShouldRun, Step}; use crate::core::config::TargetSelection; use crate::utils::channel::GitInfo; +use crate::utils::exec::BootstrapCommand; use crate::utils::helpers::{add_dylib_path, exe, t}; use crate::Compiler; use crate::Mode; @@ -108,8 +109,8 @@ impl Step for ToolBuild { ); let mut cargo = Command::from(cargo); - #[allow(deprecated)] // we check this in `is_optional_tool` in a second - let is_expected = builder.config.try_run(&mut cargo).is_ok(); + // we check this in `is_optional_tool` in a second + let is_expected = builder.run_cmd(BootstrapCommand::from(&mut cargo).allow_failure()); builder.save_toolstate( tool, 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/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index 705c27bb922..8dd1a698dfa 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -23,11 +23,12 @@ use std::fmt::Display; use std::fs::{self, File}; use std::io; use std::path::{Path, PathBuf}; -use std::process::{Command, Stdio}; +use std::process::{Command, Output, Stdio}; use std::str; use build_helper::ci::{gha, CiEnv}; use build_helper::exit; +use build_helper::util::fail; use filetime::FileTime; use once_cell::sync::OnceCell; use termcolor::{ColorChoice, StandardStream, WriteColor}; @@ -39,10 +40,8 @@ use crate::core::config::flags; use crate::core::config::{DryRun, Target}; use crate::core::config::{LlvmLibunwind, TargetSelection}; use crate::utils::cache::{Interned, INTERNER}; -use crate::utils::helpers::{ - self, dir_is_empty, exe, libdir, mtime, output, run, run_suppressed, symlink_dir, - try_run_suppressed, -}; +use crate::utils::exec::{BehaviorOnFailure, BootstrapCommand, OutputMode}; +use crate::utils::helpers::{self, dir_is_empty, exe, libdir, mtime, output, symlink_dir}; mod core; mod utils; @@ -580,15 +579,15 @@ impl Build { } // Save any local changes, but avoid running `git stash pop` if there are none (since it will exit with an error). - #[allow(deprecated)] // diff-index reports the modifications through the exit status - let has_local_modifications = self - .config - .try_run( + // diff-index reports the modifications through the exit status + let has_local_modifications = !self.run_cmd( + BootstrapCommand::from( Command::new("git") .args(&["diff-index", "--quiet", "HEAD"]) .current_dir(&absolute_path), ) - .is_err(); + .allow_failure(), + ); if has_local_modifications { self.run(Command::new("git").args(&["stash", "push"]).current_dir(&absolute_path)); } @@ -921,55 +920,103 @@ impl Build { /// Runs a command, printing out nice contextual information if it fails. fn run(&self, cmd: &mut Command) { - if self.config.dry_run() { - return; - } - self.verbose(&format!("running: {cmd:?}")); - run(cmd, self.is_verbose()) + self.run_cmd(BootstrapCommand::from(cmd).fail_fast().output_mode( + match self.is_verbose() { + true => OutputMode::PrintAll, + false => OutputMode::PrintOutput, + }, + )); + } + + /// Runs a command, printing out contextual info if it fails, and delaying errors until the build finishes. + pub(crate) fn run_delaying_failure(&self, cmd: &mut Command) -> bool { + self.run_cmd(BootstrapCommand::from(cmd).delay_failure().output_mode( + match self.is_verbose() { + true => OutputMode::PrintAll, + false => OutputMode::PrintOutput, + }, + )) } /// Runs a command, printing out nice contextual information if it fails. fn run_quiet(&self, cmd: &mut Command) { - if self.config.dry_run() { - return; - } - self.verbose(&format!("running: {cmd:?}")); - run_suppressed(cmd) + self.run_cmd( + BootstrapCommand::from(cmd).fail_fast().output_mode(OutputMode::SuppressOnSuccess), + ); } /// Runs a command, printing out nice contextual information if it fails. /// Exits if the command failed to execute at all, otherwise returns its /// `status.success()`. fn run_quiet_delaying_failure(&self, cmd: &mut Command) -> bool { + self.run_cmd( + BootstrapCommand::from(cmd).delay_failure().output_mode(OutputMode::SuppressOnSuccess), + ) + } + + /// A centralized function for running commands that do not return output. + pub(crate) fn run_cmd<'a, C: Into<BootstrapCommand<'a>>>(&self, cmd: C) -> bool { if self.config.dry_run() { return true; } - if !self.fail_fast { - self.verbose(&format!("running: {cmd:?}")); - if !try_run_suppressed(cmd) { - let mut failures = self.delayed_failures.borrow_mut(); - failures.push(format!("{cmd:?}")); - return false; + + let command = cmd.into(); + self.verbose(&format!("running: {command:?}")); + + let (output, print_error) = match command.output_mode { + mode @ (OutputMode::PrintAll | OutputMode::PrintOutput) => ( + command.command.status().map(|status| Output { + status, + stdout: Vec::new(), + stderr: Vec::new(), + }), + matches!(mode, OutputMode::PrintAll), + ), + OutputMode::SuppressOnSuccess => (command.command.output(), true), + }; + + let output = match output { + Ok(output) => output, + Err(e) => fail(&format!("failed to execute command: {:?}\nerror: {}", command, e)), + }; + let result = if !output.status.success() { + if print_error { + println!( + "\n\ncommand did not execute successfully: {:?}\n\ + expected success, got: {}\n\n\ + stdout ----\n{}\n\ + stderr ----\n{}\n\n", + command.command, + output.status, + String::from_utf8_lossy(&output.stdout), + String::from_utf8_lossy(&output.stderr) + ); } + Err(()) } else { - self.run_quiet(cmd); - } - true - } + Ok(()) + }; - /// Runs a command, printing out contextual info if it fails, and delaying errors until the build finishes. - pub(crate) fn run_delaying_failure(&self, cmd: &mut Command) -> bool { - if !self.fail_fast { - #[allow(deprecated)] // can't use Build::try_run, that's us - if self.config.try_run(cmd).is_err() { - let mut failures = self.delayed_failures.borrow_mut(); - failures.push(format!("{cmd:?}")); - return false; + match result { + Ok(_) => true, + Err(_) => { + match command.failure_behavior { + BehaviorOnFailure::DelayFail => { + if self.fail_fast { + exit!(1); + } + + let mut failures = self.delayed_failures.borrow_mut(); + failures.push(format!("{command:?}")); + } + BehaviorOnFailure::Exit => { + exit!(1); + } + BehaviorOnFailure::Ignore => {} + } + false } - } else { - self.run(cmd); } - true } pub fn is_verbose_than(&self, level: usize) -> bool { diff --git a/src/bootstrap/src/utils/exec.rs b/src/bootstrap/src/utils/exec.rs new file mode 100644 index 00000000000..9c1c21cd958 --- /dev/null +++ b/src/bootstrap/src/utils/exec.rs @@ -0,0 +1,60 @@ +use std::process::Command; + +/// What should be done when the command fails. +#[derive(Debug, Copy, Clone)] +pub enum BehaviorOnFailure { + /// Immediately stop bootstrap. + Exit, + /// Delay failure until the end of bootstrap invocation. + DelayFail, + /// Ignore the failure, the command can fail in an expected way. + Ignore, +} + +/// How should the output of the command be handled. +#[derive(Debug, Copy, Clone)] +pub enum OutputMode { + /// Print both the output (by inheriting stdout/stderr) and also the command itself, if it + /// fails. + PrintAll, + /// Print the output (by inheriting stdout/stderr). + PrintOutput, + /// Suppress the output if the command succeeds, otherwise print the output. + SuppressOnSuccess, +} + +/// Wrapper around `std::process::Command`. +#[derive(Debug)] +pub struct BootstrapCommand<'a> { + pub command: &'a mut Command, + pub failure_behavior: BehaviorOnFailure, + pub output_mode: OutputMode, +} + +impl<'a> BootstrapCommand<'a> { + pub fn delay_failure(self) -> Self { + Self { failure_behavior: BehaviorOnFailure::DelayFail, ..self } + } + + pub fn fail_fast(self) -> Self { + Self { failure_behavior: BehaviorOnFailure::Exit, ..self } + } + + pub fn allow_failure(self) -> Self { + Self { failure_behavior: BehaviorOnFailure::Ignore, ..self } + } + + pub fn output_mode(self, output_mode: OutputMode) -> Self { + Self { output_mode, ..self } + } +} + +impl<'a> From<&'a mut Command> for BootstrapCommand<'a> { + fn from(command: &'a mut Command) -> Self { + Self { + command, + failure_behavior: BehaviorOnFailure::Exit, + output_mode: OutputMode::SuppressOnSuccess, + } + } +} diff --git a/src/bootstrap/src/utils/helpers.rs b/src/bootstrap/src/utils/helpers.rs index bb84b70d987..b58a1c25842 100644 --- a/src/bootstrap/src/utils/helpers.rs +++ b/src/bootstrap/src/utils/helpers.rs @@ -3,7 +3,7 @@ //! Simple things like testing the various filesystem operations here and there, //! not a lot of interesting happenings here unfortunately. -use build_helper::util::{fail, try_run}; +use build_helper::util::fail; use std::env; use std::fs; use std::io; @@ -216,12 +216,6 @@ pub fn is_valid_test_suite_arg<'a, P: AsRef<Path>>( } } -pub fn run(cmd: &mut Command, print_cmd_on_fail: bool) { - if try_run(cmd, print_cmd_on_fail).is_err() { - crate::exit!(1); - } -} - pub fn check_run(cmd: &mut Command, print_cmd_on_fail: bool) -> bool { let status = match cmd.status() { Ok(status) => status, @@ -239,32 +233,6 @@ pub fn check_run(cmd: &mut Command, print_cmd_on_fail: bool) -> bool { status.success() } -pub fn run_suppressed(cmd: &mut Command) { - if !try_run_suppressed(cmd) { - crate::exit!(1); - } -} - -pub fn try_run_suppressed(cmd: &mut Command) -> bool { - let output = match cmd.output() { - Ok(status) => status, - Err(e) => fail(&format!("failed to execute command: {cmd:?}\nerror: {e}")), - }; - if !output.status.success() { - println!( - "\n\ncommand did not execute successfully: {:?}\n\ - expected success, got: {}\n\n\ - stdout ----\n{}\n\ - stderr ----\n{}\n\n", - cmd, - output.status, - String::from_utf8_lossy(&output.stdout), - String::from_utf8_lossy(&output.stderr) - ); - } - output.status.success() -} - pub fn make(host: &str) -> PathBuf { if host.contains("dragonfly") || host.contains("freebsd") diff --git a/src/bootstrap/src/utils/mod.rs b/src/bootstrap/src/utils/mod.rs index 7dcb6a82862..8ca22d00865 100644 --- a/src/bootstrap/src/utils/mod.rs +++ b/src/bootstrap/src/utils/mod.rs @@ -6,6 +6,7 @@ pub(crate) mod cache; pub(crate) mod cc_detect; pub(crate) mod channel; pub(crate) mod dylib; +pub(crate) mod exec; pub(crate) mod helpers; pub(crate) mod job; #[cfg(feature = "build-metrics")] 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/rustc/src/profile-guided-optimization.md b/src/doc/rustc/src/profile-guided-optimization.md index d9cf7ce30f9..38b655b7542 100644 --- a/src/doc/rustc/src/profile-guided-optimization.md +++ b/src/doc/rustc/src/profile-guided-optimization.md @@ -145,3 +145,26 @@ in Clang's documentation is therefore an interesting read for anyone who wants to use PGO with Rust. [clang-pgo]: https://clang.llvm.org/docs/UsersManual.html#profile-guided-optimization + +## Community Maintained Tools + +As an alternative to directly using the compiler for Profile-Guided Optimization, +you may choose to go with `cargo-pgo`, which has an intuitive command-line API +and saves you the trouble of doing all the manual work. You can read more about +it in their repository accessible from this link: https://github.com/Kobzol/cargo-pgo + +For the sake of completeness, here are the corresponding steps using `cargo-pgo`: + +```bash +# Install if you haven't already +cargo install cargo-pgo + +cargo pgo build +cargo pgo optimize +``` + +These steps will do the following just as before: + +1. Build an instrumented binary from the source code. +2. Run the instrumented binary to gather PGO profiles. +3. Use the gathered PGO profiles from the last step to build an optimized binary. 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/Cargo.toml b/src/librustdoc/Cargo.toml index 38935b7d1bb..0e01c100f9c 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -10,6 +10,7 @@ path = "lib.rs" arrayvec = { version = "0.7", default-features = false } askama = { version = "0.12", default-features = false, features = ["config"] } itertools = "0.10.1" +indexmap = "2" minifier = "0.2.3" once_cell = "1.10.0" regex = "1" diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 89796761126..013814b1f7d 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -26,6 +26,8 @@ use crate::clean::{ use crate::core::DocContext; use crate::formats::item_type::ItemType; +use super::Item; + /// Attempt to inline a definition into this AST. /// /// This function will fetch the definition specified, and if it is @@ -83,7 +85,7 @@ pub(crate) fn try_inline( Res::Def(DefKind::TyAlias, did) => { record_extern_fqn(cx, did, ItemType::TypeAlias); build_impls(cx, did, attrs_without_docs, &mut ret); - clean::TypeAliasItem(build_type_alias(cx, did)) + clean::TypeAliasItem(build_type_alias(cx, did, &mut ret)) } Res::Def(DefKind::Enum, did) => { record_extern_fqn(cx, did, ItemType::Enum); @@ -281,11 +283,15 @@ fn build_union(cx: &mut DocContext<'_>, did: DefId) -> clean::Union { clean::Union { generics, fields } } -fn build_type_alias(cx: &mut DocContext<'_>, did: DefId) -> Box<clean::TypeAlias> { +fn build_type_alias( + cx: &mut DocContext<'_>, + did: DefId, + ret: &mut Vec<Item>, +) -> Box<clean::TypeAlias> { let predicates = cx.tcx.explicit_predicates_of(did); let ty = cx.tcx.type_of(did).instantiate_identity(); let type_ = clean_middle_ty(ty::Binder::dummy(ty), cx, Some(did), None); - let inner_type = clean_ty_alias_inner_type(ty, cx); + let inner_type = clean_ty_alias_inner_type(ty, cx, ret); Box::new(clean::TypeAlias { type_, diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 125b1fecf18..f2447b877ca 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -934,11 +934,16 @@ fn clean_ty_generics<'tcx>( fn clean_ty_alias_inner_type<'tcx>( ty: Ty<'tcx>, cx: &mut DocContext<'tcx>, + ret: &mut Vec<Item>, ) -> Option<TypeAliasInnerType> { let ty::Adt(adt_def, args) = ty.kind() else { return None; }; + if !adt_def.did().is_local() { + inline::build_impls(cx, adt_def.did(), None, ret); + } + Some(if adt_def.is_enum() { let variants: rustc_index::IndexVec<_, _> = adt_def .variants() @@ -946,6 +951,10 @@ fn clean_ty_alias_inner_type<'tcx>( .map(|variant| clean_variant_def_with_args(variant, args, cx)) .collect(); + if !adt_def.did().is_local() { + inline::record_extern_fqn(cx, adt_def.did(), ItemType::Enum); + } + TypeAliasInnerType::Enum { variants, is_non_exhaustive: adt_def.is_variant_list_non_exhaustive(), @@ -961,8 +970,14 @@ fn clean_ty_alias_inner_type<'tcx>( clean_variant_def_with_args(variant, args, cx).kind.inner_items().cloned().collect(); if adt_def.is_struct() { + if !adt_def.did().is_local() { + inline::record_extern_fqn(cx, adt_def.did(), ItemType::Struct); + } TypeAliasInnerType::Struct { ctor_kind: variant.ctor_kind(), fields } } else { + if !adt_def.did().is_local() { + inline::record_extern_fqn(cx, adt_def.did(), ItemType::Union); + } TypeAliasInnerType::Union { fields } } }) @@ -2744,14 +2759,24 @@ fn clean_maybe_renamed_item<'tcx>( } let ty = cx.tcx.type_of(def_id).instantiate_identity(); - let inner_type = clean_ty_alias_inner_type(ty, cx); - TypeAliasItem(Box::new(TypeAlias { - generics, - inner_type, - type_: rustdoc_ty, - item_type: Some(type_), - })) + let mut ret = Vec::new(); + let inner_type = clean_ty_alias_inner_type(ty, cx, &mut ret); + + ret.push(generate_item_with_correct_attrs( + cx, + TypeAliasItem(Box::new(TypeAlias { + generics, + inner_type, + type_: rustdoc_ty, + item_type: Some(type_), + })), + item.owner_id.def_id.to_def_id(), + name, + import_id, + renamed, + )); + return ret; } ItemKind::Enum(ref def, generics) => EnumItem(Enum { variants: def.variants.iter().map(|v| clean_variant(v, cx)).collect(), 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/formats/cache.rs b/src/librustdoc/formats/cache.rs index 4ccb5f2be34..abff77253ea 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -50,8 +50,8 @@ pub(crate) struct Cache { /// Unlike 'paths', this mapping ignores any renames that occur /// due to 'use' statements. /// - /// This map is used when writing out the special 'implementors' - /// javascript file. By using the exact path that the type + /// This map is used when writing out the `impl.trait` and `impl.type` + /// javascript files. By using the exact path that the type /// is declared with, we ensure that each path will be identical /// to the path used if the corresponding type is inlined. By /// doing this, we can detect duplicate impls on a trait page, and only display diff --git a/src/librustdoc/formats/item_type.rs b/src/librustdoc/formats/item_type.rs index e37d16f5bd0..def3a90c8e8 100644 --- a/src/librustdoc/formats/item_type.rs +++ b/src/librustdoc/formats/item_type.rs @@ -180,6 +180,9 @@ impl ItemType { pub(crate) fn is_method(&self) -> bool { matches!(*self, ItemType::Method | ItemType::TyMethod) } + pub(crate) fn is_adt(&self) -> bool { + matches!(*self, ItemType::Struct | ItemType::Union | ItemType::Enum) + } } impl fmt::Display for ItemType { diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs index bf8d1a80337..6da9e45a1da 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs @@ -7,10 +7,8 @@ use std::sync::mpsc::{channel, Receiver}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::def_id::{DefIdMap, LOCAL_CRATE}; -use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; use rustc_middle::ty::TyCtxt; use rustc_session::Session; -use rustc_span::def_id::DefId; use rustc_span::edition::Edition; use rustc_span::source_map::FileName; use rustc_span::{sym, Symbol}; @@ -25,13 +23,13 @@ use super::{ AllTypes, LinkFromSrc, StylePath, }; use crate::clean::utils::has_doc_flag; -use crate::clean::{self, types::ExternalLocation, ExternalCrate, TypeAliasItem}; +use crate::clean::{self, types::ExternalLocation, ExternalCrate}; use crate::config::{ModuleSorting, RenderOptions}; use crate::docfs::{DocFS, PathError}; use crate::error::Error; use crate::formats::cache::Cache; use crate::formats::item_type::ItemType; -use crate::formats::{self, FormatRenderer}; +use crate::formats::FormatRenderer; use crate::html::escape::Escape; use crate::html::format::{join_with_double_colon, Buffer}; use crate::html::markdown::{self, plain_text_summary, ErrorCodes, IdMap}; @@ -150,53 +148,6 @@ impl SharedContext<'_> { pub(crate) fn edition(&self) -> Edition { self.tcx.sess.edition() } - - /// Returns a list of impls on the given type, and, if it's a type alias, - /// other types that it aliases. - pub(crate) fn all_impls_for_item<'a>( - &'a self, - it: &clean::Item, - did: DefId, - ) -> Vec<&'a formats::Impl> { - let tcx = self.tcx; - let cache = &self.cache; - let mut saw_impls = FxHashSet::default(); - let mut v: Vec<&formats::Impl> = cache - .impls - .get(&did) - .map(Vec::as_slice) - .unwrap_or(&[]) - .iter() - .filter(|i| saw_impls.insert(i.def_id())) - .collect(); - if let TypeAliasItem(ait) = &*it.kind && - let aliased_clean_type = ait.item_type.as_ref().unwrap_or(&ait.type_) && - let Some(aliased_type_defid) = aliased_clean_type.def_id(cache) && - let Some(av) = cache.impls.get(&aliased_type_defid) && - let Some(alias_def_id) = it.item_id.as_def_id() - { - // This branch of the compiler compares types structually, but does - // not check trait bounds. That's probably fine, since type aliases - // don't normally constrain on them anyway. - // https://github.com/rust-lang/rust/issues/21903 - // - // FIXME(lazy_type_alias): Once the feature is complete or stable, rewrite this to use type unification. - // Be aware of `tests/rustdoc/issue-112515-impl-ty-alias.rs` which might regress. - let aliased_ty = tcx.type_of(alias_def_id).skip_binder(); - let reject_cx = DeepRejectCtxt { - treat_obligation_params: TreatParams::AsCandidateKey, - }; - v.extend(av.iter().filter(|impl_| { - if let Some(impl_def_id) = impl_.impl_item.item_id.as_def_id() { - reject_cx.types_may_unify(aliased_ty, tcx.type_of(impl_def_id).skip_binder()) - && saw_impls.insert(impl_def_id) - } else { - false - } - })); - } - v - } } impl<'tcx> Context<'tcx> { diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 89e29d8b59b..d9086433608 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, @@ -1132,13 +1145,13 @@ pub(crate) fn render_all_impls( fn render_assoc_items<'a, 'cx: 'a>( cx: &'a mut Context<'cx>, containing_item: &'a clean::Item, - did: DefId, + it: DefId, what: AssocItemRender<'a>, ) -> impl fmt::Display + 'a + Captures<'cx> { let mut derefs = DefIdSet::default(); - derefs.insert(did); + derefs.insert(it); display_fn(move |f| { - render_assoc_items_inner(f, cx, containing_item, did, what, &mut derefs); + render_assoc_items_inner(f, cx, containing_item, it, what, &mut derefs); Ok(()) }) } @@ -1147,17 +1160,15 @@ fn render_assoc_items_inner( mut w: &mut dyn fmt::Write, cx: &mut Context<'_>, containing_item: &clean::Item, - did: DefId, + it: DefId, what: AssocItemRender<'_>, derefs: &mut DefIdSet, ) { info!("Documenting associated items of {:?}", containing_item.name); let shared = Rc::clone(&cx.shared); - let v = shared.all_impls_for_item(containing_item, did); - let v = v.as_slice(); - let (non_trait, traits): (Vec<&Impl>, _) = - v.iter().partition(|i| i.inner_impl().trait_.is_none()); - let mut saw_impls = FxHashSet::default(); + let cache = &shared.cache; + let Some(v) = cache.impls.get(&it) else { return }; + let (non_trait, traits): (Vec<_>, _) = v.iter().partition(|i| i.inner_impl().trait_.is_none()); if !non_trait.is_empty() { let mut tmp_buf = Buffer::html(); let (render_mode, id, class_html) = match what { @@ -1186,9 +1197,6 @@ fn render_assoc_items_inner( }; let mut impls_buf = Buffer::html(); for i in &non_trait { - if !saw_impls.insert(i.def_id()) { - continue; - } render_impl( &mut impls_buf, cx, @@ -1234,10 +1242,8 @@ fn render_assoc_items_inner( let (synthetic, concrete): (Vec<&Impl>, Vec<&Impl>) = traits.into_iter().partition(|t| t.inner_impl().kind.is_auto()); - let (blanket_impl, concrete): (Vec<&Impl>, _) = concrete - .into_iter() - .filter(|t| saw_impls.insert(t.def_id())) - .partition(|t| t.inner_impl().kind.is_blanket()); + let (blanket_impl, concrete): (Vec<&Impl>, _) = + concrete.into_iter().partition(|t| t.inner_impl().kind.is_blanket()); render_all_impls(w, cx, containing_item, &concrete, &synthetic, &blanket_impl); } diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index f6432dc61ae..fdf45569061 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -1066,6 +1066,8 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: } } + // [RUSTDOCIMPL] trait.impl + // // Include implementors in crates that depend on the current crate. // // This is complicated by the way rustdoc is invoked, which is basically @@ -1101,7 +1103,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: // ``` // // Basically, we want `C::Baz` and `A::Foo` to show the same set of - // impls, which is easier if they both treat `/implementors/A/trait.Foo.js` + // impls, which is easier if they both treat `/trait.impl/A/trait.Foo.js` // as the Single Source of Truth. // // We also want the `impl Baz for Quux` to be written to @@ -1110,7 +1112,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: // because that'll load faster, and it's better for SEO. And we don't want // the same impl to show up twice on the same page. // - // To make this work, the implementors JS file has a structure kinda + // To make this work, the trait.impl/A/trait.Foo.js JS file has a structure kinda // like this: // // ```js @@ -1127,7 +1129,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: // So C's HTML will have something like this: // // ```html - // <script src="/implementors/A/trait.Foo.js" + // <script src="/trait.impl/A/trait.Foo.js" // data-ignore-extern-crates="A,B" async></script> // ``` // @@ -1137,7 +1139,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: // [JSONP]: https://en.wikipedia.org/wiki/JSONP let mut js_src_path: UrlPartsBuilder = std::iter::repeat("..") .take(cx.current.len()) - .chain(std::iter::once("implementors")) + .chain(std::iter::once("trait.impl")) .collect(); if let Some(did) = it.item_id.as_def_id() && let get_extern = { || cache.external_paths.get(&did).map(|s| &s.0) } && @@ -1319,6 +1321,102 @@ fn item_type_alias(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &c // we need #14072 to make sense of the generics. write!(w, "{}", render_assoc_items(cx, it, def_id, AssocItemRender::All)); write!(w, "{}", document_type_layout(cx, def_id)); + + // [RUSTDOCIMPL] type.impl + // + // Include type definitions from the alias target type. + // + // Earlier versions of this code worked by having `render_assoc_items` + // include this data directly. That generates *O*`(types*impls)` of HTML + // text, and some real crates have a lot of types and impls. + // + // To create the same UX without generating half a gigabyte of HTML for a + // crate that only contains 20 megabytes of actual documentation[^115718], + // rustdoc stashes these type-alias-inlined docs in a [JSONP] + // "database-lite". The file itself is generated in `write_shared.rs`, + // and hooks into functions provided by `main.js`. + // + // The format of `trait.impl` and `type.impl` JS files are superficially + // similar. Each line, except the JSONP wrapper itself, belongs to a crate, + // and they are otherwise separate (rustdoc should be idempotent). The + // "meat" of the file is HTML strings, so the frontend code is very simple. + // Links are relative to the doc root, though, so the frontend needs to fix + // that up, and inlined docs can reuse these files. + // + // However, there are a few differences, caused by the sophisticated + // features that type aliases have. Consider this crate graph: + // + // ```text + // --------------------------------- + // | crate A: struct Foo<T> | + // | type Bar = Foo<i32> | + // | impl X for Foo<i8> | + // | impl Y for Foo<i32> | + // --------------------------------- + // | + // ---------------------------------- + // | crate B: type Baz = A::Foo<i8> | + // | type Xyy = A::Foo<i8> | + // | impl Z for Xyy | + // ---------------------------------- + // ``` + // + // The type.impl/A/struct.Foo.js JS file has a structure kinda like this: + // + // ```js + // JSONP({ + // "A": [["impl Y for Foo<i32>", "Y", "A::Bar"]], + // "B": [["impl X for Foo<i8>", "X", "B::Baz", "B::Xyy"], ["impl Z for Xyy", "Z", "B::Baz"]], + // }); + // ``` + // + // When the type.impl file is loaded, only the current crate's docs are + // actually used. The main reason to bundle them together is that there's + // enough duplication in them for DEFLATE to remove the redundancy. + // + // The contents of a crate are a list of impl blocks, themselves + // represented as lists. The first item in the sublist is the HTML block, + // the second item is the name of the trait (which goes in the sidebar), + // and all others are the names of type aliases that successfully match. + // + // This way: + // + // - There's no need to generate these files for types that have no aliases + // in the current crate. If a dependent crate makes a type alias, it'll + // take care of generating its own docs. + // - There's no need to reimplement parts of the type checker in + // JavaScript. The Rust backend does the checking, and includes its + // results in the file. + // - Docs defined directly on the type alias are dropped directly in the + // HTML by `render_assoc_items`, and are accessible without JavaScript. + // The JSONP file will not list impl items that are known to be part + // of the main HTML file already. + // + // [JSONP]: https://en.wikipedia.org/wiki/JSONP + // [^115718]: https://github.com/rust-lang/rust/issues/115718 + let cloned_shared = Rc::clone(&cx.shared); + let cache = &cloned_shared.cache; + if let Some(target_did) = t.type_.def_id(cache) && + let get_extern = { || cache.external_paths.get(&target_did) } && + let Some(&(ref target_fqp, target_type)) = cache.paths.get(&target_did).or_else(get_extern) && + target_type.is_adt() && // primitives cannot be inlined + let Some(self_did) = it.item_id.as_def_id() && + let get_local = { || cache.paths.get(&self_did).map(|(p, _)| p) } && + let Some(self_fqp) = cache.exact_paths.get(&self_did).or_else(get_local) + { + let mut js_src_path: UrlPartsBuilder = std::iter::repeat("..") + .take(cx.current.len()) + .chain(std::iter::once("type.impl")) + .collect(); + js_src_path.extend(target_fqp[..target_fqp.len() - 1].iter().copied()); + js_src_path.push_fmt(format_args!("{target_type}.{}.js", target_fqp.last().unwrap())); + let self_path = self_fqp.iter().map(Symbol::as_str).collect::<Vec<&str>>().join("::"); + write!( + w, + "<script src=\"{src}\" data-self-path=\"{self_path}\" async></script>", + src = js_src_path.finish(), + ); + } } fn item_union(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean::Union) { diff --git a/src/librustdoc/html/render/sidebar.rs b/src/librustdoc/html/render/sidebar.rs index fb429f237e3..4e8d88c55b6 100644 --- a/src/librustdoc/html/render/sidebar.rs +++ b/src/librustdoc/html/render/sidebar.rs @@ -38,18 +38,19 @@ pub(crate) struct LinkBlock<'a> { /// as well as the link to it, e.g. `#implementations`. /// Will be rendered inside an `<h3>` tag heading: Link<'a>, + class: &'static str, links: Vec<Link<'a>>, /// Render the heading even if there are no links force_render: bool, } impl<'a> LinkBlock<'a> { - pub fn new(heading: Link<'a>, links: Vec<Link<'a>>) -> Self { - Self { heading, links, force_render: false } + pub fn new(heading: Link<'a>, class: &'static str, links: Vec<Link<'a>>) -> Self { + Self { heading, links, class, force_render: false } } - pub fn forced(heading: Link<'a>) -> Self { - Self { heading, links: vec![], force_render: true } + pub fn forced(heading: Link<'a>, class: &'static str) -> Self { + Self { heading, links: vec![], class, force_render: true } } pub fn should_render(&self) -> bool { @@ -157,7 +158,7 @@ fn sidebar_struct<'a>( }; let mut items = vec![]; if let Some(name) = field_name { - items.push(LinkBlock::new(Link::new("fields", name), fields)); + items.push(LinkBlock::new(Link::new("fields", name), "structfield", fields)); } sidebar_assoc_items(cx, it, &mut items); items @@ -214,12 +215,15 @@ fn sidebar_trait<'a>( ("foreign-impls", "Implementations on Foreign Types", foreign_impls), ] .into_iter() - .map(|(id, title, items)| LinkBlock::new(Link::new(id, title), items)) + .map(|(id, title, items)| LinkBlock::new(Link::new(id, title), "", items)) .collect(); sidebar_assoc_items(cx, it, &mut blocks); - blocks.push(LinkBlock::forced(Link::new("implementors", "Implementors"))); + blocks.push(LinkBlock::forced(Link::new("implementors", "Implementors"), "impl")); if t.is_auto(cx.tcx()) { - blocks.push(LinkBlock::forced(Link::new("synthetic-implementors", "Auto Implementors"))); + blocks.push(LinkBlock::forced( + Link::new("synthetic-implementors", "Auto Implementors"), + "impl-auto", + )); } blocks } @@ -245,7 +249,7 @@ fn sidebar_type_alias<'a>( ) -> Vec<LinkBlock<'a>> { let mut items = vec![]; if let Some(inner_type) = &t.inner_type { - items.push(LinkBlock::forced(Link::new("aliased-type", "Aliased type"))); + items.push(LinkBlock::forced(Link::new("aliased-type", "Aliased type"), "type")); match inner_type { clean::TypeAliasInnerType::Enum { variants, is_non_exhaustive: _ } => { let mut variants = variants @@ -256,12 +260,12 @@ fn sidebar_type_alias<'a>( .collect::<Vec<_>>(); variants.sort_unstable(); - items.push(LinkBlock::new(Link::new("variants", "Variants"), variants)); + items.push(LinkBlock::new(Link::new("variants", "Variants"), "variant", variants)); } clean::TypeAliasInnerType::Union { fields } | clean::TypeAliasInnerType::Struct { ctor_kind: _, fields } => { let fields = get_struct_fields_name(fields); - items.push(LinkBlock::new(Link::new("fields", "Fields"), fields)); + items.push(LinkBlock::new(Link::new("fields", "Fields"), "field", fields)); } } } @@ -275,7 +279,7 @@ fn sidebar_union<'a>( u: &'a clean::Union, ) -> Vec<LinkBlock<'a>> { let fields = get_struct_fields_name(&u.fields); - let mut items = vec![LinkBlock::new(Link::new("fields", "Fields"), fields)]; + let mut items = vec![LinkBlock::new(Link::new("fields", "Fields"), "structfield", fields)]; sidebar_assoc_items(cx, it, &mut items); items } @@ -287,12 +291,11 @@ fn sidebar_assoc_items<'a>( links: &mut Vec<LinkBlock<'a>>, ) { let did = it.item_id.expect_def_id(); - let v = cx.shared.all_impls_for_item(it, it.item_id.expect_def_id()); - let v = v.as_slice(); + let cache = cx.cache(); let mut assoc_consts = Vec::new(); let mut methods = Vec::new(); - if !v.is_empty() { + if let Some(v) = cache.impls.get(&did) { let mut used_links = FxHashSet::default(); let mut id_map = IdMap::new(); @@ -328,7 +331,7 @@ fn sidebar_assoc_items<'a>( cx, &mut deref_methods, impl_, - v.iter().copied(), + v, &mut derefs, &mut used_links, ); @@ -341,12 +344,16 @@ fn sidebar_assoc_items<'a>( sidebar_render_assoc_items(cx, &mut id_map, concrete, synthetic, blanket_impl) } else { - std::array::from_fn(|_| LinkBlock::new(Link::empty(), vec![])) + std::array::from_fn(|_| LinkBlock::new(Link::empty(), "", vec![])) }; let mut blocks = vec![ - LinkBlock::new(Link::new("implementations", "Associated Constants"), assoc_consts), - LinkBlock::new(Link::new("implementations", "Methods"), methods), + LinkBlock::new( + Link::new("implementations", "Associated Constants"), + "associatedconstant", + assoc_consts, + ), + LinkBlock::new(Link::new("implementations", "Methods"), "method", methods), ]; blocks.append(&mut deref_methods); blocks.extend([concrete, synthetic, blanket]); @@ -358,7 +365,7 @@ fn sidebar_deref_methods<'a>( cx: &'a Context<'_>, out: &mut Vec<LinkBlock<'a>>, impl_: &Impl, - v: impl Iterator<Item = &'a Impl>, + v: &[Impl], derefs: &mut DefIdSet, used_links: &mut FxHashSet<String>, ) { @@ -383,7 +390,7 @@ fn sidebar_deref_methods<'a>( // Avoid infinite cycles return; } - let deref_mut = { v }.any(|i| i.trait_did() == cx.tcx().lang_items().deref_mut_trait()); + let deref_mut = v.iter().any(|i| i.trait_did() == cx.tcx().lang_items().deref_mut_trait()); let inner_impl = target .def_id(c) .or_else(|| { @@ -415,7 +422,7 @@ fn sidebar_deref_methods<'a>( ); // We want links' order to be reproducible so we don't use unstable sort. ret.sort(); - out.push(LinkBlock::new(Link::new(id, title), ret)); + out.push(LinkBlock::new(Link::new(id, title), "deref-methods", ret)); } } @@ -434,7 +441,7 @@ fn sidebar_deref_methods<'a>( cx, out, target_deref_impl, - target_impls.iter(), + target_impls, derefs, used_links, ); @@ -454,7 +461,7 @@ fn sidebar_enum<'a>( .collect::<Vec<_>>(); variants.sort_unstable(); - let mut items = vec![LinkBlock::new(Link::new("variants", "Variants"), variants)]; + let mut items = vec![LinkBlock::new(Link::new("variants", "Variants"), "variant", variants)]; sidebar_assoc_items(cx, it, &mut items); items } @@ -468,7 +475,7 @@ pub(crate) fn sidebar_module_like( .filter(|sec| item_sections_in_use.contains(sec)) .map(|sec| Link::new(sec.id(), sec.name())) .collect(); - LinkBlock::new(Link::empty(), item_sections) + LinkBlock::new(Link::empty(), "", item_sections) } fn sidebar_module(items: &[clean::Item]) -> LinkBlock<'static> { @@ -529,12 +536,21 @@ fn sidebar_render_assoc_items( let synthetic = format_impls(synthetic, id_map); let blanket = format_impls(blanket_impl, id_map); [ - LinkBlock::new(Link::new("trait-implementations", "Trait Implementations"), concrete), + LinkBlock::new( + Link::new("trait-implementations", "Trait Implementations"), + "trait-implementation", + concrete, + ), LinkBlock::new( Link::new("synthetic-implementations", "Auto Trait Implementations"), + "synthetic-implementation", synthetic, ), - LinkBlock::new(Link::new("blanket-implementations", "Blanket Implementations"), blanket), + LinkBlock::new( + Link::new("blanket-implementations", "Blanket Implementations"), + "blanket-implementation", + blanket, + ), ] } diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs index e68d5ab2fbd..3e58dd96ed9 100644 --- a/src/librustdoc/html/render/write_shared.rs +++ b/src/librustdoc/html/render/write_shared.rs @@ -5,18 +5,28 @@ use std::io::{self, BufReader}; use std::path::{Component, Path}; use std::rc::{Rc, Weak}; +use indexmap::IndexMap; use itertools::Itertools; use rustc_data_structures::flock; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; +use rustc_span::def_id::DefId; +use rustc_span::Symbol; use serde::ser::SerializeSeq; use serde::{Serialize, Serializer}; use super::{collect_paths_for_type, ensure_trailing_slash, Context}; -use crate::clean::Crate; +use crate::clean::{Crate, Item, ItemId, ItemKind}; use crate::config::{EmitType, RenderOptions}; use crate::docfs::PathError; use crate::error::Error; +use crate::formats::cache::Cache; +use crate::formats::item_type::ItemType; +use crate::formats::{Impl, RenderMode}; +use crate::html::format::Buffer; +use crate::html::render::{AssocItemLink, ImplRenderingParameters}; use crate::html::{layout, static_files}; +use crate::visit::DocVisitor; use crate::{try_err, try_none}; /// Rustdoc writes out two kinds of shared files: @@ -361,9 +371,264 @@ if (typeof exports !== 'undefined') {exports.searchIndex = searchIndex}; } } + let cloned_shared = Rc::clone(&cx.shared); + let cache = &cloned_shared.cache; + + // Collect the list of aliased types and their aliases. + // <https://github.com/search?q=repo%3Arust-lang%2Frust+[RUSTDOCIMPL]+type.impl&type=code> + // + // The clean AST has type aliases that point at their types, but + // this visitor works to reverse that: `aliased_types` is a map + // from target to the aliases that reference it, and each one + // will generate one file. + struct TypeImplCollector<'cx, 'cache> { + // Map from DefId-of-aliased-type to its data. + aliased_types: IndexMap<DefId, AliasedType<'cache>>, + visited_aliases: FxHashSet<DefId>, + cache: &'cache Cache, + cx: &'cache mut Context<'cx>, + } + // Data for an aliased type. + // + // In the final file, the format will be roughly: + // + // ```json + // // type.impl/CRATE/TYPENAME.js + // JSONP( + // "CRATE": [ + // ["IMPL1 HTML", "ALIAS1", "ALIAS2", ...], + // ["IMPL2 HTML", "ALIAS3", "ALIAS4", ...], + // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ struct AliasedType + // ... + // ] + // ) + // ``` + struct AliasedType<'cache> { + // This is used to generate the actual filename of this aliased type. + target_fqp: &'cache [Symbol], + target_type: ItemType, + // This is the data stored inside the file. + // ItemId is used to deduplicate impls. + impl_: IndexMap<ItemId, AliasedTypeImpl<'cache>>, + } + // The `impl_` contains data that's used to figure out if an alias will work, + // and to generate the HTML at the end. + // + // The `type_aliases` list is built up with each type alias that matches. + struct AliasedTypeImpl<'cache> { + impl_: &'cache Impl, + type_aliases: Vec<(&'cache [Symbol], Item)>, + } + impl<'cx, 'cache> DocVisitor for TypeImplCollector<'cx, 'cache> { + fn visit_item(&mut self, it: &Item) { + self.visit_item_recur(it); + let cache = self.cache; + let ItemKind::TypeAliasItem(ref t) = *it.kind else { return }; + let Some(self_did) = it.item_id.as_def_id() else { return }; + if !self.visited_aliases.insert(self_did) { + return; + } + let Some(target_did) = t.type_.def_id(cache) else { return }; + let get_extern = { || cache.external_paths.get(&target_did) }; + let Some(&(ref target_fqp, target_type)) = + cache.paths.get(&target_did).or_else(get_extern) + else { + return; + }; + let aliased_type = self.aliased_types.entry(target_did).or_insert_with(|| { + let impl_ = cache + .impls + .get(&target_did) + .map(|v| &v[..]) + .unwrap_or_default() + .iter() + .map(|impl_| { + ( + impl_.impl_item.item_id, + AliasedTypeImpl { impl_, type_aliases: Vec::new() }, + ) + }) + .collect(); + AliasedType { target_fqp: &target_fqp[..], target_type, impl_ } + }); + let get_local = { || cache.paths.get(&self_did).map(|(p, _)| p) }; + let Some(self_fqp) = cache.exact_paths.get(&self_did).or_else(get_local) else { + return; + }; + let aliased_ty = self.cx.tcx().type_of(self_did).skip_binder(); + // Exclude impls that are directly on this type. They're already in the HTML. + // Some inlining scenarios can cause there to be two versions of the same + // impl: one on the type alias and one on the underlying target type. + let mut seen_impls: FxHashSet<ItemId> = cache + .impls + .get(&self_did) + .map(|s| &s[..]) + .unwrap_or_default() + .iter() + .map(|i| i.impl_item.item_id) + .collect(); + for (impl_item_id, aliased_type_impl) in &mut aliased_type.impl_ { + // Only include this impl if it actually unifies with this alias. + // Synthetic impls are not included; those are also included in the HTML. + // + // FIXME(lazy_type_alias): Once the feature is complete or stable, rewrite this + // to use type unification. + // Be aware of `tests/rustdoc/type-alias/deeply-nested-112515.rs` which might regress. + let Some(impl_did) = impl_item_id.as_def_id() else { continue }; + let for_ty = self.cx.tcx().type_of(impl_did).skip_binder(); + let reject_cx = + DeepRejectCtxt { treat_obligation_params: TreatParams::AsCandidateKey }; + if !reject_cx.types_may_unify(aliased_ty, for_ty) { + continue; + } + // Avoid duplicates + if !seen_impls.insert(*impl_item_id) { + continue; + } + // This impl was not found in the set of rejected impls + aliased_type_impl.type_aliases.push((&self_fqp[..], it.clone())); + } + } + } + let mut type_impl_collector = TypeImplCollector { + aliased_types: IndexMap::default(), + visited_aliases: FxHashSet::default(), + cache, + cx, + }; + DocVisitor::visit_crate(&mut type_impl_collector, &krate); + // Final serialized form of the alias impl + struct AliasSerializableImpl { + text: String, + trait_: Option<String>, + aliases: Vec<String>, + } + impl Serialize for AliasSerializableImpl { + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: Serializer, + { + let mut seq = serializer.serialize_seq(None)?; + seq.serialize_element(&self.text)?; + if let Some(trait_) = &self.trait_ { + seq.serialize_element(trait_)?; + } else { + seq.serialize_element(&0)?; + } + for type_ in &self.aliases { + seq.serialize_element(type_)?; + } + seq.end() + } + } + let cx = type_impl_collector.cx; + let dst = cx.dst.join("type.impl"); + let aliased_types = type_impl_collector.aliased_types; + for aliased_type in aliased_types.values() { + let impls = aliased_type + .impl_ + .values() + .flat_map(|AliasedTypeImpl { impl_, type_aliases }| { + let mut ret = Vec::new(); + let trait_ = impl_ + .inner_impl() + .trait_ + .as_ref() + .map(|trait_| format!("{:#}", trait_.print(cx))); + // render_impl will filter out "impossible-to-call" methods + // to make that functionality work here, it needs to be called with + // each type alias, and if it gives a different result, split the impl + for &(type_alias_fqp, ref type_alias_item) in type_aliases { + let mut buf = Buffer::html(); + cx.id_map = Default::default(); + cx.deref_id_map = Default::default(); + let target_did = impl_ + .inner_impl() + .trait_ + .as_ref() + .map(|trait_| trait_.def_id()) + .or_else(|| impl_.inner_impl().for_.def_id(cache)); + let provided_methods; + let assoc_link = if let Some(target_did) = target_did { + provided_methods = impl_.inner_impl().provided_trait_methods(cx.tcx()); + AssocItemLink::GotoSource(ItemId::DefId(target_did), &provided_methods) + } else { + AssocItemLink::Anchor(None) + }; + super::render_impl( + &mut buf, + cx, + *impl_, + &type_alias_item, + assoc_link, + RenderMode::Normal, + None, + &[], + ImplRenderingParameters { + show_def_docs: true, + show_default_items: true, + show_non_assoc_items: true, + toggle_open_by_default: true, + }, + ); + let text = buf.into_inner(); + let type_alias_fqp = (*type_alias_fqp).iter().join("::"); + if Some(&text) == ret.last().map(|s: &AliasSerializableImpl| &s.text) { + ret.last_mut() + .expect("already established that ret.last() is Some()") + .aliases + .push(type_alias_fqp); + } else { + ret.push(AliasSerializableImpl { + text, + trait_: trait_.clone(), + aliases: vec![type_alias_fqp], + }) + } + } + ret + }) + .collect::<Vec<_>>(); + let impls = format!( + r#""{}":{}"#, + krate.name(cx.tcx()), + serde_json::to_string(&impls).expect("failed serde conversion"), + ); + + let mut mydst = dst.clone(); + for part in &aliased_type.target_fqp[..aliased_type.target_fqp.len() - 1] { + mydst.push(part.to_string()); + } + cx.shared.ensure_dir(&mydst)?; + let aliased_item_type = aliased_type.target_type; + mydst.push(&format!( + "{aliased_item_type}.{}.js", + aliased_type.target_fqp[aliased_type.target_fqp.len() - 1] + )); + + let (mut all_impls, _) = try_err!(collect(&mydst, krate.name(cx.tcx()).as_str()), &mydst); + all_impls.push(impls); + // Sort the implementors by crate so the file will be generated + // identically even with rustdoc running in parallel. + all_impls.sort(); + + let mut v = String::from("(function() {var type_impls = {\n"); + v.push_str(&all_impls.join(",\n")); + v.push_str("\n};"); + v.push_str( + "if (window.register_type_impls) {\ + window.register_type_impls(type_impls);\ + } else {\ + window.pending_type_impls = type_impls;\ + }", + ); + v.push_str("})()"); + cx.shared.fs.write(mydst, v)?; + } + // Update the list of all implementors for traits - let dst = cx.dst.join("implementors"); - let cache = cx.cache(); + // <https://github.com/search?q=repo%3Arust-lang%2Frust+[RUSTDOCIMPL]+trait.impl&type=code> + let dst = cx.dst.join("trait.impl"); for (&did, imps) in &cache.implementors { // Private modules can leak through to this phase of rustdoc, which // could contain implementations for otherwise private types. In some diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index 2e9897ef82b..7c052606aba 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -549,6 +549,7 @@ function preLoadCss(cssUrl) { } } + // <https://github.com/search?q=repo%3Arust-lang%2Frust+[RUSTDOCIMPL]+trait.impl&type=code> window.register_implementors = imp => { const implementors = document.getElementById("implementors-list"); const synthetic_implementors = document.getElementById("synthetic-implementors-list"); @@ -615,7 +616,7 @@ function preLoadCss(cssUrl) { onEachLazy(code.getElementsByTagName("a"), elem => { const href = elem.getAttribute("href"); - if (href && !/^(?:[a-z+]+:)?\/\//.test(href)) { + if (href && !href.startsWith("#") && !/^(?:[a-z+]+:)?\/\//.test(href)) { elem.setAttribute("href", window.rootPath + href); } }); @@ -639,6 +640,216 @@ function preLoadCss(cssUrl) { window.register_implementors(window.pending_implementors); } + /** + * <https://github.com/search?q=repo%3Arust-lang%2Frust+[RUSTDOCIMPL]+type.impl&type=code> + * + * [RUSTDOCIMPL] type.impl + * + * This code inlines implementations into the type alias docs at runtime. It's done at + * runtime because some crates have many type aliases and many methods, and we don't want + * to generate *O*`(types*methods)` HTML text. The data inside is mostly HTML fragments, + * wrapped in JSON. + * + * - It only includes docs generated for the current crate. This function accepts an + * object mapping crate names to the set of impls. + * + * - It filters down to the set of applicable impls. The Rust type checker is used to + * tag each HTML blob with the set of type aliases that can actually use it, so the + * JS only needs to consult the attached list of type aliases. + * + * - It renames the ID attributes, to avoid conflicting IDs in the resulting DOM. + * + * - It adds the necessary items to the sidebar. If it's an inherent impl, that means + * adding methods, associated types, and associated constants. If it's a trait impl, + * that means adding it to the trait impl sidebar list. + * + * - It adds the HTML block itself. If it's an inherent impl, it goes after the type + * alias's own inherent impls. If it's a trait impl, it goes in the Trait + * Implementations section. + * + * - After processing all of the impls, it sorts the sidebar items by name. + * + * @param {{[cratename: string]: Array<Array<string|0>>}} impl + */ + window.register_type_impls = imp => { + if (!imp || !imp[window.currentCrate]) { + return; + } + window.pending_type_impls = null; + const idMap = new Map(); + + let implementations = document.getElementById("implementations-list"); + let trait_implementations = document.getElementById("trait-implementations-list"); + let trait_implementations_header = document.getElementById("trait-implementations"); + + // We want to include the current type alias's impls, and no others. + const script = document.querySelector("script[data-self-path]"); + const selfPath = script ? script.getAttribute("data-self-path") : null; + + // These sidebar blocks need filled in, too. + const mainContent = document.querySelector("#main-content"); + const sidebarSection = document.querySelector(".sidebar section"); + let methods = document.querySelector(".sidebar .block.method"); + let associatedTypes = document.querySelector(".sidebar .block.associatedtype"); + let associatedConstants = document.querySelector(".sidebar .block.associatedconstant"); + let sidebarTraitList = document.querySelector(".sidebar .block.trait-implementation"); + + for (const impList of imp[window.currentCrate]) { + const types = impList.slice(2); + const text = impList[0]; + const isTrait = impList[1] !== 0; + const traitName = impList[1]; + if (types.indexOf(selfPath) === -1) { + continue; + } + let outputList = isTrait ? trait_implementations : implementations; + if (outputList === null) { + const outputListName = isTrait ? "Trait Implementations" : "Implementations"; + const outputListId = isTrait ? + "trait-implementations-list" : + "implementations-list"; + const outputListHeaderId = isTrait ? "trait-implementations" : "implementations"; + const outputListHeader = document.createElement("h2"); + outputListHeader.id = outputListHeaderId; + outputListHeader.innerText = outputListName; + outputList = document.createElement("div"); + outputList.id = outputListId; + if (isTrait) { + const link = document.createElement("a"); + link.href = `#${outputListHeaderId}`; + link.innerText = "Trait Implementations"; + const h = document.createElement("h3"); + h.appendChild(link); + trait_implementations = outputList; + trait_implementations_header = outputListHeader; + sidebarSection.appendChild(h); + sidebarTraitList = document.createElement("ul"); + sidebarTraitList.className = "block trait-implementation"; + sidebarSection.appendChild(sidebarTraitList); + mainContent.appendChild(outputListHeader); + mainContent.appendChild(outputList); + } else { + implementations = outputList; + if (trait_implementations) { + mainContent.insertBefore(outputListHeader, trait_implementations_header); + mainContent.insertBefore(outputList, trait_implementations_header); + } else { + const mainContent = document.querySelector("#main-content"); + mainContent.appendChild(outputListHeader); + mainContent.appendChild(outputList); + } + } + } + const template = document.createElement("template"); + template.innerHTML = text; + + onEachLazy(template.content.querySelectorAll("a"), elem => { + const href = elem.getAttribute("href"); + + if (href && !href.startsWith("#") && !/^(?:[a-z+]+:)?\/\//.test(href)) { + elem.setAttribute("href", window.rootPath + href); + } + }); + onEachLazy(template.content.querySelectorAll("[id]"), el => { + let i = 0; + if (idMap.has(el.id)) { + i = idMap.get(el.id); + } else if (document.getElementById(el.id)) { + i = 1; + while (document.getElementById(`${el.id}-${2 * i}`)) { + i = 2 * i; + } + while (document.getElementById(`${el.id}-${i}`)) { + i += 1; + } + } + if (i !== 0) { + const oldHref = `#${el.id}`; + const newHref = `#${el.id}-${i}`; + el.id = `${el.id}-${i}`; + onEachLazy(template.content.querySelectorAll("a[href]"), link => { + if (link.getAttribute("href") === oldHref) { + link.href = newHref; + } + }); + } + idMap.set(el.id, i + 1); + }); + const templateAssocItems = template.content.querySelectorAll("section.tymethod, " + + "section.method, section.associatedtype, section.associatedconstant"); + if (isTrait) { + const li = document.createElement("li"); + const a = document.createElement("a"); + a.href = `#${template.content.querySelector(".impl").id}`; + a.textContent = traitName; + li.appendChild(a); + sidebarTraitList.append(li); + } else { + onEachLazy(templateAssocItems, item => { + let block = hasClass(item, "associatedtype") ? associatedTypes : ( + hasClass(item, "associatedconstant") ? associatedConstants : ( + methods)); + if (!block) { + const blockTitle = hasClass(item, "associatedtype") ? "Associated Types" : ( + hasClass(item, "associatedconstant") ? "Associated Constants" : ( + "Methods")); + const blockClass = hasClass(item, "associatedtype") ? "associatedtype" : ( + hasClass(item, "associatedconstant") ? "associatedconstant" : ( + "method")); + const blockHeader = document.createElement("h3"); + const blockLink = document.createElement("a"); + blockLink.href = "#implementations"; + blockLink.innerText = blockTitle; + blockHeader.appendChild(blockLink); + block = document.createElement("ul"); + block.className = `block ${blockClass}`; + const insertionReference = methods || sidebarTraitList; + if (insertionReference) { + const insertionReferenceH = insertionReference.previousElementSibling; + sidebarSection.insertBefore(blockHeader, insertionReferenceH); + sidebarSection.insertBefore(block, insertionReferenceH); + } else { + sidebarSection.appendChild(blockHeader); + sidebarSection.appendChild(block); + } + if (hasClass(item, "associatedtype")) { + associatedTypes = block; + } else if (hasClass(item, "associatedconstant")) { + associatedConstants = block; + } else { + methods = block; + } + } + const li = document.createElement("li"); + const a = document.createElement("a"); + a.innerText = item.id.split("-")[0].split(".")[1]; + a.href = `#${item.id}`; + li.appendChild(a); + block.appendChild(li); + }); + } + outputList.appendChild(template.content); + } + + for (const list of [methods, associatedTypes, associatedConstants, sidebarTraitList]) { + if (!list) { + continue; + } + const newChildren = Array.prototype.slice.call(list.children); + newChildren.sort((a, b) => { + const aI = a.innerText; + const bI = b.innerText; + return aI < bI ? -1 : + aI > bI ? 1 : + 0; + }); + list.replaceChildren(...newChildren); + } + }; + if (window.pending_type_impls) { + window.register_type_impls(window.pending_type_impls); + } + function addSidebarCrates() { if (!window.ALL_CRATES) { return; diff --git a/src/librustdoc/html/templates/sidebar.html b/src/librustdoc/html/templates/sidebar.html index a99198141e2..d982134181c 100644 --- a/src/librustdoc/html/templates/sidebar.html +++ b/src/librustdoc/html/templates/sidebar.html @@ -18,7 +18,7 @@ <h3><a href="#{{block.heading.href|safe}}">{{block.heading.name}}</a></h3> {% endif %} {% if !block.links.is_empty() %} - <ul class="block"> + <ul class="block{% if !block.class.is_empty() +%} {{+block.class}}{% endif %}"> {% for link in block.links %} <li><a href="#{{link.href|safe}}">{{link.name}}</a></li> {% endfor %} 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/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs index ff89d4e0887..a57321b5822 100644 --- a/src/librustdoc/passes/collect_trait_impls.rs +++ b/src/librustdoc/passes/collect_trait_impls.rs @@ -36,7 +36,7 @@ pub(crate) fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> let prims: FxHashSet<PrimitiveType> = local_crate.primitives(tcx).iter().map(|p| p.1).collect(); let crate_items = { - let mut coll = ItemCollector::new(); + let mut coll = ItemAndAliasCollector::new(&cx.cache); cx.sess().time("collect_items_for_trait_impls", || coll.visit_crate(&krate)); coll.items }; @@ -235,21 +235,27 @@ impl<'a, 'tcx> DocVisitor for SyntheticImplCollector<'a, 'tcx> { } } -#[derive(Default)] -struct ItemCollector { +struct ItemAndAliasCollector<'cache> { items: FxHashSet<ItemId>, + cache: &'cache Cache, } -impl ItemCollector { - fn new() -> Self { - Self::default() +impl<'cache> ItemAndAliasCollector<'cache> { + fn new(cache: &'cache Cache) -> Self { + ItemAndAliasCollector { items: FxHashSet::default(), cache } } } -impl DocVisitor for ItemCollector { +impl<'cache> DocVisitor for ItemAndAliasCollector<'cache> { fn visit_item(&mut self, i: &Item) { self.items.insert(i.item_id); + if let TypeAliasItem(alias) = &*i.kind && + let Some(did) = alias.type_.def_id(self.cache) + { + self.items.insert(ItemId::DefId(did)); + } + self.visit_item_recur(i) } } diff --git a/src/tools/cargo b/src/tools/cargo -Subproject d2f6a048529eb8e9ebc55d793abd63456c98fac +Subproject 708383d620e183a9ece69b8fe930c411d83dee2 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/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index ac270a1f0ba..e74d66a8599 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -3546,10 +3546,6 @@ impl<'test> TestCx<'test> { cmd.env("RUSTDOC", cwd.join(rustdoc)); } - if let Some(ref rust_demangler) = self.config.rust_demangler_path { - cmd.env("RUST_DEMANGLER", cwd.join(rust_demangler)); - } - if let Some(ref node) = self.config.nodejs { cmd.env("NODE", node); } @@ -3999,10 +3995,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/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/tests/fail/dangling_pointers/dangling_pointer_deref_match_never.rs b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_deref_match_never.rs new file mode 100644 index 00000000000..723c3f1e158 --- /dev/null +++ b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_deref_match_never.rs @@ -0,0 +1,17 @@ +// Make sure we find these even with many checks disabled. +//@compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation + +#![allow(unreachable_code)] +#![feature(never_type)] + +fn main() { + let p = { + let b = Box::new(42); + &*b as *const i32 as *const ! + }; + unsafe { + match *p {} //~ ERROR: entering unreachable code + } + panic!("this should never print"); +} + diff --git a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_deref_match_never.stderr b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_deref_match_never.stderr new file mode 100644 index 00000000000..2ca6fd028b0 --- /dev/null +++ b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_deref_match_never.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: entering unreachable code + --> $DIR/dangling_pointer_deref_match_never.rs:LL:CC + | +LL | match *p {} + | ^^ entering unreachable code + | + = 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: + = note: inside `main` at $DIR/dangling_pointer_deref_match_never.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/dangling_pointers/out_of_bounds_read.rs b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read.rs index f6b8a1ad55b..658fbd16c2e 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read.rs +++ b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read.rs @@ -1,5 +1,3 @@ -#![feature(pointer_byte_offsets)] - fn main() { let v: Vec<u16> = vec![1, 2]; // This read is also misaligned. We make sure that the OOB message has priority. diff --git a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_write.rs b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_write.rs index 4ead91744c8..2ff537b1ffc 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_write.rs +++ b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_write.rs @@ -1,5 +1,3 @@ -#![feature(pointer_byte_offsets)] - fn main() { let mut v: Vec<u16> = vec![1, 2]; // This read is also misaligned. We make sure that the OOB message has priority. diff --git a/src/tools/miri/tests/fail/never_match_never.rs b/src/tools/miri/tests/fail/never_match_never.rs new file mode 100644 index 00000000000..5f2f471bf60 --- /dev/null +++ b/src/tools/miri/tests/fail/never_match_never.rs @@ -0,0 +1,10 @@ +// This should fail even without validation +//@compile-flags: -Zmiri-disable-validation + +#![feature(never_type)] +#![allow(unreachable_code)] + +fn main() { + let ptr: *const (i32, !) = &0i32 as *const i32 as *const _; + unsafe { match (*ptr).1 {} } //~ ERROR: entering unreachable code +} diff --git a/src/tools/miri/tests/fail/never_match_never.stderr b/src/tools/miri/tests/fail/never_match_never.stderr new file mode 100644 index 00000000000..33dab81d5b0 --- /dev/null +++ b/src/tools/miri/tests/fail/never_match_never.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: entering unreachable code + --> $DIR/never_match_never.rs:LL:CC + | +LL | unsafe { match (*ptr).1 {} } + | ^^^^^^^^ entering unreachable code + | + = 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: + = note: inside `main` at $DIR/never_match_never.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/pass/dangling_pointer_deref_match_underscore.rs b/src/tools/miri/tests/pass/dangling_pointer_deref_match_underscore.rs new file mode 100644 index 00000000000..c3cff1f4280 --- /dev/null +++ b/src/tools/miri/tests/pass/dangling_pointer_deref_match_underscore.rs @@ -0,0 +1,14 @@ +// A `_` binding in a match is a nop, so we do not detect that the pointer is dangling. +//@compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation + +fn main() { + let p = { + let b = Box::new(42); + &*b as *const i32 + }; + unsafe { + match *p { + _ => {} + } + } +} diff --git a/src/tools/miri/tests/pass/provenance.rs b/src/tools/miri/tests/pass/provenance.rs index 835daa36cfc..9e8a9651b3d 100644 --- a/src/tools/miri/tests/pass/provenance.rs +++ b/src/tools/miri/tests/pass/provenance.rs @@ -1,7 +1,6 @@ //@revisions: stack tree //@[tree]compile-flags: -Zmiri-tree-borrows #![feature(strict_provenance)] -#![feature(pointer_byte_offsets)] use std::{mem, ptr}; const PTR_SIZE: usize = mem::size_of::<&i32>(); diff --git a/src/tools/miri/tests/pass/union-uninhabited-match-underscore.rs b/src/tools/miri/tests/pass/union-uninhabited-match-underscore.rs new file mode 100644 index 00000000000..33db9c2d347 --- /dev/null +++ b/src/tools/miri/tests/pass/union-uninhabited-match-underscore.rs @@ -0,0 +1,17 @@ +fn main() { + #[derive(Copy, Clone)] + enum Void {} + union Uninit<T: Copy> { + value: T, + uninit: (), + } + unsafe { + let x: Uninit<Void> = Uninit { uninit: () }; + match x.value { + // rustc warns about un unreachable pattern, + // but is wrong in unsafe code. + #[allow(unreachable_patterns)] + _ => println!("hi from the void!"), + } + } +} diff --git a/src/tools/miri/tests/pass/union-uninhabited-match-underscore.stdout b/src/tools/miri/tests/pass/union-uninhabited-match-underscore.stdout new file mode 100644 index 00000000000..ff731696f01 --- /dev/null +++ b/src/tools/miri/tests/pass/union-uninhabited-match-underscore.stdout @@ -0,0 +1 @@ +hi from the void! 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/codegen/char-ascii-branchless.rs b/tests/codegen/char-ascii-branchless.rs new file mode 100644 index 00000000000..b612b24c7c7 --- /dev/null +++ b/tests/codegen/char-ascii-branchless.rs @@ -0,0 +1,47 @@ +// Checks that these functions are branchless. +// +// compile-flags: -O + +#![crate_type = "lib"] + +// CHECK-LABEL: @is_ascii_alphanumeric_char +#[no_mangle] +pub fn is_ascii_alphanumeric_char(x: char) -> bool { + // CHECK-NOT: br + x.is_ascii_alphanumeric() +} + +// CHECK-LABEL: @is_ascii_alphanumeric_u8 +#[no_mangle] +pub fn is_ascii_alphanumeric_u8(x: u8) -> bool { + // CHECK-NOT: br + x.is_ascii_alphanumeric() +} + +// CHECK-LABEL: @is_ascii_hexdigit_char +#[no_mangle] +pub fn is_ascii_hexdigit_char(x: char) -> bool { + // CHECK-NOT: br + x.is_ascii_hexdigit() +} + +// CHECK-LABEL: @is_ascii_hexdigit_u8 +#[no_mangle] +pub fn is_ascii_hexdigit_u8(x: u8) -> bool { + // CHECK-NOT: br + x.is_ascii_hexdigit() +} + +// CHECK-LABEL: @is_ascii_punctuation_char +#[no_mangle] +pub fn is_ascii_punctuation_char(x: char) -> bool { + // CHECK-NOT: br + x.is_ascii_punctuation() +} + +// CHECK-LABEL: @is_ascii_punctuation_u8 +#[no_mangle] +pub fn is_ascii_punctuation_u8(x: u8) -> bool { + // CHECK-NOT: br + x.is_ascii_punctuation() +} diff --git a/tests/mir-opt/building/async_await.b-{closure#0}.coroutine_resume.0.mir b/tests/mir-opt/building/async_await.b-{closure#0}.coroutine_resume.0.mir index f64b540c3a5..396e4a378f6 100644 --- a/tests/mir-opt/building/async_await.b-{closure#0}.coroutine_resume.0.mir +++ b/tests/mir-opt/building/async_await.b-{closure#0}.coroutine_resume.0.mir @@ -127,6 +127,7 @@ fn b::{closure#0}(_1: Pin<&mut {async fn body@$DIR/async_await.rs:15:18: 18:2}>, bb3: { StorageDead(_5); + PlaceMention(_4); nop; (((*(_1.0: &mut {async fn body@$DIR/async_await.rs:15:18: 18:2})) as variant#3).0: {async fn body@$DIR/async_await.rs:12:14: 12:16}) = move _4; goto -> bb4; @@ -162,6 +163,7 @@ fn b::{closure#0}(_1: Pin<&mut {async fn body@$DIR/async_await.rs:15:18: 18:2}>, bb7: { StorageDead(_13); StorageDead(_10); + PlaceMention(_9); _16 = discriminant(_9); switchInt(move _16) -> [0: bb10, 1: bb8, otherwise: bb9]; } @@ -223,6 +225,7 @@ fn b::{closure#0}(_1: Pin<&mut {async fn body@$DIR/async_await.rs:15:18: 18:2}>, bb15: { StorageDead(_22); + PlaceMention(_21); nop; (((*(_1.0: &mut {async fn body@$DIR/async_await.rs:15:18: 18:2})) as variant#4).0: {async fn body@$DIR/async_await.rs:12:14: 12:16}) = move _21; goto -> bb16; @@ -258,6 +261,7 @@ fn b::{closure#0}(_1: Pin<&mut {async fn body@$DIR/async_await.rs:15:18: 18:2}>, bb19: { StorageDead(_29); StorageDead(_26); + PlaceMention(_25); _32 = discriminant(_25); switchInt(move _32) -> [0: bb21, 1: bb20, otherwise: bb9]; } diff --git a/tests/mir-opt/building/issue_101867.main.built.after.mir b/tests/mir-opt/building/issue_101867.main.built.after.mir index fb60f0f0c2b..57f8cca9abc 100644 --- a/tests/mir-opt/building/issue_101867.main.built.after.mir +++ b/tests/mir-opt/building/issue_101867.main.built.after.mir @@ -25,7 +25,7 @@ fn main() -> () { FakeRead(ForLet(None), _1); AscribeUserType(_1, o, UserTypeProjection { base: UserType(1), projs: [] }); StorageLive(_5); - FakeRead(ForMatchedPlace(None), _1); + PlaceMention(_1); _6 = discriminant(_1); switchInt(move _6) -> [1: bb4, otherwise: bb3]; } diff --git a/tests/mir-opt/building/issue_49232.main.built.after.mir b/tests/mir-opt/building/issue_49232.main.built.after.mir index f809132bc63..ac50b388910 100644 --- a/tests/mir-opt/building/issue_49232.main.built.after.mir +++ b/tests/mir-opt/building/issue_49232.main.built.after.mir @@ -24,7 +24,7 @@ fn main() -> () { StorageLive(_2); StorageLive(_3); _3 = const true; - FakeRead(ForMatchedPlace(None), _3); + PlaceMention(_3); switchInt(_3) -> [0: bb3, otherwise: bb4]; } diff --git a/tests/mir-opt/building/logical_or_in_conditional.test_complex.built.after.mir b/tests/mir-opt/building/logical_or_in_conditional.test_complex.built.after.mir index 096aaec4a38..7407e7a8b2a 100644 --- a/tests/mir-opt/building/logical_or_in_conditional.test_complex.built.after.mir +++ b/tests/mir-opt/building/logical_or_in_conditional.test_complex.built.after.mir @@ -23,7 +23,7 @@ fn test_complex() -> () { } bb1: { - FakeRead(ForMatchedPlace(None), _2); + PlaceMention(_2); _3 = discriminant(_2); switchInt(move _3) -> [0: bb2, otherwise: bb3]; } @@ -151,7 +151,7 @@ fn test_complex() -> () { } bb25: { - FakeRead(ForMatchedPlace(None), _12); + PlaceMention(_12); _13 = discriminant(_12); switchInt(move _13) -> [1: bb27, otherwise: bb26]; } diff --git a/tests/mir-opt/building/match_false_edges.full_tested_match.built.after.mir b/tests/mir-opt/building/match_false_edges.full_tested_match.built.after.mir index bd4cd4eb678..1946c70e476 100644 --- a/tests/mir-opt/building/match_false_edges.full_tested_match.built.after.mir +++ b/tests/mir-opt/building/match_false_edges.full_tested_match.built.after.mir @@ -26,7 +26,7 @@ fn full_tested_match() -> () { StorageLive(_1); StorageLive(_2); _2 = Option::<i32>::Some(const 42_i32); - FakeRead(ForMatchedPlace(None), _2); + PlaceMention(_2); _3 = discriminant(_2); switchInt(move _3) -> [0: bb1, 1: bb2, otherwise: bb4]; } @@ -45,6 +45,7 @@ fn full_tested_match() -> () { } bb4: { + FakeRead(ForMatchedPlace(None), _2); unreachable; } diff --git a/tests/mir-opt/building/match_false_edges.full_tested_match2.built.after.mir b/tests/mir-opt/building/match_false_edges.full_tested_match2.built.after.mir index 595e3ab9224..b6175b05156 100644 --- a/tests/mir-opt/building/match_false_edges.full_tested_match2.built.after.mir +++ b/tests/mir-opt/building/match_false_edges.full_tested_match2.built.after.mir @@ -26,7 +26,7 @@ fn full_tested_match2() -> () { StorageLive(_1); StorageLive(_2); _2 = Option::<i32>::Some(const 42_i32); - FakeRead(ForMatchedPlace(None), _2); + PlaceMention(_2); _3 = discriminant(_2); switchInt(move _3) -> [0: bb1, 1: bb2, otherwise: bb4]; } @@ -51,6 +51,7 @@ fn full_tested_match2() -> () { } bb4: { + FakeRead(ForMatchedPlace(None), _2); unreachable; } diff --git a/tests/mir-opt/building/match_false_edges.main.built.after.mir b/tests/mir-opt/building/match_false_edges.main.built.after.mir index 91fe2f90e35..0b57d1b97e1 100644 --- a/tests/mir-opt/building/match_false_edges.main.built.after.mir +++ b/tests/mir-opt/building/match_false_edges.main.built.after.mir @@ -37,7 +37,7 @@ fn main() -> () { StorageLive(_1); StorageLive(_2); _2 = Option::<i32>::Some(const 1_i32); - FakeRead(ForMatchedPlace(None), _2); + PlaceMention(_2); _4 = discriminant(_2); switchInt(move _4) -> [1: bb2, otherwise: bb1]; } diff --git a/tests/mir-opt/building/simple_match.match_bool.built.after.mir b/tests/mir-opt/building/simple_match.match_bool.built.after.mir index c89ea2b6c85..06de4c51051 100644 --- a/tests/mir-opt/building/simple_match.match_bool.built.after.mir +++ b/tests/mir-opt/building/simple_match.match_bool.built.after.mir @@ -5,7 +5,7 @@ fn match_bool(_1: bool) -> usize { let mut _0: usize; bb0: { - FakeRead(ForMatchedPlace(None), _1); + PlaceMention(_1); switchInt(_1) -> [0: bb2, otherwise: bb1]; } diff --git a/tests/mir-opt/const_prop/transmute.unreachable_box.ConstProp.32bit.diff b/tests/mir-opt/const_prop/transmute.unreachable_box.ConstProp.32bit.diff index 100982382dd..16519749b82 100644 --- a/tests/mir-opt/const_prop/transmute.unreachable_box.ConstProp.32bit.diff +++ b/tests/mir-opt/const_prop/transmute.unreachable_box.ConstProp.32bit.diff @@ -4,6 +4,7 @@ fn unreachable_box() -> ! { let mut _0: !; let _1: std::boxed::Box<Never>; + let mut _2: *const Never; scope 1 { debug x => _1; } @@ -13,7 +14,9 @@ bb0: { StorageLive(_1); - _1 = const 1_usize as std::boxed::Box<Never> (Transmute); +- _2 = (((_1.0: std::ptr::Unique<Never>).0: std::ptr::NonNull<Never>).0: *const Never); + _1 = const Box::<Never>(Unique::<Never> {{ pointer: NonNull::<Never> {{ pointer: {0x1 as *const Never} }}, _marker: PhantomData::<Never> }}, std::alloc::Global); ++ _2 = const {0x1 as *const Never}; unreachable; } } diff --git a/tests/mir-opt/const_prop/transmute.unreachable_box.ConstProp.64bit.diff b/tests/mir-opt/const_prop/transmute.unreachable_box.ConstProp.64bit.diff index 100982382dd..16519749b82 100644 --- a/tests/mir-opt/const_prop/transmute.unreachable_box.ConstProp.64bit.diff +++ b/tests/mir-opt/const_prop/transmute.unreachable_box.ConstProp.64bit.diff @@ -4,6 +4,7 @@ fn unreachable_box() -> ! { let mut _0: !; let _1: std::boxed::Box<Never>; + let mut _2: *const Never; scope 1 { debug x => _1; } @@ -13,7 +14,9 @@ bb0: { StorageLive(_1); - _1 = const 1_usize as std::boxed::Box<Never> (Transmute); +- _2 = (((_1.0: std::ptr::Unique<Never>).0: std::ptr::NonNull<Never>).0: *const Never); + _1 = const Box::<Never>(Unique::<Never> {{ pointer: NonNull::<Never> {{ pointer: {0x1 as *const Never} }}, _marker: PhantomData::<Never> }}, std::alloc::Global); ++ _2 = const {0x1 as *const Never}; unreachable; } } diff --git a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_box.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_box.DataflowConstProp.32bit.diff index d0c298ba233..5d17c47ae66 100644 --- a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_box.DataflowConstProp.32bit.diff +++ b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_box.DataflowConstProp.32bit.diff @@ -4,6 +4,7 @@ fn unreachable_box() -> ! { let mut _0: !; let _1: std::boxed::Box<Never>; + let mut _2: *const Never; scope 1 { debug x => _1; } @@ -14,6 +15,7 @@ StorageLive(_1); - _1 = const 1_usize as std::boxed::Box<Never> (Transmute); + _1 = const Box::<Never>(Unique::<Never> {{ pointer: NonNull::<Never> {{ pointer: {0x1 as *const Never} }}, _marker: PhantomData::<Never> }}, std::alloc::Global); + _2 = (((_1.0: std::ptr::Unique<Never>).0: std::ptr::NonNull<Never>).0: *const Never); unreachable; } } diff --git a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_box.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_box.DataflowConstProp.64bit.diff index d0c298ba233..5d17c47ae66 100644 --- a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_box.DataflowConstProp.64bit.diff +++ b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_box.DataflowConstProp.64bit.diff @@ -4,6 +4,7 @@ fn unreachable_box() -> ! { let mut _0: !; let _1: std::boxed::Box<Never>; + let mut _2: *const Never; scope 1 { debug x => _1; } @@ -14,6 +15,7 @@ StorageLive(_1); - _1 = const 1_usize as std::boxed::Box<Never> (Transmute); + _1 = const Box::<Never>(Unique::<Never> {{ pointer: NonNull::<Never> {{ pointer: {0x1 as *const Never} }}, _marker: PhantomData::<Never> }}, std::alloc::Global); + _2 = (((_1.0: std::ptr::Unique<Never>).0: std::ptr::NonNull<Never>).0: *const Never); unreachable; } } diff --git a/tests/mir-opt/derefer_complex_case.main.Derefer.panic-abort.diff b/tests/mir-opt/derefer_complex_case.main.Derefer.panic-abort.diff index 1f3b3ad649d..0fad716a2cb 100644 --- a/tests/mir-opt/derefer_complex_case.main.Derefer.panic-abort.diff +++ b/tests/mir-opt/derefer_complex_case.main.Derefer.panic-abort.diff @@ -35,6 +35,7 @@ bb1: { StorageDead(_2); + PlaceMention(_1); StorageLive(_4); _4 = move _1; goto -> bb2; @@ -52,6 +53,7 @@ bb3: { StorageDead(_8); + PlaceMention(_7); _10 = discriminant(_7); switchInt(move _10) -> [0: bb6, 1: bb4, otherwise: bb5]; } diff --git a/tests/mir-opt/derefer_complex_case.main.Derefer.panic-unwind.diff b/tests/mir-opt/derefer_complex_case.main.Derefer.panic-unwind.diff index da4cc188cfa..ae5656f02a5 100644 --- a/tests/mir-opt/derefer_complex_case.main.Derefer.panic-unwind.diff +++ b/tests/mir-opt/derefer_complex_case.main.Derefer.panic-unwind.diff @@ -35,6 +35,7 @@ bb1: { StorageDead(_2); + PlaceMention(_1); StorageLive(_4); _4 = move _1; goto -> bb2; @@ -52,6 +53,7 @@ bb3: { StorageDead(_8); + PlaceMention(_7); _10 = discriminant(_7); switchInt(move _10) -> [0: bb6, 1: bb4, otherwise: bb5]; } diff --git a/tests/mir-opt/derefer_terminator_test.main.Derefer.panic-abort.diff b/tests/mir-opt/derefer_terminator_test.main.Derefer.panic-abort.diff index 895dcf5798e..f4c034517f7 100644 --- a/tests/mir-opt/derefer_terminator_test.main.Derefer.panic-abort.diff +++ b/tests/mir-opt/derefer_terminator_test.main.Derefer.panic-abort.diff @@ -12,6 +12,9 @@ + let mut _10: &&&bool; + let mut _11: &&bool; + let mut _12: &bool; ++ let mut _13: &&&bool; ++ let mut _14: &&bool; ++ let mut _15: &bool; scope 1 { debug b => _1; let _2: bool; @@ -48,11 +51,16 @@ _6 = &_7; _5 = &_6; _4 = &_5; +- PlaceMention((*(*(*(*_4))))); - switchInt((*(*(*(*_4))))) -> [0: bb3, otherwise: bb4]; + _10 = deref_copy (*_4); + _11 = deref_copy (*_10); + _12 = deref_copy (*_11); -+ switchInt((*_12)) -> [0: bb3, otherwise: bb4]; ++ PlaceMention((*_12)); ++ _13 = deref_copy (*_4); ++ _14 = deref_copy (*_13); ++ _15 = deref_copy (*_14); ++ switchInt((*_15)) -> [0: bb3, otherwise: bb4]; } bb3: { diff --git a/tests/mir-opt/derefer_terminator_test.main.Derefer.panic-unwind.diff b/tests/mir-opt/derefer_terminator_test.main.Derefer.panic-unwind.diff index 19b26c901cb..e3c0c6b7dd2 100644 --- a/tests/mir-opt/derefer_terminator_test.main.Derefer.panic-unwind.diff +++ b/tests/mir-opt/derefer_terminator_test.main.Derefer.panic-unwind.diff @@ -12,6 +12,9 @@ + let mut _10: &&&bool; + let mut _11: &&bool; + let mut _12: &bool; ++ let mut _13: &&&bool; ++ let mut _14: &&bool; ++ let mut _15: &bool; scope 1 { debug b => _1; let _2: bool; @@ -48,11 +51,16 @@ _6 = &_7; _5 = &_6; _4 = &_5; +- PlaceMention((*(*(*(*_4))))); - switchInt((*(*(*(*_4))))) -> [0: bb3, otherwise: bb4]; + _10 = deref_copy (*_4); + _11 = deref_copy (*_10); + _12 = deref_copy (*_11); -+ switchInt((*_12)) -> [0: bb3, otherwise: bb4]; ++ PlaceMention((*_12)); ++ _13 = deref_copy (*_4); ++ _14 = deref_copy (*_13); ++ _15 = deref_copy (*_14); ++ switchInt((*_15)) -> [0: bb3, otherwise: bb4]; } bb3: { diff --git a/tests/mir-opt/exponential_or.match_tuple.SimplifyCfg-initial.after.mir b/tests/mir-opt/exponential_or.match_tuple.SimplifyCfg-initial.after.mir index fba616d0474..b04e09e88b8 100644 --- a/tests/mir-opt/exponential_or.match_tuple.SimplifyCfg-initial.after.mir +++ b/tests/mir-opt/exponential_or.match_tuple.SimplifyCfg-initial.after.mir @@ -18,7 +18,7 @@ fn match_tuple(_1: (u32, bool, Option<i32>, u32)) -> u32 { } bb0: { - FakeRead(ForMatchedPlace(None), _1); + PlaceMention(_1); switchInt((_1.0: u32)) -> [1: bb2, 4: bb2, otherwise: bb1]; } 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/mir-opt/issue_41888.main.ElaborateDrops.panic-abort.diff b/tests/mir-opt/issue_41888.main.ElaborateDrops.panic-abort.diff index ae18ddc8366..55d2629a551 100644 --- a/tests/mir-opt/issue_41888.main.ElaborateDrops.panic-abort.diff +++ b/tests/mir-opt/issue_41888.main.ElaborateDrops.panic-abort.diff @@ -60,6 +60,7 @@ bb5: { StorageDead(_3); + PlaceMention(_1); _5 = discriminant(_1); switchInt(move _5) -> [0: bb6, otherwise: bb7]; } diff --git a/tests/mir-opt/issue_41888.main.ElaborateDrops.panic-unwind.diff b/tests/mir-opt/issue_41888.main.ElaborateDrops.panic-unwind.diff index d08113c0ba5..c731b5646f6 100644 --- a/tests/mir-opt/issue_41888.main.ElaborateDrops.panic-unwind.diff +++ b/tests/mir-opt/issue_41888.main.ElaborateDrops.panic-unwind.diff @@ -60,6 +60,7 @@ bb5: { StorageDead(_3); + PlaceMention(_1); _5 = discriminant(_1); switchInt(move _5) -> [0: bb6, otherwise: bb7]; } diff --git a/tests/mir-opt/issue_62289.test.ElaborateDrops.before.panic-abort.mir b/tests/mir-opt/issue_62289.test.ElaborateDrops.before.panic-abort.mir index 73462967850..fadfdfc87be 100644 --- a/tests/mir-opt/issue_62289.test.ElaborateDrops.before.panic-abort.mir +++ b/tests/mir-opt/issue_62289.test.ElaborateDrops.before.panic-abort.mir @@ -45,6 +45,7 @@ fn test() -> Option<Box<u32>> { bb2: { StorageDead(_7); + PlaceMention(_6); _8 = discriminant(_6); switchInt(move _8) -> [0: bb3, 1: bb5, otherwise: bb4]; } diff --git a/tests/mir-opt/issue_62289.test.ElaborateDrops.before.panic-unwind.mir b/tests/mir-opt/issue_62289.test.ElaborateDrops.before.panic-unwind.mir index 8264e2cabbc..8f94165a108 100644 --- a/tests/mir-opt/issue_62289.test.ElaborateDrops.before.panic-unwind.mir +++ b/tests/mir-opt/issue_62289.test.ElaborateDrops.before.panic-unwind.mir @@ -45,6 +45,7 @@ fn test() -> Option<Box<u32>> { bb2: { StorageDead(_7); + PlaceMention(_6); _8 = discriminant(_6); switchInt(move _8) -> [0: bb3, 1: bb5, otherwise: bb4]; } diff --git a/tests/mir-opt/issue_72181_1.f.built.after.mir b/tests/mir-opt/issue_72181_1.f.built.after.mir index 16f34e4a449..89da9a80113 100644 --- a/tests/mir-opt/issue_72181_1.f.built.after.mir +++ b/tests/mir-opt/issue_72181_1.f.built.after.mir @@ -5,6 +5,7 @@ fn f(_1: Void) -> ! { let mut _0: !; bb0: { + PlaceMention(_1); FakeRead(ForMatchedPlace(None), _1); unreachable; } diff --git a/tests/mir-opt/issue_99325.main.built.after.32bit.mir b/tests/mir-opt/issue_99325.main.built.after.32bit.mir index 188b53d28d7..ffb1aedd2ea 100644 --- a/tests/mir-opt/issue_99325.main.built.after.32bit.mir +++ b/tests/mir-opt/issue_99325.main.built.after.32bit.mir @@ -81,7 +81,7 @@ fn main() -> () { _2 = (move _3, move _5); StorageDead(_5); StorageDead(_3); - FakeRead(ForMatchedPlace(None), _2); + PlaceMention(_2); StorageLive(_8); _8 = (_2.0: &&[u8]); StorageLive(_9); @@ -180,7 +180,7 @@ fn main() -> () { _23 = (move _24, move _26); StorageDead(_26); StorageDead(_24); - FakeRead(ForMatchedPlace(None), _23); + PlaceMention(_23); StorageLive(_28); _28 = (_23.0: &&[u8]); StorageLive(_29); diff --git a/tests/mir-opt/issue_99325.main.built.after.64bit.mir b/tests/mir-opt/issue_99325.main.built.after.64bit.mir index 188b53d28d7..ffb1aedd2ea 100644 --- a/tests/mir-opt/issue_99325.main.built.after.64bit.mir +++ b/tests/mir-opt/issue_99325.main.built.after.64bit.mir @@ -81,7 +81,7 @@ fn main() -> () { _2 = (move _3, move _5); StorageDead(_5); StorageDead(_3); - FakeRead(ForMatchedPlace(None), _2); + PlaceMention(_2); StorageLive(_8); _8 = (_2.0: &&[u8]); StorageLive(_9); @@ -180,7 +180,7 @@ fn main() -> () { _23 = (move _24, move _26); StorageDead(_26); StorageDead(_24); - FakeRead(ForMatchedPlace(None), _23); + PlaceMention(_23); StorageLive(_28); _28 = (_23.0: &&[u8]); StorageLive(_29); diff --git a/tests/mir-opt/lower_intrinsics.transmute_to_box_uninhabited.LowerIntrinsics.panic-abort.diff b/tests/mir-opt/lower_intrinsics.transmute_to_box_uninhabited.LowerIntrinsics.panic-abort.diff index 49cc8b1afe3..c4a3358ffa3 100644 --- a/tests/mir-opt/lower_intrinsics.transmute_to_box_uninhabited.LowerIntrinsics.panic-abort.diff +++ b/tests/mir-opt/lower_intrinsics.transmute_to_box_uninhabited.LowerIntrinsics.panic-abort.diff @@ -4,6 +4,7 @@ fn transmute_to_box_uninhabited() -> ! { let mut _0: !; let _1: std::boxed::Box<Never>; + let mut _2: *const Never; scope 1 { debug x => _1; } @@ -16,6 +17,8 @@ } bb1: { + _2 = (((_1.0: std::ptr::Unique<Never>).0: std::ptr::NonNull<Never>).0: *const Never); + PlaceMention((*_2)); unreachable; } } diff --git a/tests/mir-opt/lower_intrinsics.transmute_to_box_uninhabited.LowerIntrinsics.panic-unwind.diff b/tests/mir-opt/lower_intrinsics.transmute_to_box_uninhabited.LowerIntrinsics.panic-unwind.diff index 49cc8b1afe3..c4a3358ffa3 100644 --- a/tests/mir-opt/lower_intrinsics.transmute_to_box_uninhabited.LowerIntrinsics.panic-unwind.diff +++ b/tests/mir-opt/lower_intrinsics.transmute_to_box_uninhabited.LowerIntrinsics.panic-unwind.diff @@ -4,6 +4,7 @@ fn transmute_to_box_uninhabited() -> ! { let mut _0: !; let _1: std::boxed::Box<Never>; + let mut _2: *const Never; scope 1 { debug x => _1; } @@ -16,6 +17,8 @@ } bb1: { + _2 = (((_1.0: std::ptr::Unique<Never>).0: std::ptr::NonNull<Never>).0: *const Never); + PlaceMention((*_2)); unreachable; } } diff --git a/tests/mir-opt/lower_intrinsics.transmute_to_mut_uninhabited.LowerIntrinsics.panic-abort.diff b/tests/mir-opt/lower_intrinsics.transmute_to_mut_uninhabited.LowerIntrinsics.panic-abort.diff index 94c7ebe1520..c2c4ec0003c 100644 --- a/tests/mir-opt/lower_intrinsics.transmute_to_mut_uninhabited.LowerIntrinsics.panic-abort.diff +++ b/tests/mir-opt/lower_intrinsics.transmute_to_mut_uninhabited.LowerIntrinsics.panic-abort.diff @@ -16,6 +16,7 @@ } bb1: { + PlaceMention((*_1)); unreachable; } } diff --git a/tests/mir-opt/lower_intrinsics.transmute_to_mut_uninhabited.LowerIntrinsics.panic-unwind.diff b/tests/mir-opt/lower_intrinsics.transmute_to_mut_uninhabited.LowerIntrinsics.panic-unwind.diff index 94c7ebe1520..c2c4ec0003c 100644 --- a/tests/mir-opt/lower_intrinsics.transmute_to_mut_uninhabited.LowerIntrinsics.panic-unwind.diff +++ b/tests/mir-opt/lower_intrinsics.transmute_to_mut_uninhabited.LowerIntrinsics.panic-unwind.diff @@ -16,6 +16,7 @@ } bb1: { + PlaceMention((*_1)); unreachable; } } diff --git a/tests/mir-opt/lower_intrinsics.transmute_to_ref_uninhabited.LowerIntrinsics.panic-abort.diff b/tests/mir-opt/lower_intrinsics.transmute_to_ref_uninhabited.LowerIntrinsics.panic-abort.diff index 6576616e0ca..1b516a1f53b 100644 --- a/tests/mir-opt/lower_intrinsics.transmute_to_ref_uninhabited.LowerIntrinsics.panic-abort.diff +++ b/tests/mir-opt/lower_intrinsics.transmute_to_ref_uninhabited.LowerIntrinsics.panic-abort.diff @@ -16,6 +16,7 @@ } bb1: { + PlaceMention((*_1)); unreachable; } } diff --git a/tests/mir-opt/lower_intrinsics.transmute_to_ref_uninhabited.LowerIntrinsics.panic-unwind.diff b/tests/mir-opt/lower_intrinsics.transmute_to_ref_uninhabited.LowerIntrinsics.panic-unwind.diff index 6576616e0ca..1b516a1f53b 100644 --- a/tests/mir-opt/lower_intrinsics.transmute_to_ref_uninhabited.LowerIntrinsics.panic-unwind.diff +++ b/tests/mir-opt/lower_intrinsics.transmute_to_ref_uninhabited.LowerIntrinsics.panic-unwind.diff @@ -16,6 +16,7 @@ } bb1: { + PlaceMention((*_1)); unreachable; } } diff --git a/tests/mir-opt/match_arm_scopes.complicated_match.panic-abort.SimplifyCfg-initial.after-ElaborateDrops.after.diff b/tests/mir-opt/match_arm_scopes.complicated_match.panic-abort.SimplifyCfg-initial.after-ElaborateDrops.after.diff index 3e817ff433b..2989582d038 100644 --- a/tests/mir-opt/match_arm_scopes.complicated_match.panic-abort.SimplifyCfg-initial.after-ElaborateDrops.after.diff +++ b/tests/mir-opt/match_arm_scopes.complicated_match.panic-abort.SimplifyCfg-initial.after-ElaborateDrops.after.diff @@ -31,7 +31,7 @@ } bb0: { -- FakeRead(ForMatchedPlace(None), _2); + PlaceMention(_2); - switchInt((_2.0: bool)) -> [0: bb1, otherwise: bb2]; + switchInt((_2.0: bool)) -> [0: bb5, otherwise: bb1]; } diff --git a/tests/mir-opt/match_arm_scopes.complicated_match.panic-unwind.SimplifyCfg-initial.after-ElaborateDrops.after.diff b/tests/mir-opt/match_arm_scopes.complicated_match.panic-unwind.SimplifyCfg-initial.after-ElaborateDrops.after.diff index 3e817ff433b..2989582d038 100644 --- a/tests/mir-opt/match_arm_scopes.complicated_match.panic-unwind.SimplifyCfg-initial.after-ElaborateDrops.after.diff +++ b/tests/mir-opt/match_arm_scopes.complicated_match.panic-unwind.SimplifyCfg-initial.after-ElaborateDrops.after.diff @@ -31,7 +31,7 @@ } bb0: { -- FakeRead(ForMatchedPlace(None), _2); + PlaceMention(_2); - switchInt((_2.0: bool)) -> [0: bb1, otherwise: bb2]; + switchInt((_2.0: bool)) -> [0: bb5, otherwise: bb1]; } diff --git a/tests/mir-opt/match_test.main.SimplifyCfg-initial.after.mir b/tests/mir-opt/match_test.main.SimplifyCfg-initial.after.mir index 7f8eb82c772..90ec3ab49ad 100644 --- a/tests/mir-opt/match_test.main.SimplifyCfg-initial.after.mir +++ b/tests/mir-opt/match_test.main.SimplifyCfg-initial.after.mir @@ -26,7 +26,7 @@ fn main() -> () { _2 = const true; FakeRead(ForLet(None), _2); StorageLive(_3); - FakeRead(ForMatchedPlace(None), _1); + PlaceMention(_1); _6 = Le(const 0_i32, _1); switchInt(move _6) -> [0: bb4, otherwise: bb1]; } diff --git a/tests/mir-opt/remove_fake_borrows.match_guard.CleanupPostBorrowck.panic-abort.diff b/tests/mir-opt/remove_fake_borrows.match_guard.CleanupPostBorrowck.panic-abort.diff index 33322c41b01..61329bb75d1 100644 --- a/tests/mir-opt/remove_fake_borrows.match_guard.CleanupPostBorrowck.panic-abort.diff +++ b/tests/mir-opt/remove_fake_borrows.match_guard.CleanupPostBorrowck.panic-abort.diff @@ -13,8 +13,7 @@ let mut _8: bool; bb0: { -- FakeRead(ForMatchedPlace(None), _1); -+ nop; + PlaceMention(_1); _3 = discriminant(_1); switchInt(move _3) -> [1: bb2, otherwise: bb1]; } diff --git a/tests/mir-opt/remove_fake_borrows.match_guard.CleanupPostBorrowck.panic-unwind.diff b/tests/mir-opt/remove_fake_borrows.match_guard.CleanupPostBorrowck.panic-unwind.diff index 33322c41b01..61329bb75d1 100644 --- a/tests/mir-opt/remove_fake_borrows.match_guard.CleanupPostBorrowck.panic-unwind.diff +++ b/tests/mir-opt/remove_fake_borrows.match_guard.CleanupPostBorrowck.panic-unwind.diff @@ -13,8 +13,7 @@ let mut _8: bool; bb0: { -- FakeRead(ForMatchedPlace(None), _1); -+ nop; + PlaceMention(_1); _3 = discriminant(_1); switchInt(move _3) -> [1: bb2, otherwise: bb1]; } 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/rust-lld-custom-target/Makefile b/tests/run-make/rust-lld-custom-target/Makefile new file mode 100644 index 00000000000..007493ab0b9 --- /dev/null +++ b/tests/run-make/rust-lld-custom-target/Makefile @@ -0,0 +1,7 @@ +include ../tools.mk + +# needs-rust-lld +# only-x86_64-unknown-linux-gnu +all: + RUSTC_LOG=rustc_codegen_ssa::back::link=info $(RUSTC) --crate-type cdylib --target custom-target.json -Clink-args=-Wl,-v lib.rs 2> $(TMPDIR)/output.txt + $(CGREP) -e "^LLD [0-9]+\.[0-9]+\.[0-9]+" < $(TMPDIR)/output.txt diff --git a/tests/run-make/rust-lld-custom-target/custom-target.json b/tests/run-make/rust-lld-custom-target/custom-target.json new file mode 100644 index 00000000000..7828a99f235 --- /dev/null +++ b/tests/run-make/rust-lld-custom-target/custom-target.json @@ -0,0 +1,57 @@ +{ + "arch": "x86_64", + "cpu": "x86-64", + "crt-static-respected": true, + "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128", + "dynamic-linking": true, + "env": "gnu", + "has-rpath": true, + "has-thread-local": true, + "link-self-contained": { + "components": [ + "linker" + ] + }, + "linker-flavor": "gnu-lld-cc", + "llvm-target": "x86_64-unknown-linux-gnu", + "max-atomic-width": 64, + "os": "linux", + "plt-by-default": false, + "position-independent-executables": true, + "pre-link-args": { + "gnu-cc": [ + "-m64" + ], + "gnu-lld-cc": [ + "-m64" + ] + }, + "relro-level": "full", + "stack-probes": { + "kind": "inline-or-call", + "min-llvm-version-for-inline": [ + 16, + 0, + 0 + ] + }, + "static-position-independent-executables": true, + "supported-sanitizers": [ + "address", + "cfi", + "leak", + "memory", + "thread", + "safestack" + ], + "supported-split-debuginfo": [ + "packed", + "unpacked", + "off" + ], + "supports-xray": true, + "target-family": [ + "unix" + ], + "target-pointer-width": "64" +} diff --git a/tests/run-make/rust-lld-custom-target/lib.rs b/tests/run-make/rust-lld-custom-target/lib.rs new file mode 100644 index 00000000000..d8f5e310821 --- /dev/null +++ b/tests/run-make/rust-lld-custom-target/lib.rs @@ -0,0 +1,9 @@ +// Test linking using `cc` with `rust-lld`, using a custom target with features described in MCP 510 +// see https://github.com/rust-lang/compiler-team/issues/510 for more info: +// +// Starting from the `x86_64-unknown-linux-gnu` target spec, we add the following options: +// - a linker-flavor using lld via a C compiler +// - the self-contained linker component is enabled + +#![feature(no_core)] +#![no_core] 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-gui/code-tags.goml b/tests/rustdoc-gui/code-tags.goml index 3405d3295e6..577f932e576 100644 --- a/tests/rustdoc-gui/code-tags.goml +++ b/tests/rustdoc-gui/code-tags.goml @@ -1,6 +1,6 @@ // This test ensures that items and documentation code blocks are wrapped in <pre><code> -// We need to disable this check because `implementors/test_docs/trait.AnotherOne.js` +// We need to disable this check because `trait.impl/test_docs/trait.AnotherOne.js` // doesn't exist. fail-on-request-error: false go-to: "file://" + |DOC_PATH| + "/test_docs/fn.foo.html" diff --git a/tests/rustdoc-gui/item-decl-colors.goml b/tests/rustdoc-gui/item-decl-colors.goml index a777842735c..7bbd20c4ee0 100644 --- a/tests/rustdoc-gui/item-decl-colors.goml +++ b/tests/rustdoc-gui/item-decl-colors.goml @@ -1,6 +1,6 @@ // This test ensures that the color of the items in the type decl are working as expected. -// We need to disable this check because `implementors/test_docs/trait.TraitWithoutGenerics.js` +// We need to disable this check because `trait.impl/test_docs/trait.TraitWithoutGenerics.js` // doesn't exist. fail-on-request-error: false diff --git a/tests/rustdoc-gui/no-docblock.goml b/tests/rustdoc-gui/no-docblock.goml index 1b4638ef067..2115b6f5390 100644 --- a/tests/rustdoc-gui/no-docblock.goml +++ b/tests/rustdoc-gui/no-docblock.goml @@ -1,6 +1,6 @@ // This test checks that there are margins applied to methods with no docblocks. -// We need to disable this check because `implementors/test_docs/trait.TraitWithNoDocblock.js` +// We need to disable this check because `trait.impl/test_docs/trait.TraitWithNoDocblock.js` // doesn't exist. fail-on-request-error: false diff --git a/tests/rustdoc-gui/search-tab.goml b/tests/rustdoc-gui/search-tab.goml index 427201e1b5d..1c0c9e79e40 100644 --- a/tests/rustdoc-gui/search-tab.goml +++ b/tests/rustdoc-gui/search-tab.goml @@ -79,8 +79,8 @@ call-function: ("check-colors", { set-window-size: (851, 600) // Check the size and count in tabs -assert-text: ("#search-tabs > button:nth-child(1) > .count", " (23) ") -assert-text: ("#search-tabs > button:nth-child(2) > .count", " (4)  ") +assert-text: ("#search-tabs > button:nth-child(1) > .count", " (24) ") +assert-text: ("#search-tabs > button:nth-child(2) > .count", " (5)  ") assert-text: ("#search-tabs > button:nth-child(3) > .count", " (0)  ") store-property: ("#search-tabs > button:nth-child(1)", {"offsetWidth": buttonWidth}) assert-property: ("#search-tabs > button:nth-child(2)", {"offsetWidth": |buttonWidth|}) diff --git a/tests/rustdoc-gui/setting-auto-hide-content-large-items.goml b/tests/rustdoc-gui/setting-auto-hide-content-large-items.goml index 6cd725043f4..b55a1cfd92b 100644 --- a/tests/rustdoc-gui/setting-auto-hide-content-large-items.goml +++ b/tests/rustdoc-gui/setting-auto-hide-content-large-items.goml @@ -1,7 +1,7 @@ // This test ensures that the "Auto-hide item contents for large items" setting is working as // expected. -// We need to disable this check because `implementors/test_docs/trait.Iterator.js` doesn't exist. +// We need to disable this check because `trait.impl/test_docs/trait.Iterator.js` doesn't exist. fail-on-request-error: false define-function: ( diff --git a/tests/rustdoc-gui/src/test_docs/lib.rs b/tests/rustdoc-gui/src/test_docs/lib.rs index 5c91bcbb4ee..138a1b302fd 100644 --- a/tests/rustdoc-gui/src/test_docs/lib.rs +++ b/tests/rustdoc-gui/src/test_docs/lib.rs @@ -160,6 +160,33 @@ pub mod keyword {} /// Just some type alias. pub type SomeType = u32; +/// Another type alias, this time with methods. +pub type SomeOtherTypeWithMethodsAndInlining = Foo; + +impl SomeOtherTypeWithMethodsAndInlining { + pub fn some_other_method_directly(&self) {} +} + +/// Another type alias, this time with methods. +pub struct UnderlyingFooBarBaz; +pub type SomeOtherTypeWithMethodsAndInliningAndTraits = UnderlyingFooBarBaz; + +impl AsRef<str> for UnderlyingFooBarBaz { + fn as_ref(&self) -> &str { + "hello" + } +} + +impl UnderlyingFooBarBaz { + pub fn inherent_fn(&self) {} +} + +impl AsRef<u8> for SomeOtherTypeWithMethodsAndInliningAndTraits { + fn as_ref(&self) -> &u8 { + b"hello" + } +} + pub mod huge_amount_of_consts { include!(concat!(env!("OUT_DIR"), "/huge_amount_of_consts.rs")); } diff --git a/tests/rustdoc-gui/trait-sidebar-item-order.goml b/tests/rustdoc-gui/trait-sidebar-item-order.goml index 9330ef040ec..73e362ca813 100644 --- a/tests/rustdoc-gui/trait-sidebar-item-order.goml +++ b/tests/rustdoc-gui/trait-sidebar-item-order.goml @@ -1,6 +1,6 @@ // Checks that the elements in the sidebar are alphabetically sorted. -// We need to disable this check because `implementors/test_docs/trait.AnotherOne.js` +// We need to disable this check because `trait.impl/test_docs/trait.AnotherOne.js` // doesn't exist. fail-on-request-error: false diff --git a/tests/rustdoc-gui/type-declation-overflow.goml b/tests/rustdoc-gui/type-declation-overflow.goml index f212781e9b3..5780f5c88f8 100644 --- a/tests/rustdoc-gui/type-declation-overflow.goml +++ b/tests/rustdoc-gui/type-declation-overflow.goml @@ -2,7 +2,7 @@ // This test ensures that the items declaration content overflow is handled inside the <pre> directly. // We need to disable this check because -// `implementors/test_docs/trait.ALongNameBecauseItHelpsTestingTheCurrentProblem.js` +// `trait.impl/test_docs/trait.ALongNameBecauseItHelpsTestingTheCurrentProblem.js` // doesn't exist. fail-on-request-error: false diff --git a/tests/rustdoc-gui/type-impls.goml b/tests/rustdoc-gui/type-impls.goml new file mode 100644 index 00000000000..870a9cbe53f --- /dev/null +++ b/tests/rustdoc-gui/type-impls.goml @@ -0,0 +1,86 @@ +// The goal of this test is to check that the inlined type alias impls, generated with JS, +// have the same display than the "local" ones. +go-to: "file://" + |DOC_PATH| + "/test_docs/type.SomeOtherTypeWithMethodsAndInlining.html" + +// method directly on type alias +wait-for: "//*[@id='method.some_other_method_directly']" + +// methods on foo +assert: "//*[@id='method.as_ref']" +assert: "//*[@id='method.must_use']" +assert: "//*[@id='method.warning1']" +assert: "//*[@id='method.warning2']" + +// sidebar items +assert: "//*[@class='sidebar-elems']//li/a[@href='#method.must_use']" +assert: "//*[@class='sidebar-elems']//li/a[@href='#method.some_other_method_directly']" +assert: "//*[@class='sidebar-elems']//li/a[@href='#method.warning1']" +assert: "//*[@class='sidebar-elems']//li/a[@href='#method.warning2']" +assert: "//*[@class='sidebar-elems']//li/a[@href='#impl-AsRef%3Cstr%3E-for-Foo']" + +// sorting +assert-text: (".block.method li:nth-child(1)", 'must_use') +assert-text: (".block.method li:nth-child(2)", 'some_other_method_directly') +assert-text: (".block.method li:nth-child(3)", 'warning1') +assert-text: (".block.method li:nth-child(4)", 'warning2') + +// Now try trait implementation merging and duplicate renumbering +go-to: "file://" + |DOC_PATH| + "/test_docs/type.SomeOtherTypeWithMethodsAndInliningAndTraits.html" + +// method directly on type alias +assert: "//*[@id='method.as_ref']" +assert-count: ("//*[@id='method.as_ref']", 1) +// method on underlying type +assert: "//*[@id='method.as_ref-1']" + +// sidebar items +assert-count: ( + "//*[@class='sidebar-elems']//h3/a[@href='#trait-implementations']", + 1 +) +assert-text: ("//*[@class='sidebar-elems']//li/a[@href='#impl-AsRef%3Cstr%3E-for-UnderlyingFooBarBaz']", "AsRef<str>") +assert-text: ( + "//*[@class='sidebar-elems']//li/a[@href='#impl-AsRef%3Cu8%3E-for-UnderlyingFooBarBaz']", + "AsRef<u8>" +) +assert-count: ("#trait-implementations-list", 1) +assert-count: ("#trait-implementations-list > details", 2) +// Both links point at the underlying trait +store-property: ("//*[@id='method.as_ref']//a[@class='fn']", {"href": href}) +assert-property: ("//*[@id='method.as_ref-1']//a[@class='fn']", {"href": |href|}) +// Both links have a self-anchor +assert: "//*[@id='method.as_ref']//a[@class='anchor'][@href='#method.as_ref']" +assert: "//*[@id='method.as_ref-1']//a[@class='anchor'][@href='#method.as_ref-1']" + +/////////////////////////////////////////////////////////////////////////// +// Now, if JavaScript is disabled, only the first method will be present // +/////////////////////////////////////////////////////////////////////////// +javascript: false +go-to: "file://" + |DOC_PATH| + "/test_docs/type.SomeOtherTypeWithMethodsAndInlining.html" + +// method directly on type alias +wait-for: "//*[@id='method.some_other_method_directly']" + +// methods on foo +assert-false: "//*[@id='method.must_use']" +assert-false: "//*[@id='method.warning1']" +assert-false: "//*[@id='method.warning2']" + +// Now try trait implementation merging and duplicate renumbering +go-to: "file://" + |DOC_PATH| + "/test_docs/type.SomeOtherTypeWithMethodsAndInliningAndTraits.html" + +// methods directly on type alias +assert: "//*[@id='method.as_ref']" +assert-count: ("//*[@id='method.as_ref']", 1) +// method on target type +assert-false: "//*[@id='method.as_ref-1']" + +// sidebar items +assert-count: ( + "//*[@class='sidebar-elems']//h3/a[@href='#trait-implementations']", + 1 +) +assert-false: "//a[@href='#impl-AsRef%3Cstr%3E-for-UnderlyingFooBarBaz']" +assert: "//a[@href='#impl-AsRef%3Cu8%3E-for-UnderlyingFooBarBaz']" +assert-count: ("#trait-implementations-list", 1) +assert-count: ("#trait-implementations-list > details", 1) diff --git a/tests/rustdoc/deref/deref-mut-methods.rs b/tests/rustdoc/deref/deref-mut-methods.rs index fdf8434224f..65681f81245 100644 --- a/tests/rustdoc/deref/deref-mut-methods.rs +++ b/tests/rustdoc/deref/deref-mut-methods.rs @@ -9,7 +9,7 @@ impl Foo { } // @has foo/struct.Bar.html -// @has - '//*[@class="sidebar-elems"]//*[@class="block"]//a[@href="#method.foo"]' 'foo' +// @has - '//*[@class="sidebar-elems"]//*[@class="block deref-methods"]//a[@href="#method.foo"]' 'foo' pub struct Bar { foo: Foo, } diff --git a/tests/rustdoc/deref/deref-recursive-pathbuf.rs b/tests/rustdoc/deref/deref-recursive-pathbuf.rs index be2b42b5ac6..7aee3147ba8 100644 --- a/tests/rustdoc/deref/deref-recursive-pathbuf.rs +++ b/tests/rustdoc/deref/deref-recursive-pathbuf.rs @@ -8,9 +8,9 @@ // @has '-' '//*[@id="deref-methods-Path"]' 'Methods from Deref<Target = Path>' // @has '-' '//*[@class="impl-items"]//*[@id="method.exists"]' 'pub fn exists(&self)' // @has '-' '//div[@class="sidebar-elems"]//h3/a[@href="#deref-methods-PathBuf"]' 'Methods from Deref<Target=PathBuf>' -// @has '-' '//*[@class="sidebar-elems"]//*[@class="block"]//a[@href="#method.as_path"]' 'as_path' +// @has '-' '//*[@class="sidebar-elems"]//*[@class="block deref-methods"]//a[@href="#method.as_path"]' 'as_path' // @has '-' '//div[@class="sidebar-elems"]//h3/a[@href="#deref-methods-Path"]' 'Methods from Deref<Target=Path>' -// @has '-' '//*[@class="sidebar-elems"]//*[@class="block"]//a[@href="#method.exists"]' 'exists' +// @has '-' '//*[@class="sidebar-elems"]//*[@class="block deref-methods"]//a[@href="#method.exists"]' 'exists' #![crate_name = "foo"] diff --git a/tests/rustdoc/hidden-impls.rs b/tests/rustdoc/hidden-impls.rs index 26e2e0e0660..3283fbfecce 100644 --- a/tests/rustdoc/hidden-impls.rs +++ b/tests/rustdoc/hidden-impls.rs @@ -12,6 +12,6 @@ pub mod __hidden { // @has foo/trait.Clone.html // @!hasraw - 'Foo' -// @has implementors/core/clone/trait.Clone.js +// @has trait.impl/core/clone/trait.Clone.js // @!hasraw - 'Foo' pub use std::clone::Clone; 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/impl-parts-crosscrate.rs b/tests/rustdoc/impl-parts-crosscrate.rs index 34733f1f8cc..da109ea7090 100644 --- a/tests/rustdoc/impl-parts-crosscrate.rs +++ b/tests/rustdoc/impl-parts-crosscrate.rs @@ -12,7 +12,7 @@ pub struct Bar<T> { t: T } // full impl string. Instead, just make sure something from each part // is mentioned. -// @hasraw implementors/rustdoc_impl_parts_crosscrate/trait.AnAutoTrait.js Bar +// @hasraw trait.impl/rustdoc_impl_parts_crosscrate/trait.AnAutoTrait.js Bar // @hasraw - Send // @hasraw - !AnAutoTrait // @hasraw - Copy diff --git a/tests/rustdoc/inline_cross/implementors-js.rs b/tests/rustdoc/inline_cross/implementors-js.rs index c79f05d8d3c..c17d52d0f41 100644 --- a/tests/rustdoc/inline_cross/implementors-js.rs +++ b/tests/rustdoc/inline_cross/implementors-js.rs @@ -4,13 +4,13 @@ extern crate implementors_inline; -// @!has implementors/implementors_js/trait.MyTrait.js -// @has implementors/implementors_inline/my_trait/trait.MyTrait.js -// @!has implementors/implementors_inline/prelude/trait.MyTrait.js +// @!has trait.impl/implementors_js/trait.MyTrait.js +// @has trait.impl/implementors_inline/my_trait/trait.MyTrait.js +// @!has trait.impl/implementors_inline/prelude/trait.MyTrait.js // @has implementors_inline/my_trait/trait.MyTrait.html -// @has - '//script/@src' '../../implementors/implementors_inline/my_trait/trait.MyTrait.js' +// @has - '//script/@src' '../../trait.impl/implementors_inline/my_trait/trait.MyTrait.js' // @has implementors_js/trait.MyTrait.html -// @has - '//script/@src' '../implementors/implementors_inline/my_trait/trait.MyTrait.js' +// @has - '//script/@src' '../trait.impl/implementors_inline/my_trait/trait.MyTrait.js' /// When re-exporting this trait, the HTML will be inlined, /// but, vitally, the JavaScript will be located only at the /// one canonical path. diff --git a/tests/rustdoc/issue-43701.rs b/tests/rustdoc/issue-43701.rs index 44335e961f9..de772881e73 100644 --- a/tests/rustdoc/issue-43701.rs +++ b/tests/rustdoc/issue-43701.rs @@ -2,4 +2,4 @@ pub use std::vec::Vec; -// @!has implementors/core/clone/trait.Clone.js +// @!has trait.impl/core/clone/trait.Clone.js 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/strip-enum-variant.no-not-shown.html b/tests/rustdoc/strip-enum-variant.no-not-shown.html index 782198956a0..e072335297d 100644 --- a/tests/rustdoc/strip-enum-variant.no-not-shown.html +++ b/tests/rustdoc/strip-enum-variant.no-not-shown.html @@ -1 +1 @@ -<ul class="block"><li><a href="#variant.Shown">Shown</a></li></ul> \ No newline at end of file +<ul class="block variant"><li><a href="#variant.Shown">Shown</a></li></ul> \ No newline at end of file diff --git a/tests/rustdoc/strip-enum-variant.rs b/tests/rustdoc/strip-enum-variant.rs index 8753a7dc613..2512fa34b39 100644 --- a/tests/rustdoc/strip-enum-variant.rs +++ b/tests/rustdoc/strip-enum-variant.rs @@ -3,7 +3,7 @@ // @!has - '//code' 'NotShown' // @has - '//code' '// some variants omitted' // Also check that `NotShown` isn't displayed in the sidebar. -// @snapshot no-not-shown - '//*[@class="sidebar-elems"]/section/*[@class="block"][1]' +// @snapshot no-not-shown - '//*[@class="sidebar-elems"]/section/*[@class="block variant"]' pub enum MyThing { Shown, #[doc(hidden)] diff --git a/tests/rustdoc/type-alias/auxiliary/parent-crate-115718.rs b/tests/rustdoc/type-alias/auxiliary/parent-crate-115718.rs new file mode 100644 index 00000000000..3607612c27a --- /dev/null +++ b/tests/rustdoc/type-alias/auxiliary/parent-crate-115718.rs @@ -0,0 +1,9 @@ +pub struct MyStruct<T>(T); + +pub trait MyTrait1 { + fn method_trait_1(); +} + +impl MyTrait1 for MyStruct<u16> { + fn method_trait_1() {} +} diff --git a/tests/rustdoc/type-alias/cross-crate-115718.rs b/tests/rustdoc/type-alias/cross-crate-115718.rs new file mode 100644 index 00000000000..372e62e4213 --- /dev/null +++ b/tests/rustdoc/type-alias/cross-crate-115718.rs @@ -0,0 +1,34 @@ +// aux-build: parent-crate-115718.rs + +// https://github.com/rust-lang/rust/issues/115718 +#![crate_name = "foo"] + +extern crate parent_crate_115718; + +use parent_crate_115718::MyStruct; + +pub trait MyTrait2 { + fn method_trait_2(); +} + +impl MyTrait2 for MyStruct<u16> { + fn method_trait_2() {} +} + +pub trait MyTrait3 { + fn method_trait_3(); +} + +impl MyTrait3 for MyType { + fn method_trait_3() {} +} + +// @hasraw 'type.impl/parent_crate_115718/struct.MyStruct.js' 'method_trait_1' +// @hasraw 'type.impl/parent_crate_115718/struct.MyStruct.js' 'method_trait_2' +// Avoid duplicating these docs. +// @!hasraw 'foo/type.MyType.html' 'method_trait_1' +// @!hasraw 'foo/type.MyType.html' 'method_trait_2' +// The one made directly on the type alias should be attached to the HTML instead. +// @!hasraw 'type.impl/parent_crate_115718/struct.MyStruct.js' 'method_trait_3' +// @hasraw 'foo/type.MyType.html' 'method_trait_3' +pub type MyType = MyStruct<u16>; diff --git a/tests/rustdoc/issue-112515-impl-ty-alias.rs b/tests/rustdoc/type-alias/deeply-nested-112515.rs index 161188ee576..161188ee576 100644 --- a/tests/rustdoc/issue-112515-impl-ty-alias.rs +++ b/tests/rustdoc/type-alias/deeply-nested-112515.rs diff --git a/tests/rustdoc/type-alias-impls-32077.rs b/tests/rustdoc/type-alias/deref-32077.rs index 7bb763f86af..186ebb1a632 100644 --- a/tests/rustdoc/type-alias-impls-32077.rs +++ b/tests/rustdoc/type-alias/deref-32077.rs @@ -1,6 +1,5 @@ // Regression test for <https://github.com/rust-lang/rust/issues/32077>. -// https://github.com/rust-lang/rust/issues/32077 #![crate_name = "foo"] pub struct GenericStruct<T>(T); @@ -25,18 +24,19 @@ impl Bar for GenericStruct<u32> {} // We check that we have the implementation of the type alias itself. // @has - '//*[@id="impl-GenericStruct%3Cu8%3E"]/h3' 'impl TypedefStruct' // @has - '//*[@id="method.on_alias"]/h4' 'pub fn on_alias()' -// @has - '//*[@id="impl-GenericStruct%3CT%3E"]/h3' 'impl<T> GenericStruct<T>' -// @has - '//*[@id="method.on_gen"]/h4' 'pub fn on_gen(arg: T)' -// @has - '//*[@id="impl-Foo-for-GenericStruct%3CT%3E"]/h3' 'impl<T> Foo for GenericStruct<T>' // This trait implementation doesn't match the type alias parameters so shouldn't appear in docs. // @!has - '//h3' 'impl Bar for GenericStruct<u32> {}' // Same goes for the `Deref` impl. // @!has - '//h2' 'Methods from Deref<Target = u32>' // @count - '//nav[@class="sidebar"]//a' 'on_alias' 1 -// @count - '//nav[@class="sidebar"]//a' 'on_gen' 1 -// @count - '//nav[@class="sidebar"]//a' 'Foo' 1 +// @!has - '//nav[@class="sidebar"]//a' 'on_gen' +// @!has - '//nav[@class="sidebar"]//a' 'Foo' // @!has - '//nav[@class="sidebar"]//a' 'Bar' // @!has - '//nav[@class="sidebar"]//a' 'on_u32' +// TypedefStruct inlined to GenericStruct +// @hasraw 'type.impl/foo/struct.GenericStruct.js' 'TypedefStruct' +// @hasraw 'type.impl/foo/struct.GenericStruct.js' 'method.on_gen' +// @hasraw 'type.impl/foo/struct.GenericStruct.js' 'Foo' pub type TypedefStruct = GenericStruct<u8>; impl TypedefStruct { @@ -54,8 +54,11 @@ impl std::ops::Deref for GenericStruct<u32> { pub struct Wrap<T>(GenericStruct<T>); // @has 'foo/type.Alias.html' -// @has - '//h2' 'Methods from Deref<Target = u32>' -// @has - '//*[@id="impl-Deref-for-Wrap%3CT%3E"]/h3' 'impl<T> Deref for Wrap<T>' +// @!has - '//h2' 'Methods from Deref<Target = u32>' +// @!has - '//*[@id="impl-Deref-for-Wrap%3CT%3E"]/h3' 'impl<T> Deref for Wrap<T>' +// @hasraw 'type.impl/foo/struct.Wrap.js' 'impl-Deref-for-Wrap%3CT%3E' +// Deref Methods aren't gathered for type aliases, though the actual impl is. +// @!hasraw 'type.impl/foo/struct.Wrap.js' 'BITS' pub type Alias = Wrap<u32>; impl<T> std::ops::Deref for Wrap<T> { diff --git a/tests/rustdoc/type-alias/same-crate-115718.rs b/tests/rustdoc/type-alias/same-crate-115718.rs new file mode 100644 index 00000000000..26e5db85cd6 --- /dev/null +++ b/tests/rustdoc/type-alias/same-crate-115718.rs @@ -0,0 +1,34 @@ +// https://github.com/rust-lang/rust/issues/115718 +#![crate_name = "foo"] + +pub trait MyTrait1 { + fn method_trait_1(); +} + +pub trait MyTrait2 { + fn method_trait_2(); +} + +pub struct MyStruct<T>(T); + +impl MyStruct<u32> { + pub fn method_u32() {} +} + +impl MyStruct<u16> { + pub fn method_u16() {} +} + +impl MyTrait1 for MyStruct<u32> { + fn method_trait_1() {} +} + +impl MyTrait2 for MyStruct<u16> { + fn method_trait_2() {} +} + +// @hasraw 'type.impl/foo/struct.MyStruct.js' 'method_u16' +// @!hasraw 'type.impl/foo/struct.MyStruct.js' 'method_u32' +// @!hasraw 'type.impl/foo/struct.MyStruct.js' 'method_trait_1' +// @hasraw 'type.impl/foo/struct.MyStruct.js' 'method_trait_2' +pub type MyType = MyStruct<u16>; 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 ee82bc77aed..a340877752d 100644 --- a/tests/ui-fulldeps/stable-mir/check_instance.rs +++ b/tests/ui-fulldeps/stable-mir/check_instance.rs @@ -59,7 +59,7 @@ 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!() }; + 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()); 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 index 5ad05559cb4..b0596b18823 100644 --- a/tests/ui-fulldeps/stable-mir/smir_internal.rs +++ b/tests/ui-fulldeps/stable-mir/smir_internal.rs @@ -29,7 +29,7 @@ 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 orig_ty = body.locals()[0].ty; let rustc_ty = rustc_internal::internal(&orig_ty); assert!(rustc_ty.is_unit()); ControlFlow::Continue(()) 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-type-bounds/do-not-look-at-parent-item-in-suggestion-for-type-param-of-current-assoc-item.rs b/tests/ui/associated-type-bounds/do-not-look-at-parent-item-in-suggestion-for-type-param-of-current-assoc-item.rs new file mode 100644 index 00000000000..c1047d85645 --- /dev/null +++ b/tests/ui/associated-type-bounds/do-not-look-at-parent-item-in-suggestion-for-type-param-of-current-assoc-item.rs @@ -0,0 +1,28 @@ +use std::collections::HashMap; +use std::hash::Hash; + +trait LowT: Identify {} + +trait Identify { + type Id: Clone + Hash + PartialEq + Eq; + fn identify(&self) -> Self::Id; +} + +struct MapStore<L, I> +where + L: LowT + Identify<Id = I>, +{ + lows: HashMap<I, L>, +} + +impl<L, I> MapStore<L, I> +where + L: LowT + Identify<Id = I>, + I: Clone + Hash + PartialEq + Eq, +{ + fn remove_low(&mut self, low: &impl LowT) { + let _low = self.lows.remove(low.identify()).unwrap(); //~ ERROR mismatched types + } +} + +fn main() {} diff --git a/tests/ui/associated-type-bounds/do-not-look-at-parent-item-in-suggestion-for-type-param-of-current-assoc-item.stderr b/tests/ui/associated-type-bounds/do-not-look-at-parent-item-in-suggestion-for-type-param-of-current-assoc-item.stderr new file mode 100644 index 00000000000..78bf93c32d5 --- /dev/null +++ b/tests/ui/associated-type-bounds/do-not-look-at-parent-item-in-suggestion-for-type-param-of-current-assoc-item.stderr @@ -0,0 +1,18 @@ +error[E0308]: mismatched types + --> $DIR/do-not-look-at-parent-item-in-suggestion-for-type-param-of-current-assoc-item.rs:24:37 + | +LL | let _low = self.lows.remove(low.identify()).unwrap(); + | ------ ^^^^^^^^^^^^^^ expected `&I`, found associated type + | | + | arguments to this method are incorrect + | + = note: expected reference `&I` + found associated type `<impl LowT as Identify>::Id` + = help: consider constraining the associated type `<impl LowT as Identify>::Id` to `&I` + = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html +note: method defined here + --> $SRC_DIR/std/src/collections/hash/map.rs:LL:COL + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. 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/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/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/unix_sigpipe/unix_sigpipe-crate.stderr b/tests/ui/attributes/unix_sigpipe/unix_sigpipe-crate.stderr index a1fb4d6787c..225b8e8f32f 100644 --- a/tests/ui/attributes/unix_sigpipe/unix_sigpipe-crate.stderr +++ b/tests/ui/attributes/unix_sigpipe/unix_sigpipe-crate.stderr @@ -3,11 +3,15 @@ error: `unix_sigpipe` attribute cannot be used at crate level | LL | #![unix_sigpipe = "inherit"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | fn main() {} + | ---- the inner attribute doesn't annotate this function | help: perhaps you meant to use an outer attribute | -LL | #[unix_sigpipe = "inherit"] - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +LL - #![unix_sigpipe = "inherit"] +LL + #[unix_sigpipe = "inherit"] + | error: aborting due to previous error diff --git a/tests/ui/binding/issue-53114-borrow-checks.rs b/tests/ui/binding/issue-53114-borrow-checks.rs index 7646472f45f..6ab1f4f47df 100644 --- a/tests/ui/binding/issue-53114-borrow-checks.rs +++ b/tests/ui/binding/issue-53114-borrow-checks.rs @@ -1,8 +1,9 @@ +// check-pass // Issue #53114: NLL's borrow check had some deviations from the old borrow // checker, and both had some deviations from our ideal state. This test // captures the behavior of how `_` bindings are handled with respect to how we // flag expressions that are meant to request unsafe blocks. -#![allow(irrefutable_let_patterns)] +#![allow(irrefutable_let_patterns, dropping_references)] struct M; fn let_wild_gets_moved_expr() { @@ -19,29 +20,23 @@ fn let_wild_gets_moved_expr() { fn match_moved_expr_to_wild() { let m = M; drop(m); - match m { _ => { } } // #53114: should eventually be accepted too - //~^ ERROR [E0382] + match m { _ => { } } // #53114: accepted too let mm = (M, M); // variation on above with `_` in substructure match mm { (_x, _) => { } } match mm { (_, _y) => { } } - //~^ ERROR [E0382] match mm { (_, _) => { } } - //~^ ERROR [E0382] } fn if_let_moved_expr_to_wild() { let m = M; drop(m); - if let _ = m { } // #53114: should eventually be accepted too - //~^ ERROR [E0382] + if let _ = m { } // #53114: accepted too let mm = (M, M); // variation on above with `_` in substructure if let (_x, _) = mm { } if let (_, _y) = mm { } - //~^ ERROR [E0382] if let (_, _) = mm { } - //~^ ERROR [E0382] } fn let_wild_gets_borrowed_expr() { diff --git a/tests/ui/binding/issue-53114-borrow-checks.stderr b/tests/ui/binding/issue-53114-borrow-checks.stderr deleted file mode 100644 index 0ec2ae8839e..00000000000 --- a/tests/ui/binding/issue-53114-borrow-checks.stderr +++ /dev/null @@ -1,81 +0,0 @@ -error[E0382]: use of moved value: `m` - --> $DIR/issue-53114-borrow-checks.rs:22:11 - | -LL | let m = M; - | - move occurs because `m` has type `M`, which does not implement the `Copy` trait -LL | drop(m); - | - value moved here -LL | match m { _ => { } } // #53114: should eventually be accepted too - | ^ value used here after move - -error[E0382]: use of partially moved value: `mm` - --> $DIR/issue-53114-borrow-checks.rs:27:11 - | -LL | match mm { (_x, _) => { } } - | -- value partially moved here -LL | match mm { (_, _y) => { } } - | ^^ value used here after partial move - | - = note: partial move occurs because `mm.0` has type `M`, which does not implement the `Copy` trait -help: borrow this binding in the pattern to avoid moving the value - | -LL | match mm { (ref _x, _) => { } } - | +++ - -error[E0382]: use of partially moved value: `mm` - --> $DIR/issue-53114-borrow-checks.rs:29:11 - | -LL | match mm { (_, _y) => { } } - | -- value partially moved here -LL | -LL | match mm { (_, _) => { } } - | ^^ value used here after partial move - | - = note: partial move occurs because `mm.1` has type `M`, which does not implement the `Copy` trait -help: borrow this binding in the pattern to avoid moving the value - | -LL | match mm { (_, ref _y) => { } } - | +++ - -error[E0382]: use of moved value: `m` - --> $DIR/issue-53114-borrow-checks.rs:36:16 - | -LL | let m = M; - | - move occurs because `m` has type `M`, which does not implement the `Copy` trait -LL | drop(m); - | - value moved here -LL | if let _ = m { } // #53114: should eventually be accepted too - | ^ value used here after move - -error[E0382]: use of partially moved value: `mm` - --> $DIR/issue-53114-borrow-checks.rs:41:22 - | -LL | if let (_x, _) = mm { } - | -- value partially moved here -LL | if let (_, _y) = mm { } - | ^^ value used here after partial move - | - = note: partial move occurs because `mm.0` has type `M`, which does not implement the `Copy` trait -help: borrow this binding in the pattern to avoid moving the value - | -LL | if let (ref _x, _) = mm { } - | +++ - -error[E0382]: use of partially moved value: `mm` - --> $DIR/issue-53114-borrow-checks.rs:43:21 - | -LL | if let (_, _y) = mm { } - | -- value partially moved here -LL | -LL | if let (_, _) = mm { } - | ^^ value used here after partial move - | - = note: partial move occurs because `mm.1` has type `M`, which does not implement the `Copy` trait -help: borrow this binding in the pattern to avoid moving the value - | -LL | if let (_, ref _y) = mm { } - | +++ - -error: aborting due to 6 previous errors - -For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/borrowck/borrowck-move-out-from-array-match.rs b/tests/ui/borrowck/borrowck-move-out-from-array-match.rs index ced4d002b38..d2a5da66de9 100644 --- a/tests/ui/borrowck/borrowck-move-out-from-array-match.rs +++ b/tests/ui/borrowck/borrowck-move-out-from-array-match.rs @@ -42,8 +42,8 @@ fn move_out_by_const_index_and_subslice() { [_x, _, _] => {} } match a { - //~^ ERROR use of partially moved value [_y @ .., _, _] => {} + //~^ ERROR use of partially moved value } } @@ -53,8 +53,8 @@ fn move_out_by_const_index_end_and_subslice() { [.., _x] => {} } match a { - //~^ ERROR use of partially moved value [_, _, _y @ ..] => {} + //~^ ERROR use of partially moved value } } @@ -64,8 +64,8 @@ fn move_out_by_const_index_field_and_subslice() { [(_x, _), _, _] => {} } match a { - //~^ ERROR use of partially moved value [_y @ .., _, _] => {} + //~^ ERROR use of partially moved value } } @@ -75,8 +75,8 @@ fn move_out_by_const_index_end_field_and_subslice() { [.., (_x, _)] => {} } match a { - //~^ ERROR use of partially moved value [_, _, _y @ ..] => {} + //~^ ERROR use of partially moved value } } @@ -108,8 +108,8 @@ fn move_out_by_subslice_and_subslice() { [x @ .., _] => {} } match a { - //~^ ERROR use of partially moved value [_, _y @ ..] => {} + //~^ ERROR use of partially moved value } } diff --git a/tests/ui/borrowck/borrowck-move-out-from-array-match.stderr b/tests/ui/borrowck/borrowck-move-out-from-array-match.stderr index 67b00c1dd90..d827776845e 100644 --- a/tests/ui/borrowck/borrowck-move-out-from-array-match.stderr +++ b/tests/ui/borrowck/borrowck-move-out-from-array-match.stderr @@ -44,13 +44,13 @@ LL | [_, _, (ref _x, _)] => {} | +++ error[E0382]: use of partially moved value: `a` - --> $DIR/borrowck-move-out-from-array-match.rs:44:11 + --> $DIR/borrowck-move-out-from-array-match.rs:45:10 | LL | [_x, _, _] => {} | -- value partially moved here -LL | } -LL | match a { - | ^ value used here after partial move +... +LL | [_y @ .., _, _] => {} + | ^^ value used here after partial move | = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait help: borrow this binding in the pattern to avoid moving the value @@ -59,13 +59,13 @@ LL | [ref _x, _, _] => {} | +++ error[E0382]: use of partially moved value: `a` - --> $DIR/borrowck-move-out-from-array-match.rs:55:11 + --> $DIR/borrowck-move-out-from-array-match.rs:56:16 | LL | [.., _x] => {} | -- value partially moved here -LL | } -LL | match a { - | ^ value used here after partial move +... +LL | [_, _, _y @ ..] => {} + | ^^ value used here after partial move | = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait help: borrow this binding in the pattern to avoid moving the value @@ -74,13 +74,13 @@ LL | [.., ref _x] => {} | +++ error[E0382]: use of partially moved value: `a` - --> $DIR/borrowck-move-out-from-array-match.rs:66:11 + --> $DIR/borrowck-move-out-from-array-match.rs:67:10 | LL | [(_x, _), _, _] => {} | -- value partially moved here -LL | } -LL | match a { - | ^ value used here after partial move +... +LL | [_y @ .., _, _] => {} + | ^^ value used here after partial move | = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait help: borrow this binding in the pattern to avoid moving the value @@ -89,13 +89,13 @@ LL | [(ref _x, _), _, _] => {} | +++ error[E0382]: use of partially moved value: `a` - --> $DIR/borrowck-move-out-from-array-match.rs:77:11 + --> $DIR/borrowck-move-out-from-array-match.rs:78:16 | LL | [.., (_x, _)] => {} | -- value partially moved here -LL | } -LL | match a { - | ^ value used here after partial move +... +LL | [_, _, _y @ ..] => {} + | ^^ value used here after partial move | = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait help: borrow this binding in the pattern to avoid moving the value @@ -134,13 +134,13 @@ LL | [_, _, ref _y @ ..] => {} | +++ error[E0382]: use of partially moved value: `a` - --> $DIR/borrowck-move-out-from-array-match.rs:110:11 + --> $DIR/borrowck-move-out-from-array-match.rs:111:13 | LL | [x @ .., _] => {} | - value partially moved here -LL | } -LL | match a { - | ^ value used here after partial move +... +LL | [_, _y @ ..] => {} + | ^^ value used here after partial move | = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait help: borrow this binding in the pattern to avoid moving the value diff --git a/tests/ui/borrowck/borrowck-move-out-from-array-no-overlap-match.rs b/tests/ui/borrowck/borrowck-move-out-from-array-no-overlap-match.rs index 97db70f34cc..1e401b7e92e 100644 --- a/tests/ui/borrowck/borrowck-move-out-from-array-no-overlap-match.rs +++ b/tests/ui/borrowck/borrowck-move-out-from-array-no-overlap-match.rs @@ -1,3 +1,4 @@ +// check-pass // Due to #53114, which causes a "read" of the `_` patterns, // the borrow-checker refuses this code, while it should probably be allowed. // Once the bug is fixed, the test, which is derived from a @@ -15,7 +16,6 @@ fn move_out_from_begin_and_one_from_end() { [_, _, _x] => {} } match a { - //~^ ERROR use of partially moved value [.., _y, _] => {} } } @@ -26,7 +26,6 @@ fn move_out_from_begin_field_and_end_field() { [_, _, (_x, _)] => {} } match a { - //~^ ERROR use of partially moved value [.., (_, _y)] => {} } } @@ -39,7 +38,6 @@ fn move_out_by_const_index_and_subslice() { [_x, _, _] => {} } match a { - //~^ ERROR use of partially moved value [_, _y @ ..] => {} } } @@ -50,7 +48,6 @@ fn move_out_by_const_index_end_and_subslice() { [.., _x] => {} } match a { - //~^ ERROR use of partially moved value [_y @ .., _] => {} } } @@ -61,7 +58,6 @@ fn move_out_by_const_index_field_and_subslice() { [(_x, _), _, _] => {} } match a { - //~^ ERROR use of partially moved value [_, _y @ ..] => {} } } @@ -72,7 +68,6 @@ fn move_out_by_const_index_end_field_and_subslice() { [.., (_x, _)] => {} } match a { - //~^ ERROR use of partially moved value [_y @ .., _] => {} } } @@ -83,7 +78,6 @@ fn move_out_by_const_subslice_and_index_field() { [_, _y @ ..] => {} } match a { - //~^ ERROR use of partially moved value [(_x, _), _, _] => {} } } @@ -94,7 +88,6 @@ fn move_out_by_const_subslice_and_end_index_field() { [_y @ .., _] => {} } match a { - //~^ ERROR use of partially moved value [.., (_x, _)] => {} } } @@ -107,7 +100,6 @@ fn move_out_by_subslice_and_subslice() { [x @ .., _, _] => {} } match a { - //~^ ERROR use of partially moved value [_, _y @ ..] => {} } } diff --git a/tests/ui/borrowck/borrowck-move-out-from-array-no-overlap-match.stderr b/tests/ui/borrowck/borrowck-move-out-from-array-no-overlap-match.stderr deleted file mode 100644 index 47429ea3eeb..00000000000 --- a/tests/ui/borrowck/borrowck-move-out-from-array-no-overlap-match.stderr +++ /dev/null @@ -1,138 +0,0 @@ -error[E0382]: use of partially moved value: `a` - --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:17:11 - | -LL | [_, _, _x] => {} - | -- value partially moved here -LL | } -LL | match a { - | ^ value used here after partial move - | - = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait -help: borrow this binding in the pattern to avoid moving the value - | -LL | [_, _, ref _x] => {} - | +++ - -error[E0382]: use of partially moved value: `a` - --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:28:11 - | -LL | [_, _, (_x, _)] => {} - | -- value partially moved here -LL | } -LL | match a { - | ^ value used here after partial move - | - = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait -help: borrow this binding in the pattern to avoid moving the value - | -LL | [_, _, (ref _x, _)] => {} - | +++ - -error[E0382]: use of partially moved value: `a` - --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:41:11 - | -LL | [_x, _, _] => {} - | -- value partially moved here -LL | } -LL | match a { - | ^ value used here after partial move - | - = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait -help: borrow this binding in the pattern to avoid moving the value - | -LL | [ref _x, _, _] => {} - | +++ - -error[E0382]: use of partially moved value: `a` - --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:52:11 - | -LL | [.., _x] => {} - | -- value partially moved here -LL | } -LL | match a { - | ^ value used here after partial move - | - = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait -help: borrow this binding in the pattern to avoid moving the value - | -LL | [.., ref _x] => {} - | +++ - -error[E0382]: use of partially moved value: `a` - --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:63:11 - | -LL | [(_x, _), _, _] => {} - | -- value partially moved here -LL | } -LL | match a { - | ^ value used here after partial move - | - = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait -help: borrow this binding in the pattern to avoid moving the value - | -LL | [(ref _x, _), _, _] => {} - | +++ - -error[E0382]: use of partially moved value: `a` - --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:74:11 - | -LL | [.., (_x, _)] => {} - | -- value partially moved here -LL | } -LL | match a { - | ^ value used here after partial move - | - = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait -help: borrow this binding in the pattern to avoid moving the value - | -LL | [.., (ref _x, _)] => {} - | +++ - -error[E0382]: use of partially moved value: `a` - --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:85:11 - | -LL | [_, _y @ ..] => {} - | -- value partially moved here -LL | } -LL | match a { - | ^ value used here after partial move - | - = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait -help: borrow this binding in the pattern to avoid moving the value - | -LL | [_, ref _y @ ..] => {} - | +++ - -error[E0382]: use of partially moved value: `a` - --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:96:11 - | -LL | [_y @ .., _] => {} - | -- value partially moved here -LL | } -LL | match a { - | ^ value used here after partial move - | - = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait -help: borrow this binding in the pattern to avoid moving the value - | -LL | [ref _y @ .., _] => {} - | +++ - -error[E0382]: use of partially moved value: `a` - --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:109:11 - | -LL | [x @ .., _, _] => {} - | - value partially moved here -LL | } -LL | match a { - | ^ value used here after partial move - | - = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait -help: borrow this binding in the pattern to avoid moving the value - | -LL | [ref x @ .., _, _] => {} - | +++ - -error: aborting due to 9 previous errors - -For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/borrowck/borrowck-move-out-from-array-use-match.rs b/tests/ui/borrowck/borrowck-move-out-from-array-use-match.rs index 604a25cdcc1..fbcf126f3ea 100644 --- a/tests/ui/borrowck/borrowck-move-out-from-array-use-match.rs +++ b/tests/ui/borrowck/borrowck-move-out-from-array-use-match.rs @@ -42,8 +42,8 @@ fn move_out_by_const_index_and_subslice() { [_x, _, _] => {} } match a { - //~^ ERROR [E0382] [ref _y @ .., _, _] => {} + //~^ ERROR [E0382] } } @@ -53,8 +53,8 @@ fn move_out_by_const_index_end_and_subslice() { [.., _x] => {} } match a { - //~^ ERROR [E0382] [_, _, ref _y @ ..] => {} + //~^ ERROR [E0382] } } @@ -64,8 +64,8 @@ fn move_out_by_const_index_field_and_subslice() { [(_x, _), _, _] => {} } match a { - //~^ ERROR [E0382] [ref _y @ .., _, _] => {} + //~^ ERROR [E0382] } } @@ -75,8 +75,8 @@ fn move_out_by_const_index_end_field_and_subslice() { [.., (_x, _)] => {} } match a { - //~^ ERROR [E0382] [_, _, ref _y @ ..] => {} + //~^ ERROR [E0382] } } @@ -108,8 +108,8 @@ fn move_out_by_subslice_and_subslice() { [x @ .., _] => {} } match a { - //~^ ERROR [E0382] [_, ref _y @ ..] => {} + //~^ ERROR [E0382] } } diff --git a/tests/ui/borrowck/borrowck-move-out-from-array-use-match.stderr b/tests/ui/borrowck/borrowck-move-out-from-array-use-match.stderr index bfab13d42d2..da76b5c4a65 100644 --- a/tests/ui/borrowck/borrowck-move-out-from-array-use-match.stderr +++ b/tests/ui/borrowck/borrowck-move-out-from-array-use-match.stderr @@ -43,14 +43,14 @@ help: borrow this binding in the pattern to avoid moving the value LL | [_, _, (ref _x, _)] => {} | +++ -error[E0382]: use of partially moved value: `a` - --> $DIR/borrowck-move-out-from-array-use-match.rs:44:11 +error[E0382]: borrow of partially moved value: `a` + --> $DIR/borrowck-move-out-from-array-use-match.rs:45:10 | LL | [_x, _, _] => {} | -- value partially moved here -LL | } -LL | match a { - | ^ value used here after partial move +... +LL | [ref _y @ .., _, _] => {} + | ^^^^^^ value borrowed here after partial move | = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait help: borrow this binding in the pattern to avoid moving the value @@ -58,14 +58,14 @@ help: borrow this binding in the pattern to avoid moving the value LL | [ref _x, _, _] => {} | +++ -error[E0382]: use of partially moved value: `a` - --> $DIR/borrowck-move-out-from-array-use-match.rs:55:11 +error[E0382]: borrow of partially moved value: `a` + --> $DIR/borrowck-move-out-from-array-use-match.rs:56:16 | LL | [.., _x] => {} | -- value partially moved here -LL | } -LL | match a { - | ^ value used here after partial move +... +LL | [_, _, ref _y @ ..] => {} + | ^^^^^^ value borrowed here after partial move | = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait help: borrow this binding in the pattern to avoid moving the value @@ -73,14 +73,14 @@ help: borrow this binding in the pattern to avoid moving the value LL | [.., ref _x] => {} | +++ -error[E0382]: use of partially moved value: `a` - --> $DIR/borrowck-move-out-from-array-use-match.rs:66:11 +error[E0382]: borrow of partially moved value: `a` + --> $DIR/borrowck-move-out-from-array-use-match.rs:67:10 | LL | [(_x, _), _, _] => {} | -- value partially moved here -LL | } -LL | match a { - | ^ value used here after partial move +... +LL | [ref _y @ .., _, _] => {} + | ^^^^^^ value borrowed here after partial move | = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait help: borrow this binding in the pattern to avoid moving the value @@ -88,14 +88,14 @@ help: borrow this binding in the pattern to avoid moving the value LL | [(ref _x, _), _, _] => {} | +++ -error[E0382]: use of partially moved value: `a` - --> $DIR/borrowck-move-out-from-array-use-match.rs:77:11 +error[E0382]: borrow of partially moved value: `a` + --> $DIR/borrowck-move-out-from-array-use-match.rs:78:16 | LL | [.., (_x, _)] => {} | -- value partially moved here -LL | } -LL | match a { - | ^ value used here after partial move +... +LL | [_, _, ref _y @ ..] => {} + | ^^^^^^ value borrowed here after partial move | = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait help: borrow this binding in the pattern to avoid moving the value @@ -133,14 +133,14 @@ help: borrow this binding in the pattern to avoid moving the value LL | [_, _, ref _y @ ..] => {} | +++ -error[E0382]: use of partially moved value: `a` - --> $DIR/borrowck-move-out-from-array-use-match.rs:110:11 +error[E0382]: borrow of partially moved value: `a` + --> $DIR/borrowck-move-out-from-array-use-match.rs:111:13 | LL | [x @ .., _] => {} | - value partially moved here -LL | } -LL | match a { - | ^ value used here after partial move +... +LL | [_, ref _y @ ..] => {} + | ^^^^^^ value borrowed here after partial move | = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait help: borrow this binding in the pattern to avoid moving the value diff --git a/tests/ui/borrowck/borrowck-move-out-from-array-use-no-overlap-match.rs b/tests/ui/borrowck/borrowck-move-out-from-array-use-no-overlap-match.rs index 017ca90b81a..2f6ce430b35 100644 --- a/tests/ui/borrowck/borrowck-move-out-from-array-use-no-overlap-match.rs +++ b/tests/ui/borrowck/borrowck-move-out-from-array-use-no-overlap-match.rs @@ -1,3 +1,4 @@ +// check-pass // Due to #53114, which causes a "read" of the `_` patterns, // the borrow-checker refuses this code, while it should probably be allowed. // Once the bug is fixed, the test, which is derived from a @@ -15,7 +16,6 @@ fn move_out_from_begin_and_one_from_end() { [_, _, _x] => {} } match a { - //~^ ERROR use of partially moved value [.., ref _y, _] => {} } } @@ -26,7 +26,6 @@ fn move_out_from_begin_field_and_end_field() { [_, _, (_x, _)] => {} } match a { - //~^ ERROR use of partially moved value [.., (_, ref _y)] => {} } } @@ -39,7 +38,6 @@ fn move_out_by_const_index_and_subslice() { [_x, _, _] => {} } match a { - //~^ ERROR use of partially moved value [_, ref _y @ ..] => {} } } @@ -50,7 +48,6 @@ fn move_out_by_const_index_end_and_subslice() { [.., _x] => {} } match a { - //~^ ERROR use of partially moved value [ref _y @ .., _] => {} } } @@ -61,7 +58,6 @@ fn move_out_by_const_index_field_and_subslice() { [(_x, _), _, _] => {} } match a { - //~^ ERROR use of partially moved value [_, ref _y @ ..] => {} } } @@ -72,7 +68,6 @@ fn move_out_by_const_index_end_field_and_subslice() { [.., (_x, _)] => {} } match a { - //~^ ERROR use of partially moved value [ref _y @ .., _] => {} } } @@ -83,7 +78,6 @@ fn move_out_by_const_subslice_and_index_field() { [_, _y @ ..] => {} } match a { - //~^ ERROR use of partially moved value [(ref _x, _), _, _] => {} } } @@ -94,7 +88,6 @@ fn move_out_by_const_subslice_and_end_index_field() { [_y @ .., _] => {} } match a { - //~^ ERROR use of partially moved value [.., (ref _x, _)] => {} } } @@ -107,7 +100,6 @@ fn move_out_by_subslice_and_subslice() { [x @ .., _, _] => {} } match a { - //~^ ERROR use of partially moved value [_, ref _y @ ..] => {} } } diff --git a/tests/ui/borrowck/borrowck-move-out-from-array-use-no-overlap-match.stderr b/tests/ui/borrowck/borrowck-move-out-from-array-use-no-overlap-match.stderr deleted file mode 100644 index 8412c24fe61..00000000000 --- a/tests/ui/borrowck/borrowck-move-out-from-array-use-no-overlap-match.stderr +++ /dev/null @@ -1,138 +0,0 @@ -error[E0382]: use of partially moved value: `a` - --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:17:11 - | -LL | [_, _, _x] => {} - | -- value partially moved here -LL | } -LL | match a { - | ^ value used here after partial move - | - = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait -help: borrow this binding in the pattern to avoid moving the value - | -LL | [_, _, ref _x] => {} - | +++ - -error[E0382]: use of partially moved value: `a` - --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:28:11 - | -LL | [_, _, (_x, _)] => {} - | -- value partially moved here -LL | } -LL | match a { - | ^ value used here after partial move - | - = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait -help: borrow this binding in the pattern to avoid moving the value - | -LL | [_, _, (ref _x, _)] => {} - | +++ - -error[E0382]: use of partially moved value: `a` - --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:41:11 - | -LL | [_x, _, _] => {} - | -- value partially moved here -LL | } -LL | match a { - | ^ value used here after partial move - | - = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait -help: borrow this binding in the pattern to avoid moving the value - | -LL | [ref _x, _, _] => {} - | +++ - -error[E0382]: use of partially moved value: `a` - --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:52:11 - | -LL | [.., _x] => {} - | -- value partially moved here -LL | } -LL | match a { - | ^ value used here after partial move - | - = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait -help: borrow this binding in the pattern to avoid moving the value - | -LL | [.., ref _x] => {} - | +++ - -error[E0382]: use of partially moved value: `a` - --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:63:11 - | -LL | [(_x, _), _, _] => {} - | -- value partially moved here -LL | } -LL | match a { - | ^ value used here after partial move - | - = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait -help: borrow this binding in the pattern to avoid moving the value - | -LL | [(ref _x, _), _, _] => {} - | +++ - -error[E0382]: use of partially moved value: `a` - --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:74:11 - | -LL | [.., (_x, _)] => {} - | -- value partially moved here -LL | } -LL | match a { - | ^ value used here after partial move - | - = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait -help: borrow this binding in the pattern to avoid moving the value - | -LL | [.., (ref _x, _)] => {} - | +++ - -error[E0382]: use of partially moved value: `a` - --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:85:11 - | -LL | [_, _y @ ..] => {} - | -- value partially moved here -LL | } -LL | match a { - | ^ value used here after partial move - | - = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait -help: borrow this binding in the pattern to avoid moving the value - | -LL | [_, ref _y @ ..] => {} - | +++ - -error[E0382]: use of partially moved value: `a` - --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:96:11 - | -LL | [_y @ .., _] => {} - | -- value partially moved here -LL | } -LL | match a { - | ^ value used here after partial move - | - = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait -help: borrow this binding in the pattern to avoid moving the value - | -LL | [ref _y @ .., _] => {} - | +++ - -error[E0382]: use of partially moved value: `a` - --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:109:11 - | -LL | [x @ .., _, _] => {} - | - value partially moved here -LL | } -LL | match a { - | ^ value used here after partial move - | - = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait -help: borrow this binding in the pattern to avoid moving the value - | -LL | [ref x @ .., _, _] => {} - | +++ - -error: aborting due to 9 previous errors - -For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/borrowck/issue-62107-match-arm-scopes.rs b/tests/ui/borrowck/issue-62107-match-arm-scopes.rs index 93ce34d2fe5..7dbcad9d37f 100644 --- a/tests/ui/borrowck/issue-62107-match-arm-scopes.rs +++ b/tests/ui/borrowck/issue-62107-match-arm-scopes.rs @@ -1,8 +1,8 @@ fn main() { let e: i32; match e { - //~^ ERROR E0381 ref u if true => {} + //~^ ERROR E0381 ref v if true => { let tx = 0; &tx; diff --git a/tests/ui/borrowck/issue-62107-match-arm-scopes.stderr b/tests/ui/borrowck/issue-62107-match-arm-scopes.stderr index 9683da919aa..8fe8fa71064 100644 --- a/tests/ui/borrowck/issue-62107-match-arm-scopes.stderr +++ b/tests/ui/borrowck/issue-62107-match-arm-scopes.stderr @@ -1,10 +1,11 @@ error[E0381]: used binding `e` isn't initialized - --> $DIR/issue-62107-match-arm-scopes.rs:3:11 + --> $DIR/issue-62107-match-arm-scopes.rs:4:9 | LL | let e: i32; | - binding declared here but left uninitialized LL | match e { - | ^ `e` used here but it isn't initialized +LL | ref u if true => {} + | ^^^^^ `e` used here but it isn't initialized | help: consider assigning a value | diff --git a/tests/ui/borrowck/let_underscore_temporary.rs b/tests/ui/borrowck/let_underscore_temporary.rs index 835cd20798f..a5ea3b3a7ab 100644 --- a/tests/ui/borrowck/let_underscore_temporary.rs +++ b/tests/ui/borrowck/let_underscore_temporary.rs @@ -52,4 +52,42 @@ fn let_ascribe(string: &Option<&str>, mut num: Option<i32>) { }; } +fn matched(string: &Option<&str>, mut num: Option<i32>) { + match if let Some(s) = *string { s.len() } else { 0 } { + _ => {} + }; + match if let Some(s) = &num { s } else { &0 } { + _ => {} + }; + match if let Some(s) = &mut num { + *s += 1; + s + } else { + &mut 0 + //~^ ERROR temporary value dropped while borrowed + } { + _ => {} + }; + match if let Some(ref s) = num { s } else { &0 } { + _ => {} + }; + match if let Some(mut s) = num { + s += 1; + s + } else { + 0 + } { + _ => {} + }; + match if let Some(ref mut s) = num { + *s += 1; + s + } else { + &mut 0 + //~^ ERROR temporary value dropped while borrowed + } { + _ => {} + }; +} + fn main() {} diff --git a/tests/ui/borrowck/let_underscore_temporary.stderr b/tests/ui/borrowck/let_underscore_temporary.stderr index 74f3598c4d0..6bccf329181 100644 --- a/tests/ui/borrowck/let_underscore_temporary.stderr +++ b/tests/ui/borrowck/let_underscore_temporary.stderr @@ -74,6 +74,44 @@ LL | | }; | = note: consider using a `let` binding to create a longer lived value -error: aborting due to 4 previous errors +error[E0716]: temporary value dropped while borrowed + --> $DIR/let_underscore_temporary.rs:66:14 + | +LL | match if let Some(s) = &mut num { + | ___________- +LL | | *s += 1; +LL | | s +LL | | } else { +LL | | &mut 0 + | | ^ creates a temporary value which is freed while still in use +LL | | +LL | | } { + | | - + | | | + | |_____temporary value is freed at the end of this statement + | borrow later used here + | + = note: consider using a `let` binding to create a longer lived value + +error[E0716]: temporary value dropped while borrowed + --> $DIR/let_underscore_temporary.rs:86:14 + | +LL | match if let Some(ref mut s) = num { + | ___________- +LL | | *s += 1; +LL | | s +LL | | } else { +LL | | &mut 0 + | | ^ creates a temporary value which is freed while still in use +LL | | +LL | | } { + | | - + | | | + | |_____temporary value is freed at the end of this statement + | borrow later used here + | + = note: consider using a `let` binding to create a longer lived value + +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0716`. 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/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/const-ptr/allowed_slices.rs b/tests/ui/const-ptr/allowed_slices.rs index 3f19cd4d804..3561338a758 100644 --- a/tests/ui/const-ptr/allowed_slices.rs +++ b/tests/ui/const-ptr/allowed_slices.rs @@ -2,8 +2,6 @@ #![feature( slice_from_ptr_range, const_slice_from_ptr_range, - pointer_byte_offsets, - const_pointer_byte_offsets )] use std::{ mem::MaybeUninit, diff --git a/tests/ui/const-ptr/forbidden_slices.rs b/tests/ui/const-ptr/forbidden_slices.rs index 03d6499aefb..0374ac7f714 100644 --- a/tests/ui/const-ptr/forbidden_slices.rs +++ b/tests/ui/const-ptr/forbidden_slices.rs @@ -5,8 +5,6 @@ #![feature( slice_from_ptr_range, const_slice_from_ptr_range, - pointer_byte_offsets, - const_pointer_byte_offsets )] use std::{ mem::{size_of, MaybeUninit}, diff --git a/tests/ui/const-ptr/forbidden_slices.stderr b/tests/ui/const-ptr/forbidden_slices.stderr index 00230d59a37..105683940cf 100644 --- a/tests/ui/const-ptr/forbidden_slices.stderr +++ b/tests/ui/const-ptr/forbidden_slices.stderr @@ -1,5 +1,5 @@ error[E0080]: it is undefined behavior to use this value - --> $DIR/forbidden_slices.rs:18:1 + --> $DIR/forbidden_slices.rs:16:1 | LL | pub static S0: &[u32] = unsafe { from_raw_parts(ptr::null(), 0) }; | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null reference @@ -10,7 +10,7 @@ LL | pub static S0: &[u32] = unsafe { from_raw_parts(ptr::null(), 0) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/forbidden_slices.rs:20:1 + --> $DIR/forbidden_slices.rs:18:1 | LL | pub static S1: &[()] = unsafe { from_raw_parts(ptr::null(), 0) }; | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null reference @@ -21,7 +21,7 @@ LL | pub static S1: &[()] = unsafe { from_raw_parts(ptr::null(), 0) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/forbidden_slices.rs:24:1 + --> $DIR/forbidden_slices.rs:22:1 | LL | pub static S2: &[u32] = unsafe { from_raw_parts(&D0, 2) }; | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation) @@ -32,7 +32,7 @@ LL | pub static S2: &[u32] = unsafe { from_raw_parts(&D0, 2) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/forbidden_slices.rs:28:1 + --> $DIR/forbidden_slices.rs:26:1 | LL | pub static S4: &[u8] = unsafe { from_raw_parts((&D1) as *const _ as _, 1) }; | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered uninitialized memory, but expected an integer @@ -43,7 +43,7 @@ LL | pub static S4: &[u8] = unsafe { from_raw_parts((&D1) as *const _ as _, 1) } } error[E0080]: it is undefined behavior to use this value - --> $DIR/forbidden_slices.rs:30:1 + --> $DIR/forbidden_slices.rs:28:1 | LL | pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, size_of::<&u32>()) }; | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered a pointer, but expected an integer @@ -56,7 +56,7 @@ LL | pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, size = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported error[E0080]: it is undefined behavior to use this value - --> $DIR/forbidden_slices.rs:32:1 + --> $DIR/forbidden_slices.rs:30:1 | LL | pub static S6: &[bool] = unsafe { from_raw_parts((&D0) as *const _ as _, 4) }; | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered 0x11, but expected a boolean @@ -67,7 +67,7 @@ LL | pub static S6: &[bool] = unsafe { from_raw_parts((&D0) as *const _ as _, 4) } error[E0080]: it is undefined behavior to use this value - --> $DIR/forbidden_slices.rs:35:1 + --> $DIR/forbidden_slices.rs:33:1 | LL | pub static S7: &[u16] = unsafe { | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[1]: encountered uninitialized memory, but expected an integer @@ -78,7 +78,7 @@ LL | pub static S7: &[u16] = unsafe { } error[E0080]: it is undefined behavior to use this value - --> $DIR/forbidden_slices.rs:43:1 + --> $DIR/forbidden_slices.rs:41:1 | LL | pub static S8: &[u64] = unsafe { | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation) @@ -98,7 +98,7 @@ note: inside `ptr::const_ptr::<impl *const u32>::sub_ptr` note: inside `from_ptr_range::<'_, u32>` --> $SRC_DIR/core/src/slice/raw.rs:LL:COL note: inside `R0` - --> $DIR/forbidden_slices.rs:50:34 + --> $DIR/forbidden_slices.rs:48:34 | LL | pub static R0: &[u32] = unsafe { from_ptr_range(ptr::null()..ptr::null()) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -113,7 +113,7 @@ note: inside `ptr::const_ptr::<impl *const ()>::sub_ptr` note: inside `from_ptr_range::<'_, ()>` --> $SRC_DIR/core/src/slice/raw.rs:LL:COL note: inside `R1` - --> $DIR/forbidden_slices.rs:51:33 + --> $DIR/forbidden_slices.rs:49:33 | LL | pub static R1: &[()] = unsafe { from_ptr_range(ptr::null()..ptr::null()) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -127,13 +127,13 @@ error[E0080]: could not evaluate static initializer note: inside `ptr::const_ptr::<impl *const u32>::add` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL note: inside `R2` - --> $DIR/forbidden_slices.rs:54:25 + --> $DIR/forbidden_slices.rs:52:25 | LL | from_ptr_range(ptr..ptr.add(2)) | ^^^^^^^^^^ error[E0080]: it is undefined behavior to use this value - --> $DIR/forbidden_slices.rs:56:1 + --> $DIR/forbidden_slices.rs:54:1 | LL | pub static R4: &[u8] = unsafe { | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered uninitialized memory, but expected an integer @@ -144,7 +144,7 @@ LL | pub static R4: &[u8] = unsafe { } error[E0080]: it is undefined behavior to use this value - --> $DIR/forbidden_slices.rs:61:1 + --> $DIR/forbidden_slices.rs:59:1 | LL | pub static R5: &[u8] = unsafe { | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered a pointer, but expected an integer @@ -157,7 +157,7 @@ LL | pub static R5: &[u8] = unsafe { = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported error[E0080]: it is undefined behavior to use this value - --> $DIR/forbidden_slices.rs:66:1 + --> $DIR/forbidden_slices.rs:64:1 | LL | pub static R6: &[bool] = unsafe { | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered 0x11, but expected a boolean @@ -168,7 +168,7 @@ LL | pub static R6: &[bool] = unsafe { } error[E0080]: it is undefined behavior to use this value - --> $DIR/forbidden_slices.rs:71:1 + --> $DIR/forbidden_slices.rs:69:1 | LL | pub static R7: &[u16] = unsafe { | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1) @@ -186,7 +186,7 @@ error[E0080]: could not evaluate static initializer note: inside `ptr::const_ptr::<impl *const u64>::add` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL note: inside `R8` - --> $DIR/forbidden_slices.rs:78:25 + --> $DIR/forbidden_slices.rs:76:25 | LL | from_ptr_range(ptr..ptr.add(1)) | ^^^^^^^^^^ @@ -201,7 +201,7 @@ note: inside `ptr::const_ptr::<impl *const u32>::sub_ptr` note: inside `from_ptr_range::<'_, u32>` --> $SRC_DIR/core/src/slice/raw.rs:LL:COL note: inside `R9` - --> $DIR/forbidden_slices.rs:83:34 + --> $DIR/forbidden_slices.rs:81:34 | LL | pub static R9: &[u32] = unsafe { from_ptr_range(&D0..(&D0 as *const u32).add(1)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -216,7 +216,7 @@ note: inside `ptr::const_ptr::<impl *const u32>::sub_ptr` note: inside `from_ptr_range::<'_, u32>` --> $SRC_DIR/core/src/slice/raw.rs:LL:COL note: inside `R10` - --> $DIR/forbidden_slices.rs:84:35 + --> $DIR/forbidden_slices.rs:82:35 | LL | pub static R10: &[u32] = unsafe { from_ptr_range(&D0..&D0) }; | ^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/consts/const-eval/raw-pointer-ub.rs b/tests/ui/consts/const-eval/raw-pointer-ub.rs index 9b79a0a7d34..3341f3c78e0 100644 --- a/tests/ui/consts/const-eval/raw-pointer-ub.rs +++ b/tests/ui/consts/const-eval/raw-pointer-ub.rs @@ -1,5 +1,3 @@ -#![feature(const_pointer_byte_offsets)] -#![feature(pointer_byte_offsets)] #![feature(const_mut_refs)] diff --git a/tests/ui/consts/const-eval/raw-pointer-ub.stderr b/tests/ui/consts/const-eval/raw-pointer-ub.stderr index f644e5f8748..60fcd461cde 100644 --- a/tests/ui/consts/const-eval/raw-pointer-ub.stderr +++ b/tests/ui/consts/const-eval/raw-pointer-ub.stderr @@ -1,11 +1,11 @@ error[E0080]: evaluation of constant value failed - --> $DIR/raw-pointer-ub.rs:9:16 + --> $DIR/raw-pointer-ub.rs:7:16 | LL | let _val = *ptr; | ^^^^ accessing memory based on pointer with alignment 1, but alignment 4 is required error[E0080]: evaluation of constant value failed - --> $DIR/raw-pointer-ub.rs:16:5 + --> $DIR/raw-pointer-ub.rs:14:5 | LL | *ptr = 0; | ^^^^^^^^ accessing memory based on pointer with alignment 1, but alignment 4 is required @@ -20,19 +20,19 @@ note: inside `copy_nonoverlapping::<u32>` note: inside `ptr::const_ptr::<impl *const u32>::copy_to_nonoverlapping` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL note: inside `MISALIGNED_COPY` - --> $DIR/raw-pointer-ub.rs:24:5 + --> $DIR/raw-pointer-ub.rs:22:5 | LL | y.copy_to_nonoverlapping(&mut z, 1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0080]: evaluation of constant value failed - --> $DIR/raw-pointer-ub.rs:36:16 + --> $DIR/raw-pointer-ub.rs:34:16 | LL | let _val = (*ptr).0; | ^^^^^^^^ accessing memory based on pointer with alignment 4, but alignment 16 is required error[E0080]: evaluation of constant value failed - --> $DIR/raw-pointer-ub.rs:43:16 + --> $DIR/raw-pointer-ub.rs:41:16 | LL | let _val = *ptr; | ^^^^ memory access failed: ALLOC0 has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds 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/consts/extra-const-ub/detect-extra-ub.rs b/tests/ui/consts/extra-const-ub/detect-extra-ub.rs index 15c06908447..39f918379d1 100644 --- a/tests/ui/consts/extra-const-ub/detect-extra-ub.rs +++ b/tests/ui/consts/extra-const-ub/detect-extra-ub.rs @@ -1,7 +1,7 @@ // revisions: no_flag with_flag // [no_flag] check-pass // [with_flag] compile-flags: -Zextra-const-ub-checks -#![feature(never_type, pointer_byte_offsets)] +#![feature(never_type)] use std::mem::transmute; use std::ptr::addr_of; diff --git a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.32bit.stderr b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.32bit.stderr index de59d743b17..492d8718a13 100644 --- a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.32bit.stderr +++ b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.32bit.stderr @@ -108,6 +108,11 @@ help: skipping check that does not even have a feature gate | LL | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/const_refers_to_static_cross_crate.rs:27:20 + | +LL | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 8 previous errors; 1 warning emitted diff --git a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.64bit.stderr b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.64bit.stderr index e62520ef6ad..f6d82d6c0ba 100644 --- a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.64bit.stderr +++ b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.64bit.stderr @@ -108,6 +108,11 @@ help: skipping check that does not even have a feature gate | LL | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/const_refers_to_static_cross_crate.rs:27:20 + | +LL | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 8 previous errors; 1 warning emitted diff --git a/tests/ui/consts/miri_unleashed/ptr_arith.rs b/tests/ui/consts/miri_unleashed/ptr_arith.rs index 5cda3c41152..e59c6725269 100644 --- a/tests/ui/consts/miri_unleashed/ptr_arith.rs +++ b/tests/ui/consts/miri_unleashed/ptr_arith.rs @@ -1,5 +1,4 @@ // compile-flags: -Zunleash-the-miri-inside-of-you -#![feature(core_intrinsics, pointer_byte_offsets)] // During CTFE, we prevent pointer-to-int casts. // Pointer comparisons are prevented in the trait system. diff --git a/tests/ui/consts/miri_unleashed/ptr_arith.stderr b/tests/ui/consts/miri_unleashed/ptr_arith.stderr index 25ca6bc4eaa..213966f90b8 100644 --- a/tests/ui/consts/miri_unleashed/ptr_arith.stderr +++ b/tests/ui/consts/miri_unleashed/ptr_arith.stderr @@ -1,11 +1,11 @@ error[E0080]: could not evaluate static initializer - --> $DIR/ptr_arith.rs:8:13 + --> $DIR/ptr_arith.rs:7:13 | LL | let x = &0 as *const _ as usize; | ^^^^^^^^^^^^^^^^^^^^^^^ exposing pointers is not possible at compile-time error[E0080]: could not evaluate static initializer - --> $DIR/ptr_arith.rs:16:14 + --> $DIR/ptr_arith.rs:15:14 | LL | let _v = x + 0; | ^ unable to turn pointer into integer @@ -16,7 +16,7 @@ LL | let _v = x + 0; warning: skipping const checks | help: skipping check that does not even have a feature gate - --> $DIR/ptr_arith.rs:8:13 + --> $DIR/ptr_arith.rs:7:13 | LL | let x = &0 as *const _ as usize; | ^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/derives/issue-36617.stderr b/tests/ui/derives/issue-36617.stderr index 9cc0a29b065..98be7963e5e 100644 --- a/tests/ui/derives/issue-36617.stderr +++ b/tests/ui/derives/issue-36617.stderr @@ -43,55 +43,75 @@ error: `derive` attribute cannot be used at crate level | LL | #![derive(Copy)] | ^^^^^^^^^^^^^^^^ +... +LL | fn main() {} + | ---- the inner attribute doesn't annotate this function | help: perhaps you meant to use an outer attribute | -LL | #[derive(Copy)] - | ~~~~~~~~~~~~~~~ +LL - #![derive(Copy)] +LL + #[derive(Copy)] + | error: `test` attribute cannot be used at crate level --> $DIR/issue-36617.rs:4:1 | LL | #![test] | ^^^^^^^^ +... +LL | fn main() {} + | ---- the inner attribute doesn't annotate this function | help: perhaps you meant to use an outer attribute | -LL | #[test] - | ~~~~~~~ +LL - #![test] +LL + #[test] + | error: `test_case` attribute cannot be used at crate level --> $DIR/issue-36617.rs:7:1 | LL | #![test_case] | ^^^^^^^^^^^^^ +... +LL | fn main() {} + | ---- the inner attribute doesn't annotate this function | help: perhaps you meant to use an outer attribute | -LL | #[test_case] - | ~~~~~~~~~~~~ +LL - #![test_case] +LL + #[test_case] + | error: `bench` attribute cannot be used at crate level --> $DIR/issue-36617.rs:10:1 | LL | #![bench] | ^^^^^^^^^ +... +LL | fn main() {} + | ---- the inner attribute doesn't annotate this function | help: perhaps you meant to use an outer attribute | -LL | #[bench] - | ~~~~~~~~ +LL - #![bench] +LL + #[bench] + | error: `global_allocator` attribute cannot be used at crate level --> $DIR/issue-36617.rs:13:1 | LL | #![global_allocator] | ^^^^^^^^^^^^^^^^^^^^ +... +LL | fn main() {} + | ---- the inner attribute doesn't annotate this function | help: perhaps you meant to use an outer attribute | -LL | #[global_allocator] - | ~~~~~~~~~~~~~~~~~~~ +LL - #![global_allocator] +LL + #[global_allocator] + | error: aborting due to 10 previous errors 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/error-codes/E0396.rs b/tests/ui/error-codes/E0396.rs index 4415b70e75e..383eda3d636 100644 --- a/tests/ui/error-codes/E0396.rs +++ b/tests/ui/error-codes/E0396.rs @@ -9,9 +9,11 @@ const unsafe fn unreachable() -> ! { const INFALLIBLE: *mut Infallible = &[] as *const [Infallible] as *const _ as _; match *INFALLIBLE {} //~^ ERROR dereferencing raw mutable pointers in constant functions is unstable + //~| ERROR dereferencing raw mutable pointers in constant functions is unstable const BAD: () = unsafe { match *INFALLIBLE {} }; //~^ ERROR dereferencing raw mutable pointers in constants is unstable + //~| ERROR dereferencing raw mutable pointers in constants is unstable } fn main() { diff --git a/tests/ui/error-codes/E0396.stderr b/tests/ui/error-codes/E0396.stderr index 8c87f40674f..a84a1216e0a 100644 --- a/tests/ui/error-codes/E0396.stderr +++ b/tests/ui/error-codes/E0396.stderr @@ -16,15 +16,35 @@ LL | match *INFALLIBLE {} = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable +error[E0658]: dereferencing raw mutable pointers in constant functions is unstable + --> $DIR/E0396.rs:10:11 + | +LL | match *INFALLIBLE {} + | ^^^^^^^^^^^ + | + = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0658]: dereferencing raw mutable pointers in constants is unstable + --> $DIR/E0396.rs:14:36 + | +LL | const BAD: () = unsafe { match *INFALLIBLE {} }; + | ^^^^^^^^^^^ + | + = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + error[E0658]: dereferencing raw mutable pointers in constants is unstable - --> $DIR/E0396.rs:13:36 + --> $DIR/E0396.rs:14:36 | LL | const BAD: () = unsafe { match *INFALLIBLE {} }; | ^^^^^^^^^^^ | = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: aborting due to 3 previous errors +error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/expr/malformed_closure/block_instead_of_closure_in_arg.rs b/tests/ui/expr/malformed_closure/block_instead_of_closure_in_arg.rs new file mode 100644 index 00000000000..9c685590b8b --- /dev/null +++ b/tests/ui/expr/malformed_closure/block_instead_of_closure_in_arg.rs @@ -0,0 +1,10 @@ +fn main() { + let number = 2; + Some(true).filter({ //~ ERROR expected a `FnOnce<(&bool,)>` closure, found `bool` + if number % 2 == 0 { + number == 0 + } else { + number != 0 + } + }); +} diff --git a/tests/ui/expr/malformed_closure/block_instead_of_closure_in_arg.stderr b/tests/ui/expr/malformed_closure/block_instead_of_closure_in_arg.stderr new file mode 100644 index 00000000000..b72360562f2 --- /dev/null +++ b/tests/ui/expr/malformed_closure/block_instead_of_closure_in_arg.stderr @@ -0,0 +1,27 @@ +error[E0277]: expected a `FnOnce<(&bool,)>` closure, found `bool` + --> $DIR/block_instead_of_closure_in_arg.rs:3:23 + | +LL | Some(true).filter({ + | _________________------_^ + | | | + | | required by a bound introduced by this call +LL | |/ if number % 2 == 0 { +LL | || number == 0 +LL | || } else { +LL | || number != 0 +LL | || } + | ||_________- this tail expression is of type `bool` +LL | | }); + | |______^ expected an `FnOnce<(&bool,)>` closure, found `bool` + | + = help: the trait `for<'a> FnOnce<(&'a bool,)>` is not implemented for `bool` +note: required by a bound in `Option::<T>::filter` + --> $SRC_DIR/core/src/option.rs:LL:COL +help: you might have meant to create the closure instead of a block + | +LL | Some(true).filter(|_| { + | +++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/expr/malformed_closure/ruby_style_closure_successful_parse.rs b/tests/ui/expr/malformed_closure/ruby_style_closure_successful_parse.rs new file mode 100644 index 00000000000..982b9fd00f6 --- /dev/null +++ b/tests/ui/expr/malformed_closure/ruby_style_closure_successful_parse.rs @@ -0,0 +1,7 @@ +const x: usize =42; +fn main() { + let p = Some(45).and_then({|x| //~ ERROR expected a `FnOnce<({integer},)>` closure, found `Option<usize>` + 1 + 1; + Some(x * 2) + }); +} diff --git a/tests/ui/expr/malformed_closure/ruby_style_closure_successful_parse.stderr b/tests/ui/expr/malformed_closure/ruby_style_closure_successful_parse.stderr new file mode 100644 index 00000000000..32d34430b7c --- /dev/null +++ b/tests/ui/expr/malformed_closure/ruby_style_closure_successful_parse.stderr @@ -0,0 +1,25 @@ +error[E0277]: expected a `FnOnce<({integer},)>` closure, found `Option<usize>` + --> $DIR/ruby_style_closure_successful_parse.rs:3:31 + | +LL | let p = Some(45).and_then({|x| + | ______________________--------_^ + | | | + | | required by a bound introduced by this call +LL | | 1 + 1; +LL | | Some(x * 2) + | | ----------- this tail expression is of type `Option<usize>` +LL | | }); + | |_____^ expected an `FnOnce<({integer},)>` closure, found `Option<usize>` + | + = help: the trait `FnOnce<({integer},)>` is not implemented for `Option<usize>` +note: required by a bound in `Option::<T>::and_then` + --> $SRC_DIR/core/src/option.rs:LL:COL +help: you might have meant to open the closure body instead of placing a closure within a block + | +LL - let p = Some(45).and_then({|x| +LL + let p = Some(45).and_then(|x| { + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/feature-gates/issue-43106-gating-of-bench.stderr b/tests/ui/feature-gates/issue-43106-gating-of-bench.stderr index 6b332211942..8270d46d492 100644 --- a/tests/ui/feature-gates/issue-43106-gating-of-bench.stderr +++ b/tests/ui/feature-gates/issue-43106-gating-of-bench.stderr @@ -11,10 +11,14 @@ error: `bench` attribute cannot be used at crate level | LL | #![bench = "4100"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | fn main() {} + | ---- the inner attribute doesn't annotate this function | help: perhaps you meant to use an outer attribute | -LL | #[bench = "4100"] +LL - #![bench = "4100"] +LL + #[bench = "4100"] | error: aborting due to 2 previous errors diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.rs b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.rs index 1fe133ac2bc..0f833f793bd 100644 --- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.rs +++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.rs @@ -32,6 +32,12 @@ //~^ ERROR attribute should be applied to function or closure mod inline { //~^ NOTE not a function or closure + //~| NOTE the inner attribute doesn't annotate this module + //~| NOTE the inner attribute doesn't annotate this module + //~| NOTE the inner attribute doesn't annotate this module + //~| NOTE the inner attribute doesn't annotate this module + //~| NOTE the inner attribute doesn't annotate this module + //~| NOTE the inner attribute doesn't annotate this module mod inner { #![inline] } //~^ ERROR attribute should be applied to function or closure diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr index 78767040421..f01153dcb96 100644 --- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr +++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr @@ -7,7 +7,7 @@ LL | #![rustc_main] = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable error: attribute must be of the form `#[inline]` or `#[inline(always|never)]` - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:40:5 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:46:5 | LL | #[inline = "2100"] fn f() { } | ^^^^^^^^^^^^^^^^^^ @@ -17,31 +17,31 @@ LL | #[inline = "2100"] fn f() { } = note: `#[deny(ill_formed_attribute_input)]` on by default error: `start` attribute can only be used on functions - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:119:1 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:125:1 | LL | #[start] | ^^^^^^^^ error: `start` attribute can only be used on functions - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:122:17 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:128:17 | LL | mod inner { #![start] } | ^^^^^^^^^ error: `start` attribute can only be used on functions - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:127:5 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:133:5 | LL | #[start] struct S; | ^^^^^^^^ error: `start` attribute can only be used on functions - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:130:5 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:136:5 | LL | #[start] type T = S; | ^^^^^^^^ error: `start` attribute can only be used on functions - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:133:5 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:139:5 | LL | #[start] impl S { } | ^^^^^^^^ @@ -55,14 +55,14 @@ LL | LL | / mod inline { LL | | LL | | -LL | | mod inner { #![inline] } +LL | | ... | LL | | LL | | } | |_- not a function or closure error: attribute should be applied to an `extern crate` item - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:59:1 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:65:1 | LL | #[no_link] | ^^^^^^^^^^ @@ -77,7 +77,7 @@ LL | | } | |_- not an `extern crate` item error: attribute should be applied to a free function, impl method or static - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:85:1 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:91:1 | LL | #[export_name = "2200"] | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -92,7 +92,7 @@ LL | | } | |_- not a free function, impl method or static error[E0517]: attribute should be applied to a struct, enum, or union - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:137:8 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:143:8 | LL | #[repr(C)] | ^ @@ -129,10 +129,14 @@ error: `macro_export` attribute cannot be used at crate level | LL | #![macro_export] | ^^^^^^^^^^^^^^^^ +... +LL | mod inline { + | ------ the inner attribute doesn't annotate this module | help: perhaps you meant to use an outer attribute | -LL | #[macro_export] +LL - #![macro_export] +LL + #[macro_export] | error: `rustc_main` attribute cannot be used at crate level @@ -140,21 +144,29 @@ error: `rustc_main` attribute cannot be used at crate level | LL | #![rustc_main] | ^^^^^^^^^^^^^^ +... +LL | mod inline { + | ------ the inner attribute doesn't annotate this module | help: perhaps you meant to use an outer attribute | -LL | #[rustc_main] - | ~~~~~~~~~~~~~ +LL - #![rustc_main] +LL + #[rustc_main] + | error: `start` attribute cannot be used at crate level --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:16:1 | LL | #![start] | ^^^^^^^^^ +... +LL | mod inline { + | ------ the inner attribute doesn't annotate this module | help: perhaps you meant to use an outer attribute | -LL | #[start] +LL - #![start] +LL + #[start] | error: `repr` attribute cannot be used at crate level @@ -162,10 +174,14 @@ error: `repr` attribute cannot be used at crate level | LL | #![repr()] | ^^^^^^^^^^ +... +LL | mod inline { + | ------ the inner attribute doesn't annotate this module | help: perhaps you meant to use an outer attribute | -LL | #[repr()] +LL - #![repr()] +LL + #[repr()] | error: `path` attribute cannot be used at crate level @@ -173,10 +189,14 @@ error: `path` attribute cannot be used at crate level | LL | #![path = "3800"] | ^^^^^^^^^^^^^^^^^ +... +LL | mod inline { + | ------ the inner attribute doesn't annotate this module | help: perhaps you meant to use an outer attribute | -LL | #[path = "3800"] +LL - #![path = "3800"] +LL + #[path = "3800"] | error: `automatically_derived` attribute cannot be used at crate level @@ -184,122 +204,126 @@ error: `automatically_derived` attribute cannot be used at crate level | LL | #![automatically_derived] | ^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | mod inline { + | ------ the inner attribute doesn't annotate this module | help: perhaps you meant to use an outer attribute | -LL | #[automatically_derived] +LL - #![automatically_derived] +LL + #[automatically_derived] | error[E0518]: attribute should be applied to function or closure - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:36:17 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:42:17 | LL | mod inner { #![inline] } | ------------^^^^^^^^^^-- not a function or closure error[E0518]: attribute should be applied to function or closure - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:46:5 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:52:5 | LL | #[inline] struct S; | ^^^^^^^^^ --------- not a function or closure error[E0518]: attribute should be applied to function or closure - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:50:5 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:56:5 | LL | #[inline] type T = S; | ^^^^^^^^^ ----------- not a function or closure error[E0518]: attribute should be applied to function or closure - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:54:5 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:60:5 | LL | #[inline] impl S { } | ^^^^^^^^^ ---------- not a function or closure error: attribute should be applied to an `extern crate` item - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:64:17 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:70:17 | LL | mod inner { #![no_link] } | ------------^^^^^^^^^^^-- not an `extern crate` item error: attribute should be applied to an `extern crate` item - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:68:5 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:74:5 | LL | #[no_link] fn f() { } | ^^^^^^^^^^ ---------- not an `extern crate` item error: attribute should be applied to an `extern crate` item - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:72:5 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:78:5 | LL | #[no_link] struct S; | ^^^^^^^^^^ --------- not an `extern crate` item error: attribute should be applied to an `extern crate` item - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:76:5 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:82:5 | LL | #[no_link]type T = S; | ^^^^^^^^^^----------- not an `extern crate` item error: attribute should be applied to an `extern crate` item - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:80:5 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:86:5 | LL | #[no_link] impl S { } | ^^^^^^^^^^ ---------- not an `extern crate` item error: attribute should be applied to a free function, impl method or static - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:90:17 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:96:17 | LL | mod inner { #![export_name="2200"] } | ------------^^^^^^^^^^^^^^^^^^^^^^-- not a free function, impl method or static error: attribute should be applied to a free function, impl method or static - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:96:5 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:102:5 | LL | #[export_name = "2200"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^ --------- not a free function, impl method or static error: attribute should be applied to a free function, impl method or static - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:100:5 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:106:5 | LL | #[export_name = "2200"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^ ----------- not a free function, impl method or static error: attribute should be applied to a free function, impl method or static - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:104:5 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:110:5 | LL | #[export_name = "2200"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^ ---------- not a free function, impl method or static error: attribute should be applied to a free function, impl method or static - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:109:9 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:115:9 | LL | #[export_name = "2200"] fn foo(); | ^^^^^^^^^^^^^^^^^^^^^^^ --------- not a free function, impl method or static error: attribute should be applied to a free function, impl method or static - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:113:9 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:119:9 | LL | #[export_name = "2200"] fn bar() {} | ^^^^^^^^^^^^^^^^^^^^^^^ ----------- not a free function, impl method or static error[E0517]: attribute should be applied to a struct, enum, or union - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:141:25 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:147:25 | LL | mod inner { #![repr(C)] } | --------------------^---- not a struct, enum, or union error[E0517]: attribute should be applied to a struct, enum, or union - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:145:12 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:151:12 | LL | #[repr(C)] fn f() { } | ^ ---------- not a struct, enum, or union error[E0517]: attribute should be applied to a struct, enum, or union - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:151:12 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:157:12 | LL | #[repr(C)] type T = S; | ^ ----------- not a struct, enum, or union error[E0517]: attribute should be applied to a struct, enum, or union - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:155:12 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:161:12 | LL | #[repr(C)] impl S { } | ^ ---------- not a struct, enum, or union diff --git a/tests/ui/feature-gates/issue-43106-gating-of-test.stderr b/tests/ui/feature-gates/issue-43106-gating-of-test.stderr index 300a9966dd8..922c9861aa3 100644 --- a/tests/ui/feature-gates/issue-43106-gating-of-test.stderr +++ b/tests/ui/feature-gates/issue-43106-gating-of-test.stderr @@ -11,10 +11,14 @@ error: `test` attribute cannot be used at crate level | LL | #![test = "4200"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | fn main() {} + | ---- the inner attribute doesn't annotate this function | help: perhaps you meant to use an outer attribute | -LL | #[test = "4200"] +LL - #![test = "4200"] +LL + #[test = "4200"] | 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/auto-trait-leak.rs b/tests/ui/impl-trait/auto-trait-leak.rs index 1f90292f457..de4f523c23a 100644 --- a/tests/ui/impl-trait/auto-trait-leak.rs +++ b/tests/ui/impl-trait/auto-trait-leak.rs @@ -9,8 +9,6 @@ fn main() {} // independently resolved and only require the concrete // return type, which can't depend on the obligation. fn cycle1() -> impl Clone { - //~^ ERROR cycle detected - //~| ERROR cycle detected send(cycle2().clone()); Rc::new(Cell::new(5)) diff --git a/tests/ui/impl-trait/auto-trait-leak.stderr b/tests/ui/impl-trait/auto-trait-leak.stderr index 62341f6de0c..28643ec03e1 100644 --- a/tests/ui/impl-trait/auto-trait-leak.stderr +++ b/tests/ui/impl-trait/auto-trait-leak.stderr @@ -1,66 +1,5 @@ -error[E0391]: cycle detected when computing type of opaque `cycle1::{opaque#0}` - --> $DIR/auto-trait-leak.rs:11:16 - | -LL | fn cycle1() -> impl Clone { - | ^^^^^^^^^^ - | -note: ...which requires type-checking `cycle1`... - --> $DIR/auto-trait-leak.rs:14:5 - | -LL | send(cycle2().clone()); - | ^^^^ - = note: ...which requires evaluating trait selection obligation `cycle2::{opaque#0}: core::marker::Send`... -note: ...which requires computing type of opaque `cycle2::{opaque#0}`... - --> $DIR/auto-trait-leak.rs:19:16 - | -LL | fn cycle2() -> impl Clone { - | ^^^^^^^^^^ -note: ...which requires type-checking `cycle2`... - --> $DIR/auto-trait-leak.rs:20:5 - | -LL | send(cycle1().clone()); - | ^^^^ - = note: ...which requires evaluating trait selection obligation `cycle1::{opaque#0}: core::marker::Send`... - = note: ...which again requires computing type of opaque `cycle1::{opaque#0}`, completing the cycle -note: cycle used when computing type of `cycle1::{opaque#0}` - --> $DIR/auto-trait-leak.rs:11:16 - | -LL | fn cycle1() -> impl Clone { - | ^^^^^^^^^^ - = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information - -error[E0391]: cycle detected when computing type of opaque `cycle1::{opaque#0}` - --> $DIR/auto-trait-leak.rs:11:16 - | -LL | fn cycle1() -> impl Clone { - | ^^^^^^^^^^ - | -note: ...which requires type-checking `cycle1`... - --> $DIR/auto-trait-leak.rs:14:5 - | -LL | send(cycle2().clone()); - | ^^^^ - = note: ...which requires evaluating trait selection obligation `cycle2::{opaque#0}: core::marker::Send`... -note: ...which requires computing type of opaque `cycle2::{opaque#0}`... - --> $DIR/auto-trait-leak.rs:19:16 - | -LL | fn cycle2() -> impl Clone { - | ^^^^^^^^^^ -note: ...which requires type-checking `cycle2`... - --> $DIR/auto-trait-leak.rs:19:1 - | -LL | fn cycle2() -> impl Clone { - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: ...which again requires computing type of opaque `cycle1::{opaque#0}`, completing the cycle -note: cycle used when computing type of `cycle1::{opaque#0}` - --> $DIR/auto-trait-leak.rs:11:16 - | -LL | fn cycle1() -> impl Clone { - | ^^^^^^^^^^ - = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information - error: cannot check whether the hidden type of opaque type satisfies auto traits - --> $DIR/auto-trait-leak.rs:20:10 + --> $DIR/auto-trait-leak.rs:18:10 | LL | send(cycle1().clone()); | ---- ^^^^^^^^^^^^^^^^ @@ -73,7 +12,7 @@ note: opaque type is declared here LL | fn cycle1() -> impl Clone { | ^^^^^^^^^^ note: this item depends on auto traits of the hidden type, but may also be registering the hidden type. This is not supported right now. You can try moving the opaque type and the item that actually registers a hidden type into a new submodule - --> $DIR/auto-trait-leak.rs:19:4 + --> $DIR/auto-trait-leak.rs:17:4 | LL | fn cycle2() -> impl Clone { | ^^^^^^ @@ -83,6 +22,5 @@ note: required by a bound in `send` LL | fn send<T: Send>(_: T) {} | ^^^^ required by this bound in `send` -error: aborting due to 3 previous errors +error: aborting due to previous error -For more information about this error, try `rustc --explain E0391`. 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-28134.stderr b/tests/ui/imports/issue-28134.stderr index 33cb53f202a..5315c2e9fee 100644 --- a/tests/ui/imports/issue-28134.stderr +++ b/tests/ui/imports/issue-28134.stderr @@ -14,8 +14,9 @@ LL | #![test] | help: perhaps you meant to use an outer attribute | -LL | #[test] - | ~~~~~~~ +LL - #![test] +LL + #[test] + | error: aborting due to 2 previous errors 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.thir.stderr b/tests/ui/inline-const/pat-unsafe.thir.stderr index d62c87fc8f3..0318b3ff2cc 100644 --- a/tests/ui/inline-const/pat-unsafe.thir.stderr +++ b/tests/ui/inline-const/pat-unsafe.thir.stderr @@ -1,9 +1,6 @@ warning: unnecessary `unsafe` block --> $DIR/pat-unsafe.rs:19:17 | -LL | unsafe { - | ------ because it's nested under this `unsafe` block -... LL | unsafe {} | ^^^^^^ unnecessary `unsafe` block | @@ -16,9 +13,6 @@ LL | #![warn(unused_unsafe)] warning: unnecessary `unsafe` block --> $DIR/pat-unsafe.rs:26:17 | -LL | unsafe { - | ------ because it's nested under this `unsafe` block -... LL | unsafe {} | ^^^^^^ unnecessary `unsafe` block 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-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-functions.stderr b/tests/ui/instrument-coverage/unstable.branch.stderr index acc633a2a6d..acc633a2a6d 100644 --- a/tests/ui/instrument-coverage/except-unused-functions.stderr +++ b/tests/ui/instrument-coverage/unstable.branch.stderr diff --git a/tests/ui/instrument-coverage/except-unused-generics.stderr b/tests/ui/instrument-coverage/unstable.except-unused-functions.stderr index acc633a2a6d..acc633a2a6d 100644 --- a/tests/ui/instrument-coverage/except-unused-generics.stderr +++ b/tests/ui/instrument-coverage/unstable.except-unused-functions.stderr 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-76168-hr-outlives-3.rs b/tests/ui/lifetimes/issue-76168-hr-outlives-3.rs new file mode 100644 index 00000000000..081e962028c --- /dev/null +++ b/tests/ui/lifetimes/issue-76168-hr-outlives-3.rs @@ -0,0 +1,19 @@ +// edition:2018 + +#![feature(unboxed_closures)] +use std::future::Future; + +async fn wrapper<F>(f: F) +//~^ ERROR: expected a `FnOnce<(&'a mut i32,)>` closure, found `i32` +//~| ERROR: expected a `FnOnce<(&'a mut i32,)>` closure, found `i32` +//~| ERROR: expected a `FnOnce<(&'a mut i32,)>` closure, found `i32` +where + F:, + for<'a> <i32 as FnOnce<(&'a mut i32,)>>::Output: Future<Output = ()> + 'a, +{ + //~^ ERROR: expected a `FnOnce<(&'a mut i32,)>` closure, found `i32` + let mut i = 41; + &mut i; +} + +fn main() {} diff --git a/tests/ui/lifetimes/issue-76168-hr-outlives-3.stderr b/tests/ui/lifetimes/issue-76168-hr-outlives-3.stderr new file mode 100644 index 00000000000..9d8c15d4a6a --- /dev/null +++ b/tests/ui/lifetimes/issue-76168-hr-outlives-3.stderr @@ -0,0 +1,51 @@ +error[E0277]: expected a `FnOnce<(&'a mut i32,)>` closure, found `i32` + --> $DIR/issue-76168-hr-outlives-3.rs:6:1 + | +LL | / async fn wrapper<F>(f: F) +LL | | +LL | | +LL | | +LL | | where +LL | | F:, +LL | | for<'a> <i32 as FnOnce<(&'a mut i32,)>>::Output: Future<Output = ()> + 'a, + | |______________________________________________________________________________^ expected an `FnOnce<(&'a mut i32,)>` closure, found `i32` + | + = help: the trait `for<'a> FnOnce<(&'a mut i32,)>` is not implemented for `i32` + +error[E0277]: expected a `FnOnce<(&'a mut i32,)>` closure, found `i32` + --> $DIR/issue-76168-hr-outlives-3.rs:6:10 + | +LL | async fn wrapper<F>(f: F) + | ^^^^^^^ expected an `FnOnce<(&'a mut i32,)>` closure, found `i32` + | + = help: the trait `for<'a> FnOnce<(&'a mut i32,)>` is not implemented for `i32` + +error[E0277]: expected a `FnOnce<(&'a mut i32,)>` closure, found `i32` + --> $DIR/issue-76168-hr-outlives-3.rs:13:1 + | +LL | / { +LL | | +LL | | let mut i = 41; +LL | | &mut i; +LL | | } + | |_^ expected an `FnOnce<(&'a mut i32,)>` closure, found `i32` + | + = help: the trait `for<'a> FnOnce<(&'a mut i32,)>` is not implemented for `i32` + +error[E0277]: expected a `FnOnce<(&'a mut i32,)>` closure, found `i32` + --> $DIR/issue-76168-hr-outlives-3.rs:6:1 + | +LL | / async fn wrapper<F>(f: F) +LL | | +LL | | +LL | | +LL | | where +LL | | F:, +LL | | for<'a> <i32 as FnOnce<(&'a mut i32,)>>::Output: Future<Output = ()> + 'a, + | |______________________________________________________________________________^ expected an `FnOnce<(&'a mut i32,)>` closure, found `i32` + | + = help: the trait `for<'a> FnOnce<(&'a mut i32,)>` is not implemented for `i32` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/macros/stringify.rs b/tests/ui/macros/stringify.rs index 1e9e7a89dde..f1bbd4a6210 100644 --- a/tests/ui/macros/stringify.rs +++ b/tests/ui/macros/stringify.rs @@ -2,496 +2,441 @@ // edition:2021 // compile-flags: --test +#![allow(incomplete_features)] #![feature(async_closure)] #![feature(auto_traits)] #![feature(box_patterns)] #![feature(const_trait_impl)] -#![feature(decl_macro)] #![feature(coroutines)] +#![feature(decl_macro)] +#![feature(explicit_tail_calls)] #![feature(more_qualified_paths)] #![feature(raw_ref_op)] #![feature(trait_alias)] #![feature(try_blocks)] #![feature(type_ascription)] +#![feature(yeet_expr)] #![deny(unused_macros)] -macro_rules! stringify_block { - ($block:block) => { - stringify!($block) - }; -} - -macro_rules! stringify_expr { - ($expr:expr) => { - stringify!($expr) - }; -} - -macro_rules! stringify_item { - ($item:item) => { - stringify!($item) - }; -} - -macro_rules! stringify_meta { - ($meta:meta) => { - stringify!($meta) - }; -} - -macro_rules! stringify_pat { - ($pat:pat) => { - stringify!($pat) - }; -} - -macro_rules! stringify_path { - ($path:path) => { - stringify!($path) - }; -} - -macro_rules! stringify_stmt { - ($stmt:stmt) => { - stringify!($stmt) - }; -} - -macro_rules! stringify_ty { - ($ty:ty) => { - stringify!($ty) +// These macros force the use of AST pretty-printing by converting the input to +// a particular fragment specifier. +macro_rules! block { ($block:block) => { stringify!($block) }; } +macro_rules! expr { ($expr:expr) => { stringify!($expr) }; } +macro_rules! item { ($item:item) => { stringify!($item) }; } +macro_rules! meta { ($meta:meta) => { stringify!($meta) }; } +macro_rules! pat { ($pat:pat) => { stringify!($pat) }; } +macro_rules! path { ($path:path) => { stringify!($path) }; } +macro_rules! stmt { ($stmt:stmt) => { stringify!($stmt) }; } +macro_rules! ty { ($ty:ty) => { stringify!($ty) }; } +macro_rules! vis { ($vis:vis) => { stringify!($vis) }; } + +// Use this when AST pretty-printing and TokenStream pretty-printing give +// the same result (which is preferable.) +macro_rules! c1 { + ($frag:ident, [$($tt:tt)*], $s:literal) => { + assert_eq!($frag!($($tt)*), $s); + assert_eq!(stringify!($($tt)*), $s); }; } -macro_rules! stringify_vis { - ($vis:vis) => { - stringify!($vis) +// Use this when AST pretty-printing and TokenStream pretty-printing give +// different results. +// +// `c1` and `c2` could be in a single macro, but having them separate makes it +// easy to find the cases where the two pretty-printing approaches give +// different results. +macro_rules! c2 { + ($frag:ident, [$($tt:tt)*], $s1:literal, $s2:literal) => { + assert_ne!($s1, $s2, "should use `c1!` instead"); + assert_eq!($frag!($($tt)*), $s1); + assert_eq!(stringify!($($tt)*), $s2); }; } #[test] fn test_block() { - assert_eq!(stringify_block!({}), "{}"); - assert_eq!(stringify_block!({ true }), "{ true }"); - assert_eq!(stringify_block!({ return }), "{ return }"); - assert_eq!( - stringify_block!({ + c1!(block, [ {} ], "{}"); + c1!(block, [ { true } ], "{ true }"); + c1!(block, [ { return } ], "{ return }"); + c2!(block, [ { return; - }), + } ], "{ return; }", + "{ return ; }" ); - assert_eq!( - stringify_block!({ + c2!(block, + [ { let _; true - }), + } ], "{ let _; true }", + "{ let _ ; true }" ); } #[test] fn test_expr() { // ExprKind::Array - assert_eq!(stringify_expr!([]), "[]"); - assert_eq!(stringify_expr!([true]), "[true]"); - assert_eq!(stringify_expr!([true,]), "[true]"); - assert_eq!(stringify_expr!([true, true]), "[true, true]"); + c1!(expr, [ [] ], "[]"); + c1!(expr, [ [true] ], "[true]"); + c2!(expr, [ [true,] ], "[true]", "[true,]"); + c1!(expr, [ [true, true] ], "[true, true]"); + + // ExprKind::ConstBlock + // FIXME: todo // ExprKind::Call - assert_eq!(stringify_expr!(f()), "f()"); - assert_eq!(stringify_expr!(f::<u8>()), "f::<u8>()"); - assert_eq!(stringify_expr!(f::<1>()), "f::<1>()"); - assert_eq!(stringify_expr!(f::<'a, u8, 1>()), "f::<'a, u8, 1>()"); - assert_eq!(stringify_expr!(f(true)), "f(true)"); - assert_eq!(stringify_expr!(f(true,)), "f(true)"); - assert_eq!(stringify_expr!(()()), "()()"); + c1!(expr, [ f() ], "f()"); + c2!(expr, [ f::<u8>() ], "f::<u8>()", "f :: < u8 > ()"); + c2!(expr, [ f::<1>() ], "f::<1>()", "f :: < 1 > ()"); + c2!(expr, [ f::<'a, u8, 1>() ], "f::<'a, u8, 1>()", "f :: < 'a, u8, 1 > ()"); + c1!(expr, [ f(true) ], "f(true)"); + c2!(expr, [ f(true,) ], "f(true)", "f(true,)"); + c2!(expr, [ ()() ], "()()", "() ()"); // ExprKind::MethodCall - assert_eq!(stringify_expr!(x.f()), "x.f()"); - assert_eq!(stringify_expr!(x.f::<u8>()), "x.f::<u8>()"); + c1!(expr, [ x.f() ], "x.f()"); + c2!(expr, [ x.f::<u8>() ], "x.f::<u8>()", "x.f :: < u8 > ()"); + c2!(expr, [ x.collect::<Vec<_>>() ], "x.collect::<Vec<_>>()", "x.collect :: < Vec < _ >> ()"); // ExprKind::Tup - assert_eq!(stringify_expr!(()), "()"); - assert_eq!(stringify_expr!((true,)), "(true,)"); - assert_eq!(stringify_expr!((true, false)), "(true, false)"); - assert_eq!(stringify_expr!((true, false,)), "(true, false)"); + c1!(expr, [ () ], "()"); + c1!(expr, [ (true,) ], "(true,)"); + c1!(expr, [ (true, false) ], "(true, false)"); + c2!(expr, [ (true, false,) ], "(true, false)", "(true, false,)"); // ExprKind::Binary - assert_eq!(stringify_expr!(true || false), "true || false"); - assert_eq!(stringify_expr!(true || false && false), "true || false && false"); + c1!(expr, [ true || false ], "true || false"); + c1!(expr, [ true || false && false ], "true || false && false"); + c1!(expr, [ a < 1 && 2 < b && c > 3 && 4 > d ], "a < 1 && 2 < b && c > 3 && 4 > d"); + c2!(expr, [ a & b & !c ], "a & b & !c", "a & b &! c"); // FIXME + c2!(expr, + [ a + b * c - d + -1 * -2 - -3], + "a + b * c - d + -1 * -2 - -3", + "a + b * c - d + - 1 * - 2 - - 3" + ); // ExprKind::Unary - assert_eq!(stringify_expr!(*expr), "*expr"); - assert_eq!(stringify_expr!(!expr), "!expr"); - assert_eq!(stringify_expr!(-expr), "-expr"); + c2!(expr, [ *expr ], "*expr", "* expr"); + c2!(expr, [ !expr ], "!expr", "! expr"); + c2!(expr, [ -expr ], "-expr", "- expr"); // ExprKind::Lit - assert_eq!(stringify_expr!('x'), "'x'"); - assert_eq!(stringify_expr!(1_000_i8), "1_000_i8"); - assert_eq!(stringify_expr!(1.00000000000000001), "1.00000000000000001"); + c1!(expr, [ 'x' ], "'x'"); + c1!(expr, [ 1_000_i8 ], "1_000_i8"); + c1!(expr, [ 1.00000000000000001 ], "1.00000000000000001"); // ExprKind::Cast - assert_eq!(stringify_expr!(expr as T), "expr as T"); - assert_eq!(stringify_expr!(expr as T<u8>), "expr as T<u8>"); + c1!(expr, [ expr as T ], "expr as T"); + c2!(expr, [ expr as T<u8> ], "expr as T<u8>", "expr as T < u8 >"); - // ExprKind::Type - // There is no syntax for type ascription. + // ExprKind::Type: there is no syntax for type ascription. + + // ExprKind::Let + c1!(expr, [ if let Some(a) = b { c } else { d } ], "if let Some(a) = b { c } else { d }"); // ExprKind::If - assert_eq!(stringify_expr!(if true {}), "if true {}"); - assert_eq!( - stringify_expr!(if true { - } else { - }), - "if true {} else {}", - ); - assert_eq!( - stringify_expr!(if let true = true { - } else { - }), - "if let true = true {} else {}", - ); - assert_eq!( - stringify_expr!(if true { + c1!(expr, [ if true {} ], "if true {}"); + c2!(expr, + [ if ::std::blah() { } else { } ], + "if ::std::blah() {} else {}", + "if :: std :: blah() {} else {}" + ); + c1!(expr, [ if let true = true {} else {} ], "if let true = true {} else {}"); + c1!(expr, + [ if true { } else if false { - }), - "if true {} else if false {}", + } ], + "if true {} else if false {}" ); - assert_eq!( - stringify_expr!(if true { + c1!(expr, + [ if true { } else if false { } else { - }), - "if true {} else if false {} else {}", + } ], + "if true {} else if false {} else {}" ); - assert_eq!( - stringify_expr!(if true { + c2!(expr, + [ if true { return; } else if false { 0 } else { 0 - }), + } ], "if true { return; } else if false { 0 } else { 0 }", + "if true { return ; } else if false { 0 } else { 0 }" ); // ExprKind::While - assert_eq!(stringify_expr!(while true {}), "while true {}"); - assert_eq!(stringify_expr!('a: while true {}), "'a: while true {}"); - assert_eq!(stringify_expr!(while let true = true {}), "while let true = true {}"); + c1!(expr, [ while true {} ], "while true {}"); + c2!(expr, [ 'a: while true {} ], "'a: while true {}", "'a : while true {}"); + c1!(expr, [ while let true = true {} ], "while let true = true {}"); // ExprKind::ForLoop - assert_eq!(stringify_expr!(for _ in x {}), "for _ in x {}"); - assert_eq!(stringify_expr!('a: for _ in x {}), "'a: for _ in x {}"); + c1!(expr, [ for _ in x {} ], "for _ in x {}"); + c2!(expr, [ 'a: for _ in x {} ], "'a: for _ in x {}", "'a : for _ in x {}"); // ExprKind::Loop - assert_eq!(stringify_expr!(loop {}), "loop {}"); - assert_eq!(stringify_expr!('a: loop {}), "'a: loop {}"); + c1!(expr, [ loop {} ], "loop {}"); + c2!(expr, [ 'a: loop {} ], "'a: loop {}", "'a : loop {}"); // ExprKind::Match - assert_eq!(stringify_expr!(match self {}), "match self {}"); - assert_eq!( - stringify_expr!(match self { + c1!(expr, [ match self {} ], "match self {}"); + c1!(expr, + [ match self { Ok => 1, - }), - "match self { Ok => 1, }", + } ], + "match self { Ok => 1, }" ); - assert_eq!( - stringify_expr!(match self { + c1!(expr, + [ match self { Ok => 1, Err => 0, - }), - "match self { Ok => 1, Err => 0, }", + } ], + "match self { Ok => 1, Err => 0, }" ); // ExprKind::Closure - assert_eq!(stringify_expr!(|| {}), "|| {}"); - assert_eq!(stringify_expr!(|x| {}), "|x| {}"); - assert_eq!(stringify_expr!(|x: u8| {}), "|x: u8| {}"); - assert_eq!(stringify_expr!(|| ()), "|| ()"); - assert_eq!(stringify_expr!(move || self), "move || self"); - assert_eq!(stringify_expr!(async || self), "async || self"); - assert_eq!(stringify_expr!(async move || self), "async move || self"); - assert_eq!(stringify_expr!(static || self), "static || self"); - assert_eq!(stringify_expr!(static move || self), "static move || self"); - #[rustfmt::skip] // https://github.com/rust-lang/rustfmt/issues/5149 - assert_eq!( - stringify_expr!(static async || self), - "static async || self", - ); - #[rustfmt::skip] // https://github.com/rust-lang/rustfmt/issues/5149 - assert_eq!( - stringify_expr!(static async move || self), - "static async move || self", - ); - assert_eq!(stringify_expr!(|| -> u8 { self }), "|| -> u8 { self }"); - assert_eq!(stringify_expr!(1 + || {}), "1 + (|| {})"); // ?? + c1!(expr, [ || {} ], "|| {}"); + c2!(expr, [ |x| {} ], "|x| {}", "| x | {}"); + c2!(expr, [ |x: u8| {} ], "|x: u8| {}", "| x : u8 | {}"); + c1!(expr, [ || () ], "|| ()"); + c1!(expr, [ move || self ], "move || self"); + c1!(expr, [ async || self ], "async || self"); + c1!(expr, [ async move || self ], "async move || self"); + c1!(expr, [ static || self ], "static || self"); + c1!(expr, [ static move || self ], "static move || self"); + c1!(expr, [ static async || self ], "static async || self"); + c1!(expr, [ static async move || self ], "static async move || self"); + c1!(expr, [ || -> u8 { self } ], "|| -> u8 { self }"); + c2!(expr, [ 1 + || {} ], "1 + (|| {})", "1 + || {}"); // AST?? // ExprKind::Block - assert_eq!(stringify_expr!({}), "{}"); - assert_eq!(stringify_expr!(unsafe {}), "unsafe {}"); - assert_eq!(stringify_expr!('a: {}), "'a: {}"); - assert_eq!( - stringify_expr!( - #[attr] - {} - ), - "#[attr] {}", - ); - assert_eq!( - stringify_expr!( + c1!(expr, [ {} ], "{}"); + c1!(expr, [ unsafe {} ], "unsafe {}"); + c2!(expr, [ 'a: {} ], "'a: {}", "'a : {}"); + c1!(expr, [ #[attr] {} ], "#[attr] {}"); + c2!(expr, + [ { #![attr] } - ), + ], "{\n\ \x20 #![attr]\n\ }", + "{ #! [attr] }" ); // ExprKind::Async - assert_eq!(stringify_expr!(async {}), "async {}"); - assert_eq!(stringify_expr!(async move {}), "async move {}"); + c1!(expr, [ async {} ], "async {}"); + c1!(expr, [ async move {} ], "async move {}"); // ExprKind::Await - assert_eq!(stringify_expr!(expr.await), "expr.await"); + c1!(expr, [ expr.await ], "expr.await"); // ExprKind::TryBlock - assert_eq!(stringify_expr!(try {}), "try {}"); + c1!(expr, [ try {} ], "try {}"); // ExprKind::Assign - assert_eq!(stringify_expr!(expr = true), "expr = true"); + c1!(expr, [ expr = true ], "expr = true"); // ExprKind::AssignOp - assert_eq!(stringify_expr!(expr += true), "expr += true"); + c1!(expr, [ expr += true ], "expr += true"); // ExprKind::Field - assert_eq!(stringify_expr!(expr.field), "expr.field"); - assert_eq!(stringify_expr!(expr.0), "expr.0"); + c1!(expr, [ expr.field ], "expr.field"); + c1!(expr, [ expr.0 ], "expr.0"); // ExprKind::Index - assert_eq!(stringify_expr!(expr[true]), "expr[true]"); + c2!(expr, [ expr[true] ], "expr[true]", "expr [true]"); // ExprKind::Range - assert_eq!(stringify_expr!(..), ".."); - assert_eq!(stringify_expr!(..hi), "..hi"); - assert_eq!(stringify_expr!(lo..), "lo.."); - assert_eq!(stringify_expr!(lo..hi), "lo..hi"); - assert_eq!(stringify_expr!(..=hi), "..=hi"); - assert_eq!(stringify_expr!(lo..=hi), "lo..=hi"); - assert_eq!(stringify_expr!(-2..=-1), "-2..=-1"); + c1!(expr, [ .. ], ".."); + c2!(expr, [ ..hi ], "..hi", ".. hi"); + c2!(expr, [ lo.. ], "lo..", "lo .."); + c2!(expr, [ lo..hi ], "lo..hi", "lo .. hi"); + c2!(expr, [ ..=hi ], "..=hi", "..= hi"); + c2!(expr, [ lo..=hi ], "lo..=hi", "lo ..= hi"); + c2!(expr, [ -2..=-1 ], "-2..=-1", "- 2 ..= - 1"); + + // ExprKind::Underscore + // FIXME: todo // ExprKind::Path - assert_eq!(stringify_expr!(thing), "thing"); - assert_eq!(stringify_expr!(m::thing), "m::thing"); - assert_eq!(stringify_expr!(self::thing), "self::thing"); - assert_eq!(stringify_expr!(crate::thing), "crate::thing"); - assert_eq!(stringify_expr!(Self::thing), "Self::thing"); - assert_eq!(stringify_expr!(<Self as T>::thing), "<Self as T>::thing"); - assert_eq!(stringify_expr!(Self::<'static>), "Self::<'static>"); + c1!(expr, [ thing ], "thing"); + c2!(expr, [ m::thing ], "m::thing", "m :: thing"); + c2!(expr, [ self::thing ], "self::thing", "self :: thing"); + c2!(expr, [ crate::thing ], "crate::thing", "crate :: thing"); + c2!(expr, [ Self::thing ], "Self::thing", "Self :: thing"); + c2!(expr, [ <Self as T>::thing ], "<Self as T>::thing", "< Self as T > :: thing"); + c2!(expr, [ Self::<'static> ], "Self::<'static>", "Self :: < 'static >"); // ExprKind::AddrOf - assert_eq!(stringify_expr!(&expr), "&expr"); - assert_eq!(stringify_expr!(&mut expr), "&mut expr"); - assert_eq!(stringify_expr!(&raw const expr), "&raw const expr"); - assert_eq!(stringify_expr!(&raw mut expr), "&raw mut expr"); + c2!(expr, [ &expr ], "&expr", "& expr"); + c2!(expr, [ &mut expr ], "&mut expr", "& mut expr"); + c2!(expr, [ &raw const expr ], "&raw const expr", "& raw const expr"); + c2!(expr, [ &raw mut expr ], "&raw mut expr", "& raw mut expr"); // ExprKind::Break - assert_eq!(stringify_expr!(break), "break"); - assert_eq!(stringify_expr!(break 'a), "break 'a"); - assert_eq!(stringify_expr!(break true), "break true"); - assert_eq!(stringify_expr!(break 'a true), "break 'a true"); + c1!(expr, [ break ], "break"); + c1!(expr, [ break 'a ], "break 'a"); + c1!(expr, [ break true ], "break true"); + c1!(expr, [ break 'a true ], "break 'a true"); // ExprKind::Continue - assert_eq!(stringify_expr!(continue), "continue"); - assert_eq!(stringify_expr!(continue 'a), "continue 'a"); + c1!(expr, [ continue ], "continue"); + c1!(expr, [ continue 'a ], "continue 'a"); // ExprKind::Ret - assert_eq!(stringify_expr!(return), "return"); - assert_eq!(stringify_expr!(return true), "return true"); + c1!(expr, [ return ], "return"); + c1!(expr, [ return true ], "return true"); + + // ExprKind::InlineAsm: untestable because this test works pre-expansion. + + // ExprKind::OffsetOf: untestable because this test works pre-expansion. // ExprKind::MacCall - assert_eq!(stringify_expr!(mac!(...)), "mac!(...)"); - assert_eq!(stringify_expr!(mac![...]), "mac![...]"); - assert_eq!(stringify_expr!(mac! { ... }), "mac! { ... }"); + c2!(expr, [ mac!(...) ], "mac!(...)", "mac! (...)"); + c2!(expr, [ mac![...] ], "mac![...]", "mac! [...]"); + c1!(expr, [ mac! { ... } ], "mac! { ... }"); // ExprKind::Struct - assert_eq!(stringify_expr!(Struct {}), "Struct {}"); - #[rustfmt::skip] // https://github.com/rust-lang/rustfmt/issues/5151 - assert_eq!(stringify_expr!(<Struct as Trait>::Type {}), "<Struct as Trait>::Type {}"); - assert_eq!(stringify_expr!(Struct { .. }), "Struct { .. }"); - assert_eq!(stringify_expr!(Struct { ..base }), "Struct { ..base }"); - assert_eq!(stringify_expr!(Struct { x }), "Struct { x }"); - assert_eq!(stringify_expr!(Struct { x, .. }), "Struct { x, .. }"); - assert_eq!(stringify_expr!(Struct { x, ..base }), "Struct { x, ..base }"); - assert_eq!(stringify_expr!(Struct { x: true }), "Struct { x: true }"); - assert_eq!(stringify_expr!(Struct { x: true, .. }), "Struct { x: true, .. }"); - assert_eq!(stringify_expr!(Struct { x: true, ..base }), "Struct { x: true, ..base }"); + c1!(expr, [ Struct {} ], "Struct {}"); + c2!(expr, + [ <Struct as Trait>::Type {} ], + "<Struct as Trait>::Type {}", + "< Struct as Trait > :: Type {}" + ); + c1!(expr, [ Struct { .. } ], "Struct { .. }"); + c2!(expr, [ Struct { ..base } ], "Struct { ..base }", "Struct { .. base }"); + c1!(expr, [ Struct { x } ], "Struct { x }"); + c1!(expr, [ Struct { x, .. } ], "Struct { x, .. }"); + c2!(expr, [ Struct { x, ..base } ], "Struct { x, ..base }", "Struct { x, .. base }"); + c2!(expr, [ Struct { x: true } ], "Struct { x: true }", "Struct { x : true }"); + c2!(expr, [ Struct { x: true, .. } ], "Struct { x: true, .. }", "Struct { x : true, .. }"); + c2!(expr, + [ Struct { x: true, ..base } ], + "Struct { x: true, ..base }", + "Struct { x : true, .. base }" + ); // ExprKind::Repeat - assert_eq!(stringify_expr!([(); 0]), "[(); 0]"); + c2!(expr, [ [(); 0] ], "[(); 0]", "[() ; 0]"); // ExprKind::Paren - assert_eq!(stringify_expr!((expr)), "(expr)"); + c1!(expr, [ (expr) ], "(expr)"); // ExprKind::Try - assert_eq!(stringify_expr!(expr?), "expr?"); + c2!(expr, [ expr? ], "expr?", "expr ?"); // ExprKind::Yield - assert_eq!(stringify_expr!(yield), "yield"); - assert_eq!(stringify_expr!(yield true), "yield true"); + c1!(expr, [ yield ], "yield"); + c1!(expr, [ yield true ], "yield true"); + + // ExprKind::Yeet + c1!(expr, [ do yeet ], "do yeet"); + c1!(expr, [ do yeet 0 ], "do yeet 0"); + + // ExprKind::Become + // FIXME: todo + + // ExprKind::IncludedBytes + // FIXME: todo + + // ExprKind::FormatArgs: untestable because this test works pre-expansion. + + // ExprKind::Err: untestable. } #[test] fn test_item() { // ItemKind::ExternCrate - assert_eq!( - stringify_item!( - extern crate std; - ), - "extern crate std;", - ); - assert_eq!( - stringify_item!( - pub extern crate self as std; - ), + c2!(item, [ extern crate std; ], "extern crate std;", "extern crate std ;"); + c2!(item, + [ pub extern crate self as std; ], "pub extern crate self as std;", + "pub extern crate self as std ;" ); // ItemKind::Use - assert_eq!( - stringify_item!( - pub use crate::{a, b::c}; - ), + c2!(item, + [ pub use crate::{a, b::c}; ], "pub use crate::{a, b::c};", + "pub use crate :: { a, b :: c } ;" ); + c2!(item, [ pub use A::*; ], "pub use A::*;", "pub use A :: * ;"); // ItemKind::Static - assert_eq!( - stringify_item!( - pub static S: () = {}; - ), - "pub static S: () = {};", - ); - assert_eq!( - stringify_item!( - static mut S: () = {}; - ), - "static mut S: () = {};", - ); - assert_eq!( - stringify_item!( - static S: (); - ), - "static S: ();", - ); - assert_eq!( - stringify_item!( - static mut S: (); - ), - "static mut S: ();", - ); + c2!(item, [ pub static S: () = {}; ], "pub static S: () = {};", "pub static S : () = {} ;"); + c2!(item, [ static mut S: () = {}; ], "static mut S: () = {};", "static mut S : () = {} ;"); + c2!(item, [ static S: (); ], "static S: ();", "static S : () ;"); + c2!(item, [ static mut S: (); ], "static mut S: ();", "static mut S : () ;"); // ItemKind::Const - assert_eq!( - stringify_item!( - pub const S: () = {}; - ), - "pub const S: () = {};", - ); - assert_eq!( - stringify_item!( - const S: (); - ), - "const S: ();", - ); + c2!(item, [ pub const S: () = {}; ], "pub const S: () = {};", "pub const S : () = {} ;"); + c2!(item, [ const S: (); ], "const S: ();", "const S : () ;"); // ItemKind::Fn - assert_eq!( - stringify_item!( - pub default const async unsafe extern "C" fn f() {} - ), - "pub default const async unsafe extern \"C\" fn f() {}", + c1!(item, + [ pub default const async unsafe extern "C" fn f() {} ], + "pub default const async unsafe extern \"C\" fn f() {}" + ); + c2!(item, + [ fn g<T>(t: Vec<Vec<Vec<T>>>) {} ], + "fn g<T>(t: Vec<Vec<Vec<T>>>) {}", + "fn g < T > (t : Vec < Vec < Vec < T >> >) {}" + ); + c2!(item, + [ fn h<'a>(t: &'a Vec<Cell<dyn D>>) {} ], + "fn h<'a>(t: &'a Vec<Cell<dyn D>>) {}", + "fn h < 'a > (t : & 'a Vec < Cell < dyn D >>) {}" ); // ItemKind::Mod - assert_eq!( - stringify_item!( - pub mod m; - ), - "pub mod m;", - ); - assert_eq!( - stringify_item!( - mod m {} - ), - "mod m {}", - ); - assert_eq!( - stringify_item!( - unsafe mod m; - ), - "unsafe mod m;", - ); - assert_eq!( - stringify_item!( - unsafe mod m {} - ), - "unsafe mod m {}", - ); + c2!(item, [ pub mod m; ], "pub mod m;", "pub mod m ;"); + c1!(item, [ mod m {} ], "mod m {}"); + c2!(item, [ unsafe mod m; ], "unsafe mod m;", "unsafe mod m ;"); + c1!(item, [ unsafe mod m {} ], "unsafe mod m {}"); // ItemKind::ForeignMod - assert_eq!( - stringify_item!( - extern "C" {} - ), - "extern \"C\" {}", - ); - #[rustfmt::skip] - assert_eq!( - stringify_item!( - pub extern "C" {} - ), - "extern \"C\" {}", - ); - assert_eq!( - stringify_item!( - unsafe extern "C++" {} - ), - "unsafe extern \"C++\" {}", + c1!(item, [ extern "C" {} ], "extern \"C\" {}"); + c2!(item, + [ pub extern "C" {} ], + "extern \"C\" {}", // ?? + "pub extern \"C\" {}" ); + c1!(item, [ unsafe extern "C++" {} ], "unsafe extern \"C++\" {}"); + + // ItemKind::GlobalAsm: untestable because this test works pre-expansion. // ItemKind::TyAlias - #[rustfmt::skip] - assert_eq!( - stringify_item!( + c2!(item, + [ pub default type Type<'a>: Bound where Self: 'a, = T; - ), + ], "pub default type Type<'a>: Bound where Self: 'a = T;", + "pub default type Type < 'a > : Bound where Self : 'a, = T ;" ); // ItemKind::Enum - assert_eq!( - stringify_item!( - pub enum Void {} - ), - "pub enum Void {}", - ); - assert_eq!( - stringify_item!( + c1!(item, [ pub enum Void {} ], "pub enum Void {}"); + c1!(item, + [ enum Empty { Unit, Tuple(), Struct {}, } - ), - "enum Empty { Unit, Tuple(), Struct {}, }", + ], + "enum Empty { Unit, Tuple(), Struct {}, }" ); - assert_eq!( - stringify_item!( + c2!(item, + [ enum Enum<T> where T: 'a, @@ -500,7 +445,7 @@ fn test_item() { Tuple(T), Struct { t: T }, } - ), + ], "enum Enum<T> where T: 'a {\n\ \x20 Unit,\n\ \x20 Tuple(T),\n\ @@ -508,378 +453,349 @@ fn test_item() { \x20 t: T,\n\ \x20 },\n\ }", + "enum Enum < T > where T : 'a, { Unit, Tuple(T), Struct { t : T }, }" ); // ItemKind::Struct - assert_eq!( - stringify_item!( - pub struct Unit; - ), - "pub struct Unit;", - ); - assert_eq!( - stringify_item!( - struct Tuple(); - ), - "struct Tuple();", - ); - assert_eq!( - stringify_item!( - struct Tuple(T); - ), - "struct Tuple(T);", - ); - assert_eq!( - stringify_item!( - struct Struct {} - ), - "struct Struct {}", - ); - assert_eq!( - stringify_item!( + c2!(item, [ pub struct Unit; ], "pub struct Unit;", "pub struct Unit ;"); + c2!(item, [ struct Tuple(); ], "struct Tuple();", "struct Tuple() ;"); + c2!(item, [ struct Tuple(T); ], "struct Tuple(T);", "struct Tuple(T) ;"); + c1!(item, [ struct Struct {} ], "struct Struct {}"); + c2!(item, + [ struct Struct<T> where T: 'a, { t: T, } - ), + ], "struct Struct<T> where T: 'a {\n\ \x20 t: T,\n\ }", + "struct Struct < T > where T : 'a, { t : T, }" ); // ItemKind::Union - assert_eq!( - stringify_item!( - pub union Union {} - ), - "pub union Union {}", - ); - assert_eq!( - stringify_item!( + c1!(item, [ pub union Union {} ], "pub union Union {}"); + c2!(item, + [ union Union<T> where T: 'a { t: T, } - ), + ], "union Union<T> where T: 'a {\n\ \x20 t: T,\n\ }", + "union Union < T > where T : 'a { t : T, }" ); // ItemKind::Trait - assert_eq!( - stringify_item!( - pub unsafe auto trait Send {} - ), - "pub unsafe auto trait Send {}", - ); - assert_eq!( - stringify_item!( + c1!(item, [ pub unsafe auto trait Send {} ], "pub unsafe auto trait Send {}"); + c2!(item, + [ trait Trait<'a>: Sized where Self: 'a, { } - ), + ], "trait Trait<'a>: Sized where Self: 'a {}", + "trait Trait < 'a > : Sized where Self : 'a, {}" ); // ItemKind::TraitAlias - assert_eq!( - stringify_item!( - pub trait Trait<T> = Sized where T: 'a; - ), + c2!(item, + [ pub trait Trait<T> = Sized where T: 'a; ], "pub trait Trait<T> = Sized where T: 'a;", + "pub trait Trait < T > = Sized where T : 'a ;" ); // ItemKind::Impl - assert_eq!( - stringify_item!( - pub impl Struct {} - ), - "pub impl Struct {}", - ); - assert_eq!( - stringify_item!( - impl<T> Struct<T> {} - ), - "impl<T> Struct<T> {}", - ); - assert_eq!( - stringify_item!( - pub impl Trait for Struct {} - ), - "pub impl Trait for Struct {}", - ); - assert_eq!( - stringify_item!( - impl<T> const Trait for T {} - ), + c1!(item, [ pub impl Struct {} ], "pub impl Struct {}"); + c2!(item, [ impl<T> Struct<T> {} ], "impl<T> Struct<T> {}", "impl < T > Struct < T > {}"); + c1!(item, [ pub impl Trait for Struct {} ], "pub impl Trait for Struct {}"); + c2!(item, + [ impl<T> const Trait for T {} ], "impl<T> const Trait for T {}", + "impl < T > const Trait for T {}" ); - assert_eq!( - stringify_item!( - impl ~const Struct {} - ), - "impl ~const Struct {}", - ); + c2!(item, [ impl ~const Struct {} ], "impl ~const Struct {}", "impl ~ const Struct {}"); // ItemKind::MacCall - assert_eq!(stringify_item!(mac!(...);), "mac!(...);"); - assert_eq!(stringify_item!(mac![...];), "mac![...];"); - assert_eq!(stringify_item!(mac! { ... }), "mac! { ... }"); + c2!(item, [ mac!(...); ], "mac!(...);", "mac! (...) ;"); + c2!(item, [ mac![...]; ], "mac![...];", "mac! [...] ;"); + c1!(item, [ mac! { ... } ], "mac! { ... }"); // ItemKind::MacroDef - assert_eq!( - stringify_item!( + c1!(item, + [ macro_rules! stringify { () => {}; } - ), - "macro_rules! stringify { () => {} ; }", // FIXME + ], + "macro_rules! stringify { () => {} ; }" ); - assert_eq!( - stringify_item!( - pub macro stringify() {} - ), - "pub macro stringify { () => {} }", + c2!(item, + [ pub macro stringify() {} ], + "pub macro stringify { () => {} }", // ?? + "pub macro stringify() {}" ); } #[test] fn test_meta() { - assert_eq!(stringify_meta!(k), "k"); - assert_eq!(stringify_meta!(k = "v"), "k = \"v\""); - assert_eq!(stringify_meta!(list(k1, k2 = "v")), "list(k1, k2 = \"v\")"); - assert_eq!(stringify_meta!(serde::k), "serde::k"); + c1!(meta, [ k ], "k"); + c1!(meta, [ k = "v" ], "k = \"v\""); + c1!(meta, [ list(k1, k2 = "v") ], "list(k1, k2 = \"v\")"); + c2!(meta, [ serde::k ], "serde::k", "serde :: k"); } #[test] fn test_pat() { // PatKind::Wild - assert_eq!(stringify_pat!(_), "_"); + c1!(pat, [ _ ], "_"); // PatKind::Ident - assert_eq!(stringify_pat!(_x), "_x"); - assert_eq!(stringify_pat!(ref _x), "ref _x"); - assert_eq!(stringify_pat!(mut _x), "mut _x"); - assert_eq!(stringify_pat!(ref mut _x), "ref mut _x"); - assert_eq!(stringify_pat!(ref mut _x @ _), "ref mut _x @ _"); + c1!(pat, [ _x ], "_x"); + c1!(pat, [ ref _x ], "ref _x"); + c1!(pat, [ mut _x ], "mut _x"); + c1!(pat, [ ref mut _x ], "ref mut _x"); + c1!(pat, [ ref mut _x @ _ ], "ref mut _x @ _"); // PatKind::Struct - assert_eq!(stringify_pat!(Struct {}), "Struct {}"); - assert_eq!(stringify_pat!(Struct::<u8> {}), "Struct::<u8> {}"); - assert_eq!(stringify_pat!(Struct::<'static> {}), "Struct::<'static> {}"); - assert_eq!(stringify_pat!(Struct { x }), "Struct { x }"); - assert_eq!(stringify_pat!(Struct { x: _x }), "Struct { x: _x }"); - assert_eq!(stringify_pat!(Struct { .. }), "Struct { .. }"); - assert_eq!(stringify_pat!(Struct { x, .. }), "Struct { x, .. }"); - assert_eq!(stringify_pat!(Struct { x: _x, .. }), "Struct { x: _x, .. }"); - #[rustfmt::skip] // https://github.com/rust-lang/rustfmt/issues/5151 - assert_eq!( - stringify_pat!(<Struct as Trait>::Type {}), + c1!(pat, [ Struct {} ], "Struct {}"); + c2!(pat, [ Struct::<u8> {} ], "Struct::<u8> {}", "Struct :: < u8 > {}"); + c2!(pat, [ Struct::<'static> {} ], "Struct::<'static> {}", "Struct :: < 'static > {}"); + c1!(pat, [ Struct { x } ], "Struct { x }"); + c2!(pat, [ Struct { x: _x } ], "Struct { x: _x }", "Struct { x : _x }"); + c1!(pat, [ Struct { .. } ], "Struct { .. }"); + c1!(pat, [ Struct { x, .. } ], "Struct { x, .. }"); + c2!(pat, [ Struct { x: _x, .. } ], "Struct { x: _x, .. }", "Struct { x : _x, .. }"); + c2!(pat, + [ <Struct as Trait>::Type {} ], "<Struct as Trait>::Type {}", + "< Struct as Trait > :: Type {}" ); // PatKind::TupleStruct - assert_eq!(stringify_pat!(Tuple()), "Tuple()"); - assert_eq!(stringify_pat!(Tuple::<u8>()), "Tuple::<u8>()"); - assert_eq!(stringify_pat!(Tuple::<'static>()), "Tuple::<'static>()"); - assert_eq!(stringify_pat!(Tuple(x)), "Tuple(x)"); - assert_eq!(stringify_pat!(Tuple(..)), "Tuple(..)"); - assert_eq!(stringify_pat!(Tuple(x, ..)), "Tuple(x, ..)"); - assert_eq!(stringify_pat!(<Struct as Trait>::Type()), "<Struct as Trait>::Type()"); + c1!(pat, [ Tuple() ], "Tuple()"); + c2!(pat, [ Tuple::<u8>() ], "Tuple::<u8>()", "Tuple :: < u8 > ()"); + c2!(pat, [ Tuple::<'static>() ], "Tuple::<'static>()", "Tuple :: < 'static > ()"); + c1!(pat, [ Tuple(x) ], "Tuple(x)"); + c1!(pat, [ Tuple(..) ], "Tuple(..)"); + c1!(pat, [ Tuple(x, ..) ], "Tuple(x, ..)"); + c2!(pat, + [ <Struct as Trait>::Type() ], + "<Struct as Trait>::Type()", + "< Struct as Trait > :: Type()" + ); // PatKind::Or - assert_eq!(stringify_pat!(true | false), "true | false"); - assert_eq!(stringify_pat!(| true), "true"); - assert_eq!(stringify_pat!(|true| false), "true | false"); + c1!(pat, [ true | false ], "true | false"); + c2!(pat, [ | true ], "true", "| true"); + c2!(pat, [ |true| false ], "true | false", "| true | false"); // PatKind::Path - assert_eq!(stringify_pat!(crate::Path), "crate::Path"); - assert_eq!(stringify_pat!(Path::<u8>), "Path::<u8>"); - assert_eq!(stringify_pat!(Path::<'static>), "Path::<'static>"); - assert_eq!(stringify_pat!(<Struct as Trait>::Type), "<Struct as Trait>::Type"); + c2!(pat, [ crate::Path ], "crate::Path", "crate :: Path"); + c2!(pat, [ Path::<u8> ], "Path::<u8>", "Path :: < u8 >"); + c2!(pat, [ Path::<'static> ], "Path::<'static>", "Path :: < 'static >"); + c2!(pat, [ <Struct as Trait>::Type ], "<Struct as Trait>::Type", "< Struct as Trait > :: Type"); // PatKind::Tuple - assert_eq!(stringify_pat!(()), "()"); - assert_eq!(stringify_pat!((true,)), "(true,)"); - assert_eq!(stringify_pat!((true, false)), "(true, false)"); + c1!(pat, [ () ], "()"); + c1!(pat, [ (true,) ], "(true,)"); + c1!(pat, [ (true, false) ], "(true, false)"); // PatKind::Box - assert_eq!(stringify_pat!(box pat), "box pat"); + c1!(pat, [ box pat ], "box pat"); // PatKind::Ref - assert_eq!(stringify_pat!(&pat), "&pat"); - assert_eq!(stringify_pat!(&mut pat), "&mut pat"); + c2!(pat, [ &pat ], "&pat", "& pat"); + c2!(pat, [ &mut pat ], "&mut pat", "& mut pat"); // PatKind::Lit - assert_eq!(stringify_pat!(1_000_i8), "1_000_i8"); + c1!(pat, [ 1_000_i8 ], "1_000_i8"); // PatKind::Range - assert_eq!(stringify_pat!(..1), "..1"); - assert_eq!(stringify_pat!(0..), "0.."); - assert_eq!(stringify_pat!(0..1), "0..1"); - assert_eq!(stringify_pat!(0..=1), "0..=1"); - assert_eq!(stringify_pat!(-2..=-1), "-2..=-1"); + c2!(pat, [ ..1 ], "..1", ".. 1"); + c2!(pat, [ 0.. ], "0..", "0 .."); + c2!(pat, [ 0..1 ], "0..1", "0 .. 1"); + c2!(pat, [ 0..=1 ], "0..=1", "0 ..= 1"); + c2!(pat, [ -2..=-1 ], "-2..=-1", "- 2 ..= - 1"); // PatKind::Slice - assert_eq!(stringify_pat!([]), "[]"); - assert_eq!(stringify_pat!([true]), "[true]"); - assert_eq!(stringify_pat!([true,]), "[true]"); - assert_eq!(stringify_pat!([true, false]), "[true, false]"); + c1!(pat, [ [] ], "[]"); + c1!(pat, [ [true] ], "[true]"); + c2!(pat, [ [true,] ], "[true]", "[true,]"); + c1!(pat, [ [true, false] ], "[true, false]"); // PatKind::Rest - assert_eq!(stringify_pat!(..), ".."); + c1!(pat, [ .. ], ".."); // PatKind::Paren - assert_eq!(stringify_pat!((pat)), "(pat)"); + c1!(pat, [ (pat) ], "(pat)"); // PatKind::MacCall - assert_eq!(stringify_pat!(mac!(...)), "mac!(...)"); - assert_eq!(stringify_pat!(mac![...]), "mac![...]"); - assert_eq!(stringify_pat!(mac! { ... }), "mac! { ... }"); + c2!(pat, [ mac!(...) ], "mac!(...)", "mac! (...)"); + c2!(pat, [ mac![...] ], "mac![...]", "mac! [...]"); + c1!(pat, [ mac! { ... } ], "mac! { ... }"); } #[test] fn test_path() { - assert_eq!(stringify_path!(thing), "thing"); - assert_eq!(stringify_path!(m::thing), "m::thing"); - assert_eq!(stringify_path!(self::thing), "self::thing"); - assert_eq!(stringify_path!(crate::thing), "crate::thing"); - assert_eq!(stringify_path!(Self::thing), "Self::thing"); - assert_eq!(stringify_path!(Self<'static>), "Self<'static>"); - assert_eq!(stringify_path!(Self::<'static>), "Self<'static>"); - assert_eq!(stringify_path!(Self()), "Self()"); - assert_eq!(stringify_path!(Self() -> ()), "Self() -> ()"); + c1!(path, [ thing ], "thing"); + c2!(path, [ m::thing ], "m::thing", "m :: thing"); + c2!(path, [ self::thing ], "self::thing", "self :: thing"); + c2!(path, [ crate::thing ], "crate::thing", "crate :: thing"); + c2!(path, [ Self::thing ], "Self::thing", "Self :: thing"); + c2!(path, [ Self<'static> ], "Self<'static>", "Self < 'static >"); + c2!(path, [ Self::<'static> ], "Self<'static>", "Self :: < 'static >"); + c1!(path, [ Self() ], "Self()"); + c1!(path, [ Self() -> () ], "Self() -> ()"); } #[test] fn test_stmt() { // StmtKind::Local - assert_eq!(stringify_stmt!(let _), "let _;"); - assert_eq!(stringify_stmt!(let x = true), "let x = true;"); - assert_eq!(stringify_stmt!(let x: bool = true), "let x: bool = true;"); + c2!(stmt, [ let _ ], "let _;", "let _"); + c2!(stmt, [ let x = true ], "let x = true;", "let x = true"); + c2!(stmt, [ let x: bool = true ], "let x: bool = true;", "let x : bool = true"); + c2!(stmt, [ let (a, b) = (1, 2) ], "let (a, b) = (1, 2);", "let(a, b) = (1, 2)"); // FIXME + c2!(stmt, + [ let (a, b): (u32, u32) = (1, 2) ], + "let (a, b): (u32, u32) = (1, 2);", + "let(a, b) : (u32, u32) = (1, 2)" + ); // StmtKind::Item - assert_eq!( - stringify_stmt!( - struct S; - ), - "struct S;", - ); + c2!(stmt, [ struct S; ], "struct S;", "struct S ;"); + c1!(stmt, [ struct S {} ], "struct S {}"); // StmtKind::Expr - assert_eq!(stringify_stmt!(loop {}), "loop {}"); + c1!(stmt, [ loop {} ], "loop {}"); // StmtKind::Semi - assert_eq!(stringify_stmt!(1 + 1), "1 + 1;"); + c2!(stmt, [ 1 + 1 ], "1 + 1;", "1 + 1"); // StmtKind::Empty - assert_eq!(stringify_stmt!(;), ";"); + c1!(stmt, [ ; ], ";"); // StmtKind::MacCall - assert_eq!(stringify_stmt!(mac!(...)), "mac!(...)"); - assert_eq!(stringify_stmt!(mac![...]), "mac![...]"); - assert_eq!(stringify_stmt!(mac! { ... }), "mac! { ... }"); + c2!(stmt, [ mac!(...) ], "mac!(...)", "mac! (...)"); + c2!(stmt, [ mac![...] ], "mac![...]", "mac! [...]"); + c1!(stmt, [ mac! { ... } ], "mac! { ... }"); } #[test] fn test_ty() { // TyKind::Slice - assert_eq!(stringify_ty!([T]), "[T]"); + c1!(ty, [ [T] ], "[T]"); // TyKind::Array - assert_eq!(stringify_ty!([T; 0]), "[T; 0]"); + c2!(ty, [ [T; 0] ], "[T; 0]", "[T ; 0]"); // TyKind::Ptr - assert_eq!(stringify_ty!(*const T), "*const T"); - assert_eq!(stringify_ty!(*mut T), "*mut T"); + c2!(ty, [ *const T ], "*const T", "* const T"); + c2!(ty, [ *mut T ], "*mut T", "* mut T"); // TyKind::Ref - assert_eq!(stringify_ty!(&T), "&T"); - assert_eq!(stringify_ty!(&mut T), "&mut T"); - assert_eq!(stringify_ty!(&'a T), "&'a T"); - assert_eq!(stringify_ty!(&'a mut T), "&'a mut T"); + c2!(ty, [ &T ], "&T", "& T"); + c2!(ty, [ &mut T ], "&mut T", "& mut T"); + c2!(ty, [ &'a T ], "&'a T", "& 'a T"); + c2!(ty, [ &'a mut [T] ], "&'a mut [T]", "& 'a mut [T]"); + c2!(ty, [ &A<B<C<D<E>>>> ], "&A<B<C<D<E>>>>", "& A < B < C < D < E >> >>"); // TyKind::BareFn - assert_eq!(stringify_ty!(fn()), "fn()"); - assert_eq!(stringify_ty!(fn() -> ()), "fn() -> ()"); - assert_eq!(stringify_ty!(fn(u8)), "fn(u8)"); - assert_eq!(stringify_ty!(fn(x: u8)), "fn(x: u8)"); - #[rustfmt::skip] - assert_eq!(stringify_ty!(for<> fn()), "fn()"); - assert_eq!(stringify_ty!(for<'a> fn()), "for<'a> fn()"); + c1!(ty, [ fn() ], "fn()"); + c1!(ty, [ fn() -> () ], "fn() -> ()"); + c1!(ty, [ fn(u8) ], "fn(u8)"); + c2!(ty, [ fn(x: u8) ], "fn(x: u8)", "fn(x : u8)"); + c2!(ty, [ for<> fn() ], "fn()", "for < > fn()"); + c2!(ty, [ for<'a> fn() ], "for<'a> fn()", "for < 'a > fn()"); // TyKind::Never - assert_eq!(stringify_ty!(!), "!"); + c1!(ty, [ ! ], "!"); // TyKind::Tup - assert_eq!(stringify_ty!(()), "()"); - assert_eq!(stringify_ty!((T,)), "(T,)"); - assert_eq!(stringify_ty!((T, U)), "(T, U)"); + c1!(ty, [ () ], "()"); + c1!(ty, [ (T,) ], "(T,)"); + c1!(ty, [ (T, U) ], "(T, U)"); + + // TyKind::AnonStruct: untestable in isolation. + + // TyKind::AnonUnion: untestable in isolation. // TyKind::Path - assert_eq!(stringify_ty!(T), "T"); - assert_eq!(stringify_ty!(Ref<'a>), "Ref<'a>"); - assert_eq!(stringify_ty!(PhantomData<T>), "PhantomData<T>"); - assert_eq!(stringify_ty!(PhantomData::<T>), "PhantomData<T>"); - assert_eq!(stringify_ty!(Fn() -> !), "Fn() -> !"); - assert_eq!(stringify_ty!(Fn(u8) -> !), "Fn(u8) -> !"); - assert_eq!(stringify_ty!(<Struct as Trait>::Type), "<Struct as Trait>::Type"); + c1!(ty, [ T ], "T"); + c2!(ty, [ Ref<'a> ], "Ref<'a>", "Ref < 'a >"); + c2!(ty, [ PhantomData<T> ], "PhantomData<T>", "PhantomData < T >"); + c2!(ty, [ PhantomData::<T> ], "PhantomData<T>", "PhantomData :: < T >"); + c2!(ty, [ Fn() -> ! ], "Fn() -> !", "Fn() ->!"); + c2!(ty, [ Fn(u8) -> ! ], "Fn(u8) -> !", "Fn(u8) ->!"); // FIXME + c2!(ty, [ <Struct as Trait>::Type ], "<Struct as Trait>::Type", "< Struct as Trait > :: Type"); // TyKind::TraitObject - assert_eq!(stringify_ty!(dyn Send), "dyn Send"); - assert_eq!(stringify_ty!(dyn Send + 'a), "dyn Send + 'a"); - assert_eq!(stringify_ty!(dyn 'a + Send), "dyn 'a + Send"); - assert_eq!(stringify_ty!(dyn ?Sized), "dyn ?Sized"); - assert_eq!(stringify_ty!(dyn ~const Clone), "dyn ~const Clone"); - assert_eq!(stringify_ty!(dyn for<'a> Send), "dyn for<'a> Send"); + c1!(ty, [ dyn Send ], "dyn Send"); + c1!(ty, [ dyn Send + 'a ], "dyn Send + 'a"); + c1!(ty, [ dyn 'a + Send ], "dyn 'a + Send"); + c2!(ty, [ dyn ?Sized ], "dyn ?Sized", "dyn ? Sized"); + c2!(ty, [ dyn ~const Clone ], "dyn ~const Clone", "dyn ~ const Clone"); + c2!(ty, [ dyn for<'a> Send ], "dyn for<'a> Send", "dyn for < 'a > Send"); // TyKind::ImplTrait - assert_eq!(stringify_ty!(impl Send), "impl Send"); - assert_eq!(stringify_ty!(impl Send + 'a), "impl Send + 'a"); - assert_eq!(stringify_ty!(impl 'a + Send), "impl 'a + Send"); - assert_eq!(stringify_ty!(impl ?Sized), "impl ?Sized"); - assert_eq!(stringify_ty!(impl ~const Clone), "impl ~const Clone"); - assert_eq!(stringify_ty!(impl for<'a> Send), "impl for<'a> Send"); + c1!(ty, [ impl Send ], "impl Send"); + c1!(ty, [ impl Send + 'a ], "impl Send + 'a"); + c1!(ty, [ impl 'a + Send ], "impl 'a + Send"); + c2!(ty, [ impl ?Sized ], "impl ?Sized", "impl ? Sized"); + c2!(ty, [ impl ~const Clone ], "impl ~const Clone", "impl ~ const Clone"); + c2!(ty, [ impl for<'a> Send ], "impl for<'a> Send", "impl for < 'a > Send"); // TyKind::Paren - assert_eq!(stringify_ty!((T)), "(T)"); + c1!(ty, [ (T) ], "(T)"); + + // TyKind::Typeof: unused for now. // TyKind::Infer - assert_eq!(stringify_ty!(_), "_"); + c1!(ty, [ _ ], "_"); + + // TyKind::ImplicitSelf: there is no syntax for this. // TyKind::MacCall - assert_eq!(stringify_ty!(mac!(...)), "mac!(...)"); - assert_eq!(stringify_ty!(mac![...]), "mac![...]"); - assert_eq!(stringify_ty!(mac! { ... }), "mac! { ... }"); + c2!(ty, [ mac!(...) ], "mac!(...)", "mac! (...)"); + c2!(ty, [ mac![...] ], "mac![...]", "mac! [...]"); + c1!(ty, [ mac! { ... } ], "mac! { ... }"); + + // TyKind::Err: untestable. + + // TyKind::CVarArgs + // FIXME: todo } #[test] fn test_vis() { // VisibilityKind::Public - assert_eq!(stringify_vis!(pub), "pub "); + c2!(vis, [ pub ], "pub ", "pub"); // VisibilityKind::Restricted - assert_eq!(stringify_vis!(pub(crate)), "pub(crate) "); - assert_eq!(stringify_vis!(pub(self)), "pub(self) "); - assert_eq!(stringify_vis!(pub(super)), "pub(super) "); - assert_eq!(stringify_vis!(pub(in crate)), "pub(in crate) "); - assert_eq!(stringify_vis!(pub(in self)), "pub(in self) "); - assert_eq!(stringify_vis!(pub(in super)), "pub(in super) "); - assert_eq!(stringify_vis!(pub(in path::to)), "pub(in path::to) "); - assert_eq!(stringify_vis!(pub(in ::path::to)), "pub(in ::path::to) "); - assert_eq!(stringify_vis!(pub(in self::path::to)), "pub(in self::path::to) "); - assert_eq!(stringify_vis!(pub(in super::path::to)), "pub(in super::path::to) "); + c2!(vis, [ pub(crate) ], "pub(crate) ", "pub(crate)"); + c2!(vis, [ pub(self) ], "pub(self) ", "pub(self)"); + c2!(vis, [ pub(super) ], "pub(super) ", "pub(super)"); + c2!(vis, [ pub(in crate) ], "pub(in crate) ", "pub(in crate)"); + c2!(vis, [ pub(in self) ], "pub(in self) ", "pub(in self)"); + c2!(vis, [ pub(in super) ], "pub(in super) ", "pub(in super)"); + c2!(vis, [ pub(in path::to) ], "pub(in path::to) ", "pub(in path :: to)"); + c2!(vis, [ pub(in ::path::to) ], "pub(in ::path::to) ", "pub(in :: path :: to)"); + c2!(vis, [ pub(in self::path::to) ], "pub(in self::path::to) ", "pub(in self :: path :: to)"); + c2!(vis, + [ pub(in super::path::to) ], + "pub(in super::path::to) ", + "pub(in super :: path :: to)" + ); // VisibilityKind::Inherited - // Directly calling `stringify_vis!()` does not work. - macro_rules! stringify_inherited_vis { - ($vis:vis struct) => { - stringify_vis!($vis) - }; - } - assert_eq!(stringify_inherited_vis!(struct), ""); + // This one is different because directly calling `vis!` does not work. + macro_rules! inherited_vis { ($vis:vis struct) => { vis!($vis) }; } + assert_eq!(inherited_vis!(struct), ""); + assert_eq!(stringify!(), ""); } diff --git a/tests/ui/malformed/do-not-ice-on-note_and_explain.rs b/tests/ui/malformed/do-not-ice-on-note_and_explain.rs new file mode 100644 index 00000000000..e65276fb738 --- /dev/null +++ b/tests/ui/malformed/do-not-ice-on-note_and_explain.rs @@ -0,0 +1,7 @@ +struct A<B>(B); +impl<B>A<B>{fn d(){fn d(){Self(1)}}} +//~^ ERROR the size for values of type `B` cannot be known at compilation time +//~| ERROR the size for values of type `B` cannot be known at compilation time +//~| ERROR mismatched types +//~| ERROR mismatched types +//~| ERROR `main` function not found in crate diff --git a/tests/ui/malformed/do-not-ice-on-note_and_explain.stderr b/tests/ui/malformed/do-not-ice-on-note_and_explain.stderr new file mode 100644 index 00000000000..27b86145e90 --- /dev/null +++ b/tests/ui/malformed/do-not-ice-on-note_and_explain.stderr @@ -0,0 +1,79 @@ +error[E0601]: `main` function not found in crate `do_not_ice_on_note_and_explain` + --> $DIR/do-not-ice-on-note_and_explain.rs:2:37 + | +LL | impl<B>A<B>{fn d(){fn d(){Self(1)}}} + | ^ consider adding a `main` function to `$DIR/do-not-ice-on-note_and_explain.rs` + +error[E0277]: the size for values of type `B` cannot be known at compilation time + --> $DIR/do-not-ice-on-note_and_explain.rs:2:32 + | +LL | impl<B>A<B>{fn d(){fn d(){Self(1)}}} + | - ---- ^ doesn't have a size known at compile-time + | | | + | | required by a bound introduced by this call + | this type parameter needs to be `Sized` + | +note: required by a bound in `A` + --> $DIR/do-not-ice-on-note_and_explain.rs:1:10 + | +LL | struct A<B>(B); + | ^ required by this bound in `A` + +error[E0308]: mismatched types + --> $DIR/do-not-ice-on-note_and_explain.rs:2:32 + | +LL | impl<B>A<B>{fn d(){fn d(){Self(1)}}} + | ---- ^ expected type parameter `B`, found integer + | | + | arguments to this function are incorrect + | + = note: expected type parameter `B` + found type `{integer}` +note: tuple struct defined here + --> $DIR/do-not-ice-on-note_and_explain.rs:1:8 + | +LL | struct A<B>(B); + | ^ + +error[E0308]: mismatched types + --> $DIR/do-not-ice-on-note_and_explain.rs:2:27 + | +LL | impl<B>A<B>{fn d(){fn d(){Self(1)}}} + | ^^^^^^^ expected `()`, found `A<B>` + | + = note: expected unit type `()` + found struct `A<B>` +help: consider using a semicolon here + | +LL | impl<B>A<B>{fn d(){fn d(){Self(1);}}} + | + +help: try adding a return type + | +LL | impl<B>A<B>{fn d(){fn d() -> A<B>{Self(1)}}} + | +++++++ + +error[E0277]: the size for values of type `B` cannot be known at compilation time + --> $DIR/do-not-ice-on-note_and_explain.rs:2:27 + | +LL | impl<B>A<B>{fn d(){fn d(){Self(1)}}} + | - ^^^^^^^ doesn't have a size known at compile-time + | | + | this type parameter needs to be `Sized` + | +note: required by a bound in `A` + --> $DIR/do-not-ice-on-note_and_explain.rs:1:10 + | +LL | struct A<B>(B); + | ^ required by this bound in `A` +help: you could relax the implicit `Sized` bound on `B` if it were used through indirection like `&B` or `Box<B>` + --> $DIR/do-not-ice-on-note_and_explain.rs:1:10 + | +LL | struct A<B>(B); + | ^ - ...if indirection were used here: `Box<B>` + | | + | this could be changed to `B: ?Sized`... + +error: aborting due to 5 previous errors + +Some errors have detailed explanations: E0277, E0308, E0601. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/mir/mir_match_test.rs b/tests/ui/mir/mir_match_test.rs index 1f96d6737e0..d41a7f4a1db 100644 --- a/tests/ui/mir/mir_match_test.rs +++ b/tests/ui/mir/mir_match_test.rs @@ -1,4 +1,5 @@ #![feature(exclusive_range_pattern)] +#![allow(overlapping_range_endpoints)] // run-pass 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/parser/deep-unmatched-angle-brackets.rs b/tests/ui/parser/deep-unmatched-angle-brackets.rs new file mode 100644 index 00000000000..f8d490e1c5e --- /dev/null +++ b/tests/ui/parser/deep-unmatched-angle-brackets.rs @@ -0,0 +1,17 @@ +trait Mul<T> { + type Output; +} +trait Matrix: Mul<<Self as Matrix>::Row, Output = ()> { + type Row; + type Transpose: Matrix<Row = Self::Row>; +} +fn is_mul<S, T: Mul<S, Output = ()>>() {} +fn f<T: Matrix>() { + is_mul::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::< + f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::< + f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::< + f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f:: + <f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<>(); + //~^ ERROR expected one of `!`, `+`, `,`, `::`, or `>`, found `(` +} +fn main() {} diff --git a/tests/ui/parser/deep-unmatched-angle-brackets.stderr b/tests/ui/parser/deep-unmatched-angle-brackets.stderr new file mode 100644 index 00000000000..1f285037482 --- /dev/null +++ b/tests/ui/parser/deep-unmatched-angle-brackets.stderr @@ -0,0 +1,13 @@ +error: expected one of `!`, `+`, `,`, `::`, or `>`, found `(` + --> $DIR/deep-unmatched-angle-brackets.rs:14:63 + | +LL | <f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<>(); + | ^ expected one of `!`, `+`, `,`, `::`, or `>` + | +help: you might have meant to end the type parameters here + | +LL | <f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<f::<>>(); + | + + +error: aborting due to previous error + diff --git a/tests/ui/parser/issue-100197-mut-let.fixed b/tests/ui/parser/issues/issue-100197-mut-let.fixed index 5a895622200..5a895622200 100644 --- a/tests/ui/parser/issue-100197-mut-let.fixed +++ b/tests/ui/parser/issues/issue-100197-mut-let.fixed diff --git a/tests/ui/parser/issue-100197-mut-let.rs b/tests/ui/parser/issues/issue-100197-mut-let.rs index 71103813a6e..71103813a6e 100644 --- a/tests/ui/parser/issue-100197-mut-let.rs +++ b/tests/ui/parser/issues/issue-100197-mut-let.rs diff --git a/tests/ui/parser/issue-100197-mut-let.stderr b/tests/ui/parser/issues/issue-100197-mut-let.stderr index 86658e4f39f..86658e4f39f 100644 --- a/tests/ui/parser/issue-100197-mut-let.stderr +++ b/tests/ui/parser/issues/issue-100197-mut-let.stderr diff --git a/tests/ui/parser/issue-101477-enum.fixed b/tests/ui/parser/issues/issue-101477-enum.fixed index 1dfeae22aea..1dfeae22aea 100644 --- a/tests/ui/parser/issue-101477-enum.fixed +++ b/tests/ui/parser/issues/issue-101477-enum.fixed diff --git a/tests/ui/parser/issue-101477-enum.rs b/tests/ui/parser/issues/issue-101477-enum.rs index ea7051d69a4..ea7051d69a4 100644 --- a/tests/ui/parser/issue-101477-enum.rs +++ b/tests/ui/parser/issues/issue-101477-enum.rs diff --git a/tests/ui/parser/issue-101477-enum.stderr b/tests/ui/parser/issues/issue-101477-enum.stderr index 94130671f1c..94130671f1c 100644 --- a/tests/ui/parser/issue-101477-enum.stderr +++ b/tests/ui/parser/issues/issue-101477-enum.stderr diff --git a/tests/ui/parser/issue-101477-let.fixed b/tests/ui/parser/issues/issue-101477-let.fixed index 9989ad81524..9989ad81524 100644 --- a/tests/ui/parser/issue-101477-let.fixed +++ b/tests/ui/parser/issues/issue-101477-let.fixed diff --git a/tests/ui/parser/issue-101477-let.rs b/tests/ui/parser/issues/issue-101477-let.rs index 8b0e8bee179..8b0e8bee179 100644 --- a/tests/ui/parser/issue-101477-let.rs +++ b/tests/ui/parser/issues/issue-101477-let.rs diff --git a/tests/ui/parser/issue-101477-let.stderr b/tests/ui/parser/issues/issue-101477-let.stderr index 1b30d4b1786..1b30d4b1786 100644 --- a/tests/ui/parser/issue-101477-let.stderr +++ b/tests/ui/parser/issues/issue-101477-let.stderr diff --git a/tests/ui/parser/issue-102806.rs b/tests/ui/parser/issues/issue-102806.rs index ba297bdc967..ba297bdc967 100644 --- a/tests/ui/parser/issue-102806.rs +++ b/tests/ui/parser/issues/issue-102806.rs diff --git a/tests/ui/parser/issue-102806.stderr b/tests/ui/parser/issues/issue-102806.stderr index ba8174a823b..ba8174a823b 100644 --- a/tests/ui/parser/issue-102806.stderr +++ b/tests/ui/parser/issues/issue-102806.stderr diff --git a/tests/ui/parser/issue-103143.rs b/tests/ui/parser/issues/issue-103143.rs index a584274c405..a584274c405 100644 --- a/tests/ui/parser/issue-103143.rs +++ b/tests/ui/parser/issues/issue-103143.rs diff --git a/tests/ui/parser/issue-103143.stderr b/tests/ui/parser/issues/issue-103143.stderr index 4035c69afa7..4035c69afa7 100644 --- a/tests/ui/parser/issue-103143.stderr +++ b/tests/ui/parser/issues/issue-103143.stderr diff --git a/tests/ui/parser/issue-103381.fixed b/tests/ui/parser/issues/issue-103381.fixed index 6a9fb991097..6a9fb991097 100644 --- a/tests/ui/parser/issue-103381.fixed +++ b/tests/ui/parser/issues/issue-103381.fixed diff --git a/tests/ui/parser/issue-103381.rs b/tests/ui/parser/issues/issue-103381.rs index bf79e10103e..bf79e10103e 100644 --- a/tests/ui/parser/issue-103381.rs +++ b/tests/ui/parser/issues/issue-103381.rs diff --git a/tests/ui/parser/issue-103381.stderr b/tests/ui/parser/issues/issue-103381.stderr index 85fcc18e76b..85fcc18e76b 100644 --- a/tests/ui/parser/issue-103381.stderr +++ b/tests/ui/parser/issues/issue-103381.stderr diff --git a/tests/ui/parser/issue-103425.rs b/tests/ui/parser/issues/issue-103425.rs index c2f8123ca4e..c2f8123ca4e 100644 --- a/tests/ui/parser/issue-103425.rs +++ b/tests/ui/parser/issues/issue-103425.rs diff --git a/tests/ui/parser/issue-103425.stderr b/tests/ui/parser/issues/issue-103425.stderr index 0efe3e3ca71..0efe3e3ca71 100644 --- a/tests/ui/parser/issue-103425.stderr +++ b/tests/ui/parser/issues/issue-103425.stderr diff --git a/tests/ui/parser/issue-103451.rs b/tests/ui/parser/issues/issue-103451.rs index be33213f3cb..be33213f3cb 100644 --- a/tests/ui/parser/issue-103451.rs +++ b/tests/ui/parser/issues/issue-103451.rs diff --git a/tests/ui/parser/issue-103451.stderr b/tests/ui/parser/issues/issue-103451.stderr index 6aacd5012c1..6aacd5012c1 100644 --- a/tests/ui/parser/issue-103451.stderr +++ b/tests/ui/parser/issues/issue-103451.stderr diff --git a/tests/ui/parser/issue-103748-ICE-wrong-braces.rs b/tests/ui/parser/issues/issue-103748-ICE-wrong-braces.rs index 8012cb652bd..8012cb652bd 100644 --- a/tests/ui/parser/issue-103748-ICE-wrong-braces.rs +++ b/tests/ui/parser/issues/issue-103748-ICE-wrong-braces.rs diff --git a/tests/ui/parser/issue-103748-ICE-wrong-braces.stderr b/tests/ui/parser/issues/issue-103748-ICE-wrong-braces.stderr index b0d8b03ae08..b0d8b03ae08 100644 --- a/tests/ui/parser/issue-103748-ICE-wrong-braces.stderr +++ b/tests/ui/parser/issues/issue-103748-ICE-wrong-braces.stderr diff --git a/tests/ui/parser/issue-104620.rs b/tests/ui/parser/issues/issue-104620.rs index f49476c4408..f49476c4408 100644 --- a/tests/ui/parser/issue-104620.rs +++ b/tests/ui/parser/issues/issue-104620.rs diff --git a/tests/ui/parser/issue-104620.stderr b/tests/ui/parser/issues/issue-104620.stderr index d06a6b2554b..d06a6b2554b 100644 --- a/tests/ui/parser/issue-104620.stderr +++ b/tests/ui/parser/issues/issue-104620.stderr diff --git a/tests/ui/parser/issue-104867-inc-dec-2.rs b/tests/ui/parser/issues/issue-104867-inc-dec-2.rs index a006421a975..a006421a975 100644 --- a/tests/ui/parser/issue-104867-inc-dec-2.rs +++ b/tests/ui/parser/issues/issue-104867-inc-dec-2.rs diff --git a/tests/ui/parser/issue-104867-inc-dec-2.stderr b/tests/ui/parser/issues/issue-104867-inc-dec-2.stderr index 4e2d0546851..4e2d0546851 100644 --- a/tests/ui/parser/issue-104867-inc-dec-2.stderr +++ b/tests/ui/parser/issues/issue-104867-inc-dec-2.stderr diff --git a/tests/ui/parser/issue-104867-inc-dec.rs b/tests/ui/parser/issues/issue-104867-inc-dec.rs index 760c67b4bed..760c67b4bed 100644 --- a/tests/ui/parser/issue-104867-inc-dec.rs +++ b/tests/ui/parser/issues/issue-104867-inc-dec.rs diff --git a/tests/ui/parser/issue-104867-inc-dec.stderr b/tests/ui/parser/issues/issue-104867-inc-dec.stderr index 78bfd3e82f0..78bfd3e82f0 100644 --- a/tests/ui/parser/issue-104867-inc-dec.stderr +++ b/tests/ui/parser/issues/issue-104867-inc-dec.stderr diff --git a/tests/ui/parser/issue-105366.fixed b/tests/ui/parser/issues/issue-105366.fixed index ad26643c327..ad26643c327 100644 --- a/tests/ui/parser/issue-105366.fixed +++ b/tests/ui/parser/issues/issue-105366.fixed diff --git a/tests/ui/parser/issue-105366.rs b/tests/ui/parser/issues/issue-105366.rs index 311b6a60f1a..311b6a60f1a 100644 --- a/tests/ui/parser/issue-105366.rs +++ b/tests/ui/parser/issues/issue-105366.rs diff --git a/tests/ui/parser/issue-105366.stderr b/tests/ui/parser/issues/issue-105366.stderr index 0a7408e2c17..0a7408e2c17 100644 --- a/tests/ui/parser/issue-105366.stderr +++ b/tests/ui/parser/issues/issue-105366.stderr diff --git a/tests/ui/parser/issue-105634.rs b/tests/ui/parser/issues/issue-105634.rs index 579aa6e5bfb..579aa6e5bfb 100644 --- a/tests/ui/parser/issue-105634.rs +++ b/tests/ui/parser/issues/issue-105634.rs diff --git a/tests/ui/parser/issue-107705.rs b/tests/ui/parser/issues/issue-107705.rs index b80984fcdb0..b80984fcdb0 100644 --- a/tests/ui/parser/issue-107705.rs +++ b/tests/ui/parser/issues/issue-107705.rs diff --git a/tests/ui/parser/issue-107705.stderr b/tests/ui/parser/issues/issue-107705.stderr index d2d61346118..d2d61346118 100644 --- a/tests/ui/parser/issue-107705.stderr +++ b/tests/ui/parser/issues/issue-107705.stderr diff --git a/tests/ui/parser/issue-108495-dec.rs b/tests/ui/parser/issues/issue-108495-dec.rs index e0816f84e5c..e0816f84e5c 100644 --- a/tests/ui/parser/issue-108495-dec.rs +++ b/tests/ui/parser/issues/issue-108495-dec.rs diff --git a/tests/ui/parser/issue-108495-dec.stderr b/tests/ui/parser/issues/issue-108495-dec.stderr index 85b29038f7c..85b29038f7c 100644 --- a/tests/ui/parser/issue-108495-dec.stderr +++ b/tests/ui/parser/issues/issue-108495-dec.stderr diff --git a/tests/ui/parser/issue-112188.fixed b/tests/ui/parser/issues/issue-112188.fixed index 5e73d8e38de..5e73d8e38de 100644 --- a/tests/ui/parser/issue-112188.fixed +++ b/tests/ui/parser/issues/issue-112188.fixed diff --git a/tests/ui/parser/issue-112188.rs b/tests/ui/parser/issues/issue-112188.rs index 27ca192e522..27ca192e522 100644 --- a/tests/ui/parser/issue-112188.rs +++ b/tests/ui/parser/issues/issue-112188.rs diff --git a/tests/ui/parser/issue-112188.stderr b/tests/ui/parser/issues/issue-112188.stderr index 6d2d8e6a3b0..6d2d8e6a3b0 100644 --- a/tests/ui/parser/issue-112188.stderr +++ b/tests/ui/parser/issues/issue-112188.stderr diff --git a/tests/ui/parser/issue-113342.rs b/tests/ui/parser/issues/issue-113342.rs index 18b502736f7..18b502736f7 100644 --- a/tests/ui/parser/issue-113342.rs +++ b/tests/ui/parser/issues/issue-113342.rs diff --git a/tests/ui/parser/issue-113342.stderr b/tests/ui/parser/issues/issue-113342.stderr index a0c5e665ff8..a0c5e665ff8 100644 --- a/tests/ui/parser/issue-113342.stderr +++ b/tests/ui/parser/issues/issue-113342.stderr diff --git a/tests/ui/parser/issue-17718-parse-const.rs b/tests/ui/parser/issues/issue-17718-parse-const.rs index d5a5f445d5b..d5a5f445d5b 100644 --- a/tests/ui/parser/issue-17718-parse-const.rs +++ b/tests/ui/parser/issues/issue-17718-parse-const.rs diff --git a/tests/ui/parser/issue-39616.rs b/tests/ui/parser/issues/issue-39616.rs index 46b5aa334ca..46b5aa334ca 100644 --- a/tests/ui/parser/issue-39616.rs +++ b/tests/ui/parser/issues/issue-39616.rs diff --git a/tests/ui/parser/issue-39616.stderr b/tests/ui/parser/issues/issue-39616.stderr index 393d1f2e2ce..393d1f2e2ce 100644 --- a/tests/ui/parser/issue-39616.stderr +++ b/tests/ui/parser/issues/issue-39616.stderr diff --git a/tests/ui/parser/issue-49257.rs b/tests/ui/parser/issues/issue-49257.rs index a7fa19d52fd..a7fa19d52fd 100644 --- a/tests/ui/parser/issue-49257.rs +++ b/tests/ui/parser/issues/issue-49257.rs diff --git a/tests/ui/parser/issue-49257.stderr b/tests/ui/parser/issues/issue-49257.stderr index 97e16f88b8d..97e16f88b8d 100644 --- a/tests/ui/parser/issue-49257.stderr +++ b/tests/ui/parser/issues/issue-49257.stderr diff --git a/tests/ui/parser/issue-61858.rs b/tests/ui/parser/issues/issue-61858.rs index 6c3b56586c4..6c3b56586c4 100644 --- a/tests/ui/parser/issue-61858.rs +++ b/tests/ui/parser/issues/issue-61858.rs diff --git a/tests/ui/parser/issue-61858.stderr b/tests/ui/parser/issues/issue-61858.stderr index 03f51c6e3a8..03f51c6e3a8 100644 --- a/tests/ui/parser/issue-61858.stderr +++ b/tests/ui/parser/issues/issue-61858.stderr diff --git a/tests/ui/parser/issue-68091-unicode-ident-after-if.rs b/tests/ui/parser/issues/issue-68091-unicode-ident-after-if.rs index 57d36feb37b..57d36feb37b 100644 --- a/tests/ui/parser/issue-68091-unicode-ident-after-if.rs +++ b/tests/ui/parser/issues/issue-68091-unicode-ident-after-if.rs diff --git a/tests/ui/parser/issue-68091-unicode-ident-after-if.stderr b/tests/ui/parser/issues/issue-68091-unicode-ident-after-if.stderr index 6674b924e9c..6674b924e9c 100644 --- a/tests/ui/parser/issue-68091-unicode-ident-after-if.stderr +++ b/tests/ui/parser/issues/issue-68091-unicode-ident-after-if.stderr diff --git a/tests/ui/parser/issue-68092-unicode-ident-after-incomplete-expr.rs b/tests/ui/parser/issues/issue-68092-unicode-ident-after-incomplete-expr.rs index 1a90b4724d4..1a90b4724d4 100644 --- a/tests/ui/parser/issue-68092-unicode-ident-after-incomplete-expr.rs +++ b/tests/ui/parser/issues/issue-68092-unicode-ident-after-incomplete-expr.rs diff --git a/tests/ui/parser/issue-68092-unicode-ident-after-incomplete-expr.stderr b/tests/ui/parser/issues/issue-68092-unicode-ident-after-incomplete-expr.stderr index 0b9c364f1f1..0b9c364f1f1 100644 --- a/tests/ui/parser/issue-68092-unicode-ident-after-incomplete-expr.stderr +++ b/tests/ui/parser/issues/issue-68092-unicode-ident-after-incomplete-expr.stderr diff --git a/tests/ui/parser/issue-68987-unmatch-issue-1.rs b/tests/ui/parser/issues/issue-68987-unmatch-issue-1.rs index 30e7ef46736..30e7ef46736 100644 --- a/tests/ui/parser/issue-68987-unmatch-issue-1.rs +++ b/tests/ui/parser/issues/issue-68987-unmatch-issue-1.rs diff --git a/tests/ui/parser/issue-68987-unmatch-issue-1.stderr b/tests/ui/parser/issues/issue-68987-unmatch-issue-1.stderr index 2d873b46193..2d873b46193 100644 --- a/tests/ui/parser/issue-68987-unmatch-issue-1.stderr +++ b/tests/ui/parser/issues/issue-68987-unmatch-issue-1.stderr diff --git a/tests/ui/parser/issue-68987-unmatch-issue-2.rs b/tests/ui/parser/issues/issue-68987-unmatch-issue-2.rs index 89aaa68ba40..89aaa68ba40 100644 --- a/tests/ui/parser/issue-68987-unmatch-issue-2.rs +++ b/tests/ui/parser/issues/issue-68987-unmatch-issue-2.rs diff --git a/tests/ui/parser/issue-68987-unmatch-issue-2.stderr b/tests/ui/parser/issues/issue-68987-unmatch-issue-2.stderr index 0ecb748a0a4..0ecb748a0a4 100644 --- a/tests/ui/parser/issue-68987-unmatch-issue-2.stderr +++ b/tests/ui/parser/issues/issue-68987-unmatch-issue-2.stderr diff --git a/tests/ui/parser/issue-68987-unmatch-issue-3.rs b/tests/ui/parser/issues/issue-68987-unmatch-issue-3.rs index e98df8d7c3c..e98df8d7c3c 100644 --- a/tests/ui/parser/issue-68987-unmatch-issue-3.rs +++ b/tests/ui/parser/issues/issue-68987-unmatch-issue-3.rs diff --git a/tests/ui/parser/issue-68987-unmatch-issue-3.stderr b/tests/ui/parser/issues/issue-68987-unmatch-issue-3.stderr index dfc4407ed65..dfc4407ed65 100644 --- a/tests/ui/parser/issue-68987-unmatch-issue-3.stderr +++ b/tests/ui/parser/issues/issue-68987-unmatch-issue-3.stderr diff --git a/tests/ui/parser/issue-68987-unmatch-issue.rs b/tests/ui/parser/issues/issue-68987-unmatch-issue.rs index 5a3620bf24b..5a3620bf24b 100644 --- a/tests/ui/parser/issue-68987-unmatch-issue.rs +++ b/tests/ui/parser/issues/issue-68987-unmatch-issue.rs diff --git a/tests/ui/parser/issue-68987-unmatch-issue.stderr b/tests/ui/parser/issues/issue-68987-unmatch-issue.stderr index cabd133242f..cabd133242f 100644 --- a/tests/ui/parser/issue-68987-unmatch-issue.stderr +++ b/tests/ui/parser/issues/issue-68987-unmatch-issue.stderr diff --git a/tests/ui/parser/issue-81804.rs b/tests/ui/parser/issues/issue-81804.rs index ebc4752a142..ebc4752a142 100644 --- a/tests/ui/parser/issue-81804.rs +++ b/tests/ui/parser/issues/issue-81804.rs diff --git a/tests/ui/parser/issue-81804.stderr b/tests/ui/parser/issues/issue-81804.stderr index de3b33ecd95..de3b33ecd95 100644 --- a/tests/ui/parser/issue-81804.stderr +++ b/tests/ui/parser/issues/issue-81804.stderr diff --git a/tests/ui/parser/issue-81827.rs b/tests/ui/parser/issues/issue-81827.rs index 91defd12a57..91defd12a57 100644 --- a/tests/ui/parser/issue-81827.rs +++ b/tests/ui/parser/issues/issue-81827.rs diff --git a/tests/ui/parser/issue-81827.stderr b/tests/ui/parser/issues/issue-81827.stderr index 63d135f73e6..63d135f73e6 100644 --- a/tests/ui/parser/issue-81827.stderr +++ b/tests/ui/parser/issues/issue-81827.stderr diff --git a/tests/ui/parser/issue-87694-duplicated-pub.rs b/tests/ui/parser/issues/issue-87694-duplicated-pub.rs index e3ea61dc4ad..e3ea61dc4ad 100644 --- a/tests/ui/parser/issue-87694-duplicated-pub.rs +++ b/tests/ui/parser/issues/issue-87694-duplicated-pub.rs diff --git a/tests/ui/parser/issue-87694-duplicated-pub.stderr b/tests/ui/parser/issues/issue-87694-duplicated-pub.stderr index 8d242bc9de5..8d242bc9de5 100644 --- a/tests/ui/parser/issue-87694-duplicated-pub.stderr +++ b/tests/ui/parser/issues/issue-87694-duplicated-pub.stderr diff --git a/tests/ui/parser/issue-87694-misplaced-pub.rs b/tests/ui/parser/issues/issue-87694-misplaced-pub.rs index 3f824617cad..3f824617cad 100644 --- a/tests/ui/parser/issue-87694-misplaced-pub.rs +++ b/tests/ui/parser/issues/issue-87694-misplaced-pub.rs diff --git a/tests/ui/parser/issue-87694-misplaced-pub.stderr b/tests/ui/parser/issues/issue-87694-misplaced-pub.stderr index 94c6a29efcb..94c6a29efcb 100644 --- a/tests/ui/parser/issue-87694-misplaced-pub.stderr +++ b/tests/ui/parser/issues/issue-87694-misplaced-pub.stderr diff --git a/tests/ui/parser/issue-90728.rs b/tests/ui/parser/issues/issue-90728.rs index d6a898361cc..d6a898361cc 100644 --- a/tests/ui/parser/issue-90728.rs +++ b/tests/ui/parser/issues/issue-90728.rs diff --git a/tests/ui/parser/issue-90728.stderr b/tests/ui/parser/issues/issue-90728.stderr index b55c4603066..b55c4603066 100644 --- a/tests/ui/parser/issue-90728.stderr +++ b/tests/ui/parser/issues/issue-90728.stderr diff --git a/tests/ui/parser/issue-91421.rs b/tests/ui/parser/issues/issue-91421.rs index 8bba27f3724..8bba27f3724 100644 --- a/tests/ui/parser/issue-91421.rs +++ b/tests/ui/parser/issues/issue-91421.rs diff --git a/tests/ui/parser/issue-91421.stderr b/tests/ui/parser/issues/issue-91421.stderr index 2d9652051dd..2d9652051dd 100644 --- a/tests/ui/parser/issue-91421.stderr +++ b/tests/ui/parser/issues/issue-91421.stderr diff --git a/tests/ui/parser/issue-99625-enum-struct-mutually-exclusive.fixed b/tests/ui/parser/issues/issue-99625-enum-struct-mutually-exclusive.fixed index 4b4a416b1ac..4b4a416b1ac 100644 --- a/tests/ui/parser/issue-99625-enum-struct-mutually-exclusive.fixed +++ b/tests/ui/parser/issues/issue-99625-enum-struct-mutually-exclusive.fixed diff --git a/tests/ui/parser/issue-99625-enum-struct-mutually-exclusive.rs b/tests/ui/parser/issues/issue-99625-enum-struct-mutually-exclusive.rs index 9cc88664129..9cc88664129 100644 --- a/tests/ui/parser/issue-99625-enum-struct-mutually-exclusive.rs +++ b/tests/ui/parser/issues/issue-99625-enum-struct-mutually-exclusive.rs diff --git a/tests/ui/parser/issue-99625-enum-struct-mutually-exclusive.stderr b/tests/ui/parser/issues/issue-99625-enum-struct-mutually-exclusive.stderr index edc640bf5ec..edc640bf5ec 100644 --- a/tests/ui/parser/issue-99625-enum-struct-mutually-exclusive.stderr +++ b/tests/ui/parser/issues/issue-99625-enum-struct-mutually-exclusive.stderr diff --git a/tests/ui/parser/issue-99910-const-let-mutually-exclusive.fixed b/tests/ui/parser/issues/issue-99910-const-let-mutually-exclusive.fixed index 64ab6f62b77..64ab6f62b77 100644 --- a/tests/ui/parser/issue-99910-const-let-mutually-exclusive.fixed +++ b/tests/ui/parser/issues/issue-99910-const-let-mutually-exclusive.fixed diff --git a/tests/ui/parser/issue-99910-const-let-mutually-exclusive.rs b/tests/ui/parser/issues/issue-99910-const-let-mutually-exclusive.rs index 50520971ffb..50520971ffb 100644 --- a/tests/ui/parser/issue-99910-const-let-mutually-exclusive.rs +++ b/tests/ui/parser/issues/issue-99910-const-let-mutually-exclusive.rs diff --git a/tests/ui/parser/issue-99910-const-let-mutually-exclusive.stderr b/tests/ui/parser/issues/issue-99910-const-let-mutually-exclusive.stderr index 72377fc379c..72377fc379c 100644 --- a/tests/ui/parser/issue-99910-const-let-mutually-exclusive.stderr +++ b/tests/ui/parser/issues/issue-99910-const-let-mutually-exclusive.stderr diff --git a/tests/ui/parser/ternary_operator.rs b/tests/ui/parser/ternary_operator.rs index 23d537e77f7..c8810781b3d 100644 --- a/tests/ui/parser/ternary_operator.rs +++ b/tests/ui/parser/ternary_operator.rs @@ -1,69 +1,30 @@ -// A good chunk of these errors aren't shown to the user, but are still -// required in the test for it to pass. - -fn a() { //~ NOTE this function should return `Result` or `Option` to accept `?` +fn a() { let x = 5 > 2 ? true : false; //~^ ERROR Rust has no ternary operator //~| HELP use an `if-else` expression instead - //~| ERROR the `?` operator can only be applied to values that implement `Try` [E0277] - //~| HELP the trait `Try` is not implemented for `{integer}` - //~| ERROR the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`) [E0277] - //~| HELP the trait `FromResidual<_>` is not implemented for `()` - //~| NOTE in this expansion of desugaring of operator `?` - //~| NOTE the `?` operator cannot be applied to type `{integer}` - //~| NOTE in this expansion of desugaring of operator `?` - //~| NOTE in this expansion of desugaring of operator `?` - //~| NOTE cannot use the `?` operator in a function that returns `()` - //~| NOTE in this expansion of desugaring of operator `?` } -fn b() { //~ NOTE this function should return `Result` or `Option` to accept `?` +fn b() { let x = 5 > 2 ? { true } : { false }; //~^ ERROR Rust has no ternary operator //~| HELP use an `if-else` expression instead - //~| ERROR the `?` operator can only be applied to values that implement `Try` [E0277] - //~| HELP the trait `Try` is not implemented for `{integer}` - //~| ERROR the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`) [E0277] - //~| HELP the trait `FromResidual<_>` is not implemented for `()` - //~| NOTE in this expansion of desugaring of operator `?` - //~| NOTE the `?` operator cannot be applied to type `{integer}` - //~| NOTE in this expansion of desugaring of operator `?` - //~| NOTE in this expansion of desugaring of operator `?` - //~| NOTE cannot use the `?` operator in a function that returns `()` - //~| NOTE in this expansion of desugaring of operator `?` } -fn c() { //~ NOTE this function should return `Result` or `Option` to accept `?` +fn c() { let x = 5 > 2 ? f32::MAX : f32::MIN; //~^ ERROR Rust has no ternary operator //~| HELP use an `if-else` expression instead - //~| ERROR the `?` operator can only be applied to values that implement `Try` [E0277] - //~| HELP the trait `Try` is not implemented for `{integer}` - //~| ERROR the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`) [E0277] - //~| HELP the trait `FromResidual<_>` is not implemented for `()` - //~| NOTE in this expansion of desugaring of operator `?` - //~| NOTE the `?` operator cannot be applied to type `{integer}` - //~| NOTE in this expansion of desugaring of operator `?` - //~| NOTE in this expansion of desugaring of operator `?` - //~| NOTE cannot use the `?` operator in a function that returns `()` - //~| NOTE in this expansion of desugaring of operator `?` } -fn main() { //~ NOTE this function should return `Result` or `Option` to accept `?` +fn bad() { + // regression test for #117208 + v ? return; + //~^ ERROR expected one of +} + +fn main() { let x = 5 > 2 ? { let x = vec![]: Vec<u16>; x } : { false }; //~^ ERROR Rust has no ternary operator //~| HELP use an `if-else` expression instead //~| ERROR expected one of `.`, `;`, `?`, `else`, or an operator, found `:` - //~| NOTE expected one of `.`, `;`, `?`, `else`, or an operator - //~| ERROR the `?` operator can only be applied to values that implement `Try` [E0277] - //~| HELP the trait `Try` is not implemented for `{integer}` - //~| ERROR the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`) [E0277] - //~| HELP the trait `FromResidual<_>` is not implemented for `()` - //~| NOTE type ascription syntax has been removed, see issue #101728 <https://github.com/rust-lang/rust/issues/101728> - //~| NOTE in this expansion of desugaring of operator `?` - //~| NOTE the `?` operator cannot be applied to type `{integer}` - //~| NOTE in this expansion of desugaring of operator `?` - //~| NOTE in this expansion of desugaring of operator `?` - //~| NOTE cannot use the `?` operator in a function that returns `()` - //~| NOTE in this expansion of desugaring of operator `?` } diff --git a/tests/ui/parser/ternary_operator.stderr b/tests/ui/parser/ternary_operator.stderr index af9565bbead..6635e1672f7 100644 --- a/tests/ui/parser/ternary_operator.stderr +++ b/tests/ui/parser/ternary_operator.stderr @@ -1,5 +1,5 @@ error: Rust has no ternary operator - --> $DIR/ternary_operator.rs:5:19 + --> $DIR/ternary_operator.rs:2:19 | LL | let x = 5 > 2 ? true : false; | ^^^^^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | let x = 5 > 2 ? true : false; = help: use an `if-else` expression instead error: Rust has no ternary operator - --> $DIR/ternary_operator.rs:21:19 + --> $DIR/ternary_operator.rs:8:19 | LL | let x = 5 > 2 ? { true } : { false }; | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -15,15 +15,21 @@ LL | let x = 5 > 2 ? { true } : { false }; = help: use an `if-else` expression instead error: Rust has no ternary operator - --> $DIR/ternary_operator.rs:37:19 + --> $DIR/ternary_operator.rs:14:19 | LL | let x = 5 > 2 ? f32::MAX : f32::MIN; | ^^^^^^^^^^^^^^^^^^^^^^ | = help: use an `if-else` expression instead +error: expected one of `.`, `;`, `?`, `}`, or an operator, found keyword `return` + --> $DIR/ternary_operator.rs:21:9 + | +LL | v ? return; + | ^^^^^^ expected one of `.`, `;`, `?`, `}`, or an operator + error: expected one of `.`, `;`, `?`, `else`, or an operator, found `:` - --> $DIR/ternary_operator.rs:53:37 + --> $DIR/ternary_operator.rs:26:37 | LL | let x = 5 > 2 ? { let x = vec![]: Vec<u16>; x } : { false }; | ^ expected one of `.`, `;`, `?`, `else`, or an operator @@ -31,85 +37,12 @@ LL | let x = 5 > 2 ? { let x = vec![]: Vec<u16>; x } : { false }; = note: type ascription syntax has been removed, see issue #101728 <https://github.com/rust-lang/rust/issues/101728> error: Rust has no ternary operator - --> $DIR/ternary_operator.rs:53:19 + --> $DIR/ternary_operator.rs:26:19 | LL | let x = 5 > 2 ? { let x = vec![]: Vec<u16>; x } : { false }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: use an `if-else` expression instead -error[E0277]: the `?` operator can only be applied to values that implement `Try` - --> $DIR/ternary_operator.rs:5:17 - | -LL | let x = 5 > 2 ? true : false; - | ^^^ the `?` operator cannot be applied to type `{integer}` - | - = help: the trait `Try` is not implemented for `{integer}` - -error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`) - --> $DIR/ternary_operator.rs:5:19 - | -LL | fn a() { - | ------ this function should return `Result` or `Option` to accept `?` -LL | let x = 5 > 2 ? true : false; - | ^ cannot use the `?` operator in a function that returns `()` - | - = help: the trait `FromResidual<_>` is not implemented for `()` - -error[E0277]: the `?` operator can only be applied to values that implement `Try` - --> $DIR/ternary_operator.rs:21:17 - | -LL | let x = 5 > 2 ? { true } : { false }; - | ^^^ the `?` operator cannot be applied to type `{integer}` - | - = help: the trait `Try` is not implemented for `{integer}` - -error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`) - --> $DIR/ternary_operator.rs:21:19 - | -LL | fn b() { - | ------ this function should return `Result` or `Option` to accept `?` -LL | let x = 5 > 2 ? { true } : { false }; - | ^ cannot use the `?` operator in a function that returns `()` - | - = help: the trait `FromResidual<_>` is not implemented for `()` - -error[E0277]: the `?` operator can only be applied to values that implement `Try` - --> $DIR/ternary_operator.rs:37:17 - | -LL | let x = 5 > 2 ? f32::MAX : f32::MIN; - | ^^^ the `?` operator cannot be applied to type `{integer}` - | - = help: the trait `Try` is not implemented for `{integer}` - -error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`) - --> $DIR/ternary_operator.rs:37:19 - | -LL | fn c() { - | ------ this function should return `Result` or `Option` to accept `?` -LL | let x = 5 > 2 ? f32::MAX : f32::MIN; - | ^ cannot use the `?` operator in a function that returns `()` - | - = help: the trait `FromResidual<_>` is not implemented for `()` - -error[E0277]: the `?` operator can only be applied to values that implement `Try` - --> $DIR/ternary_operator.rs:53:17 - | -LL | let x = 5 > 2 ? { let x = vec![]: Vec<u16>; x } : { false }; - | ^^^ the `?` operator cannot be applied to type `{integer}` - | - = help: the trait `Try` is not implemented for `{integer}` - -error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`) - --> $DIR/ternary_operator.rs:53:19 - | -LL | fn main() { - | --------- this function should return `Result` or `Option` to accept `?` -LL | let x = 5 > 2 ? { let x = vec![]: Vec<u16>; x } : { false }; - | ^ cannot use the `?` operator in a function that returns `()` - | - = help: the trait `FromResidual<_>` is not implemented for `()` - -error: aborting due to 13 previous errors +error: aborting due to 6 previous errors -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/pattern/usefulness/integer-ranges/overlapping_range_endpoints.rs b/tests/ui/pattern/usefulness/integer-ranges/overlapping_range_endpoints.rs index 5ea92b07081..33c1dfd39d4 100644 --- a/tests/ui/pattern/usefulness/integer-ranges/overlapping_range_endpoints.rs +++ b/tests/ui/pattern/usefulness/integer-ranges/overlapping_range_endpoints.rs @@ -8,7 +8,7 @@ macro_rules! m { $t2 => {} _ => {} } - } + }; } fn main() { @@ -16,9 +16,9 @@ fn main() { m!(0u8, 30..=40, 20..=30); //~ ERROR multiple patterns overlap on their endpoints m!(0u8, 20..=30, 31..=40); m!(0u8, 20..=30, 29..=40); - m!(0u8, 20.. 30, 29..=40); //~ ERROR multiple patterns overlap on their endpoints - m!(0u8, 20.. 30, 28..=40); - m!(0u8, 20.. 30, 30..=40); + m!(0u8, 20..30, 29..=40); //~ ERROR multiple patterns overlap on their endpoints + m!(0u8, 20..30, 28..=40); + m!(0u8, 20..30, 30..=40); m!(0u8, 20..=30, 30..=30); m!(0u8, 20..=30, 30..=31); //~ ERROR multiple patterns overlap on their endpoints m!(0u8, 20..=30, 29..=30); @@ -28,7 +28,7 @@ fn main() { m!(0u8, 20..=30, 20); m!(0u8, 20..=30, 25); m!(0u8, 20..=30, 30); - m!(0u8, 20.. 30, 29); + m!(0u8, 20..30, 29); m!(0u8, 20, 20..=30); m!(0u8, 25, 20..=30); m!(0u8, 30, 20..=30); @@ -36,19 +36,21 @@ fn main() { match 0u8 { 0..=10 => {} 20..=30 => {} - 10..=20 => {} //~ ERROR multiple patterns overlap on their endpoints + 10..=20 => {} + //~^ ERROR multiple patterns overlap on their endpoints + //~| ERROR multiple patterns overlap on their endpoints _ => {} } match (0u8, true) { (0..=10, true) => {} - (10..20, true) => {} // not detected - (10..20, false) => {} + (10..20, true) => {} //~ ERROR multiple patterns overlap on their endpoints + (10..20, false) => {} //~ ERROR multiple patterns overlap on their endpoints _ => {} } match (true, 0u8) { (true, 0..=10) => {} (true, 10..20) => {} //~ ERROR multiple patterns overlap on their endpoints - (false, 10..20) => {} + (false, 10..20) => {} //~ ERROR multiple patterns overlap on their endpoints _ => {} } match Some(0u8) { diff --git a/tests/ui/pattern/usefulness/integer-ranges/overlapping_range_endpoints.stderr b/tests/ui/pattern/usefulness/integer-ranges/overlapping_range_endpoints.stderr index ea0e8f6e49e..a87205d76d1 100644 --- a/tests/ui/pattern/usefulness/integer-ranges/overlapping_range_endpoints.stderr +++ b/tests/ui/pattern/usefulness/integer-ranges/overlapping_range_endpoints.stderr @@ -24,10 +24,10 @@ LL | m!(0u8, 30..=40, 20..=30); = note: you likely meant to write mutually exclusive ranges error: multiple patterns overlap on their endpoints - --> $DIR/overlapping_range_endpoints.rs:19:22 + --> $DIR/overlapping_range_endpoints.rs:19:21 | -LL | m!(0u8, 20.. 30, 29..=40); - | ------- ^^^^^^^ ... with this range +LL | m!(0u8, 20..30, 29..=40); + | ------ ^^^^^^^ ... with this range | | | this range overlaps on `29_u8`... | @@ -59,6 +59,15 @@ error: multiple patterns overlap on their endpoints LL | 0..=10 => {} | ------ this range overlaps on `10_u8`... LL | 20..=30 => {} +LL | 10..=20 => {} + | ^^^^^^^ ... with this range + | + = note: you likely meant to write mutually exclusive ranges + +error: multiple patterns overlap on their endpoints + --> $DIR/overlapping_range_endpoints.rs:39:9 + | +LL | 20..=30 => {} | ------- this range overlaps on `20_u8`... LL | 10..=20 => {} | ^^^^^^^ ... with this range @@ -66,7 +75,28 @@ LL | 10..=20 => {} = note: you likely meant to write mutually exclusive ranges error: multiple patterns overlap on their endpoints - --> $DIR/overlapping_range_endpoints.rs:50:16 + --> $DIR/overlapping_range_endpoints.rs:46:10 + | +LL | (0..=10, true) => {} + | ------ this range overlaps on `10_u8`... +LL | (10..20, true) => {} + | ^^^^^^ ... with this range + | + = note: you likely meant to write mutually exclusive ranges + +error: multiple patterns overlap on their endpoints + --> $DIR/overlapping_range_endpoints.rs:47:10 + | +LL | (0..=10, true) => {} + | ------ this range overlaps on `10_u8`... +LL | (10..20, true) => {} +LL | (10..20, false) => {} + | ^^^^^^ ... with this range + | + = note: you likely meant to write mutually exclusive ranges + +error: multiple patterns overlap on their endpoints + --> $DIR/overlapping_range_endpoints.rs:52:16 | LL | (true, 0..=10) => {} | ------ this range overlaps on `10_u8`... @@ -76,7 +106,18 @@ LL | (true, 10..20) => {} = note: you likely meant to write mutually exclusive ranges error: multiple patterns overlap on their endpoints - --> $DIR/overlapping_range_endpoints.rs:56:14 + --> $DIR/overlapping_range_endpoints.rs:53:17 + | +LL | (true, 0..=10) => {} + | ------ this range overlaps on `10_u8`... +LL | (true, 10..20) => {} +LL | (false, 10..20) => {} + | ^^^^^^ ... with this range + | + = note: you likely meant to write mutually exclusive ranges + +error: multiple patterns overlap on their endpoints + --> $DIR/overlapping_range_endpoints.rs:58:14 | LL | Some(0..=10) => {} | ------ this range overlaps on `10_u8`... @@ -85,5 +126,5 @@ LL | Some(10..20) => {} | = note: you likely meant to write mutually exclusive ranges -error: aborting due to 8 previous errors +error: aborting due to 12 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/privacy/suggest-box-new.fixed b/tests/ui/privacy/suggest-box-new.fixed new file mode 100644 index 00000000000..f5ae5c2abfd --- /dev/null +++ b/tests/ui/privacy/suggest-box-new.fixed @@ -0,0 +1,15 @@ +// run-rustfix +#![allow(dead_code)] +struct U <T> { + wtf: Option<Box<U<T>>>, + x: T, +} +fn main() { + U { + wtf: Some(Box::new(U { //~ ERROR cannot initialize a tuple struct which contains private fields + wtf: None, + x: (), + })), + x: () + }; +} diff --git a/tests/ui/privacy/suggest-box-new.rs b/tests/ui/privacy/suggest-box-new.rs new file mode 100644 index 00000000000..2e18dba8b9f --- /dev/null +++ b/tests/ui/privacy/suggest-box-new.rs @@ -0,0 +1,15 @@ +// run-rustfix +#![allow(dead_code)] +struct U <T> { + wtf: Option<Box<U<T>>>, + x: T, +} +fn main() { + U { + wtf: Some(Box(U { //~ ERROR cannot initialize a tuple struct which contains private fields + wtf: None, + x: (), + })), + x: () + }; +} diff --git a/tests/ui/privacy/suggest-box-new.stderr b/tests/ui/privacy/suggest-box-new.stderr new file mode 100644 index 00000000000..ed7fa036408 --- /dev/null +++ b/tests/ui/privacy/suggest-box-new.stderr @@ -0,0 +1,20 @@ +error[E0423]: cannot initialize a tuple struct which contains private fields + --> $DIR/suggest-box-new.rs:9:19 + | +LL | wtf: Some(Box(U { + | ^^^ + | +note: constructor is not visible here due to private fields + --> $SRC_DIR/alloc/src/boxed.rs:LL:COL + | + = note: private field + | + = note: private field +help: you might have meant to use the `new` associated function + | +LL | wtf: Some(Box::new(U { + | +++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0423`. 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/rfcs/rfc-2294-if-let-guard/move-guard-if-let-chain.stderr b/tests/ui/rfcs/rfc-2294-if-let-guard/move-guard-if-let-chain.stderr index d27fde58244..087e54244b3 100644 --- a/tests/ui/rfcs/rfc-2294-if-let-guard/move-guard-if-let-chain.stderr +++ b/tests/ui/rfcs/rfc-2294-if-let-guard/move-guard-if-let-chain.stderr @@ -1,5 +1,5 @@ error[E0382]: use of moved value: `x` - --> $DIR/move-guard-if-let-chain.rs:12:27 + --> $DIR/move-guard-if-let-chain.rs:12:23 | LL | let x: Box<_> = Box::new(1); | - move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait @@ -7,7 +7,7 @@ LL | let x: Box<_> = Box::new(1); LL | (1, 2) if let y = x && c => (), | - value moved here LL | (1, 2) if let z = x => (), - | ^ value used here after move + | ^ value used here after move | help: borrow this binding in the pattern to avoid moving the value | @@ -15,7 +15,7 @@ LL | (1, 2) if let ref y = x && c => (), | +++ error[E0382]: use of moved value: `x` - --> $DIR/move-guard-if-let-chain.rs:36:27 + --> $DIR/move-guard-if-let-chain.rs:36:23 | LL | let x: Box<_> = Box::new(1); | - move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait @@ -23,7 +23,7 @@ LL | let x: Box<_> = Box::new(1); LL | (1, _) if let y = x && c => (), | - value moved here LL | (_, 2) if let z = x => (), - | ^ value used here after move + | ^ value used here after move | help: borrow this binding in the pattern to avoid moving the value | @@ -31,15 +31,13 @@ LL | (1, _) if let ref y = x && c => (), | +++ error[E0382]: use of moved value: `x` - --> $DIR/move-guard-if-let-chain.rs:59:36 + --> $DIR/move-guard-if-let-chain.rs:59:32 | LL | let x: Box<_> = Box::new(1); | - move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait ... LL | (1, _) | (_, 2) if let y = x && c => (), - | - ^ value used here after move - | | - | value moved here + | ^ value used here after move | help: borrow this binding in the pattern to avoid moving the value | diff --git a/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-move-semantics.stderr b/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-move-semantics.stderr index e97fdcce1c1..9dc339abc06 100644 --- a/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-move-semantics.stderr +++ b/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-move-semantics.stderr @@ -1,13 +1,14 @@ error[E0382]: use of moved value: `a` - --> $DIR/dbg-macro-move-semantics.rs:9:18 + --> $DIR/dbg-macro-move-semantics.rs:9:13 | LL | let a = NoCopy(0); | - move occurs because `a` has type `NoCopy`, which does not implement the `Copy` trait LL | let _ = dbg!(a); | ------- value moved here LL | let _ = dbg!(a); - | ^ value used here after move + | ^^^^^^^ value used here after move | + = note: this error originates in the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/auxiliary/cross-crate.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/auxiliary/cross-crate.rs new file mode 100644 index 00000000000..a74c50cc8fa --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/auxiliary/cross-crate.rs @@ -0,0 +1,12 @@ +#![feature(const_trait_impl, effects)] + +pub const fn foo() {} + +#[const_trait] +pub trait Bar { + fn bar(); +} + +impl Bar for () { + fn bar() {} +} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/no-explicit-const-params-cross-crate.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/no-explicit-const-params-cross-crate.rs new file mode 100644 index 00000000000..8e4850197de --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/no-explicit-const-params-cross-crate.rs @@ -0,0 +1,18 @@ +// aux-build: cross-crate.rs +extern crate cross_crate; + +use cross_crate::{Bar, foo}; + +fn main() { + foo::<true>(); + //~^ ERROR: function takes 0 generic arguments but 1 generic argument was supplied + <() as Bar<true>>::bar(); + //~^ ERROR: trait takes 0 generic arguments but 1 generic argument was supplied +} + +const FOO: () = { + foo::<false>(); + //~^ ERROR: function takes 0 generic arguments but 1 generic argument was supplied + <() as Bar<false>>::bar(); + //~^ ERROR: trait takes 0 generic arguments but 1 generic argument was supplied +}; diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/no-explicit-const-params-cross-crate.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/no-explicit-const-params-cross-crate.stderr new file mode 100644 index 00000000000..cc870ad336c --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/no-explicit-const-params-cross-crate.stderr @@ -0,0 +1,59 @@ +error[E0107]: function takes 0 generic arguments but 1 generic argument was supplied + --> $DIR/no-explicit-const-params-cross-crate.rs:14:5 + | +LL | foo::<false>(); + | ^^^--------- help: remove these generics + | | + | expected 0 generic arguments + | +note: function defined here, with 0 generic parameters + --> $DIR/auxiliary/cross-crate.rs:3:14 + | +LL | pub const fn foo() {} + | ^^^ + +error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplied + --> $DIR/no-explicit-const-params-cross-crate.rs:16:12 + | +LL | <() as Bar<false>>::bar(); + | ^^^------- help: remove these generics + | | + | expected 0 generic arguments + | +note: trait defined here, with 0 generic parameters + --> $DIR/auxiliary/cross-crate.rs:6:11 + | +LL | pub trait Bar { + | ^^^ + +error[E0107]: function takes 0 generic arguments but 1 generic argument was supplied + --> $DIR/no-explicit-const-params-cross-crate.rs:7:5 + | +LL | foo::<true>(); + | ^^^-------- help: remove these generics + | | + | expected 0 generic arguments + | +note: function defined here, with 0 generic parameters + --> $DIR/auxiliary/cross-crate.rs:3:14 + | +LL | pub const fn foo() {} + | ^^^ + +error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplied + --> $DIR/no-explicit-const-params-cross-crate.rs:9:12 + | +LL | <() as Bar<true>>::bar(); + | ^^^------ help: remove these generics + | | + | expected 0 generic arguments + | +note: trait defined here, with 0 generic parameters + --> $DIR/auxiliary/cross-crate.rs:6:11 + | +LL | pub trait Bar { + | ^^^ + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0107`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/no-explicit-const-params.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/no-explicit-const-params.rs new file mode 100644 index 00000000000..929da1ca8fa --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/no-explicit-const-params.rs @@ -0,0 +1,27 @@ +#![feature(const_trait_impl, effects)] + +const fn foo() {} + +#[const_trait] +trait Bar { + fn bar(); +} + +impl Bar for () { + fn bar() {} +} + +fn main() { + foo::<true>(); + //~^ ERROR: function takes 0 generic arguments but 1 generic argument was supplied + <() as Bar<true>>::bar(); + //~^ ERROR: trait takes 0 generic arguments but 1 generic argument was supplied +} + +const FOO: () = { + foo::<false>(); + //~^ ERROR: function takes 0 generic arguments but 1 generic argument was supplied + <() as Bar<false>>::bar(); + //~^ ERROR: trait takes 0 generic arguments but 1 generic argument was supplied + //~| ERROR: mismatched types +}; diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/no-explicit-const-params.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/no-explicit-const-params.stderr new file mode 100644 index 00000000000..0745d0304b9 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/no-explicit-const-params.stderr @@ -0,0 +1,69 @@ +error[E0107]: function takes 0 generic arguments but 1 generic argument was supplied + --> $DIR/no-explicit-const-params.rs:22:5 + | +LL | foo::<false>(); + | ^^^--------- help: remove these generics + | | + | expected 0 generic arguments + | +note: function defined here, with 0 generic parameters + --> $DIR/no-explicit-const-params.rs:3:10 + | +LL | const fn foo() {} + | ^^^ + +error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplied + --> $DIR/no-explicit-const-params.rs:24:12 + | +LL | <() as Bar<false>>::bar(); + | ^^^------- help: remove these generics + | | + | expected 0 generic arguments + | +note: trait defined here, with 0 generic parameters + --> $DIR/no-explicit-const-params.rs:6:7 + | +LL | trait Bar { + | ^^^ + +error[E0308]: mismatched types + --> $DIR/no-explicit-const-params.rs:24:5 + | +LL | <() as Bar<false>>::bar(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ expected `false`, found `true` + | + = note: expected constant `false` + found constant `true` + +error[E0107]: function takes 0 generic arguments but 1 generic argument was supplied + --> $DIR/no-explicit-const-params.rs:15:5 + | +LL | foo::<true>(); + | ^^^-------- help: remove these generics + | | + | expected 0 generic arguments + | +note: function defined here, with 0 generic parameters + --> $DIR/no-explicit-const-params.rs:3:10 + | +LL | const fn foo() {} + | ^^^ + +error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplied + --> $DIR/no-explicit-const-params.rs:17:12 + | +LL | <() as Bar<true>>::bar(); + | ^^^------ help: remove these generics + | | + | expected 0 generic arguments + | +note: trait defined here, with 0 generic parameters + --> $DIR/no-explicit-const-params.rs:6:7 + | +LL | trait Bar { + | ^^^ + +error: aborting due to 5 previous errors + +Some errors have detailed explanations: E0107, E0308. +For more information about an error, try `rustc --explain E0107`. 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/sized/unsized-binding.rs b/tests/ui/sized/unsized-binding.rs new file mode 100644 index 00000000000..3b99b0f6e96 --- /dev/null +++ b/tests/ui/sized/unsized-binding.rs @@ -0,0 +1,5 @@ +fn main() { + let x = *""; //~ ERROR E0277 + println!("{}", x); + println!("{}", x); +} diff --git a/tests/ui/sized/unsized-binding.stderr b/tests/ui/sized/unsized-binding.stderr new file mode 100644 index 00000000000..af306685021 --- /dev/null +++ b/tests/ui/sized/unsized-binding.stderr @@ -0,0 +1,13 @@ +error[E0277]: the size for values of type `str` cannot be known at compilation time + --> $DIR/unsized-binding.rs:2:9 + | +LL | let x = *""; + | ^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `str` + = note: all local variables must have a statically known size + = help: unsized locals are gated as an unstable feature + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/span/issue-43927-non-ADT-derive.stderr b/tests/ui/span/issue-43927-non-ADT-derive.stderr index e3ae37e3689..a22a4d2b40a 100644 --- a/tests/ui/span/issue-43927-non-ADT-derive.stderr +++ b/tests/ui/span/issue-43927-non-ADT-derive.stderr @@ -11,11 +11,15 @@ error: `derive` attribute cannot be used at crate level | LL | #![derive(Debug, PartialEq, Eq)] // should be an outer attribute! | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | struct DerivedOn; + | --------- the inner attribute doesn't annotate this struct | help: perhaps you meant to use an outer attribute | -LL | #[derive(Debug, PartialEq, Eq)] // should be an outer attribute! - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +LL - #![derive(Debug, PartialEq, Eq)] // should be an outer attribute! +LL + #[derive(Debug, PartialEq, Eq)] // should be an outer attribute! + | error: aborting due to 2 previous errors 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-sanity.rs b/tests/ui/stability-attribute/stability-attribute-sanity.rs index 7b3a7b537c1..8258b6f5ae0 100644 --- a/tests/ui/stability-attribute/stability-attribute-sanity.rs +++ b/tests/ui/stability-attribute/stability-attribute-sanity.rs @@ -60,10 +60,9 @@ fn multiple3() { } #[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 -//~^ ERROR deprecated attribute must be paired with either stable or unstable attribute #[rustc_const_unstable(feature = "c", issue = "none")] #[rustc_const_unstable(feature = "d", issue = "none")] //~ ERROR multiple stability levels -pub const fn multiple4() { } //~ ERROR function has missing stability attribute +pub const fn multiple4() { } #[stable(feature = "a", since = "1.0.0")] //~ ERROR invalid deprecation version found //~^ ERROR feature `a` is declared stable since 1.0.0 diff --git a/tests/ui/stability-attribute/stability-attribute-sanity.stderr b/tests/ui/stability-attribute/stability-attribute-sanity.stderr index f9610c90f76..955230742bd 100644 --- a/tests/ui/stability-attribute/stability-attribute-sanity.stderr +++ b/tests/ui/stability-attribute/stability-attribute-sanity.stderr @@ -101,19 +101,13 @@ LL | #[stable(feature = "e", since = "b")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0544]: multiple stability levels - --> $DIR/stability-attribute-sanity.rs:65:1 + --> $DIR/stability-attribute-sanity.rs:64:1 | LL | #[rustc_const_unstable(feature = "d", issue = "none")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0549]: deprecated attribute must be paired with either stable or unstable attribute - --> $DIR/stability-attribute-sanity.rs:62:1 - | -LL | #[deprecated(since = "b", note = "text")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - error: invalid deprecation version found - --> $DIR/stability-attribute-sanity.rs:68:1 + --> $DIR/stability-attribute-sanity.rs:67:1 | LL | #[stable(feature = "a", since = "1.0.0")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid deprecation version @@ -122,24 +116,18 @@ LL | fn invalid_deprecation_version() {} | ----------------------------------- the stability attribute annotates this item error[E0549]: deprecated attribute must be paired with either stable or unstable attribute - --> $DIR/stability-attribute-sanity.rs:73:1 + --> $DIR/stability-attribute-sanity.rs:72:1 | LL | #[deprecated(since = "a", note = "text")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: function has missing stability attribute - --> $DIR/stability-attribute-sanity.rs:66:1 - | -LL | pub const fn multiple4() { } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - 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:68:1 + --> $DIR/stability-attribute-sanity.rs:67:1 | LL | #[stable(feature = "a", since = "1.0.0")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 22 previous errors +error: aborting due to 20 previous errors Some errors have detailed explanations: E0539, E0541, E0542, E0543, E0544, E0546, E0547, E0549, E0711. For more information about an error, try `rustc --explain E0539`. 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/auto-trait-leakage3.rs b/tests/ui/type-alias-impl-trait/auto-trait-leakage3.rs index 660950d5906..cad75cffe05 100644 --- a/tests/ui/type-alias-impl-trait/auto-trait-leakage3.rs +++ b/tests/ui/type-alias-impl-trait/auto-trait-leakage3.rs @@ -5,9 +5,6 @@ mod m { pub type Foo = impl std::fmt::Debug; - //~^ ERROR: cycle detected when computing type of opaque `m::Foo::{opaque#0}` [E0391] - //~| ERROR: cycle detected when computing type of opaque `m::Foo::{opaque#0}` [E0391] - pub fn foo() -> Foo { 22_u32 } diff --git a/tests/ui/type-alias-impl-trait/auto-trait-leakage3.stderr b/tests/ui/type-alias-impl-trait/auto-trait-leakage3.stderr index d8698826660..d47b1fe3678 100644 --- a/tests/ui/type-alias-impl-trait/auto-trait-leakage3.stderr +++ b/tests/ui/type-alias-impl-trait/auto-trait-leakage3.stderr @@ -1,44 +1,5 @@ -error[E0391]: cycle detected when computing type of opaque `m::Foo::{opaque#0}` - --> $DIR/auto-trait-leakage3.rs:7:20 - | -LL | pub type Foo = impl std::fmt::Debug; - | ^^^^^^^^^^^^^^^^^^^^ - | -note: ...which requires type-checking `m::bar`... - --> $DIR/auto-trait-leakage3.rs:16:9 - | -LL | is_send(foo()); - | ^^^^^^^ - = note: ...which requires evaluating trait selection obligation `m::Foo: core::marker::Send`... - = note: ...which again requires computing type of opaque `m::Foo::{opaque#0}`, completing the cycle -note: cycle used when computing type of `m::Foo::{opaque#0}` - --> $DIR/auto-trait-leakage3.rs:7:20 - | -LL | pub type Foo = impl std::fmt::Debug; - | ^^^^^^^^^^^^^^^^^^^^ - = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information - -error[E0391]: cycle detected when computing type of opaque `m::Foo::{opaque#0}` - --> $DIR/auto-trait-leakage3.rs:7:20 - | -LL | pub type Foo = impl std::fmt::Debug; - | ^^^^^^^^^^^^^^^^^^^^ - | -note: ...which requires type-checking `m::bar`... - --> $DIR/auto-trait-leakage3.rs:15:5 - | -LL | pub fn bar() { - | ^^^^^^^^^^^^ - = note: ...which again requires computing type of opaque `m::Foo::{opaque#0}`, completing the cycle -note: cycle used when computing type of `m::Foo::{opaque#0}` - --> $DIR/auto-trait-leakage3.rs:7:20 - | -LL | pub type Foo = impl std::fmt::Debug; - | ^^^^^^^^^^^^^^^^^^^^ - = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information - error: cannot check whether the hidden type of `auto_trait_leakage3[211d]::m::Foo::{opaque#0}` satisfies auto traits - --> $DIR/auto-trait-leakage3.rs:16:17 + --> $DIR/auto-trait-leakage3.rs:13:17 | LL | is_send(foo()); | ------- ^^^^^ @@ -51,16 +12,15 @@ note: opaque type is declared here LL | pub type Foo = impl std::fmt::Debug; | ^^^^^^^^^^^^^^^^^^^^ note: this item depends on auto traits of the hidden type, but may also be registering the hidden type. This is not supported right now. You can try moving the opaque type and the item that actually registers a hidden type into a new submodule - --> $DIR/auto-trait-leakage3.rs:15:12 + --> $DIR/auto-trait-leakage3.rs:12:12 | LL | pub fn bar() { | ^^^ note: required by a bound in `is_send` - --> $DIR/auto-trait-leakage3.rs:20:19 + --> $DIR/auto-trait-leakage3.rs:17:19 | LL | fn is_send<T: Send>(_: T) {} | ^^^^ required by this bound in `is_send` -error: aborting due to 3 previous errors +error: aborting due to previous error -For more information about this error, try `rustc --explain E0391`. 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/inference-cycle.rs b/tests/ui/type-alias-impl-trait/inference-cycle.rs index 20175a4feca..6e4507ed460 100644 --- a/tests/ui/type-alias-impl-trait/inference-cycle.rs +++ b/tests/ui/type-alias-impl-trait/inference-cycle.rs @@ -3,17 +3,14 @@ mod m { pub type Foo = impl std::fmt::Debug; - //~^ ERROR cycle detected - //~| ERROR cycle detected - - // Cycle: error today, but it'd be nice if it eventually worked pub fn foo() -> Foo { is_send(bar()) } pub fn bar() { - is_send(foo()); // Today: error + // Cycle: error today, but it'd be nice if it eventually worked + is_send(foo()); //~^ ERROR: cannot check whether the hidden type of `inference_cycle[4ecc]::m::Foo::{opaque#0}` satisfies auto traits } diff --git a/tests/ui/type-alias-impl-trait/inference-cycle.stderr b/tests/ui/type-alias-impl-trait/inference-cycle.stderr index 4ab059d054b..ef7abe58864 100644 --- a/tests/ui/type-alias-impl-trait/inference-cycle.stderr +++ b/tests/ui/type-alias-impl-trait/inference-cycle.stderr @@ -1,46 +1,7 @@ -error[E0391]: cycle detected when computing type of opaque `m::Foo::{opaque#0}` - --> $DIR/inference-cycle.rs:5:20 - | -LL | pub type Foo = impl std::fmt::Debug; - | ^^^^^^^^^^^^^^^^^^^^ - | -note: ...which requires type-checking `m::bar`... - --> $DIR/inference-cycle.rs:16:9 - | -LL | is_send(foo()); // Today: error - | ^^^^^^^ - = note: ...which requires evaluating trait selection obligation `m::Foo: core::marker::Send`... - = note: ...which again requires computing type of opaque `m::Foo::{opaque#0}`, completing the cycle -note: cycle used when computing type of `m::Foo::{opaque#0}` - --> $DIR/inference-cycle.rs:5:20 - | -LL | pub type Foo = impl std::fmt::Debug; - | ^^^^^^^^^^^^^^^^^^^^ - = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information - -error[E0391]: cycle detected when computing type of opaque `m::Foo::{opaque#0}` - --> $DIR/inference-cycle.rs:5:20 - | -LL | pub type Foo = impl std::fmt::Debug; - | ^^^^^^^^^^^^^^^^^^^^ - | -note: ...which requires type-checking `m::bar`... - --> $DIR/inference-cycle.rs:15:5 - | -LL | pub fn bar() { - | ^^^^^^^^^^^^ - = note: ...which again requires computing type of opaque `m::Foo::{opaque#0}`, completing the cycle -note: cycle used when computing type of `m::Foo::{opaque#0}` - --> $DIR/inference-cycle.rs:5:20 - | -LL | pub type Foo = impl std::fmt::Debug; - | ^^^^^^^^^^^^^^^^^^^^ - = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information - error: cannot check whether the hidden type of `inference_cycle[4ecc]::m::Foo::{opaque#0}` satisfies auto traits - --> $DIR/inference-cycle.rs:16:17 + --> $DIR/inference-cycle.rs:13:17 | -LL | is_send(foo()); // Today: error +LL | is_send(foo()); | ------- ^^^^^ | | | required by a bound introduced by this call @@ -51,16 +12,15 @@ note: opaque type is declared here LL | pub type Foo = impl std::fmt::Debug; | ^^^^^^^^^^^^^^^^^^^^ note: this item depends on auto traits of the hidden type, but may also be registering the hidden type. This is not supported right now. You can try moving the opaque type and the item that actually registers a hidden type into a new submodule - --> $DIR/inference-cycle.rs:15:12 + --> $DIR/inference-cycle.rs:11:12 | LL | pub fn bar() { | ^^^ note: required by a bound in `is_send` - --> $DIR/inference-cycle.rs:24:19 + --> $DIR/inference-cycle.rs:21:19 | LL | fn is_send<T: Send>(_: T) {} | ^^^^ required by this bound in `is_send` -error: aborting due to 3 previous errors +error: aborting due to previous error -For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/type-alias-impl-trait/issue-96572-unconstrained.rs b/tests/ui/type-alias-impl-trait/issue-96572-unconstrained.rs index fdd8fa65bd0..5bd854be8c6 100644 --- a/tests/ui/type-alias-impl-trait/issue-96572-unconstrained.rs +++ b/tests/ui/type-alias-impl-trait/issue-96572-unconstrained.rs @@ -26,11 +26,9 @@ fn upvar() { fn enum_upvar() { type T = impl Copy; let foo: T = Some((1u32, 2u32)); - let x = move || { - match foo { - None => (), - Some((a, b)) => (), - } + let x = move || match foo { + None => (), + Some((a, b)) => (), }; } @@ -63,6 +61,19 @@ mod only_pattern { None => {} } } + + type V = impl Copy; + + fn baz(baz: Option<V>) { + match baz { + _ => {} + Some((mut x, mut y)) => { + x = 42; + y = "foo"; + } + None => {} + } + } } mod only_pattern_rpit { @@ -71,11 +82,7 @@ mod only_pattern_rpit { let (mut x, mut y) = foo(false); x = 42; y = "foo"; - if b { - panic!() - } else { - foo(true) - } + if b { panic!() } else { foo(true) } } fn bar(b: bool) -> Option<impl Copy> { 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/type-alias-impl-trait/reveal_local.rs b/tests/ui/type-alias-impl-trait/reveal_local.rs index 7943bb240f1..07fd989b0fa 100644 --- a/tests/ui/type-alias-impl-trait/reveal_local.rs +++ b/tests/ui/type-alias-impl-trait/reveal_local.rs @@ -3,9 +3,6 @@ use std::fmt::Debug; type Foo = impl Debug; -//~^ ERROR cycle detected -//~| ERROR cycle detected -//~| ERROR cycle detected fn is_send<T: Send>() {} diff --git a/tests/ui/type-alias-impl-trait/reveal_local.stderr b/tests/ui/type-alias-impl-trait/reveal_local.stderr index c62fd88f4e2..796e2d011dc 100644 --- a/tests/ui/type-alias-impl-trait/reveal_local.stderr +++ b/tests/ui/type-alias-impl-trait/reveal_local.stderr @@ -1,44 +1,5 @@ -error[E0391]: cycle detected when computing type of opaque `Foo::{opaque#0}` - --> $DIR/reveal_local.rs:5:12 - | -LL | type Foo = impl Debug; - | ^^^^^^^^^^ - | -note: ...which requires type-checking `not_good`... - --> $DIR/reveal_local.rs:15:5 - | -LL | is_send::<Foo>(); - | ^^^^^^^^^^^^^^ - = note: ...which requires evaluating trait selection obligation `Foo: core::marker::Send`... - = note: ...which again requires computing type of opaque `Foo::{opaque#0}`, completing the cycle -note: cycle used when computing type of `Foo::{opaque#0}` - --> $DIR/reveal_local.rs:5:12 - | -LL | type Foo = impl Debug; - | ^^^^^^^^^^ - = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information - -error[E0391]: cycle detected when computing type of opaque `Foo::{opaque#0}` - --> $DIR/reveal_local.rs:5:12 - | -LL | type Foo = impl Debug; - | ^^^^^^^^^^ - | -note: ...which requires type-checking `not_good`... - --> $DIR/reveal_local.rs:12:1 - | -LL | fn not_good() { - | ^^^^^^^^^^^^^ - = note: ...which again requires computing type of opaque `Foo::{opaque#0}`, completing the cycle -note: cycle used when computing type of `Foo::{opaque#0}` - --> $DIR/reveal_local.rs:5:12 - | -LL | type Foo = impl Debug; - | ^^^^^^^^^^ - = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information - error: cannot check whether the hidden type of `reveal_local[9507]::Foo::{opaque#0}` satisfies auto traits - --> $DIR/reveal_local.rs:15:15 + --> $DIR/reveal_local.rs:12:15 | LL | is_send::<Foo>(); | ^^^ @@ -49,37 +10,18 @@ note: opaque type is declared here LL | type Foo = impl Debug; | ^^^^^^^^^^ note: this item depends on auto traits of the hidden type, but may also be registering the hidden type. This is not supported right now. You can try moving the opaque type and the item that actually registers a hidden type into a new submodule - --> $DIR/reveal_local.rs:12:4 + --> $DIR/reveal_local.rs:9:4 | LL | fn not_good() { | ^^^^^^^^ note: required by a bound in `is_send` - --> $DIR/reveal_local.rs:10:15 + --> $DIR/reveal_local.rs:7:15 | LL | fn is_send<T: Send>() {} | ^^^^ required by this bound in `is_send` -error[E0391]: cycle detected when computing type of opaque `Foo::{opaque#0}` - --> $DIR/reveal_local.rs:5:12 - | -LL | type Foo = impl Debug; - | ^^^^^^^^^^ - | -note: ...which requires type-checking `not_gooder`... - --> $DIR/reveal_local.rs:19:1 - | -LL | fn not_gooder() -> Foo { - | ^^^^^^^^^^^^^^^^^^^^^^ - = note: ...which again requires computing type of opaque `Foo::{opaque#0}`, completing the cycle -note: cycle used when computing type of `Foo::{opaque#0}` - --> $DIR/reveal_local.rs:5:12 - | -LL | type Foo = impl Debug; - | ^^^^^^^^^^ - = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information - error: cannot check whether the hidden type of `reveal_local[9507]::Foo::{opaque#0}` satisfies auto traits - --> $DIR/reveal_local.rs:25:15 + --> $DIR/reveal_local.rs:22:15 | LL | is_send::<Foo>(); | ^^^ @@ -90,16 +32,15 @@ note: opaque type is declared here LL | type Foo = impl Debug; | ^^^^^^^^^^ note: this item depends on auto traits of the hidden type, but may also be registering the hidden type. This is not supported right now. You can try moving the opaque type and the item that actually registers a hidden type into a new submodule - --> $DIR/reveal_local.rs:19:4 + --> $DIR/reveal_local.rs:16:4 | LL | fn not_gooder() -> Foo { | ^^^^^^^^^^ note: required by a bound in `is_send` - --> $DIR/reveal_local.rs:10:15 + --> $DIR/reveal_local.rs:7:15 | LL | fn is_send<T: Send>() {} | ^^^^ required by this bound in `is_send` -error: aborting due to 5 previous errors +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/type/type-check/issue-116967-cannot-coerce-returned-result.rs b/tests/ui/type/type-check/issue-116967-cannot-coerce-returned-result.rs new file mode 100644 index 00000000000..adf3049b4ba --- /dev/null +++ b/tests/ui/type/type-check/issue-116967-cannot-coerce-returned-result.rs @@ -0,0 +1,6 @@ +fn foo() -> Result<String, ()> { + let out: Result<(), ()> = Ok(()); + out //~ ERROR mismatched types +} + +fn main() {} diff --git a/tests/ui/type/type-check/issue-116967-cannot-coerce-returned-result.stderr b/tests/ui/type/type-check/issue-116967-cannot-coerce-returned-result.stderr new file mode 100644 index 00000000000..447b22a152d --- /dev/null +++ b/tests/ui/type/type-check/issue-116967-cannot-coerce-returned-result.stderr @@ -0,0 +1,15 @@ +error[E0308]: mismatched types + --> $DIR/issue-116967-cannot-coerce-returned-result.rs:3:5 + | +LL | fn foo() -> Result<String, ()> { + | ------------------ expected `Result<String, ()>` because of return type +LL | let out: Result<(), ()> = Ok(()); +LL | out + | ^^^ expected `Result<String, ()>`, found `Result<(), ()>` + | + = note: expected enum `Result<String, _>` + found enum `Result<(), _>` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. 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/uninhabited/diverging-guard.rs b/tests/ui/uninhabited/diverging-guard.rs new file mode 100644 index 00000000000..7d57cd51c2d --- /dev/null +++ b/tests/ui/uninhabited/diverging-guard.rs @@ -0,0 +1,10 @@ +// check-pass + +enum Void {} + +fn main() { + let x: Void; + match x { + _ if { loop {} } => (), + } +} 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`. diff --git a/triagebot.toml b/triagebot.toml index dc378d52e92..d40ae9cb020 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -621,6 +621,7 @@ compiler-team = [ compiler-team-contributors = [ "@compiler-errors", "@jackh726", + "@TaKO8Ki", "@WaffleLapkin", "@b-naber", ] @@ -667,6 +668,7 @@ diagnostics = [ "@compiler-errors", "@davidtwco", "@oli-obk", + "@TaKO8Ki", ] parser = [ "@compiler-errors", |
