diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 63e20b16f7a01..19b5c8689c840 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -334,35 +334,7 @@ fn do_mir_borrowck<'tcx>( mbcx.gather_used_muts(temporary_used_locals, unused_mut_locals); debug!("mbcx.used_mut: {:?}", mbcx.used_mut); - let used_mut = std::mem::take(&mut mbcx.used_mut); - for local in mbcx.body.mut_vars_and_args_iter().filter(|local| !used_mut.contains(local)) { - let local_decl = &mbcx.body.local_decls[local]; - let lint_root = match &mbcx.body.source_scopes[local_decl.source_info.scope].local_data { - ClearCrossCrate::Set(data) => data.lint_root, - _ => continue, - }; - - // Skip over locals that begin with an underscore or have no name - match mbcx.local_names[local] { - Some(name) => { - if name.as_str().starts_with('_') { - continue; - } - } - None => continue, - } - - let span = local_decl.source_info.span; - if span.desugaring_kind().is_some() { - // If the `mut` arises as part of a desugaring, we should ignore it. - continue; - } - - let mut_span = tcx.sess.source_map().span_until_non_whitespace(span); - - tcx.emit_node_span_lint(UNUSED_MUT, lint_root, span, VarNeedNotMut { span: mut_span }) - } - + mbcx.lint_unused_mut(); let tainted_by_errors = mbcx.emit_errors(); let result = BorrowCheckResult { @@ -2390,6 +2362,38 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { // `BasicBlocks` computes dominators on-demand and caches them. self.body.basic_blocks.dominators() } + + fn lint_unused_mut(&self) { + let tcx = self.infcx.tcx; + let body = self.body; + for local in body.mut_vars_and_args_iter().filter(|local| !self.used_mut.contains(local)) { + let local_decl = &body.local_decls[local]; + let lint_root = match &body.source_scopes[local_decl.source_info.scope].local_data { + ClearCrossCrate::Set(data) => data.lint_root, + _ => continue, + }; + + // Skip over locals that begin with an underscore or have no name + match self.local_names[local] { + Some(name) => { + if name.as_str().starts_with('_') { + continue; + } + } + None => continue, + } + + let span = local_decl.source_info.span; + if span.desugaring_kind().is_some() { + // If the `mut` arises as part of a desugaring, we should ignore it. + continue; + } + + let mut_span = tcx.sess.source_map().span_until_non_whitespace(span); + + tcx.emit_node_span_lint(UNUSED_MUT, lint_root, span, VarNeedNotMut { span: mut_span }) + } + } } mod diags { diff --git a/compiler/rustc_codegen_cranelift/src/compiler_builtins.rs b/compiler/rustc_codegen_cranelift/src/compiler_builtins.rs index 4154a62234c12..f8e3a034421da 100644 --- a/compiler/rustc_codegen_cranelift/src/compiler_builtins.rs +++ b/compiler/rustc_codegen_cranelift/src/compiler_builtins.rs @@ -3,7 +3,7 @@ use std::ffi::c_int; #[cfg(feature = "jit")] use std::ffi::c_void; -// FIXME replace with core::ffi::c_size_t once stablized +// FIXME replace with core::ffi::c_size_t once stabilized #[allow(non_camel_case_types)] #[cfg(feature = "jit")] type size_t = usize; diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs index 69326f409bb3e..78ec9741f5781 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs @@ -66,7 +66,7 @@ fn get_simple_intrinsic<'gcc, 'tcx>( sym::log2f64 => "log2", sym::fmaf32 => "fmaf", sym::fmaf64 => "fma", - // FIXME: calling `fma` from libc without FMA target feature uses expensive sofware emulation + // FIXME: calling `fma` from libc without FMA target feature uses expensive software emulation sym::fmuladdf32 => "fmaf", // TODO: use gcc intrinsic analogous to llvm.fmuladd.f32 sym::fmuladdf64 => "fma", // TODO: use gcc intrinsic analogous to llvm.fmuladd.f64 sym::fabsf32 => "fabsf", diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index ac2f91cdeb3fe..f63188402fe78 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -2523,7 +2523,7 @@ impl HumanEmitter { buffer.puts(*row_num, max_line_num_len + 1, "+ ", Style::Addition); } [] => { - // FIXME: needed? Doesn't get excercised in any test. + // FIXME: needed? Doesn't get exercised in any test. self.draw_col_separator_no_space(buffer, *row_num, max_line_num_len + 1); } _ => { diff --git a/compiler/rustc_errors/src/markdown/parse.rs b/compiler/rustc_errors/src/markdown/parse.rs index 8dd146c1c337f..7a991a2ace71b 100644 --- a/compiler/rustc_errors/src/markdown/parse.rs +++ b/compiler/rustc_errors/src/markdown/parse.rs @@ -346,7 +346,7 @@ fn parse_with_end_pat<'a>( None } -/// Resturn `(match, residual)` to end of line. The EOL is returned with the +/// Return `(match, residual)` to end of line. The EOL is returned with the /// residual. fn parse_to_newline(buf: &[u8]) -> (&[u8], &[u8]) { buf.iter().position(|ch| *ch == b'\n').map_or((buf, &[]), |pos| buf.split_at(pos)) diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index 21fd11c1c5da3..5a9b8c43e7468 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -178,6 +178,8 @@ declare_features! ( (accepted, destructuring_assignment, "1.59.0", Some(71126)), /// Allows using the `#[diagnostic]` attribute tool namespace (accepted, diagnostic_namespace, "1.78.0", Some(111996)), + /// Controls errors in trait implementations. + (accepted, do_not_recommend, "CURRENT_RUSTC_VERSION", Some(51992)), /// Allows `#[doc(alias = "...")]`. (accepted, doc_alias, "1.48.0", Some(50146)), /// Allows `..` in tuple (struct) patterns. diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index a065db7f7d0f7..4b9f62fa764c0 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -1187,10 +1187,9 @@ pub static BUILTIN_ATTRIBUTE_MAP: LazyLock> map }); -pub fn is_stable_diagnostic_attribute(sym: Symbol, features: &Features) -> bool { +pub fn is_stable_diagnostic_attribute(sym: Symbol, _features: &Features) -> bool { match sym { - sym::on_unimplemented => true, - sym::do_not_recommend => features.do_not_recommend(), + sym::on_unimplemented | sym::do_not_recommend => true, _ => false, } } diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 6570f9b565fff..ebb07195a2850 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -462,8 +462,6 @@ declare_features! ( (unstable, deprecated_suggestion, "1.61.0", Some(94785)), /// Allows deref patterns. (incomplete, deref_patterns, "1.79.0", Some(87121)), - /// Controls errors in trait implementations. - (unstable, do_not_recommend, "1.67.0", Some(51992)), /// Tells rustdoc to automatically generate `#[doc(cfg(...))]`. (unstable, doc_auto_cfg, "1.58.0", Some(43781)), /// Allows `#[doc(cfg(...))]`. diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index d6948081505ca..364499378b0eb 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -146,18 +146,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!("write_ty({:?}, {:?}) in fcx {}", id, self.resolve_vars_if_possible(ty), self.tag()); let mut typeck = self.typeck_results.borrow_mut(); let mut node_ty = typeck.node_types_mut(); - if let Some(ty) = node_ty.get(id) - && let Err(e) = ty.error_reported() - { - // Do not overwrite nodes that were already marked as `{type error}`. This allows us to - // silence unnecessary errors from obligations that were set earlier than a type error - // was produced, but that is overwritten by later analysis. This happens in particular - // for `Sized` obligations introduced in gather_locals. (#117846) - self.set_tainted_by_errors(e); - return; - } - node_ty.insert(id, ty); + if let Some(prev) = node_ty.insert(id, ty) { + if prev.references_error() { + node_ty.insert(id, prev); + } else if !ty.references_error() { + // Could change this to a bug, but there's lots of diagnostic code re-lowering + // or re-typechecking nodes that were already typecked. + // Lots of that diagnostics code relies on subtle effects of re-lowering, so we'll + // let it keep doing that and just ensure that compilation won't succeed. + self.dcx().span_delayed_bug( + self.tcx.hir().span(id), + format!("`{prev}` overridden by `{ty}` for {id:?} in {:?}", self.body_id), + ); + } + } if let Err(e) = ty.error_reported() { self.set_tainted_by_errors(e); @@ -1104,7 +1107,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let Res::Local(hid) = res { let ty = self.local_ty(span, hid); let ty = self.normalize(span, ty); - self.write_ty(hir_id, ty); return (ty, res); } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index c1f08d237eb36..fffea8f640b81 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -1750,10 +1750,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - pub(in super::super) fn check_decl(&self, decl: Declaration<'tcx>) { + pub(in super::super) fn check_decl(&self, decl: Declaration<'tcx>) -> Ty<'tcx> { // Determine and write the type which we'll check the pattern against. let decl_ty = self.local_ty(decl.span, decl.hir_id); - self.write_ty(decl.hir_id, decl_ty); // Type check the initializer. if let Some(ref init) = decl.init { @@ -1785,11 +1784,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } self.diverges.set(previous_diverges); } + decl_ty } /// Type check a `let` statement. fn check_decl_local(&self, local: &'tcx hir::LetStmt<'tcx>) { - self.check_decl(local.into()); + let ty = self.check_decl(local.into()); + self.write_ty(local.hir_id, ty); if local.pat.is_never_pattern() { self.diverges.set(Diverges::Always { span: local.pat.span, diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 25d0d7b71da6f..830ae7dd00a6a 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -971,7 +971,7 @@ pub struct ParamEnv<'tcx> { } impl<'tcx> rustc_type_ir::inherent::ParamEnv> for ParamEnv<'tcx> { - fn caller_bounds(self) -> impl IntoIterator> { + fn caller_bounds(self) -> impl inherent::SliceLike> { self.caller_bounds() } } diff --git a/compiler/rustc_next_trait_solver/src/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonicalizer.rs index 63608f9e85615..2f7301d8fe515 100644 --- a/compiler/rustc_next_trait_solver/src/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonicalizer.rs @@ -3,6 +3,7 @@ use std::cmp::Ordering; use rustc_type_ir::data_structures::HashMap; use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; use rustc_type_ir::inherent::*; +use rustc_type_ir::solve::{Goal, QueryInput}; use rustc_type_ir::visit::TypeVisitableExt; use rustc_type_ir::{ self as ty, Canonical, CanonicalTyVarKind, CanonicalVarInfo, CanonicalVarKind, InferCtxtLike, @@ -17,8 +18,11 @@ use crate::delegate::SolverDelegate; /// while canonicalizing the response happens in the context of the /// query. #[derive(Debug, Clone, Copy)] -pub enum CanonicalizeMode { - Input, +enum CanonicalizeMode { + /// When canonicalizing the `param_env`, we keep `'static` as merging + /// trait candidates relies on it when deciding whether a where-bound + /// is trivial. + Input { keep_static: bool }, /// FIXME: We currently return region constraints referring to /// placeholders and inference variables from a binder instantiated /// inside of the query. @@ -59,15 +63,15 @@ pub struct Canonicalizer<'a, D: SolverDelegate, I: Interner> { } impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { - pub fn canonicalize>( + pub fn canonicalize_response>( delegate: &'a D, - canonicalize_mode: CanonicalizeMode, + max_input_universe: ty::UniverseIndex, variables: &'a mut Vec, value: T, ) -> ty::Canonical { let mut canonicalizer = Canonicalizer { delegate, - canonicalize_mode, + canonicalize_mode: CanonicalizeMode::Response { max_input_universe }, variables, variable_lookup_table: Default::default(), @@ -80,9 +84,67 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { let value = value.fold_with(&mut canonicalizer); assert!(!value.has_infer(), "unexpected infer in {value:?}"); assert!(!value.has_placeholders(), "unexpected placeholders in {value:?}"); - let (max_universe, variables) = canonicalizer.finalize(); + Canonical { max_universe, variables, value } + } + + /// When canonicalizing query inputs, we keep `'static` in the `param_env` + /// but erase it everywhere else. We generally don't want to depend on region + /// identity, so while it should not matter whether `'static` is kept in the + /// value or opaque type storage as well, this prevents us from accidentally + /// relying on it in the future. + /// + /// We want to keep the option of canonicalizing `'static` to an existential + /// variable in the future by changing the way we detect global where-bounds. + pub fn canonicalize_input>( + delegate: &'a D, + variables: &'a mut Vec, + input: QueryInput, + ) -> ty::Canonical> { + // First canonicalize the `param_env` while keeping `'static` + let mut env_canonicalizer = Canonicalizer { + delegate, + canonicalize_mode: CanonicalizeMode::Input { keep_static: true }, + + variables, + variable_lookup_table: Default::default(), + primitive_var_infos: Vec::new(), + binder_index: ty::INNERMOST, + + cache: Default::default(), + }; + let param_env = input.goal.param_env.fold_with(&mut env_canonicalizer); + debug_assert_eq!(env_canonicalizer.binder_index, ty::INNERMOST); + // Then canonicalize the rest of the input without keeping `'static` + // while *mostly* reusing the canonicalizer from above. + let mut rest_canonicalizer = Canonicalizer { + delegate, + canonicalize_mode: CanonicalizeMode::Input { keep_static: false }, + + variables: env_canonicalizer.variables, + // We're able to reuse the `variable_lookup_table` as whether or not + // it already contains an entry for `'static` does not matter. + variable_lookup_table: env_canonicalizer.variable_lookup_table, + primitive_var_infos: env_canonicalizer.primitive_var_infos, + binder_index: ty::INNERMOST, + // We do not reuse the cache as it may contain entries whose canonicalized + // value contains `'static`. While we could alternatively handle this by + // checking for `'static` when using cached entries, this does not + // feel worth the effort. I do not expect that a `ParamEnv` will ever + // contain large enough types for caching to be necessary. + cache: Default::default(), + }; + + let predicate = input.goal.predicate.fold_with(&mut rest_canonicalizer); + let goal = Goal { param_env, predicate }; + let predefined_opaques_in_body = + input.predefined_opaques_in_body.fold_with(&mut rest_canonicalizer); + let value = QueryInput { goal, predefined_opaques_in_body }; + + assert!(!value.has_infer(), "unexpected infer in {value:?}"); + assert!(!value.has_placeholders(), "unexpected placeholders in {value:?}"); + let (max_universe, variables) = rest_canonicalizer.finalize(); Canonical { max_universe, variables, value } } @@ -126,7 +188,7 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { // all information which should not matter for the solver. // // For this we compress universes as much as possible. - CanonicalizeMode::Input => {} + CanonicalizeMode::Input { .. } => {} // When canonicalizing a response we map a universes already entered // by the caller to the root universe and only return useful universe // information for placeholders and inference variables created inside @@ -290,17 +352,15 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { } }, ty::Placeholder(placeholder) => match self.canonicalize_mode { - CanonicalizeMode::Input => CanonicalVarKind::PlaceholderTy(PlaceholderLike::new( - placeholder.universe(), - self.variables.len().into(), - )), + CanonicalizeMode::Input { .. } => CanonicalVarKind::PlaceholderTy( + PlaceholderLike::new(placeholder.universe(), self.variables.len().into()), + ), CanonicalizeMode::Response { .. } => CanonicalVarKind::PlaceholderTy(placeholder), }, ty::Param(_) => match self.canonicalize_mode { - CanonicalizeMode::Input => CanonicalVarKind::PlaceholderTy(PlaceholderLike::new( - ty::UniverseIndex::ROOT, - self.variables.len().into(), - )), + CanonicalizeMode::Input { .. } => CanonicalVarKind::PlaceholderTy( + PlaceholderLike::new(ty::UniverseIndex::ROOT, self.variables.len().into()), + ), CanonicalizeMode::Response { .. } => panic!("param ty in response: {t:?}"), }, ty::Bool @@ -357,21 +417,30 @@ impl, I: Interner> TypeFolder for Canonicaliz let kind = match r.kind() { ty::ReBound(..) => return r, - // We may encounter `ReStatic` in item signatures or the hidden type - // of an opaque. `ReErased` should only be encountered in the hidden + // We don't canonicalize `ReStatic` in the `param_env` as we use it + // when checking whether a `ParamEnv` candidate is global. + ty::ReStatic => match self.canonicalize_mode { + CanonicalizeMode::Input { keep_static: false } => { + CanonicalVarKind::Region(ty::UniverseIndex::ROOT) + } + CanonicalizeMode::Input { keep_static: true } + | CanonicalizeMode::Response { .. } => return r, + }, + + // `ReErased` should only be encountered in the hidden // type of an opaque for regions that are ignored for the purposes of // captures. // // FIXME: We should investigate the perf implications of not uniquifying // `ReErased`. We may be able to short-circuit registering region // obligations if we encounter a `ReErased` on one side, for example. - ty::ReStatic | ty::ReErased | ty::ReError(_) => match self.canonicalize_mode { - CanonicalizeMode::Input => CanonicalVarKind::Region(ty::UniverseIndex::ROOT), + ty::ReErased | ty::ReError(_) => match self.canonicalize_mode { + CanonicalizeMode::Input { .. } => CanonicalVarKind::Region(ty::UniverseIndex::ROOT), CanonicalizeMode::Response { .. } => return r, }, ty::ReEarlyParam(_) | ty::ReLateParam(_) => match self.canonicalize_mode { - CanonicalizeMode::Input => CanonicalVarKind::Region(ty::UniverseIndex::ROOT), + CanonicalizeMode::Input { .. } => CanonicalVarKind::Region(ty::UniverseIndex::ROOT), CanonicalizeMode::Response { .. } => { panic!("unexpected region in response: {r:?}") } @@ -379,7 +448,7 @@ impl, I: Interner> TypeFolder for Canonicaliz ty::RePlaceholder(placeholder) => match self.canonicalize_mode { // We canonicalize placeholder regions as existentials in query inputs. - CanonicalizeMode::Input => CanonicalVarKind::Region(ty::UniverseIndex::ROOT), + CanonicalizeMode::Input { .. } => CanonicalVarKind::Region(ty::UniverseIndex::ROOT), CanonicalizeMode::Response { max_input_universe } => { // If we have a placeholder region inside of a query, it must be from // a new universe. @@ -397,7 +466,9 @@ impl, I: Interner> TypeFolder for Canonicaliz "region vid should have been resolved fully before canonicalization" ); match self.canonicalize_mode { - CanonicalizeMode::Input => CanonicalVarKind::Region(ty::UniverseIndex::ROOT), + CanonicalizeMode::Input { keep_static: _ } => { + CanonicalVarKind::Region(ty::UniverseIndex::ROOT) + } CanonicalizeMode::Response { .. } => { CanonicalVarKind::Region(self.delegate.universe_of_lt(vid).unwrap()) } @@ -434,7 +505,7 @@ impl, I: Interner> TypeFolder for Canonicaliz ty::InferConst::Fresh(_) => todo!(), }, ty::ConstKind::Placeholder(placeholder) => match self.canonicalize_mode { - CanonicalizeMode::Input => CanonicalVarKind::PlaceholderConst( + CanonicalizeMode::Input { .. } => CanonicalVarKind::PlaceholderConst( PlaceholderLike::new(placeholder.universe(), self.variables.len().into()), ), CanonicalizeMode::Response { .. } => { @@ -442,7 +513,7 @@ impl, I: Interner> TypeFolder for Canonicaliz } }, ty::ConstKind::Param(_) => match self.canonicalize_mode { - CanonicalizeMode::Input => CanonicalVarKind::PlaceholderConst( + CanonicalizeMode::Input { .. } => CanonicalVarKind::PlaceholderConst( PlaceholderLike::new(ty::UniverseIndex::ROOT, self.variables.len().into()), ), CanonicalizeMode::Response { .. } => panic!("param ty in response: {c:?}"), diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs index 198ccb000f345..02f6439b77fb7 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs @@ -11,6 +11,7 @@ use rustc_type_ir::visit::TypeVisitableExt as _; use rustc_type_ir::{self as ty, Interner, TypingMode, Upcast as _, elaborate}; use tracing::{debug, instrument}; +use super::trait_goals::TraitGoalProvenVia; use crate::delegate::SolverDelegate; use crate::solve::inspect::ProbeKind; use crate::solve::{ @@ -337,15 +338,6 @@ where self.assemble_param_env_candidates(goal, &mut candidates); - match self.typing_mode() { - TypingMode::Coherence => {} - TypingMode::Analysis { .. } - | TypingMode::PostBorrowckAnalysis { .. } - | TypingMode::PostAnalysis => { - self.discard_impls_shadowed_by_env(goal, &mut candidates); - } - } - candidates } @@ -500,7 +492,7 @@ where goal: Goal, candidates: &mut Vec>, ) { - for (i, assumption) in goal.param_env.caller_bounds().into_iter().enumerate() { + for (i, assumption) in goal.param_env.caller_bounds().iter().enumerate() { candidates.extend(G::probe_and_consider_implied_clause( self, CandidateSource::ParamEnv(i), @@ -733,72 +725,64 @@ where }) } - /// If there's a where-bound for the current goal, do not use any impl candidates - /// to prove the current goal. Most importantly, if there is a where-bound which does - /// not specify any associated types, we do not allow normalizing the associated type - /// by using an impl, even if it would apply. + /// We sadly can't simply take all possible candidates for normalization goals + /// and check whether they result in the same constraints. We want to make sure + /// that trying to normalize an alias doesn't result in constraints which aren't + /// otherwise required. + /// + /// Most notably, when proving a trait goal by via a where-bound, we should not + /// normalize via impls which have stricter region constraints than the where-bound: + /// + /// ```rust + /// trait Trait<'a> { + /// type Assoc; + /// } + /// + /// impl<'a, T: 'a> Trait<'a> for T { + /// type Assoc = u32; + /// } + /// + /// fn with_bound<'a, T: Trait<'a>>(_value: T::Assoc) {} + /// ``` /// - /// - // FIXME(@lcnr): The current structure here makes me unhappy and feels ugly. idk how - // to improve this however. However, this should make it fairly straightforward to refine - // the filtering going forward, so it seems alright-ish for now. - #[instrument(level = "debug", skip(self, goal))] - fn discard_impls_shadowed_by_env>( + /// The where-bound of `with_bound` doesn't specify the associated type, so we would + /// only be able to normalize `>::Assoc` by using the impl. This impl + /// adds a `T: 'a` bound however, which would result in a region error. Given that the + /// user explicitly wrote that `T: Trait<'a>` holds, this is undesirable and we instead + /// treat the alias as rigid. + /// + /// See trait-system-refactor-initiative#124 for more details. + #[instrument(level = "debug", skip(self), ret)] + pub(super) fn merge_candidates( &mut self, - goal: Goal, - candidates: &mut Vec>, - ) { - let cx = self.cx(); - let trait_goal: Goal> = - goal.with(cx, goal.predicate.trait_ref(cx)); - - let mut trait_candidates_from_env = vec![]; - self.probe(|_| ProbeKind::ShadowedEnvProbing).enter(|ecx| { - ecx.assemble_param_env_candidates(trait_goal, &mut trait_candidates_from_env); - ecx.assemble_alias_bound_candidates(trait_goal, &mut trait_candidates_from_env); - }); + proven_via: Option, + candidates: Vec>, + ) -> QueryResult { + let Some(proven_via) = proven_via else { + // We don't care about overflow. If proving the trait goal overflowed, then + // it's enough to report an overflow error for that, we don't also have to + // overflow during normalization. + return Ok(self.make_ambiguous_response_no_constraints(MaybeCause::Ambiguity)); + }; - if !trait_candidates_from_env.is_empty() { - let trait_env_result = self.merge_candidates(trait_candidates_from_env); - match trait_env_result.unwrap().value.certainty { - // If proving the trait goal succeeds by using the env, - // we freely drop all impl candidates. - // - // FIXME(@lcnr): It feels like this could easily hide - // a forced ambiguity candidate added earlier. - // This feels dangerous. - Certainty::Yes => { - candidates.retain(|c| match c.source { - CandidateSource::Impl(_) | CandidateSource::BuiltinImpl(_) => { - debug!(?c, "discard impl candidate"); - false - } - CandidateSource::ParamEnv(_) | CandidateSource::AliasBound => true, - CandidateSource::CoherenceUnknowable => panic!("uh oh"), - }); - } - // If it is still ambiguous we instead just force the whole goal - // to be ambig and wait for inference constraints. See - // tests/ui/traits/next-solver/env-shadows-impls/ambig-env-no-shadow.rs - Certainty::Maybe(cause) => { - debug!(?cause, "force ambiguity"); - *candidates = self.forced_ambiguity(cause).into_iter().collect(); - } - } - } - } + let responses: Vec<_> = match proven_via { + // Even when a trait bound has been proven using a where-bound, we + // still need to consider alias-bounds for normalization, see + // tests/ui/next-solver/alias-bound-shadowed-by-env.rs. + // + // FIXME(const_trait_impl): should this behavior also be used by + // constness checking. Doing so is *at least theoretically* breaking, + // see github.com/rust-lang/rust/issues/133044#issuecomment-2500709754 + TraitGoalProvenVia::ParamEnv | TraitGoalProvenVia::AliasBound => candidates + .iter() + .filter(|c| { + matches!(c.source, CandidateSource::AliasBound | CandidateSource::ParamEnv(_)) + }) + .map(|c| c.result) + .collect(), + TraitGoalProvenVia::Misc => candidates.iter().map(|c| c.result).collect(), + }; - /// If there are multiple ways to prove a trait or projection goal, we have - /// to somehow try to merge the candidates into one. If that fails, we return - /// ambiguity. - #[instrument(level = "debug", skip(self), ret)] - pub(super) fn merge_candidates(&mut self, candidates: Vec>) -> QueryResult { - // First try merging all candidates. This is complete and fully sound. - let responses = candidates.iter().map(|c| c.result).collect::>(); - if let Some(result) = self.try_merge_responses(&responses) { - return Ok(result); - } else { - self.flounder(&responses) - } + self.try_merge_responses(&responses).map_or_else(|| self.flounder(&responses), Ok) } } diff --git a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs index 81b5199002b23..ce7552e30f0fe 100644 --- a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs @@ -4,6 +4,7 @@ use rustc_type_ir::fast_reject::DeepRejectCtxt; use rustc_type_ir::inherent::*; use rustc_type_ir::lang_items::TraitSolverLangItem; +use rustc_type_ir::solve::inspect::ProbeKind; use rustc_type_ir::{self as ty, Interner, elaborate}; use tracing::instrument; @@ -391,6 +392,11 @@ where goal: Goal>, ) -> QueryResult { let candidates = self.assemble_and_evaluate_candidates(goal); - self.merge_candidates(candidates) + let (_, proven_via) = self.probe(|_| ProbeKind::ShadowedEnvProbing).enter(|ecx| { + let trait_goal: Goal> = + goal.with(ecx.cx(), goal.predicate.trait_ref); + ecx.compute_trait_goal(trait_goal) + })?; + self.merge_candidates(proven_via, candidates) } } diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs index a143af13688ba..e99cd3d272700 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs @@ -18,7 +18,7 @@ use rustc_type_ir::relate::solver_relating::RelateExt; use rustc_type_ir::{self as ty, Canonical, CanonicalVarValues, InferCtxtLike, Interner}; use tracing::{debug, instrument, trace}; -use crate::canonicalizer::{CanonicalizeMode, Canonicalizer}; +use crate::canonicalizer::Canonicalizer; use crate::delegate::SolverDelegate; use crate::resolve::EagerResolver; use crate::solve::eval_ctxt::NestedGoals; @@ -60,17 +60,13 @@ where (goal, opaque_types).fold_with(&mut EagerResolver::new(self.delegate)); let mut orig_values = Default::default(); - let canonical = Canonicalizer::canonicalize( - self.delegate, - CanonicalizeMode::Input, - &mut orig_values, - QueryInput { + let canonical = + Canonicalizer::canonicalize_input(self.delegate, &mut orig_values, QueryInput { goal, predefined_opaques_in_body: self .cx() .mk_predefined_opaques_in_body(PredefinedOpaquesData { opaque_types }), - }, - ); + }); let query_input = ty::CanonicalQueryInput { canonical, typing_mode: self.typing_mode() }; (orig_values, query_input) } @@ -148,9 +144,9 @@ where .region_constraints .retain(|outlives| outlives.0.as_region().map_or(true, |re| re != outlives.1)); - let canonical = Canonicalizer::canonicalize( + let canonical = Canonicalizer::canonicalize_response( self.delegate, - CanonicalizeMode::Response { max_input_universe: self.max_input_universe }, + self.max_input_universe, &mut Default::default(), Response { var_values, @@ -428,12 +424,7 @@ where let var_values = CanonicalVarValues { var_values: delegate.cx().mk_args(var_values) }; let state = inspect::State { var_values, data }; let state = state.fold_with(&mut EagerResolver::new(delegate)); - Canonicalizer::canonicalize( - delegate, - CanonicalizeMode::Response { max_input_universe }, - &mut vec![], - state, - ) + Canonicalizer::canonicalize_response(delegate, max_input_universe, &mut vec![], state) } // FIXME: needs to be pub to be accessed by downstream diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index 70ceb22bfea58..8c74490e0e0ee 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -440,7 +440,7 @@ where if let Some(kind) = kind.no_bound_vars() { match kind { ty::PredicateKind::Clause(ty::ClauseKind::Trait(predicate)) => { - self.compute_trait_goal(Goal { param_env, predicate }) + self.compute_trait_goal(Goal { param_env, predicate }).map(|(r, _via)| r) } ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(predicate)) => { self.compute_host_effect_goal(Goal { param_env, predicate }) diff --git a/compiler/rustc_next_trait_solver/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs index ebf1013db1ecb..37678bfd8805f 100644 --- a/compiler/rustc_next_trait_solver/src/solve/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs @@ -243,22 +243,27 @@ where .copied() } + fn bail_with_ambiguity(&mut self, responses: &[CanonicalResponse]) -> CanonicalResponse { + debug_assert!(!responses.is_empty()); + if let Certainty::Maybe(maybe_cause) = + responses.iter().fold(Certainty::AMBIGUOUS, |certainty, response| { + certainty.unify_with(response.value.certainty) + }) + { + self.make_ambiguous_response_no_constraints(maybe_cause) + } else { + panic!("expected flounder response to be ambiguous") + } + } + /// If we fail to merge responses we flounder and return overflow or ambiguity. #[instrument(level = "trace", skip(self), ret)] fn flounder(&mut self, responses: &[CanonicalResponse]) -> QueryResult { if responses.is_empty() { return Err(NoSolution); + } else { + Ok(self.bail_with_ambiguity(responses)) } - - let Certainty::Maybe(maybe_cause) = - responses.iter().fold(Certainty::AMBIGUOUS, |certainty, response| { - certainty.unify_with(response.value.certainty) - }) - else { - panic!("expected flounder response to be ambiguous") - }; - - Ok(self.make_ambiguous_response_no_constraints(maybe_cause)) } /// Normalize a type for when it is structurally matched on. diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs index 63dbee2640bff..b886719222510 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs @@ -88,10 +88,17 @@ where /// returns `NoSolution`. #[instrument(level = "trace", skip(self), ret)] fn normalize_at_least_one_step(&mut self, goal: Goal>) -> QueryResult { - match goal.predicate.alias.kind(self.cx()) { + let cx = self.cx(); + match goal.predicate.alias.kind(cx) { ty::AliasTermKind::ProjectionTy | ty::AliasTermKind::ProjectionConst => { let candidates = self.assemble_and_evaluate_candidates(goal); - self.merge_candidates(candidates) + let (_, proven_via) = + self.probe(|_| ProbeKind::ShadowedEnvProbing).enter(|ecx| { + let trait_goal: Goal> = + goal.with(cx, goal.predicate.alias.trait_ref(cx)); + ecx.compute_trait_goal(trait_goal) + })?; + self.merge_candidates(proven_via, candidates) } ty::AliasTermKind::InherentTy => self.normalize_inherent_associated_type(goal), ty::AliasTermKind::OpaqueTy => self.normalize_opaque_type(goal), diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index 12df35d30b8f3..886cdec034552 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -5,6 +5,7 @@ use rustc_type_ir::data_structures::IndexSet; use rustc_type_ir::fast_reject::DeepRejectCtxt; use rustc_type_ir::inherent::*; use rustc_type_ir::lang_items::TraitSolverLangItem; +use rustc_type_ir::solve::CanonicalResponse; use rustc_type_ir::visit::TypeVisitableExt as _; use rustc_type_ir::{self as ty, Interner, TraitPredicate, TypingMode, Upcast as _, elaborate}; use tracing::{instrument, trace}; @@ -1147,13 +1148,101 @@ where ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) }) } +} + +/// How we've proven this trait goal. +/// +/// This is used by `NormalizesTo` goals to only normalize +/// by using the same 'kind of candidate' we've used to prove +/// its corresponding trait goal. Most notably, we do not +/// normalize by using an impl if the trait goal has been +/// proven via a `ParamEnv` candidate. +/// +/// This is necessary to avoid unnecessary region constraints, +/// see trait-system-refactor-initiative#125 for more details. +#[derive(Debug, Clone, Copy)] +pub(super) enum TraitGoalProvenVia { + /// We've proven the trait goal by something which is + /// is not a non-global where-bound or an alias-bound. + /// + /// This means we don't disable any candidates during + /// normalization. + Misc, + ParamEnv, + AliasBound, +} + +impl EvalCtxt<'_, D> +where + D: SolverDelegate, + I: Interner, +{ + pub(super) fn merge_trait_candidates( + &mut self, + goal: Goal>, + candidates: Vec>, + ) -> Result<(CanonicalResponse, Option), NoSolution> { + if let TypingMode::Coherence = self.typing_mode() { + let all_candidates: Vec<_> = candidates.into_iter().map(|c| c.result).collect(); + return if let Some(response) = self.try_merge_responses(&all_candidates) { + Ok((response, Some(TraitGoalProvenVia::Misc))) + } else { + self.flounder(&all_candidates).map(|r| (r, None)) + }; + } + + // FIXME: prefer trivial builtin impls + + // If there are non-global where-bounds, prefer where-bounds + // (including global ones) over everything else. + let has_non_global_where_bounds = candidates.iter().any(|c| match c.source { + CandidateSource::ParamEnv(idx) => { + let where_bound = goal.param_env.caller_bounds().get(idx); + where_bound.has_bound_vars() || !where_bound.is_global() + } + _ => false, + }); + if has_non_global_where_bounds { + let where_bounds: Vec<_> = candidates + .iter() + .filter(|c| matches!(c.source, CandidateSource::ParamEnv(_))) + .map(|c| c.result) + .collect(); + + return if let Some(response) = self.try_merge_responses(&where_bounds) { + Ok((response, Some(TraitGoalProvenVia::ParamEnv))) + } else { + Ok((self.bail_with_ambiguity(&where_bounds), None)) + }; + } + + if candidates.iter().any(|c| matches!(c.source, CandidateSource::AliasBound)) { + let alias_bounds: Vec<_> = candidates + .iter() + .filter(|c| matches!(c.source, CandidateSource::AliasBound)) + .map(|c| c.result) + .collect(); + return if let Some(response) = self.try_merge_responses(&alias_bounds) { + Ok((response, Some(TraitGoalProvenVia::AliasBound))) + } else { + Ok((self.bail_with_ambiguity(&alias_bounds), None)) + }; + } + + let all_candidates: Vec<_> = candidates.into_iter().map(|c| c.result).collect(); + if let Some(response) = self.try_merge_responses(&all_candidates) { + Ok((response, Some(TraitGoalProvenVia::Misc))) + } else { + self.flounder(&all_candidates).map(|r| (r, None)) + } + } #[instrument(level = "trace", skip(self))] pub(super) fn compute_trait_goal( &mut self, goal: Goal>, - ) -> QueryResult { + ) -> Result<(CanonicalResponse, Option), NoSolution> { let candidates = self.assemble_and_evaluate_candidates(goal); - self.merge_candidates(candidates) + self.merge_trait_candidates(goal, candidates) } } diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index fd133ba878e10..9cc94b7562468 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -357,6 +357,9 @@ passes_ignored_derived_impls = passes_implied_feature_not_exist = feature `{$implied_by}` implying `{$feature}` does not exist +passes_incorrect_do_not_recommend_args = + `#[diagnostic::do_not_recommend]` does not expect any arguments + passes_incorrect_do_not_recommend_location = `#[diagnostic::do_not_recommend]` can only be placed on trait implementations diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index ce7947ad3ec40..2310dd9dc72db 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -115,7 +115,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { for attr in attrs { match attr.path().as_slice() { [sym::diagnostic, sym::do_not_recommend, ..] => { - self.check_do_not_recommend(attr.span, hir_id, target) + self.check_do_not_recommend(attr.span, hir_id, target, attr, item) } [sym::diagnostic, sym::on_unimplemented, ..] => { self.check_diagnostic_on_unimplemented(attr.span, hir_id, target) @@ -348,8 +348,21 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } /// Checks if `#[diagnostic::do_not_recommend]` is applied on a trait impl. - fn check_do_not_recommend(&self, attr_span: Span, hir_id: HirId, target: Target) { - if !matches!(target, Target::Impl) { + fn check_do_not_recommend( + &self, + attr_span: Span, + hir_id: HirId, + target: Target, + attr: &Attribute, + item: Option>, + ) { + if !matches!(target, Target::Impl) + || matches!( + item, + Some(ItemLike::Item(hir::Item { kind: hir::ItemKind::Impl(_impl),.. })) + if _impl.of_trait.is_none() + ) + { self.tcx.emit_node_span_lint( UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, hir_id, @@ -357,6 +370,14 @@ impl<'tcx> CheckAttrVisitor<'tcx> { errors::IncorrectDoNotRecommendLocation, ); } + if !attr.is_word() { + self.tcx.emit_node_span_lint( + UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, + hir_id, + attr_span, + errors::DoNotRecommendDoesNotExpectArgs, + ); + } } /// Checks if `#[diagnostic::on_unimplemented]` is applied to a trait definition diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index f71d528405267..5e7bfa5e3bb71 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -20,6 +20,10 @@ use crate::lang_items::Duplicate; #[diag(passes_incorrect_do_not_recommend_location)] pub(crate) struct IncorrectDoNotRecommendLocation; +#[derive(LintDiagnostic)] +#[diag(passes_incorrect_do_not_recommend_args)] +pub(crate) struct DoNotRecommendDoesNotExpectArgs; + #[derive(Diagnostic)] #[diag(passes_autodiff_attr)] pub(crate) struct AutoDiffAttr { diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index a48a2865228a2..7324d3fe7862d 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -4325,7 +4325,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { #[inline] /// If we're actually rustdoc then avoid giving a name resolution error for `cfg()` items or - // an invalid `use foo::*;` was found, which can cause unbounded ammounts of "item not found" + // an invalid `use foo::*;` was found, which can cause unbounded amounts of "item not found" // errors. We silence them all. fn should_report_errs(&self) -> bool { !(self.r.tcx.sess.opts.actually_rustdoc && self.in_func_body) diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index edee19c280a8a..b24e343c58df8 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -689,8 +689,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { && let [namespace, attribute, ..] = &*path.segments && namespace.ident.name == sym::diagnostic && !(attribute.ident.name == sym::on_unimplemented - || (attribute.ident.name == sym::do_not_recommend - && self.tcx.features().do_not_recommend())) + || attribute.ident.name == sym::do_not_recommend) { let distance = edit_distance(attribute.ident.name.as_str(), sym::on_unimplemented.as_str(), 5); diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 069d42d4018c0..1dcd0d0dfb830 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -599,7 +599,7 @@ pub fn try_evaluate_const<'tcx>( // even though it is not something we should ever actually encounter. // // Array repeat expr counts are allowed to syntactically use generic parameters - // but must not actually depend on them in order to evalaute succesfully. This means + // but must not actually depend on them in order to evalaute successfully. This means // that it is actually fine to evalaute them in their own environment rather than with // the actually provided generic arguments. tcx.dcx().delayed_bug( diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index f45c94127bd00..2db40accda39b 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -543,7 +543,7 @@ pub trait AdtDef: Copy + Debug + Hash + Eq { } pub trait ParamEnv: Copy + Debug + Hash + Eq + TypeFoldable { - fn caller_bounds(self) -> impl IntoIterator; + fn caller_bounds(self) -> impl SliceLike; } pub trait Features: Copy { diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 922866f95dcf6..18bd9bb811836 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -108,12 +108,12 @@ // Library features: // tidy-alphabetical-start #![cfg_attr(bootstrap, feature(coverage_attribute))] +#![cfg_attr(bootstrap, feature(do_not_recommend))] #![feature(array_ptr_get)] #![feature(asm_experimental_arch)] #![feature(const_eval_select)] #![feature(const_typed_swap)] #![feature(core_intrinsics)] -#![feature(do_not_recommend)] #![feature(internal_impls_macro)] #![feature(ip)] #![feature(is_ascii_octdigit)] diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 90c49270566d7..aa8fdaaee4cb8 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -344,35 +344,48 @@ impl<'a, I: Iterator>> Iterator for CodeBlocks<'_, 'a, I> { } /// Make headings links with anchor IDs and build up TOC. -struct LinkReplacer<'a, I: Iterator>> { - inner: I, +struct LinkReplacerInner<'a> { links: &'a [RenderedLink], shortcut_link: Option<&'a RenderedLink>, } +struct LinkReplacer<'a, I: Iterator>> { + iter: I, + inner: LinkReplacerInner<'a>, +} + impl<'a, I: Iterator>> LinkReplacer<'a, I> { fn new(iter: I, links: &'a [RenderedLink]) -> Self { - LinkReplacer { inner: iter, links, shortcut_link: None } + LinkReplacer { iter, inner: { LinkReplacerInner { links, shortcut_link: None } } } } } -impl<'a, I: Iterator>> Iterator for LinkReplacer<'a, I> { - type Item = Event<'a>; +// FIXME: Once we have specialized trait impl (for `Iterator` impl on `LinkReplacer`), +// we can remove this type and move back `LinkReplacerInner` fields into `LinkReplacer`. +struct SpannedLinkReplacer<'a, I: Iterator>> { + iter: I, + inner: LinkReplacerInner<'a>, +} - fn next(&mut self) -> Option { - let mut event = self.inner.next(); +impl<'a, I: Iterator>> SpannedLinkReplacer<'a, I> { + fn new(iter: I, links: &'a [RenderedLink]) -> Self { + SpannedLinkReplacer { iter, inner: { LinkReplacerInner { links, shortcut_link: None } } } + } +} +impl<'a> LinkReplacerInner<'a> { + fn handle_event(&mut self, event: &mut Event<'a>) { // Replace intra-doc links and remove disambiguators from shortcut links (`[fn@f]`). - match &mut event { + match event { // This is a shortcut link that was resolved by the broken_link_callback: `[fn@f]` // Remove any disambiguator. - Some(Event::Start(Tag::Link { + Event::Start(Tag::Link { // [fn@f] or [fn@f][] link_type: LinkType::ShortcutUnknown | LinkType::CollapsedUnknown, dest_url, title, .. - })) => { + }) => { debug!("saw start of shortcut link to {dest_url} with title {title}"); // If this is a shortcut link, it was resolved by the broken_link_callback. // So the URL will already be updated properly. @@ -389,13 +402,13 @@ impl<'a, I: Iterator>> Iterator for LinkReplacer<'a, I> { } } // Now that we're done with the shortcut link, don't replace any more text. - Some(Event::End(TagEnd::Link)) if self.shortcut_link.is_some() => { + Event::End(TagEnd::Link) if self.shortcut_link.is_some() => { debug!("saw end of shortcut link"); self.shortcut_link = None; } // Handle backticks in inline code blocks, but only if we're in the middle of a shortcut link. // [`fn@f`] - Some(Event::Code(text)) => { + Event::Code(text) => { trace!("saw code {text}"); if let Some(link) = self.shortcut_link { // NOTE: this only replaces if the code block is the *entire* text. @@ -418,7 +431,7 @@ impl<'a, I: Iterator>> Iterator for LinkReplacer<'a, I> { } // Replace plain text in links, but only in the middle of a shortcut link. // [fn@f] - Some(Event::Text(text)) => { + Event::Text(text) => { trace!("saw text {text}"); if let Some(link) = self.shortcut_link { // NOTE: same limitations as `Event::Code` @@ -434,7 +447,7 @@ impl<'a, I: Iterator>> Iterator for LinkReplacer<'a, I> { } // If this is a link, but not a shortcut link, // replace the URL, since the broken_link_callback was not called. - Some(Event::Start(Tag::Link { dest_url, title, .. })) => { + Event::Start(Tag::Link { dest_url, title, .. }) => { if let Some(link) = self.links.iter().find(|&link| *link.original_text == **dest_url) { @@ -447,12 +460,33 @@ impl<'a, I: Iterator>> Iterator for LinkReplacer<'a, I> { // Anything else couldn't have been a valid Rust path, so no need to replace the text. _ => {} } + } +} + +impl<'a, I: Iterator>> Iterator for LinkReplacer<'a, I> { + type Item = Event<'a>; + fn next(&mut self) -> Option { + let mut event = self.iter.next(); + if let Some(ref mut event) = event { + self.inner.handle_event(event); + } // Yield the modified event event } } +impl<'a, I: Iterator>> Iterator for SpannedLinkReplacer<'a, I> { + type Item = SpannedEvent<'a>; + + fn next(&mut self) -> Option { + let Some((mut event, range)) = self.iter.next() else { return None }; + self.inner.handle_event(&mut event); + // Yield the modified event + Some((event, range)) + } +} + /// Wrap HTML tables into `
` to prevent having the doc blocks width being too big. struct TableWrapper<'a, I: Iterator>> { inner: I, @@ -1339,9 +1373,9 @@ impl<'a> Markdown<'a> { ids.handle_footnotes(|ids, existing_footnotes| { let p = HeadingLinks::new(p, None, ids, heading_offset); + let p = SpannedLinkReplacer::new(p, links); let p = footnotes::Footnotes::new(p, existing_footnotes); - let p = LinkReplacer::new(p.map(|(ev, _)| ev), links); - let p = TableWrapper::new(p); + let p = TableWrapper::new(p.map(|(ev, _)| ev)); CodeBlocks::new(p, codes, edition, playground) }) } diff --git a/tests/crashes/133639.rs b/tests/crashes/133639.rs deleted file mode 100644 index d522b0730cf86..0000000000000 --- a/tests/crashes/133639.rs +++ /dev/null @@ -1,33 +0,0 @@ -//@ known-bug: #133639 - -#![feature(with_negative_coherence)] -#![feature(min_specialization)] -#![feature(generic_const_exprs)] - -#![crate_type = "lib"] -use std::str::FromStr; - -struct a; - -trait c {} - -impl FromStr for e -where - a<{ d <= 2 }>: c, -{ - type Err = (); - fn from_str(f: &str) -> Result { - unimplemented!() - } -} -struct e; - -impl FromStr for e -where - a<{ d <= 2 }>: c, -{ - type Err = (); - fn from_str(f: &str) -> Result { - unimplemented!() - } -} diff --git a/tests/rustdoc/intra-doc/link-in-footnotes-132208.rs b/tests/rustdoc/intra-doc/link-in-footnotes-132208.rs new file mode 100644 index 0000000000000..c9b97eafd2f81 --- /dev/null +++ b/tests/rustdoc/intra-doc/link-in-footnotes-132208.rs @@ -0,0 +1,24 @@ +// Rustdoc has multiple passes and if the footnote pass is run before the link replacer +// one, intra doc links are not generated inside footnote definitions. This test +// therefore ensures that intra-doc link are correctly generated inside footnote +// definitions. +// +// Regression test for . + +#![crate_name = "foo"] + +//@ has 'foo/index.html' +//@ has - '//*[@class="docblock"]//a[@href="struct.Bar.html"]' 'a' +//@ has - '//*[@class="docblock"]//*[@class="footnotes"]//a[@href="struct.Foo.html"]' 'b' + +//! [a]: crate::Bar +//! [b]: crate::Foo +//! +//! link in body: [a] +//! +//! see footnote[^1] +//! +//! [^1]: link in footnote: [b] + +pub struct Bar; +pub struct Foo; diff --git a/tests/ui/attr-bad-crate-attr.rs b/tests/ui/attr-bad-crate-attr.rs deleted file mode 100644 index b9100ecfb6761..0000000000000 --- a/tests/ui/attr-bad-crate-attr.rs +++ /dev/null @@ -1,4 +0,0 @@ -//@ error-pattern: expected item - -#![attr = "val"] -#[attr = "val"] // Unterminated diff --git a/tests/ui/attr-shebang.rs b/tests/ui/attr-shebang.rs deleted file mode 100644 index 67c371aeaace3..0000000000000 --- a/tests/ui/attr-shebang.rs +++ /dev/null @@ -1,5 +0,0 @@ -//@ run-pass - -#![allow(stable_features)] -#![feature(rust1)] -pub fn main() { } diff --git a/tests/ui/attributes/attr-bad-crate-attr.rs b/tests/ui/attributes/attr-bad-crate-attr.rs new file mode 100644 index 0000000000000..9de0abca9a75e --- /dev/null +++ b/tests/ui/attributes/attr-bad-crate-attr.rs @@ -0,0 +1,9 @@ +//! Check that we permit a crate-level inner attribute but reject a dangling outer attribute which +//! does not have a following thing that it can target. +//! +//! See . + +//@ error-pattern: expected item + +#![attr = "val"] +#[attr = "val"] // Unterminated diff --git a/tests/ui/attr-bad-crate-attr.stderr b/tests/ui/attributes/attr-bad-crate-attr.stderr similarity index 79% rename from tests/ui/attr-bad-crate-attr.stderr rename to tests/ui/attributes/attr-bad-crate-attr.stderr index 9df991f71b3fb..69eabd32230f4 100644 --- a/tests/ui/attr-bad-crate-attr.stderr +++ b/tests/ui/attributes/attr-bad-crate-attr.stderr @@ -1,5 +1,5 @@ error: expected item after attributes - --> $DIR/attr-bad-crate-attr.rs:4:1 + --> $DIR/attr-bad-crate-attr.rs:9:1 | LL | #[attr = "val"] // Unterminated | ^^^^^^^^^^^^^^^ diff --git a/tests/ui/attributes/attr-shebang.rs b/tests/ui/attributes/attr-shebang.rs new file mode 100644 index 0000000000000..af446dc56e39d --- /dev/null +++ b/tests/ui/attributes/attr-shebang.rs @@ -0,0 +1,7 @@ +//! Check that we accept crate-level inner attributes with the `#![..]` shebang syntax. + +//@ check-pass + +#![allow(stable_features)] +#![feature(rust1)] +pub fn main() { } diff --git a/tests/ui/attr-usage-inline.rs b/tests/ui/attributes/inline/attr-usage-inline.rs similarity index 66% rename from tests/ui/attr-usage-inline.rs rename to tests/ui/attributes/inline/attr-usage-inline.rs index 674c12454cdaa..d8ca0fce1631d 100644 --- a/tests/ui/attr-usage-inline.rs +++ b/tests/ui/attributes/inline/attr-usage-inline.rs @@ -1,4 +1,5 @@ -#![allow(dead_code)] +//! Check that `#[inline]` attribute can only be applied to fn-like targets (e.g. function or +//! closure), and when misapplied to other targets an error is emitted. #[inline] fn f() {} diff --git a/tests/ui/attr-usage-inline.stderr b/tests/ui/attributes/inline/attr-usage-inline.stderr similarity index 84% rename from tests/ui/attr-usage-inline.stderr rename to tests/ui/attributes/inline/attr-usage-inline.stderr index 22a0bf47e2026..2123438032cb3 100644 --- a/tests/ui/attr-usage-inline.stderr +++ b/tests/ui/attributes/inline/attr-usage-inline.stderr @@ -1,5 +1,5 @@ error[E0518]: attribute should be applied to function or closure - --> $DIR/attr-usage-inline.rs:6:1 + --> $DIR/attr-usage-inline.rs:7:1 | LL | #[inline] | ^^^^^^^^^ @@ -7,7 +7,7 @@ LL | struct S; | --------- not a function or closure error[E0518]: attribute should be applied to function or closure - --> $DIR/attr-usage-inline.rs:20:1 + --> $DIR/attr-usage-inline.rs:21:1 | LL | #[inline] | ^^^^^^^^^ not a function or closure diff --git a/tests/ui/const-generics/generic_const_exprs/specialization-fuzzing-ice-133639.rs b/tests/ui/const-generics/generic_const_exprs/specialization-fuzzing-ice-133639.rs new file mode 100644 index 0000000000000..d3ae863bee968 --- /dev/null +++ b/tests/ui/const-generics/generic_const_exprs/specialization-fuzzing-ice-133639.rs @@ -0,0 +1,19 @@ +//@ check-pass + +// Regression test for #133639. + +#![feature(with_negative_coherence)] +#![feature(min_specialization)] +#![feature(generic_const_exprs)] +//~^ WARNING the feature `generic_const_exprs` is incomplete + +#![crate_type = "lib"] +trait Trait {} +struct A; + +trait C {} + +impl Trait for E where A<{ D <= 2 }>: C {} +struct E; + +impl Trait for E where A<{ D <= 2 }>: C {} diff --git a/tests/ui/const-generics/generic_const_exprs/specialization-fuzzing-ice-133639.stderr b/tests/ui/const-generics/generic_const_exprs/specialization-fuzzing-ice-133639.stderr new file mode 100644 index 0000000000000..f17b248d856d4 --- /dev/null +++ b/tests/ui/const-generics/generic_const_exprs/specialization-fuzzing-ice-133639.stderr @@ -0,0 +1,11 @@ +warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/specialization-fuzzing-ice-133639.rs:7:12 + | +LL | #![feature(generic_const_exprs)] + | ^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #76560 for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/const-generics/min_const_generics/param-env-eager-norm-dedup.rs b/tests/ui/const-generics/min_const_generics/param-env-eager-norm-dedup.rs index 9600b3875ba48..2e97e3fe0044e 100644 --- a/tests/ui/const-generics/min_const_generics/param-env-eager-norm-dedup.rs +++ b/tests/ui/const-generics/min_const_generics/param-env-eager-norm-dedup.rs @@ -1,3 +1,6 @@ +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver //@ check-pass // This caused a regression in a crater run in #132325. diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.current.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.current.stderr index 5d0c182641101..28e7975c7a234 100644 --- a/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.current.stderr +++ b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.current.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `&str: AsExpression` is not satisfied - --> $DIR/as_expression.rs:57:15 + --> $DIR/as_expression.rs:55:15 | LL | SelectInt.check("bar"); | ^^^^^ the trait `AsExpression` is not implemented for `&str` diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr index 1e1eae852f911..1b76669ccb0d7 100644 --- a/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr +++ b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `&str: AsExpression<::SqlType>` is not satisfied - --> $DIR/as_expression.rs:57:21 + --> $DIR/as_expression.rs:55:21 | LL | SelectInt.check("bar"); | ----- ^^^^^ the trait `AsExpression<::SqlType>` is not implemented for `&str` @@ -8,7 +8,7 @@ LL | SelectInt.check("bar"); | = help: the trait `AsExpression` is implemented for `&str` note: required by a bound in `Foo::check` - --> $DIR/as_expression.rs:48:12 + --> $DIR/as_expression.rs:46:12 | LL | fn check(&self, _: T) -> ::SqlType>>::Expression | ----- required by a bound in this associated function @@ -17,7 +17,7 @@ LL | T: AsExpression, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Foo::check` error[E0277]: the trait bound `&str: AsExpression` is not satisfied - --> $DIR/as_expression.rs:57:15 + --> $DIR/as_expression.rs:55:15 | LL | SelectInt.check("bar"); | ^^^^^ the trait `AsExpression` is not implemented for `&str` @@ -27,7 +27,7 @@ LL | SelectInt.check("bar"); = help: for that trait implementation, expected `Text`, found `Integer` error[E0271]: type mismatch resolving `::SqlType == Text` - --> $DIR/as_expression.rs:57:5 + --> $DIR/as_expression.rs:55:5 | LL | SelectInt.check("bar"); | ^^^^^^^^^^^^^^^^^^^^^^ expected `Text`, found `Integer` diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.rs b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.rs index 37b4429f694cf..583b3c4675a87 100644 --- a/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.rs +++ b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.rs @@ -2,8 +2,6 @@ //@ ignore-compare-mode-next-solver (explicit revisions) //@[next] compile-flags: -Znext-solver -#![feature(do_not_recommend)] - pub trait Expression { type SqlType; } diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/do_not_apply_attribute_without_feature_flag.rs b/tests/ui/diagnostic_namespace/do_not_recommend/do_not_apply_attribute_without_feature_flag.rs deleted file mode 100644 index 5548fa2f52e17..0000000000000 --- a/tests/ui/diagnostic_namespace/do_not_recommend/do_not_apply_attribute_without_feature_flag.rs +++ /dev/null @@ -1,21 +0,0 @@ -#![allow(unknown_or_malformed_diagnostic_attributes)] - -trait Foo {} - -#[diagnostic::do_not_recommend] -impl Foo for (A,) {} - -#[diagnostic::do_not_recommend] -impl Foo for (A, B) {} - -#[diagnostic::do_not_recommend] -impl Foo for (A, B, C) {} - -impl Foo for i32 {} - -fn check(a: impl Foo) {} - -fn main() { - check(()); - //~^ ERROR the trait bound `(): Foo` is not satisfied -} diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/do_not_apply_attribute_without_feature_flag.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/do_not_apply_attribute_without_feature_flag.stderr deleted file mode 100644 index be17476524aec..0000000000000 --- a/tests/ui/diagnostic_namespace/do_not_recommend/do_not_apply_attribute_without_feature_flag.stderr +++ /dev/null @@ -1,25 +0,0 @@ -error[E0277]: the trait bound `(): Foo` is not satisfied - --> $DIR/do_not_apply_attribute_without_feature_flag.rs:19:11 - | -LL | check(()); - | ----- ^^ the trait `Foo` is not implemented for `()` - | | - | required by a bound introduced by this call - | - = help: the following other types implement trait `Foo`: - (A, B) - (A, B, C) - (A,) -note: required by a bound in `check` - --> $DIR/do_not_apply_attribute_without_feature_flag.rs:16:18 - | -LL | fn check(a: impl Foo) {} - | ^^^ required by this bound in `check` -help: use a unary tuple instead - | -LL | check(((),)); - | + ++ - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/does_not_acccept_args.current.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/does_not_acccept_args.current.stderr new file mode 100644 index 0000000000000..47597a5d405e4 --- /dev/null +++ b/tests/ui/diagnostic_namespace/do_not_recommend/does_not_acccept_args.current.stderr @@ -0,0 +1,22 @@ +warning: `#[diagnostic::do_not_recommend]` does not expect any arguments + --> $DIR/does_not_acccept_args.rs:10:1 + | +LL | #[diagnostic::do_not_recommend(not_accepted)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(unknown_or_malformed_diagnostic_attributes)]` on by default + +warning: `#[diagnostic::do_not_recommend]` does not expect any arguments + --> $DIR/does_not_acccept_args.rs:14:1 + | +LL | #[diagnostic::do_not_recommend(not_accepted = "foo")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: `#[diagnostic::do_not_recommend]` does not expect any arguments + --> $DIR/does_not_acccept_args.rs:18:1 + | +LL | #[diagnostic::do_not_recommend(not_accepted(42))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: 3 warnings emitted + diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/does_not_acccept_args.next.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/does_not_acccept_args.next.stderr new file mode 100644 index 0000000000000..47597a5d405e4 --- /dev/null +++ b/tests/ui/diagnostic_namespace/do_not_recommend/does_not_acccept_args.next.stderr @@ -0,0 +1,22 @@ +warning: `#[diagnostic::do_not_recommend]` does not expect any arguments + --> $DIR/does_not_acccept_args.rs:10:1 + | +LL | #[diagnostic::do_not_recommend(not_accepted)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(unknown_or_malformed_diagnostic_attributes)]` on by default + +warning: `#[diagnostic::do_not_recommend]` does not expect any arguments + --> $DIR/does_not_acccept_args.rs:14:1 + | +LL | #[diagnostic::do_not_recommend(not_accepted = "foo")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: `#[diagnostic::do_not_recommend]` does not expect any arguments + --> $DIR/does_not_acccept_args.rs:18:1 + | +LL | #[diagnostic::do_not_recommend(not_accepted(42))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: 3 warnings emitted + diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/does_not_acccept_args.rs b/tests/ui/diagnostic_namespace/do_not_recommend/does_not_acccept_args.rs new file mode 100644 index 0000000000000..eeff5e2e6e8fc --- /dev/null +++ b/tests/ui/diagnostic_namespace/do_not_recommend/does_not_acccept_args.rs @@ -0,0 +1,22 @@ +//@ check-pass +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver + +trait Foo {} +trait Bar {} +trait Baz {} + +#[diagnostic::do_not_recommend(not_accepted)] +//~^ WARNING `#[diagnostic::do_not_recommend]` does not expect any arguments +impl Foo for T where T: Send {} + +#[diagnostic::do_not_recommend(not_accepted = "foo")] +//~^ WARNING `#[diagnostic::do_not_recommend]` does not expect any arguments +impl Bar for T where T: Send {} + +#[diagnostic::do_not_recommend(not_accepted(42))] +//~^ WARNING `#[diagnostic::do_not_recommend]` does not expect any arguments +impl Baz for T where T: Send {} + +fn main() {} diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/feature-gate-do_not_recommend.rs b/tests/ui/diagnostic_namespace/do_not_recommend/feature-gate-do_not_recommend.rs deleted file mode 100644 index 5a26d28188c25..0000000000000 --- a/tests/ui/diagnostic_namespace/do_not_recommend/feature-gate-do_not_recommend.rs +++ /dev/null @@ -1,17 +0,0 @@ -#![feature(do_not_recommend)] - -pub trait Foo {} - -impl Foo for i32 {} - -pub trait Bar {} - -#[diagnostic::do_not_recommend] -impl Bar for T {} - -fn stuff(_: T) {} - -fn main() { - stuff(1u8); - //~^ the trait bound `u8: Bar` is not satisfied -} diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/feature-gate-do_not_recommend.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/feature-gate-do_not_recommend.stderr deleted file mode 100644 index 3951231fa2e71..0000000000000 --- a/tests/ui/diagnostic_namespace/do_not_recommend/feature-gate-do_not_recommend.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0277]: the trait bound `u8: Bar` is not satisfied - --> $DIR/feature-gate-do_not_recommend.rs:15:11 - | -LL | stuff(1u8); - | ^^^ the trait `Bar` is not implemented for `u8` - | -note: required by a bound in `stuff` - --> $DIR/feature-gate-do_not_recommend.rs:12:13 - | -LL | fn stuff(_: T) {} - | ^^^ required by this bound in `stuff` - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.current.stderr similarity index 72% rename from tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.stderr rename to tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.current.stderr index c83fd46db5841..ee6ebabadd97a 100644 --- a/tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.stderr +++ b/tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.current.stderr @@ -1,5 +1,5 @@ warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations - --> $DIR/incorrect-locations.rs:4:1 + --> $DIR/incorrect-locations.rs:6:1 | LL | #[diagnostic::do_not_recommend] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,46 +7,52 @@ LL | #[diagnostic::do_not_recommend] = note: `#[warn(unknown_or_malformed_diagnostic_attributes)]` on by default warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations - --> $DIR/incorrect-locations.rs:8:1 + --> $DIR/incorrect-locations.rs:10:1 | LL | #[diagnostic::do_not_recommend] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations - --> $DIR/incorrect-locations.rs:12:1 + --> $DIR/incorrect-locations.rs:14:1 | LL | #[diagnostic::do_not_recommend] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations - --> $DIR/incorrect-locations.rs:16:1 + --> $DIR/incorrect-locations.rs:18:1 | LL | #[diagnostic::do_not_recommend] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations - --> $DIR/incorrect-locations.rs:20:1 + --> $DIR/incorrect-locations.rs:22:1 | LL | #[diagnostic::do_not_recommend] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations - --> $DIR/incorrect-locations.rs:24:1 + --> $DIR/incorrect-locations.rs:26:1 | LL | #[diagnostic::do_not_recommend] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations - --> $DIR/incorrect-locations.rs:28:1 + --> $DIR/incorrect-locations.rs:30:1 | LL | #[diagnostic::do_not_recommend] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations - --> $DIR/incorrect-locations.rs:32:1 + --> $DIR/incorrect-locations.rs:34:1 | LL | #[diagnostic::do_not_recommend] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -warning: 8 warnings emitted +warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations + --> $DIR/incorrect-locations.rs:38:1 + | +LL | #[diagnostic::do_not_recommend] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: 9 warnings emitted diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.next.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.next.stderr new file mode 100644 index 0000000000000..ee6ebabadd97a --- /dev/null +++ b/tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.next.stderr @@ -0,0 +1,58 @@ +warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations + --> $DIR/incorrect-locations.rs:6:1 + | +LL | #[diagnostic::do_not_recommend] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(unknown_or_malformed_diagnostic_attributes)]` on by default + +warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations + --> $DIR/incorrect-locations.rs:10:1 + | +LL | #[diagnostic::do_not_recommend] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations + --> $DIR/incorrect-locations.rs:14:1 + | +LL | #[diagnostic::do_not_recommend] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations + --> $DIR/incorrect-locations.rs:18:1 + | +LL | #[diagnostic::do_not_recommend] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations + --> $DIR/incorrect-locations.rs:22:1 + | +LL | #[diagnostic::do_not_recommend] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations + --> $DIR/incorrect-locations.rs:26:1 + | +LL | #[diagnostic::do_not_recommend] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations + --> $DIR/incorrect-locations.rs:30:1 + | +LL | #[diagnostic::do_not_recommend] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations + --> $DIR/incorrect-locations.rs:34:1 + | +LL | #[diagnostic::do_not_recommend] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations + --> $DIR/incorrect-locations.rs:38:1 + | +LL | #[diagnostic::do_not_recommend] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: 9 warnings emitted + diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.rs b/tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.rs index 400ef83873e13..1cf436aa2af3f 100644 --- a/tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.rs +++ b/tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.rs @@ -1,5 +1,7 @@ //@ check-pass -#![feature(do_not_recommend)] +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver #[diagnostic::do_not_recommend] //~^WARN `#[diagnostic::do_not_recommend]` can only be placed @@ -17,6 +19,10 @@ type Type = (); //~^WARN `#[diagnostic::do_not_recommend]` can only be placed enum Enum {} +#[diagnostic::do_not_recommend] +//~^WARN `#[diagnostic::do_not_recommend]` can only be placed +impl Enum {} + #[diagnostic::do_not_recommend] //~^WARN `#[diagnostic::do_not_recommend]` can only be placed extern "C" {} diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/nested.current.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/nested.current.stderr new file mode 100644 index 0000000000000..b14c68d689766 --- /dev/null +++ b/tests/ui/diagnostic_namespace/do_not_recommend/nested.current.stderr @@ -0,0 +1,15 @@ +error[E0277]: the trait bound `(): Root` is not satisfied + --> $DIR/nested.rs:21:18 + | +LL | needs_root::<()>(); + | ^^ the trait `Root` is not implemented for `()` + | +note: required by a bound in `needs_root` + --> $DIR/nested.rs:18:18 + | +LL | fn needs_root() {} + | ^^^^ required by this bound in `needs_root` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/nested.next.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/nested.next.stderr new file mode 100644 index 0000000000000..b14c68d689766 --- /dev/null +++ b/tests/ui/diagnostic_namespace/do_not_recommend/nested.next.stderr @@ -0,0 +1,15 @@ +error[E0277]: the trait bound `(): Root` is not satisfied + --> $DIR/nested.rs:21:18 + | +LL | needs_root::<()>(); + | ^^ the trait `Root` is not implemented for `()` + | +note: required by a bound in `needs_root` + --> $DIR/nested.rs:18:18 + | +LL | fn needs_root() {} + | ^^^^ required by this bound in `needs_root` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/nested.rs b/tests/ui/diagnostic_namespace/do_not_recommend/nested.rs new file mode 100644 index 0000000000000..6534157d1fb2e --- /dev/null +++ b/tests/ui/diagnostic_namespace/do_not_recommend/nested.rs @@ -0,0 +1,23 @@ +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver + +trait Root {} +trait DontRecommend {} +trait Other {} +trait Child {} + +#[diagnostic::do_not_recommend] +impl Root for T where T: DontRecommend {} + +impl DontRecommend for T where T: Other {} + +#[diagnostic::do_not_recommend] +impl Other for T where T: Child {} + +fn needs_root() {} + +fn main() { + needs_root::<()>(); + //~^ ERROR the trait bound `(): Root` is not satisfied +} diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/simple.current.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/simple.current.stderr index 729cb5694e216..884b13c17b802 100644 --- a/tests/ui/diagnostic_namespace/do_not_recommend/simple.current.stderr +++ b/tests/ui/diagnostic_namespace/do_not_recommend/simple.current.stderr @@ -1,11 +1,11 @@ error[E0277]: the trait bound `*mut (): Foo` is not satisfied - --> $DIR/simple.rs:17:17 + --> $DIR/simple.rs:15:17 | LL | needs_foo::<*mut ()>(); | ^^^^^^^ the trait `Foo` is not implemented for `*mut ()` | note: required by a bound in `needs_foo` - --> $DIR/simple.rs:12:17 + --> $DIR/simple.rs:10:17 | LL | fn needs_foo() {} | ^^^ required by this bound in `needs_foo` diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/simple.next.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/simple.next.stderr index 729cb5694e216..884b13c17b802 100644 --- a/tests/ui/diagnostic_namespace/do_not_recommend/simple.next.stderr +++ b/tests/ui/diagnostic_namespace/do_not_recommend/simple.next.stderr @@ -1,11 +1,11 @@ error[E0277]: the trait bound `*mut (): Foo` is not satisfied - --> $DIR/simple.rs:17:17 + --> $DIR/simple.rs:15:17 | LL | needs_foo::<*mut ()>(); | ^^^^^^^ the trait `Foo` is not implemented for `*mut ()` | note: required by a bound in `needs_foo` - --> $DIR/simple.rs:12:17 + --> $DIR/simple.rs:10:17 | LL | fn needs_foo() {} | ^^^ required by this bound in `needs_foo` diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/simple.rs b/tests/ui/diagnostic_namespace/do_not_recommend/simple.rs index 780649b009c63..6bca2b724d240 100644 --- a/tests/ui/diagnostic_namespace/do_not_recommend/simple.rs +++ b/tests/ui/diagnostic_namespace/do_not_recommend/simple.rs @@ -2,8 +2,6 @@ //@ ignore-compare-mode-next-solver (explicit revisions) //@[next] compile-flags: -Znext-solver -#![feature(do_not_recommend)] - trait Foo {} #[diagnostic::do_not_recommend] diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/stacked.current.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/stacked.current.stderr index 41a10a61e1dfd..d86058063955e 100644 --- a/tests/ui/diagnostic_namespace/do_not_recommend/stacked.current.stderr +++ b/tests/ui/diagnostic_namespace/do_not_recommend/stacked.current.stderr @@ -1,11 +1,11 @@ error[E0277]: the trait bound `(): Root` is not satisfied - --> $DIR/stacked.rs:19:18 + --> $DIR/stacked.rs:17:18 | LL | needs_root::<()>(); | ^^ the trait `Root` is not implemented for `()` | note: required by a bound in `needs_root` - --> $DIR/stacked.rs:16:18 + --> $DIR/stacked.rs:14:18 | LL | fn needs_root() {} | ^^^^ required by this bound in `needs_root` diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/stacked.next.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/stacked.next.stderr index 41a10a61e1dfd..d86058063955e 100644 --- a/tests/ui/diagnostic_namespace/do_not_recommend/stacked.next.stderr +++ b/tests/ui/diagnostic_namespace/do_not_recommend/stacked.next.stderr @@ -1,11 +1,11 @@ error[E0277]: the trait bound `(): Root` is not satisfied - --> $DIR/stacked.rs:19:18 + --> $DIR/stacked.rs:17:18 | LL | needs_root::<()>(); | ^^ the trait `Root` is not implemented for `()` | note: required by a bound in `needs_root` - --> $DIR/stacked.rs:16:18 + --> $DIR/stacked.rs:14:18 | LL | fn needs_root() {} | ^^^^ required by this bound in `needs_root` diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/stacked.rs b/tests/ui/diagnostic_namespace/do_not_recommend/stacked.rs index fc355bdc4e204..842e04b9d9017 100644 --- a/tests/ui/diagnostic_namespace/do_not_recommend/stacked.rs +++ b/tests/ui/diagnostic_namespace/do_not_recommend/stacked.rs @@ -2,8 +2,6 @@ //@ ignore-compare-mode-next-solver (explicit revisions) //@[next] compile-flags: -Znext-solver -#![feature(do_not_recommend)] - trait Root {} trait DontRecommend {} trait Other {} diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.current.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.current.stderr index ca9a6ebc1c45f..95ccbb92a89b0 100644 --- a/tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.current.stderr +++ b/tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.current.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `(): Foo` is not satisfied - --> $DIR/supress_suggestions_in_help.rs:23:11 + --> $DIR/supress_suggestions_in_help.rs:21:11 | LL | check(()); | ----- ^^ the trait `Foo` is not implemented for `()` @@ -8,7 +8,7 @@ LL | check(()); | = help: the trait `Foo` is implemented for `i32` note: required by a bound in `check` - --> $DIR/supress_suggestions_in_help.rs:20:18 + --> $DIR/supress_suggestions_in_help.rs:18:18 | LL | fn check(a: impl Foo) {} | ^^^ required by this bound in `check` diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.next.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.next.stderr index ca9a6ebc1c45f..95ccbb92a89b0 100644 --- a/tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.next.stderr +++ b/tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.next.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `(): Foo` is not satisfied - --> $DIR/supress_suggestions_in_help.rs:23:11 + --> $DIR/supress_suggestions_in_help.rs:21:11 | LL | check(()); | ----- ^^ the trait `Foo` is not implemented for `()` @@ -8,7 +8,7 @@ LL | check(()); | = help: the trait `Foo` is implemented for `i32` note: required by a bound in `check` - --> $DIR/supress_suggestions_in_help.rs:20:18 + --> $DIR/supress_suggestions_in_help.rs:18:18 | LL | fn check(a: impl Foo) {} | ^^^ required by this bound in `check` diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.rs b/tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.rs index ef6f255c3518b..2c7c151612303 100644 --- a/tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.rs +++ b/tests/ui/diagnostic_namespace/do_not_recommend/supress_suggestions_in_help.rs @@ -2,8 +2,6 @@ //@ ignore-compare-mode-next-solver (explicit revisions) //@[next] compile-flags: -Znext-solver -#![feature(do_not_recommend)] - trait Foo {} #[diagnostic::do_not_recommend] diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/type_mismatch.current.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/type_mismatch.current.stderr index bcede8a255f23..b53febbb71ab8 100644 --- a/tests/ui/diagnostic_namespace/do_not_recommend/type_mismatch.current.stderr +++ b/tests/ui/diagnostic_namespace/do_not_recommend/type_mismatch.current.stderr @@ -1,11 +1,11 @@ error[E0277]: Very important message! - --> $DIR/type_mismatch.rs:25:14 + --> $DIR/type_mismatch.rs:23:14 | LL | verify::(); | ^^ the trait `TheImportantOne` is not implemented for `u8` | note: required by a bound in `verify` - --> $DIR/type_mismatch.rs:22:14 + --> $DIR/type_mismatch.rs:20:14 | LL | fn verify() {} | ^^^^^^^^^^^^^^^ required by this bound in `verify` diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/type_mismatch.next.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/type_mismatch.next.stderr index bcede8a255f23..b53febbb71ab8 100644 --- a/tests/ui/diagnostic_namespace/do_not_recommend/type_mismatch.next.stderr +++ b/tests/ui/diagnostic_namespace/do_not_recommend/type_mismatch.next.stderr @@ -1,11 +1,11 @@ error[E0277]: Very important message! - --> $DIR/type_mismatch.rs:25:14 + --> $DIR/type_mismatch.rs:23:14 | LL | verify::(); | ^^ the trait `TheImportantOne` is not implemented for `u8` | note: required by a bound in `verify` - --> $DIR/type_mismatch.rs:22:14 + --> $DIR/type_mismatch.rs:20:14 | LL | fn verify() {} | ^^^^^^^^^^^^^^^ required by this bound in `verify` diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/type_mismatch.rs b/tests/ui/diagnostic_namespace/do_not_recommend/type_mismatch.rs index d6721ccc848f8..7f30fdb06c75a 100644 --- a/tests/ui/diagnostic_namespace/do_not_recommend/type_mismatch.rs +++ b/tests/ui/diagnostic_namespace/do_not_recommend/type_mismatch.rs @@ -2,8 +2,6 @@ //@ ignore-compare-mode-next-solver (explicit revisions) //@[next] compile-flags: -Znext-solver -#![feature(do_not_recommend)] - #[diagnostic::on_unimplemented(message = "Very important message!")] trait TheImportantOne {} diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/unstable-feature.rs b/tests/ui/diagnostic_namespace/do_not_recommend/unstable-feature.rs deleted file mode 100644 index ccc687aa5b362..0000000000000 --- a/tests/ui/diagnostic_namespace/do_not_recommend/unstable-feature.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![deny(unknown_or_malformed_diagnostic_attributes)] -trait Foo {} - -#[diagnostic::do_not_recommend] -//~^ ERROR unknown diagnostic attribute [unknown_or_malformed_diagnostic_attributes] -impl Foo for i32 {} - -fn main() {} diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/unstable-feature.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/unstable-feature.stderr deleted file mode 100644 index d8332229d4fc4..0000000000000 --- a/tests/ui/diagnostic_namespace/do_not_recommend/unstable-feature.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error: unknown diagnostic attribute - --> $DIR/unstable-feature.rs:4:15 - | -LL | #[diagnostic::do_not_recommend] - | ^^^^^^^^^^^^^^^^ - | -note: the lint level is defined here - --> $DIR/unstable-feature.rs:1:9 - | -LL | #![deny(unknown_or_malformed_diagnostic_attributes)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 1 previous error - diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/with_lifetime.current.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/with_lifetime.current.stderr new file mode 100644 index 0000000000000..a8429ff60f83a --- /dev/null +++ b/tests/ui/diagnostic_namespace/do_not_recommend/with_lifetime.current.stderr @@ -0,0 +1,10 @@ +error: lifetime may not live long enough + --> $DIR/with_lifetime.rs:17:5 + | +LL | fn foo<'a>(a: &'a ()) { + | -- lifetime `'a` defined here +LL | needs_root::<&'a ()>(); + | ^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` + +error: aborting due to 1 previous error + diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/with_lifetime.next.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/with_lifetime.next.stderr new file mode 100644 index 0000000000000..a8429ff60f83a --- /dev/null +++ b/tests/ui/diagnostic_namespace/do_not_recommend/with_lifetime.next.stderr @@ -0,0 +1,10 @@ +error: lifetime may not live long enough + --> $DIR/with_lifetime.rs:17:5 + | +LL | fn foo<'a>(a: &'a ()) { + | -- lifetime `'a` defined here +LL | needs_root::<&'a ()>(); + | ^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` + +error: aborting due to 1 previous error + diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/with_lifetime.rs b/tests/ui/diagnostic_namespace/do_not_recommend/with_lifetime.rs new file mode 100644 index 0000000000000..6a67d83d5fe4d --- /dev/null +++ b/tests/ui/diagnostic_namespace/do_not_recommend/with_lifetime.rs @@ -0,0 +1,23 @@ +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver + +trait Root {} +trait DontRecommend {} + +impl Root for T where T: DontRecommend {} + +// this has no effect yet for resolving the trait error below +#[diagnostic::do_not_recommend] +impl DontRecommend for &'static T {} + +fn needs_root() {} + +fn foo<'a>(a: &'a ()) { + needs_root::<&'a ()>(); + //~^ ERROR lifetime may not live long enough +} + +fn main() { + foo(&()); +} diff --git a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/norm-before-method-resolution-opaque-type.next.stderr b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/norm-before-method-resolution-opaque-type.next.stderr deleted file mode 100644 index 9e04e90a98ac0..0000000000000 --- a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/norm-before-method-resolution-opaque-type.next.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0284]: type annotations needed: cannot satisfy `Foo == _` - --> $DIR/norm-before-method-resolution-opaque-type.rs:15:19 - | -LL | fn weird_bound(x: &>::Out) -> X - | ^ cannot satisfy `Foo == _` - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0284`. diff --git a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/norm-before-method-resolution-opaque-type.old.stderr b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/norm-before-method-resolution-opaque-type.old.stderr index 479f59843557f..57cbe16911824 100644 --- a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/norm-before-method-resolution-opaque-type.old.stderr +++ b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/norm-before-method-resolution-opaque-type.old.stderr @@ -1,12 +1,12 @@ error: item does not constrain `Foo::{opaque#0}`, but has it in its signature - --> $DIR/norm-before-method-resolution-opaque-type.rs:15:4 + --> $DIR/norm-before-method-resolution-opaque-type.rs:16:4 | LL | fn weird_bound(x: &>::Out) -> X | ^^^^^^^^^^^ | = note: consider moving the opaque type's declaration and defining uses into a separate module note: this opaque type is in the signature - --> $DIR/norm-before-method-resolution-opaque-type.rs:13:12 + --> $DIR/norm-before-method-resolution-opaque-type.rs:14:12 | LL | type Foo = impl Sized; | ^^^^^^^^^^ diff --git a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/norm-before-method-resolution-opaque-type.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/norm-before-method-resolution-opaque-type.rs index ffbfc622bb012..43207d8927649 100644 --- a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/norm-before-method-resolution-opaque-type.rs +++ b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/norm-before-method-resolution-opaque-type.rs @@ -1,5 +1,6 @@ //@ revisions: old next //@[next] compile-flags: -Znext-solver +//@[next] check-pass #![feature(type_alias_impl_trait)] trait Trait<'a> { @@ -14,7 +15,6 @@ type Foo = impl Sized; fn weird_bound(x: &>::Out) -> X //[old]~^ ERROR: item does not constrain -//[next]~^^ ERROR: cannot satisfy `Foo == _` where for<'a> X: Trait<'a>, for<'a> >::Out<()>: Copy, diff --git a/tests/ui/associated-path-shl.rs b/tests/ui/parser/associated-path-shl.rs similarity index 100% rename from tests/ui/associated-path-shl.rs rename to tests/ui/parser/associated-path-shl.rs diff --git a/tests/ui/associated-path-shl.stderr b/tests/ui/parser/associated-path-shl.stderr similarity index 100% rename from tests/ui/associated-path-shl.stderr rename to tests/ui/parser/associated-path-shl.stderr diff --git a/tests/ui/pattern/slice-pattern-refutable.stderr b/tests/ui/pattern/slice-pattern-refutable.stderr index df5b58d3e9c63..3d9f769d1341e 100644 --- a/tests/ui/pattern/slice-pattern-refutable.stderr +++ b/tests/ui/pattern/slice-pattern-refutable.stderr @@ -1,13 +1,15 @@ error[E0282]: type annotations needed - --> $DIR/slice-pattern-refutable.rs:14:9 + --> $DIR/slice-pattern-refutable.rs:14:28 | LL | let [a, b, c] = Zeroes.into() else { - | ^^^^^^^^^ + | --------- ^^^^ + | | + | type must be known at this point | -help: consider giving this pattern a type +help: try using a fully qualified path to specify the expected types | -LL | let [a, b, c]: /* Type */ = Zeroes.into() else { - | ++++++++++++ +LL | let [a, b, c] = >::into(Zeroes) else { + | ++++++++++++++++++++++++++ ~ error[E0282]: type annotations needed --> $DIR/slice-pattern-refutable.rs:21:31 diff --git a/tests/ui/pattern/slice-patterns-ambiguity.stderr b/tests/ui/pattern/slice-patterns-ambiguity.stderr index 3ef99d0e2d1bb..690776196ce15 100644 --- a/tests/ui/pattern/slice-patterns-ambiguity.stderr +++ b/tests/ui/pattern/slice-patterns-ambiguity.stderr @@ -1,13 +1,15 @@ -error[E0282]: type annotations needed for `&_` - --> $DIR/slice-patterns-ambiguity.rs:25:9 +error[E0282]: type annotations needed + --> $DIR/slice-patterns-ambiguity.rs:25:26 | LL | let &[a, b] = Zeroes.into() else { - | ^^^^^^^ + | ------ ^^^^ + | | + | type must be known at this point | -help: consider giving this pattern a type, where the placeholders `_` are specified +help: try using a fully qualified path to specify the expected types | -LL | let &[a, b]: &_ = Zeroes.into() else { - | ++++ +LL | let &[a, b] = >::into(Zeroes) else { + | +++++++++++++++++++++++++++ ~ error[E0282]: type annotations needed --> $DIR/slice-patterns-ambiguity.rs:32:29 diff --git a/tests/ui/attrs-resolution-errors.rs b/tests/ui/resolve/attr-macros-positional-rejection.rs similarity index 73% rename from tests/ui/attrs-resolution-errors.rs rename to tests/ui/resolve/attr-macros-positional-rejection.rs index 8770fb1ded8eb..11382ff13998d 100644 --- a/tests/ui/attrs-resolution-errors.rs +++ b/tests/ui/resolve/attr-macros-positional-rejection.rs @@ -1,3 +1,12 @@ +//! Check that certain positions (listed below) only permit *non-macro* attributes and reject +//! attribute macros: +//! +//! - Enum variants +//! - Struct fields +//! - Field in a struct pattern +//! - Match arm +//! - Field in struct initialization expression + enum FooEnum { #[test] //~^ ERROR expected non-macro attribute, found attribute macro @@ -32,7 +41,7 @@ fn main() { _ => {} } - let _another_foo_strunct = FooStruct { + let _another_foo_struct = FooStruct { #[test] //~^ ERROR expected non-macro attribute, found attribute macro bar: 1, diff --git a/tests/ui/attrs-resolution-errors.stderr b/tests/ui/resolve/attr-macros-positional-rejection.stderr similarity index 73% rename from tests/ui/attrs-resolution-errors.stderr rename to tests/ui/resolve/attr-macros-positional-rejection.stderr index 883f96e5c1931..faea511f31507 100644 --- a/tests/ui/attrs-resolution-errors.stderr +++ b/tests/ui/resolve/attr-macros-positional-rejection.stderr @@ -1,29 +1,29 @@ error: expected non-macro attribute, found attribute macro `test` - --> $DIR/attrs-resolution-errors.rs:2:7 + --> $DIR/attr-macros-positional-rejection.rs:11:7 | LL | #[test] | ^^^^ not a non-macro attribute error: expected non-macro attribute, found attribute macro `test` - --> $DIR/attrs-resolution-errors.rs:8:7 + --> $DIR/attr-macros-positional-rejection.rs:17:7 | LL | #[test] | ^^^^ not a non-macro attribute error: expected non-macro attribute, found attribute macro `test` - --> $DIR/attrs-resolution-errors.rs:23:15 + --> $DIR/attr-macros-positional-rejection.rs:32:15 | LL | #[test] bar | ^^^^ not a non-macro attribute error: expected non-macro attribute, found attribute macro `test` - --> $DIR/attrs-resolution-errors.rs:30:11 + --> $DIR/attr-macros-positional-rejection.rs:39:11 | LL | #[test] | ^^^^ not a non-macro attribute error: expected non-macro attribute, found attribute macro `test` - --> $DIR/attrs-resolution-errors.rs:36:11 + --> $DIR/attr-macros-positional-rejection.rs:45:11 | LL | #[test] | ^^^^ not a non-macro attribute diff --git a/tests/ui/attrs-resolution.rs b/tests/ui/resolve/non-macro-attrs-accepted.rs similarity index 66% rename from tests/ui/attrs-resolution.rs rename to tests/ui/resolve/non-macro-attrs-accepted.rs index 38dd3812d6892..76a04b2e83749 100644 --- a/tests/ui/attrs-resolution.rs +++ b/tests/ui/resolve/non-macro-attrs-accepted.rs @@ -1,3 +1,11 @@ +//! Check that certain positions (listed below) permit *non-macro* attributes. +//! +//! - Enum variants +//! - Struct fields +//! - Field in a struct pattern +//! - Match arm +//! - Field in struct initialization expression + //@ check-pass enum FooEnum { @@ -30,7 +38,7 @@ fn main() { _ => {} } - let _another_foo_strunct = FooStruct { + let _another_foo_struct = FooStruct { #[rustfmt::skip] bar: 1, }; diff --git a/tests/ui/traits/next-solver/generalize/occurs-check-nested-alias.rs b/tests/ui/traits/next-solver/generalize/occurs-check-nested-alias.rs index 00dc7a9d337d9..fbf4cadc678d5 100644 --- a/tests/ui/traits/next-solver/generalize/occurs-check-nested-alias.rs +++ b/tests/ui/traits/next-solver/generalize/occurs-check-nested-alias.rs @@ -37,9 +37,4 @@ fn foo() { // result in a cyclic type. However, we can still unify these types by first // normalizing the inner associated type. Emitting an error here would be incomplete. drop::(t); - - // FIXME(-Znext-solver): This line is necessary due to an unrelated solver bug - // and should get removed in the future. - // https://github.com/rust-lang/trait-system-refactor-initiative/issues/96 - drop::::Assoc>>(u); } diff --git a/tests/ui/traits/winnowing/global-non-global-env-1.rs b/tests/ui/traits/winnowing/global-non-global-env-1.rs index d232d32dddffd..75c184b65bf04 100644 --- a/tests/ui/traits/winnowing/global-non-global-env-1.rs +++ b/tests/ui/traits/winnowing/global-non-global-env-1.rs @@ -1,3 +1,6 @@ +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver //@ check-pass // A regression test for an edge case of candidate selection diff --git a/tests/ui/traits/winnowing/global-non-global-env-2.rs b/tests/ui/traits/winnowing/global-non-global-env-2.rs index c73d0f06cd95b..128ec2a40dab0 100644 --- a/tests/ui/traits/winnowing/global-non-global-env-2.rs +++ b/tests/ui/traits/winnowing/global-non-global-env-2.rs @@ -1,3 +1,6 @@ +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver //@ check-pass // A regression test for an edge case of candidate selection diff --git a/tests/ui/traits/winnowing/global-non-global-env-3.rs b/tests/ui/traits/winnowing/global-non-global-env-3.rs index 008d07e41446a..7e5dbd4ba8ec8 100644 --- a/tests/ui/traits/winnowing/global-non-global-env-3.rs +++ b/tests/ui/traits/winnowing/global-non-global-env-3.rs @@ -1,3 +1,6 @@ +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver //@ check-pass // A regression test for an edge case of candidate selection diff --git a/tests/ui/traits/winnowing/global-non-global-env-4.rs b/tests/ui/traits/winnowing/global-non-global-env-4.rs index 74793620c9e7d..2dc082be45c5e 100644 --- a/tests/ui/traits/winnowing/global-non-global-env-4.rs +++ b/tests/ui/traits/winnowing/global-non-global-env-4.rs @@ -1,3 +1,6 @@ +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver //@ check-pass // A regression test for an edge case of candidate selection diff --git a/tests/ui/attempted-access-non-fatal.rs b/tests/ui/typeck/attempted-access-non-fatal.rs similarity index 100% rename from tests/ui/attempted-access-non-fatal.rs rename to tests/ui/typeck/attempted-access-non-fatal.rs diff --git a/tests/ui/attempted-access-non-fatal.stderr b/tests/ui/typeck/attempted-access-non-fatal.stderr similarity index 100% rename from tests/ui/attempted-access-non-fatal.stderr rename to tests/ui/typeck/attempted-access-non-fatal.stderr