diff options
55 files changed, 837 insertions, 195 deletions
diff --git a/compiler/rustc_borrowck/src/renumber.rs b/compiler/rustc_borrowck/src/renumber.rs index d83d6ade203..e355d2b415b 100644 --- a/compiler/rustc_borrowck/src/renumber.rs +++ b/compiler/rustc_borrowck/src/renumber.rs @@ -34,7 +34,6 @@ pub(crate) enum RegionCtxt { Location(Location), TyContext(TyContext), Free(Symbol), - Bound(Symbol), LateBound(Symbol), Existential(Option<Symbol>), Placeholder(Symbol), diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs index ea965eb6545..edf612f4e97 100644 --- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs +++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs @@ -5,13 +5,14 @@ use rustc_infer::infer::canonical::QueryRegionConstraints; use rustc_infer::infer::outlives::env::RegionBoundPairs; use rustc_infer::infer::region_constraints::GenericKind; use rustc_infer::infer::{InferCtxt, outlives}; +use rustc_infer::traits::ScrubbedTraitError; use rustc_middle::mir::ConstraintCategory; use rustc_middle::traits::ObligationCause; use rustc_middle::traits::query::OutlivesBound; use rustc_middle::ty::{self, RegionVid, Ty, TypeVisitableExt}; use rustc_span::{ErrorGuaranteed, Span}; -use rustc_trait_selection::error_reporting::InferCtxtErrorExt; -use rustc_trait_selection::solve::deeply_normalize; +use rustc_trait_selection::solve::NoSolution; +use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp; use rustc_trait_selection::traits::query::type_op::{self, TypeOp}; use tracing::{debug, instrument}; use type_op::TypeOpOutput; @@ -229,24 +230,14 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { let mut constraints = vec![]; let mut known_type_outlives_obligations = vec![]; for bound in param_env.caller_bounds() { - let Some(mut outlives) = bound.as_type_outlives_clause() else { continue }; - - // In the new solver, normalize the type-outlives obligation assumptions. - if self.infcx.next_trait_solver() { - match deeply_normalize( - self.infcx.at(&ObligationCause::misc(span, defining_ty_def_id), param_env), + if let Some(outlives) = bound.as_type_outlives_clause() { + self.normalize_and_push_type_outlives_obligation( outlives, - ) { - Ok(normalized_outlives) => { - outlives = normalized_outlives; - } - Err(e) => { - self.infcx.err_ctxt().report_fulfillment_errors(e); - } - } - } - - known_type_outlives_obligations.push(outlives); + span, + &mut known_type_outlives_obligations, + &mut constraints, + ); + }; } let unnormalized_input_output_tys = self @@ -356,6 +347,44 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { } } + fn normalize_and_push_type_outlives_obligation( + &self, + mut outlives: ty::PolyTypeOutlivesPredicate<'tcx>, + span: Span, + known_type_outlives_obligations: &mut Vec<ty::PolyTypeOutlivesPredicate<'tcx>>, + constraints: &mut Vec<&QueryRegionConstraints<'tcx>>, + ) { + // In the new solver, normalize the type-outlives obligation assumptions. + if self.infcx.next_trait_solver() { + let Ok(TypeOpOutput { + output: normalized_outlives, + constraints: constraints_normalize, + error_info: _, + }) = CustomTypeOp::new( + |ocx| { + ocx.deeply_normalize( + &ObligationCause::dummy_with_span(span), + self.param_env, + outlives, + ) + .map_err(|_: Vec<ScrubbedTraitError<'tcx>>| NoSolution) + }, + "normalize type outlives obligation", + ) + .fully_perform(self.infcx, span) + else { + self.infcx.dcx().delayed_bug(format!("could not normalize {outlives:?}")); + return; + }; + outlives = normalized_outlives; + if let Some(c) = constraints_normalize { + constraints.push(c); + } + } + + known_type_outlives_obligations.push(outlives); + } + /// Update the type of a single local, which should represent /// either the return type of the MIR or one of its arguments. At /// the same time, compute and add any implied bounds that come diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index 3dc4569c57b..26af86c0cdd 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -467,15 +467,13 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { self.infcx.tcx.local_parent(self.mir_def), |r| { debug!(?r); - if !indices.indices.contains_key(&r) { - let region_vid = { - let name = r.get_name_or_anon(); - self.infcx.next_nll_region_var(FR, || RegionCtxt::LateBound(name)) - }; - - debug!(?region_vid); - indices.insert_late_bound_region(r, region_vid.as_var()); - } + let region_vid = { + let name = r.get_name_or_anon(); + self.infcx.next_nll_region_var(FR, || RegionCtxt::LateBound(name)) + }; + + debug!(?region_vid); + indices.insert_late_bound_region(r, region_vid.as_var()); }, ); @@ -484,21 +482,17 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { self.infcx.num_region_vars() }; - // "Liberate" the late-bound regions. These correspond to - // "local" free regions. + // Converse of above, if this is a function/closure then the late-bound regions declared + // on its signature are local. + // + // We manually loop over `bound_inputs_and_output` instead of using + // `for_each_late_bound_region_in_item` as we may need to add the otherwise + // implicit `ClosureEnv` region. let bound_inputs_and_output = self.compute_inputs_and_output(&indices, defining_ty); - - let inputs_and_output = self.infcx.replace_bound_regions_with_nll_infer_vars( - FR, - self.mir_def, - bound_inputs_and_output, - &mut indices, - ); - // Converse of above, if this is a function/closure then the late-bound regions declared on its - // signature are local. - for_each_late_bound_region_in_item(self.infcx.tcx, self.mir_def, |r| { - debug!(?r); - if !indices.indices.contains_key(&r) { + for (idx, bound_var) in bound_inputs_and_output.bound_vars().iter().enumerate() { + if let ty::BoundVariableKind::Region(kind) = bound_var { + let kind = ty::LateParamRegionKind::from_bound(ty::BoundVar::from_usize(idx), kind); + let r = ty::Region::new_late_param(self.infcx.tcx, self.mir_def.to_def_id(), kind); let region_vid = { let name = r.get_name_or_anon(); self.infcx.next_nll_region_var(FR, || RegionCtxt::LateBound(name)) @@ -507,7 +501,12 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { debug!(?region_vid); indices.insert_late_bound_region(r, region_vid.as_var()); } - }); + } + let inputs_and_output = self.infcx.replace_bound_regions_with_nll_infer_vars( + self.mir_def, + bound_inputs_and_output, + &indices, + ); let (unnormalized_output_ty, mut unnormalized_input_tys) = inputs_and_output.split_last().unwrap(); @@ -832,10 +831,9 @@ impl<'tcx> BorrowckInferCtxt<'tcx> { #[instrument(level = "debug", skip(self, indices))] fn replace_bound_regions_with_nll_infer_vars<T>( &self, - origin: NllRegionVariableOrigin, all_outlive_scope: LocalDefId, value: ty::Binder<'tcx, T>, - indices: &mut UniversalRegionIndices<'tcx>, + indices: &UniversalRegionIndices<'tcx>, ) -> T where T: TypeFoldable<TyCtxt<'tcx>>, @@ -845,18 +843,7 @@ impl<'tcx> BorrowckInferCtxt<'tcx> { let kind = ty::LateParamRegionKind::from_bound(br.var, br.kind); let liberated_region = ty::Region::new_late_param(self.tcx, all_outlive_scope.to_def_id(), kind); - let region_vid = { - let name = match br.kind.get_name() { - Some(name) => name, - _ => sym::anon, - }; - - self.next_nll_region_var(origin, || RegionCtxt::Bound(name)) - }; - - indices.insert_late_bound_region(liberated_region, region_vid.as_var()); - debug!(?liberated_region, ?region_vid); - region_vid + ty::Region::new_var(self.tcx, indices.to_region_vid(liberated_region)) }); value } @@ -870,7 +857,7 @@ impl<'tcx> UniversalRegionIndices<'tcx> { /// well. These are used for error reporting. fn insert_late_bound_region(&mut self, r: ty::Region<'tcx>, vid: ty::RegionVid) { debug!("insert_late_bound_region({:?}, {:?})", r, vid); - self.indices.insert(r, vid); + assert_eq!(self.indices.insert(r, vid), None); } /// Converts `r` into a local inference variable: `r` can either diff --git a/compiler/rustc_codegen_cranelift/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch b/compiler/rustc_codegen_cranelift/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch index bf07e455a75..b2eeb526336 100644 --- a/compiler/rustc_codegen_cranelift/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch +++ b/compiler/rustc_codegen_cranelift/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch @@ -16,8 +16,8 @@ index 7165c3e48af..968552ad435 100644 [dependencies] core = { path = "../core" } --compiler_builtins = { version = "=0.1.140", features = ['rustc-dep-of-std'] } -+compiler_builtins = { version = "=0.1.140", features = ['rustc-dep-of-std', 'no-f16-f128'] } +-compiler_builtins = { version = "=0.1.141", features = ['rustc-dep-of-std'] } ++compiler_builtins = { version = "=0.1.141", features = ['rustc-dep-of-std', 'no-f16-f128'] } [dev-dependencies] rand = { version = "0.8.5", default-features = false, features = ["alloc"] } diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index 0c3ed9b5c60..d7ab6eca84b 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -135,7 +135,7 @@ hir_analysis_dispatch_from_dyn_multi = implementing the `DispatchFromDyn` trait hir_analysis_dispatch_from_dyn_repr = structs implementing `DispatchFromDyn` may not have `#[repr(packed)]` or `#[repr(C)]` -hir_analysis_dispatch_from_dyn_zst = the trait `DispatchFromDyn` may only be implemented for structs containing the field being coerced, ZST fields with 1 byte alignment, and nothing else +hir_analysis_dispatch_from_dyn_zst = the trait `DispatchFromDyn` may only be implemented for structs containing the field being coerced, ZST fields with 1 byte alignment that don't mention type/const generics, and nothing else .note = extra field `{$name}` of type `{$ty}` is not allowed hir_analysis_drop_impl_negative = negative `Drop` impls are not supported diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index 3b98f358b1e..b43a808ccdc 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -259,19 +259,37 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<() let coerced_fields = fields .iter() .filter(|field| { + // Ignore PhantomData fields + let unnormalized_ty = tcx.type_of(field.did).instantiate_identity(); + if tcx + .try_normalize_erasing_regions( + ty::TypingEnv::non_body_analysis(tcx, def_a.did()), + unnormalized_ty, + ) + .unwrap_or(unnormalized_ty) + .is_phantom_data() + { + return false; + } + let ty_a = field.ty(tcx, args_a); let ty_b = field.ty(tcx, args_b); - if let Ok(layout) = - tcx.layout_of(infcx.typing_env(param_env).as_query_input(ty_a)) - { - if layout.is_1zst() { + // FIXME: We could do normalization here, but is it really worth it? + if ty_a == ty_b { + // Allow 1-ZSTs that don't mention type params. + // + // Allowing type params here would allow us to possibly transmute + // between ZSTs, which may be used to create library unsoundness. + if let Ok(layout) = + tcx.layout_of(infcx.typing_env(param_env).as_query_input(ty_a)) + && layout.is_1zst() + && !ty_a.has_non_region_param() + { // ignore 1-ZST fields return false; } - } - if ty_a == ty_b { res = Err(tcx.dcx().emit_err(errors::DispatchFromDynZST { span, name: field.name, @@ -460,8 +478,16 @@ pub(crate) fn coerce_unsized_info<'tcx>( .filter_map(|(i, f)| { let (a, b) = (f.ty(tcx, args_a), f.ty(tcx, args_b)); - if tcx.type_of(f.did).instantiate_identity().is_phantom_data() { - // Ignore PhantomData fields + // Ignore PhantomData fields + let unnormalized_ty = tcx.type_of(f.did).instantiate_identity(); + if tcx + .try_normalize_erasing_regions( + ty::TypingEnv::non_body_analysis(tcx, def_a.did()), + unnormalized_ty, + ) + .unwrap_or(unnormalized_ty) + .is_phantom_data() + { return None; } diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index c2e9498908c..0f3943cfe6a 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -1407,7 +1407,7 @@ impl<'v> RootCollector<'_, 'v> { match self.tcx.def_kind(id.owner_id) { DefKind::Enum | DefKind::Struct | DefKind::Union => { if self.strategy == MonoItemCollectionStrategy::Eager - && self.tcx.generics_of(id.owner_id).is_empty() + && !self.tcx.generics_of(id.owner_id).requires_monomorphization(self.tcx) { debug!("RootCollector: ADT drop-glue for `{id:?}`",); @@ -1420,7 +1420,10 @@ impl<'v> RootCollector<'_, 'v> { return; } - let ty = self.tcx.type_of(id.owner_id.to_def_id()).no_bound_vars().unwrap(); + let ty = self.tcx.erase_regions( + self.tcx.type_of(id.owner_id.to_def_id()).instantiate_identity(), + ); + assert!(!ty.has_non_region_param()); visit_drop_use(self.tcx, ty, true, DUMMY_SP, self.output); } } diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs index 58c0a05df1f..879f3fac21f 100644 --- a/compiler/rustc_symbol_mangling/src/legacy.rs +++ b/compiler/rustc_symbol_mangling/src/legacy.rs @@ -19,15 +19,15 @@ pub(super) fn mangle<'tcx>( let def_id = instance.def_id(); // We want to compute the "type" of this item. Unfortunately, some - // kinds of items (e.g., closures) don't have an entry in the - // item-type array. So walk back up the find the closest parent - // that DOES have an entry. + // kinds of items (e.g., synthetic static allocations from const eval) + // don't have a proper implementation for the `type_of` query. So walk + // back up the find the closest parent that DOES have a type. let mut ty_def_id = def_id; let instance_ty; loop { let key = tcx.def_key(ty_def_id); match key.disambiguated_data.data { - DefPathData::TypeNs(_) | DefPathData::ValueNs(_) => { + DefPathData::TypeNs(_) | DefPathData::ValueNs(_) | DefPathData::Closure => { instance_ty = tcx.type_of(ty_def_id).instantiate_identity(); debug!(?instance_ty); break; diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index 7db0f2bb5a7..4498beff4ea 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -264,9 +264,10 @@ fn fulfillment_error_for_no_solution<'tcx>( infcx.tcx.type_of(uv.def).instantiate(infcx.tcx, uv.args) } ty::ConstKind::Param(param_ct) => param_ct.find_ty_from_env(obligation.param_env), - _ => span_bug!( + ty::ConstKind::Value(ty, _) => ty, + kind => span_bug!( obligation.cause.span, - "ConstArgHasWrongType failed but we don't know how to compute type" + "ConstArgHasWrongType failed but we don't know how to compute type for {kind:?}" ), }; FulfillmentErrorCode::Select(SelectionError::ConstArgHasWrongType { diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 1dcd0d0dfb8..da16a742099 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -714,9 +714,18 @@ pub fn impossible_predicates<'tcx>(tcx: TyCtxt<'tcx>, predicates: Vec<ty::Clause } let errors = ocx.select_all_or_error(); - let result = !errors.is_empty(); - debug!("impossible_predicates = {:?}", result); - result + if !errors.is_empty() { + return true; + } + + // Leak check for any higher-ranked trait mismatches. + // We only need to do this in the old solver, since the new solver already + // leak-checks. + if !infcx.next_trait_solver() && infcx.leak_check(ty::UniverseIndex::ROOT, None).is_err() { + return true; + } + + false } fn instantiate_and_check_impossible_predicates<'tcx>( diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index ab606478c51..17be0bd0ab9 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -105,21 +105,27 @@ fn map_error<'tcx>( // See `tests/ui/layout/trivial-bounds-sized.rs` for an example. assert!(field.layout.is_unsized(), "invalid layout error {err:#?}"); if !field.ty.is_sized(cx.tcx(), cx.typing_env) { - cx.tcx().dcx().delayed_bug(format!( + let guar = cx.tcx().dcx().delayed_bug(format!( "encountered unexpected unsized field in layout of {ty:?}: {field:#?}" )); + LayoutError::ReferencesError(guar) + } else { + LayoutError::Unknown(ty) } - LayoutError::Unknown(ty) } LayoutCalculatorError::EmptyUnion => { // This is always a compile error. - cx.tcx().dcx().delayed_bug(format!("computed layout of empty union: {ty:?}")); - LayoutError::Unknown(ty) + let guar = + cx.tcx().dcx().delayed_bug(format!("computed layout of empty union: {ty:?}")); + LayoutError::ReferencesError(guar) } LayoutCalculatorError::ReprConflict => { // packed enums are the only known trigger of this, but others might arise - cx.tcx().dcx().delayed_bug(format!("computed impossible repr (packed enum?): {ty:?}")); - LayoutError::Unknown(ty) + let guar = cx + .tcx() + .dcx() + .delayed_bug(format!("computed impossible repr (packed enum?): {ty:?}")); + LayoutError::ReferencesError(guar) } }; error(cx, err) @@ -432,8 +438,10 @@ fn layout_of_uncached<'tcx>( ty::Adt(def, args) if def.repr().simd() => { if !def.is_struct() { // Should have yielded E0517 by now. - tcx.dcx().delayed_bug("#[repr(simd)] was applied to an ADT that is not a struct"); - return Err(error(cx, LayoutError::Unknown(ty))); + let guar = tcx + .dcx() + .delayed_bug("#[repr(simd)] was applied to an ADT that is not a struct"); + return Err(error(cx, LayoutError::ReferencesError(guar))); } let fields = &def.non_enum_variant().fields; @@ -459,10 +467,10 @@ fn layout_of_uncached<'tcx>( // (should be caught by typeck) for fi in fields { if fi.ty(tcx, args) != f0_ty { - tcx.dcx().delayed_bug( + let guar = tcx.dcx().delayed_bug( "#[repr(simd)] was applied to an ADT with heterogeneous field type", ); - return Err(error(cx, LayoutError::Unknown(ty))); + return Err(error(cx, LayoutError::ReferencesError(guar))); } } @@ -567,11 +575,11 @@ fn layout_of_uncached<'tcx>( if def.is_union() { if def.repr().pack.is_some() && def.repr().align.is_some() { - tcx.dcx().span_delayed_bug( + let guar = tcx.dcx().span_delayed_bug( tcx.def_span(def.did()), "union cannot be packed and aligned", ); - return Err(error(cx, LayoutError::Unknown(ty))); + return Err(error(cx, LayoutError::ReferencesError(guar))); } return Ok(tcx.mk_layout( diff --git a/library/Cargo.lock b/library/Cargo.lock index 207c744ee22..b01fec9b8f5 100644 --- a/library/Cargo.lock +++ b/library/Cargo.lock @@ -61,9 +61,9 @@ dependencies = [ [[package]] name = "compiler_builtins" -version = "0.1.140" +version = "0.1.141" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df14d41c5d172a886df3753d54238eefb0f61c96cbd8b363c33ccc92c457bee3" +checksum = "b5e7a0206befe4e574e37d6d7a0fe82e88fdf54bedb0608f239cb11b7a6aa6be" dependencies = [ "cc", "rustc-std-workspace-core", diff --git a/library/alloc/Cargo.toml b/library/alloc/Cargo.toml index 07596fa16f9..36f617b4526 100644 --- a/library/alloc/Cargo.toml +++ b/library/alloc/Cargo.toml @@ -10,7 +10,7 @@ edition = "2021" [dependencies] core = { path = "../core" } -compiler_builtins = { version = "=0.1.140", features = ['rustc-dep-of-std'] } +compiler_builtins = { version = "=0.1.141", features = ['rustc-dep-of-std'] } [dev-dependencies] rand = { version = "0.8.5", default-features = false, features = ["alloc"] } diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index e7f7f38cb41..f34dc185eb1 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -17,7 +17,7 @@ cfg-if = { version = "1.0", features = ['rustc-dep-of-std'] } panic_unwind = { path = "../panic_unwind", optional = true } panic_abort = { path = "../panic_abort" } core = { path = "../core", public = true } -compiler_builtins = { version = "=0.1.140" } +compiler_builtins = { version = "=0.1.141" } unwind = { path = "../unwind" } hashbrown = { version = "0.15", default-features = false, features = [ 'rustc-dep-of-std', diff --git a/src/bootstrap/src/core/build_steps/format.rs b/src/bootstrap/src/core/build_steps/format.rs index 40c908c3fa9..c7eafadee2d 100644 --- a/src/bootstrap/src/core/build_steps/format.rs +++ b/src/bootstrap/src/core/build_steps/format.rs @@ -116,7 +116,7 @@ fn print_paths(verb: &str, adjective: Option<&str>, paths: &[String]) { println!("fmt: {verb} {len} {adjective}files"); } if len > 1000 && !CiEnv::is_ci() { - println!("hint: if this number seems too high, try running `git fetch origin master"); + println!("hint: if this number seems too high, try running `git fetch origin master`"); } } diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 5af05c395d8..fdc1f30b859 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -24,8 +24,8 @@ use crate::core::config::flags::{Subcommand, get_completion}; use crate::utils::build_stamp::{self, BuildStamp}; use crate::utils::exec::{BootstrapCommand, command}; use crate::utils::helpers::{ - self, LldThreads, add_link_lib_path, add_rustdoc_cargo_linker_args, dylib_path, dylib_path_var, - linker_args, linker_flags, t, target_supports_cranelift_backend, up_to_date, + self, LldThreads, add_rustdoc_cargo_linker_args, dylib_path, dylib_path_var, linker_args, + linker_flags, t, target_supports_cranelift_backend, up_to_date, }; use crate::utils::render_tests::{add_flags_and_try_run_tests, try_run_tests}; use crate::{CLang, DocTests, GitRepo, Mode, PathSet, envify}; @@ -1975,11 +1975,17 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the // Tests that use compiler libraries may inherit the `-lLLVM` link // requirement, but the `-L` library path is not propagated across // separate compilations. We can add LLVM's library path to the - // platform-specific environment variable as a workaround. + // rustc args as a workaround. if !builder.config.dry_run() && suite.ends_with("fulldeps") { let llvm_libdir = command(&llvm_config).arg("--libdir").run_capture_stdout(builder).stdout(); - add_link_lib_path(vec![llvm_libdir.trim().into()], &mut cmd); + let mut rustflags = env::var("RUSTFLAGS").unwrap_or_default(); + if target.is_msvc() { + rustflags.push_str(&format!("-Clink-arg=-LIBPATH:{llvm_libdir}")); + } else { + rustflags.push_str(&format!("-Clink-arg=-L{llvm_libdir}")); + } + cmd.env("RUSTFLAGS", rustflags); } if !builder.config.dry_run() && matches!(mode, "run-make" | "coverage-run") { diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs index 2692a129ef3..f9fb19ddb09 100644 --- a/src/bootstrap/src/core/builder/cargo.rs +++ b/src/bootstrap/src/core/builder/cargo.rs @@ -8,9 +8,7 @@ use crate::core::build_steps::{compile, test}; use crate::core::config::SplitDebuginfo; use crate::core::config::flags::Color; use crate::utils::build_stamp; -use crate::utils::helpers::{ - self, LldThreads, add_link_lib_path, check_cfg_arg, linker_args, linker_flags, -}; +use crate::utils::helpers::{self, LldThreads, check_cfg_arg, linker_args, linker_flags}; use crate::{ BootstrapCommand, CLang, Compiler, DocTests, DryRun, EXTRA_CHECK_CFGS, GitRepo, Mode, TargetSelection, command, prepare_behaviour_dump_dir, t, @@ -947,12 +945,16 @@ impl Builder<'_> { // Tools that use compiler libraries may inherit the `-lLLVM` link // requirement, but the `-L` library path is not propagated across // separate Cargo projects. We can add LLVM's library path to the - // platform-specific environment variable as a workaround. + // rustc args as a workaround. if mode == Mode::ToolRustc || mode == Mode::Codegen { if let Some(llvm_config) = self.llvm_config(target) { let llvm_libdir = command(llvm_config).arg("--libdir").run_capture_stdout(self).stdout(); - add_link_lib_path(vec![llvm_libdir.trim().into()], &mut cargo); + if target.is_msvc() { + rustflags.arg(&format!("-Clink-arg=-LIBPATH:{llvm_libdir}")); + } else { + rustflags.arg(&format!("-Clink-arg=-L{llvm_libdir}")); + } } } diff --git a/src/bootstrap/src/utils/helpers.rs b/src/bootstrap/src/utils/helpers.rs index 516c314024b..a1b1748c85b 100644 --- a/src/bootstrap/src/utils/helpers.rs +++ b/src/bootstrap/src/utils/helpers.rs @@ -106,31 +106,6 @@ pub fn add_dylib_path(path: Vec<PathBuf>, cmd: &mut BootstrapCommand) { cmd.env(dylib_path_var(), t!(env::join_paths(list))); } -/// Adds a list of lookup paths to `cmd`'s link library lookup path. -pub fn add_link_lib_path(path: Vec<PathBuf>, cmd: &mut BootstrapCommand) { - let mut list = link_lib_path(); - for path in path { - list.insert(0, path); - } - cmd.env(link_lib_path_var(), t!(env::join_paths(list))); -} - -/// Returns the environment variable which the link library lookup path -/// resides in for this platform. -fn link_lib_path_var() -> &'static str { - if cfg!(target_env = "msvc") { "LIB" } else { "LIBRARY_PATH" } -} - -/// Parses the `link_lib_path_var()` environment variable, returning a list of -/// paths that are members of this lookup path. -fn link_lib_path() -> Vec<PathBuf> { - let var = match env::var_os(link_lib_path_var()) { - Some(v) => v, - None => return vec![], - }; - env::split_paths(&var).collect() -} - pub struct TimeIt(bool, Instant); /// Returns an RAII structure that prints out how long it took to drop. diff --git a/src/ci/docker/scripts/emscripten.sh b/src/ci/docker/scripts/emscripten.sh deleted file mode 100644 index 8b2b39ee162..00000000000 --- a/src/ci/docker/scripts/emscripten.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/sh -set -ex - -hide_output() { - set +x - on_err=" -echo ERROR: An error was encountered with the build. -cat /tmp/build.log -exit 1 -" - trap "$on_err" ERR - bash -c "while true; do sleep 30; echo \$(date) - building ...; done" & - PING_LOOP_PID=$! - "$@" &> /tmp/build.log - trap - ERR - kill $PING_LOOP_PID - rm -f /tmp/build.log - set -x -} - -git clone https://github.com/emscripten-core/emsdk.git /emsdk-portable -cd /emsdk-portable -hide_output ./emsdk install 3.1.68 -./emsdk activate 3.1.68 diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index af3c7cc7be3..80bc6cebd2a 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -303,6 +303,8 @@ pub(crate) struct RenderOptions { pub(crate) include_parts_dir: Vec<PathToParts>, /// Where to write crate-info pub(crate) parts_out_dir: Option<PathToParts>, + /// disable minification of CSS/JS + pub(crate) disable_minification: bool, } #[derive(Copy, Clone, Debug, PartialEq, Eq)] @@ -781,6 +783,9 @@ impl Options { let unstable_features = rustc_feature::UnstableFeatures::from_environment(crate_name.as_deref()); + + let disable_minification = matches.opt_present("disable-minification"); + let options = Options { bin_crate, proc_macro_crate, @@ -857,6 +862,7 @@ impl Options { should_merge, include_parts_dir, parts_out_dir, + disable_minification, }; Some((input, options, render_options)) } diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index 48a537ad5e7..62cf2b63f7f 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -337,7 +337,7 @@ enum Class { Ident(Span), Lifetime, PreludeTy(Span), - PreludeVal, + PreludeVal(Span), QuestionMark, Decoration(&'static str), } @@ -385,7 +385,7 @@ impl Class { Class::Ident(_) => "", Class::Lifetime => "lifetime", Class::PreludeTy(_) => "prelude-ty", - Class::PreludeVal => "prelude-val", + Class::PreludeVal(_) => "prelude-val", Class::QuestionMark => "question-mark", Class::Decoration(kind) => kind, } @@ -395,7 +395,11 @@ impl Class { /// a "span" (a tuple representing `(lo, hi)` equivalent of `Span`). fn get_span(self) -> Option<Span> { match self { - Self::Ident(sp) | Self::Self_(sp) | Self::Macro(sp) | Self::PreludeTy(sp) => Some(sp), + Self::Ident(sp) + | Self::Self_(sp) + | Self::Macro(sp) + | Self::PreludeTy(sp) + | Self::PreludeVal(sp) => Some(sp), Self::Comment | Self::DocComment | Self::Attribute @@ -406,7 +410,6 @@ impl Class { | Self::Number | Self::Bool | Self::Lifetime - | Self::PreludeVal | Self::QuestionMark | Self::Decoration(_) => None, } @@ -851,7 +854,9 @@ impl<'src> Classifier<'src> { TokenKind::Ident => match get_real_ident_class(text, false) { None => match text { "Option" | "Result" => Class::PreludeTy(self.new_span(before, text)), - "Some" | "None" | "Ok" | "Err" => Class::PreludeVal, + "Some" | "None" | "Ok" | "Err" => { + Class::PreludeVal(self.new_span(before, text)) + } // "union" is a weak keyword and is only considered as a keyword when declaring // a union type. "union" if self.check_if_is_union_keyword() => Class::KeyWord, diff --git a/src/librustdoc/html/render/span_map.rs b/src/librustdoc/html/render/span_map.rs index 26f75fa241c..85f87f01afd 100644 --- a/src/librustdoc/html/render/span_map.rs +++ b/src/librustdoc/html/render/span_map.rs @@ -4,7 +4,7 @@ use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_hir::intravisit::{self, Visitor}; -use rustc_hir::{ExprKind, HirId, Item, ItemKind, Mod, Node}; +use rustc_hir::{ExprKind, HirId, Item, ItemKind, Mod, Node, Pat, PatKind, QPath}; use rustc_middle::hir::nested_filter; use rustc_middle::ty::TyCtxt; use rustc_span::hygiene::MacroKind; @@ -170,7 +170,7 @@ impl SpanMapVisitor<'_> { true } - fn handle_call(&mut self, hir_id: HirId, expr_hir_id: Option<HirId>, span: Span) { + fn infer_id(&mut self, hir_id: HirId, expr_hir_id: Option<HirId>, span: Span) { let hir = self.tcx.hir(); let body_id = hir.enclosing_body_owner(hir_id); // FIXME: this is showing error messages for parts of the code that are not @@ -189,6 +189,27 @@ impl SpanMapVisitor<'_> { self.matches.insert(span, link); } } + + fn handle_pat(&mut self, p: &Pat<'_>) { + match p.kind { + PatKind::Binding(_, _, _, Some(p)) => self.handle_pat(p), + PatKind::Struct(qpath, _, _) + | PatKind::TupleStruct(qpath, _, _) + | PatKind::Path(qpath) => match qpath { + QPath::TypeRelative(_, path) if matches!(path.res, Res::Err) => { + self.infer_id(path.hir_id, Some(p.hir_id), qpath.span()); + } + QPath::Resolved(_, path) => self.handle_path(path), + _ => {} + }, + PatKind::Or(pats) => { + for pat in pats { + self.handle_pat(pat); + } + } + _ => {} + } + } } impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> { @@ -206,6 +227,10 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> { intravisit::walk_path(self, path); } + fn visit_pat(&mut self, p: &Pat<'tcx>) { + self.handle_pat(p); + } + fn visit_mod(&mut self, m: &'tcx Mod<'tcx>, span: Span, id: HirId) { // To make the difference between "mod foo {}" and "mod foo;". In case we "import" another // file, we want to link to it. Otherwise no need to create a link. @@ -228,9 +253,9 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> { fn visit_expr(&mut self, expr: &'tcx rustc_hir::Expr<'tcx>) { match expr.kind { ExprKind::MethodCall(segment, ..) => { - self.handle_call(segment.hir_id, Some(expr.hir_id), segment.ident.span) + self.infer_id(segment.hir_id, Some(expr.hir_id), segment.ident.span) } - ExprKind::Call(call, ..) => self.handle_call(call.hir_id, None, call.span), + ExprKind::Call(call, ..) => self.infer_id(call.hir_id, None, call.span), _ => { if self.handle_macro(expr.span) { // We don't want to go deeper into the macro. diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs index ce10e5ecc24..fb6f3bc2c76 100644 --- a/src/librustdoc/html/render/write_shared.rs +++ b/src/librustdoc/html/render/write_shared.rs @@ -207,7 +207,15 @@ fn write_static_files( if opt.emit.is_empty() || opt.emit.contains(&EmitType::Toolchain) { static_files::for_each(|f: &static_files::StaticFile| { let filename = static_dir.join(f.output_filename()); - fs::write(&filename, f.minified()).map_err(|e| PathError::new(e, &filename)) + let contents: &[u8]; + let contents_vec: Vec<u8>; + if opt.disable_minification { + contents = f.bytes; + } else { + contents_vec = f.minified(); + contents = &contents_vec; + }; + fs::write(&filename, contents).map_err(|e| PathError::new(e, &filename)) })?; } diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index 5fd5eb14478..0a0550ab82f 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -2717,9 +2717,26 @@ class DocSearch { const normalizedUserQuery = parsedQuery.userQuery.toLowerCase(); const isMixedCase = normalizedUserQuery !== userQuery; const result_list = []; + const isReturnTypeQuery = parsedQuery.elems.length === 0 || + typeInfo === "returned"; for (const result of results.values()) { result.item = this.searchIndex[result.id]; result.word = this.searchIndex[result.id].word; + if (isReturnTypeQuery) { + // we are doing a return-type based search, + // deprioritize "clone-like" results, + // ie. functions that also take the queried type as an argument. + const hasType = result.item && result.item.type; + if (!hasType) { + continue; + } + const inputs = result.item.type.inputs; + const where_clause = result.item.type.where_clause; + if (containsTypeFromQuery(inputs, where_clause)) { + result.path_dist *= 100; + result.dist *= 100; + } + } result_list.push(result); } @@ -3541,6 +3558,35 @@ class DocSearch { } /** + * This function checks if the given list contains any + * (non-generic) types mentioned in the query. + * + * @param {Array<FunctionType>} list - A list of function types. + * @param {[FunctionType]} where_clause - Trait bounds for generic items. + */ + function containsTypeFromQuery(list, where_clause) { + if (!list) return false; + for (const ty of parsedQuery.returned) { + // negative type ids are generics + if (ty.id < 0) { + continue; + } + if (checkIfInList(list, ty, where_clause, null, 0)) { + return true; + } + } + for (const ty of parsedQuery.elems) { + if (ty.id < 0) { + continue; + } + if (checkIfInList(list, ty, where_clause, null, 0)) { + return true; + } + } + return false; + } + + /** * This function checks if the object (`row`) matches the given type (`elem`) and its * generics (if any). * diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index 7fcdfe3fb22..33166a39574 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -622,7 +622,7 @@ impl FromClean<clean::Type> for Type { impl FromClean<clean::Path> for Path { fn from_clean(path: clean::Path, renderer: &JsonRenderer<'_>) -> Path { Path { - name: path.whole_name(), + name: path.last_opt().map_or(String::from(""), |s| String::from(s.as_str())), id: renderer.id_from_item_default(path.def_id().into()), args: path.segments.last().map(|args| Box::new(args.clone().args.into_json(renderer))), } diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 96ca96ee6bc..ba620b6cb6b 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -651,8 +651,15 @@ fn opts() -> Vec<RustcOptGroup> { "", "add arguments to be used when compiling doctests", ), + opt( + Unstable, + FlagMulti, + "", + "disable-minification", + "disable the minification of CSS/JS files (perma-unstable, do not use with cached files)", + "", + ), // deprecated / removed options - opt(Unstable, FlagMulti, "", "disable-minification", "removed", ""), opt( Stable, Multi, diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs index 84b33e3d860..5a99977ded5 100644 --- a/src/rustdoc-json-types/lib.rs +++ b/src/rustdoc-json-types/lib.rs @@ -30,7 +30,7 @@ pub type FxHashMap<K, V> = HashMap<K, V>; // re-export for use in src/librustdoc /// This integer is incremented with every breaking change to the API, /// and is returned along with the JSON blob as [`Crate::format_version`]. /// Consuming code should assert that this value matches the format version(s) that it supports. -pub const FORMAT_VERSION: u32 = 37; +pub const FORMAT_VERSION: u32 = 38; /// The root of the emitted JSON blob. /// diff --git a/tests/codegen-units/item-collection/closures.rs b/tests/codegen-units/item-collection/closures.rs index 5fc80230925..864f98817a8 100644 --- a/tests/codegen-units/item-collection/closures.rs +++ b/tests/codegen-units/item-collection/closures.rs @@ -10,3 +10,9 @@ pub async fn async_fn() {} pub fn closure() { let _ = || {}; } + +//~ MONO_ITEM fn A::{constant#0}::{closure#0} @@ +trait A where + [(); (|| {}, 1).1]: Sized, +{ +} diff --git a/tests/codegen-units/item-collection/drop-glue-eager.rs b/tests/codegen-units/item-collection/drop-glue-eager.rs new file mode 100644 index 00000000000..77470767ee1 --- /dev/null +++ b/tests/codegen-units/item-collection/drop-glue-eager.rs @@ -0,0 +1,43 @@ +// Ensure that we *eagerly* monomorphize drop instances for structs with lifetimes. + +//@ compile-flags:-Zprint-mono-items=eager +//@ compile-flags:--crate-type=lib + +//~ MONO_ITEM fn std::ptr::drop_in_place::<StructWithDrop> - shim(Some(StructWithDrop)) +struct StructWithDrop { + x: i32, +} + +impl Drop for StructWithDrop { + //~ MONO_ITEM fn <StructWithDrop as std::ops::Drop>::drop + fn drop(&mut self) {} +} + +struct StructNoDrop { + x: i32, +} + +//~ MONO_ITEM fn std::ptr::drop_in_place::<EnumWithDrop> - shim(Some(EnumWithDrop)) +enum EnumWithDrop { + A(i32), +} + +impl Drop for EnumWithDrop { + //~ MONO_ITEM fn <EnumWithDrop as std::ops::Drop>::drop + fn drop(&mut self) {} +} + +enum EnumNoDrop { + A(i32), +} + +// We should be able to monomorphize drops for struct with lifetimes. +impl<'a> Drop for StructWithDropAndLt<'a> { + //~ MONO_ITEM fn <StructWithDropAndLt<'_> as std::ops::Drop>::drop + fn drop(&mut self) {} +} + +//~ MONO_ITEM fn std::ptr::drop_in_place::<StructWithDropAndLt<'_>> - shim(Some(StructWithDropAndLt<'_>)) +struct StructWithDropAndLt<'a> { + x: &'a i32, +} diff --git a/tests/run-make/rustdoc-default-output/output-default.stdout b/tests/run-make/rustdoc-default-output/output-default.stdout index c2d9309ba2e..c1b246e849c 100644 --- a/tests/run-make/rustdoc-default-output/output-default.stdout +++ b/tests/run-make/rustdoc-default-output/output-default.stdout @@ -194,7 +194,8 @@ Options: --doctest-compilation-args add arguments to be used when compiling doctests --disable-minification - removed + disable the minification of CSS/JS files + (perma-unstable, do not use with cached files) --plugin-path DIR removed, see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for diff --git a/tests/rustdoc-js-std/return-based-sort.js b/tests/rustdoc-js-std/return-based-sort.js new file mode 100644 index 00000000000..30baf1cd36e --- /dev/null +++ b/tests/rustdoc-js-std/return-based-sort.js @@ -0,0 +1,30 @@ +// test that `clone`-like functions are sorted lower when +// a search is based soley on return type + +const FILTER_CRATE = "core"; + +const EXPECTED = [ + { + 'query': '-> AllocError', + 'others': [ + { 'path': 'core::alloc::Allocator', 'name': 'allocate' }, + { 'path': 'core::alloc::AllocError', 'name': 'clone' }, + ], + }, + { + 'query': 'AllocError', + 'returned': [ + { 'path': 'core::alloc::Allocator', 'name': 'allocate' }, + { 'path': 'core::alloc::AllocError', 'name': 'clone' }, + ], + }, + { + 'query': '-> &str', + 'others': [ + // type_name_of_val should not be consider clone-like + { 'path': 'core::any', 'name': 'type_name_of_val' }, + // this returns `Option<&str>`, and thus should be sorted lower + { 'path': 'core::str::Split', 'name': 'next' }, + ], + }, +] diff --git a/tests/rustdoc-json/return_private.rs b/tests/rustdoc-json/return_private.rs index 0b341e2bda7..c238a536e0d 100644 --- a/tests/rustdoc-json/return_private.rs +++ b/tests/rustdoc-json/return_private.rs @@ -6,7 +6,7 @@ mod secret { } //@ has "$.index[*][?(@.name=='get_secret')].inner.function" -//@ is "$.index[*][?(@.name=='get_secret')].inner.function.sig.output.resolved_path.name" \"secret::Secret\" +//@ is "$.index[*][?(@.name=='get_secret')].inner.function.sig.output.resolved_path.name" \"Secret\" pub fn get_secret() -> secret::Secret { secret::Secret } diff --git a/tests/rustdoc/jump-to-def-pats.rs b/tests/rustdoc/jump-to-def-pats.rs new file mode 100644 index 00000000000..147902b44cf --- /dev/null +++ b/tests/rustdoc/jump-to-def-pats.rs @@ -0,0 +1,52 @@ +// This test ensures that patterns also get a link generated. + +//@ compile-flags: -Zunstable-options --generate-link-to-definition + +#![crate_name = "foo"] + +//@ has 'src/foo/jump-to-def-pats.rs.html' + +use std::fmt; + +pub enum MyEnum<T, E> { + Ok(T), + Err(E), + Some(T), + None, +} + +pub enum X { + A, +} + +pub fn foo() -> Result<(), ()> { + // FIXME: would be nice to be able to check both the class and the href at the same time so + // we could check the text as well... + //@ has - '//a[@class="prelude-val"]/@href' '{{channel}}/core/result/enum.Result.html#variant.Ok' + //@ has - '//a[@href="{{channel}}/core/result/enum.Result.html#variant.Ok"]' 'Ok' + Ok(()) +} + +impl<T, E> fmt::Display for MyEnum<T, E> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + //@ has - '//a[@href="#12"]' 'Self::Ok' + Self::Ok(_) => f.write_str("MyEnum::Ok"), + //@ has - '//a[@href="#13"]' 'MyEnum::Err' + MyEnum::Err(_) => f.write_str("MyEnum::Err"), + //@ has - '//a[@href="#14"]' 'Self::Some' + Self::Some(_) => f.write_str("MyEnum::Some"), + //@ has - '//a[@href="#15"]' 'Self::None' + Self::None => f.write_str("MyEnum::None"), + } + } +} + +impl X { + fn p(&self) -> &str { + match self { + //@ has - '//a[@href="#19"]' 'Self::A' + Self::A => "X::A", + } + } +} diff --git a/tests/ui/closures/binder/nested-closures-regions.stderr b/tests/ui/closures/binder/nested-closures-regions.stderr index a30339ac67b..909cbcaa808 100644 --- a/tests/ui/closures/binder/nested-closures-regions.stderr +++ b/tests/ui/closures/binder/nested-closures-regions.stderr @@ -9,7 +9,7 @@ LL | for<'a> || -> () { for<'c> |_: &'a ()| -> () {}; }; extern "rust-call" fn((&(),)), (), ] - = note: late-bound region is '?4 + = note: late-bound region is '?3 = note: late-bound region is '?2 = note: number of external vids: 3 = note: where '?1: '?2 @@ -26,7 +26,7 @@ LL | for<'a> || -> () { for<'c> |_: &'a ()| -> () {}; }; extern "rust-call" fn(()), (), ] - = note: late-bound region is '?2 + = note: late-bound region is '?1 note: no external requirements --> $DIR/nested-closures-regions.rs:7:1 diff --git a/tests/ui/const-generics/type-mismatch-in-nested-goal.current.stderr b/tests/ui/const-generics/type-mismatch-in-nested-goal.current.stderr new file mode 100644 index 00000000000..c6fb07926c8 --- /dev/null +++ b/tests/ui/const-generics/type-mismatch-in-nested-goal.current.stderr @@ -0,0 +1,45 @@ +error: the constant `N` is not of type `bool` + --> $DIR/type-mismatch-in-nested-goal.rs:9:50 + | +LL | fn needs_a<const N: usize>(_: [u8; N]) where (): A<N> {} + | ^^^^ expected `bool`, found `usize` + | +note: required by a const generic parameter in `A` + --> $DIR/type-mismatch-in-nested-goal.rs:5:9 + | +LL | trait A<const B: bool> {} + | ^^^^^^^^^^^^^ required by this const generic parameter in `A` + +error: the constant `true` is not of type `usize` + --> $DIR/type-mismatch-in-nested-goal.rs:13:13 + | +LL | needs_a([]); + | ------- ^^ expected `usize`, found `bool` + | | + | required by a bound introduced by this call + | +note: required by a const generic parameter in `needs_a` + --> $DIR/type-mismatch-in-nested-goal.rs:9:12 + | +LL | fn needs_a<const N: usize>(_: [u8; N]) where (): A<N> {} + | ^^^^^^^^^^^^^^ required by this const generic parameter in `needs_a` + +error[E0308]: mismatched types + --> $DIR/type-mismatch-in-nested-goal.rs:13:13 + | +LL | needs_a([]); + | ------- ^^ expected an array with a size of true, found one with a size of 0 + | | + | arguments to this function are incorrect + | + = note: expected array `[u8; true]` + found array `[_; 0]` +note: function defined here + --> $DIR/type-mismatch-in-nested-goal.rs:9:4 + | +LL | fn needs_a<const N: usize>(_: [u8; N]) where (): A<N> {} + | ^^^^^^^ ---------- + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/const-generics/type-mismatch-in-nested-goal.next.stderr b/tests/ui/const-generics/type-mismatch-in-nested-goal.next.stderr new file mode 100644 index 00000000000..c6fb07926c8 --- /dev/null +++ b/tests/ui/const-generics/type-mismatch-in-nested-goal.next.stderr @@ -0,0 +1,45 @@ +error: the constant `N` is not of type `bool` + --> $DIR/type-mismatch-in-nested-goal.rs:9:50 + | +LL | fn needs_a<const N: usize>(_: [u8; N]) where (): A<N> {} + | ^^^^ expected `bool`, found `usize` + | +note: required by a const generic parameter in `A` + --> $DIR/type-mismatch-in-nested-goal.rs:5:9 + | +LL | trait A<const B: bool> {} + | ^^^^^^^^^^^^^ required by this const generic parameter in `A` + +error: the constant `true` is not of type `usize` + --> $DIR/type-mismatch-in-nested-goal.rs:13:13 + | +LL | needs_a([]); + | ------- ^^ expected `usize`, found `bool` + | | + | required by a bound introduced by this call + | +note: required by a const generic parameter in `needs_a` + --> $DIR/type-mismatch-in-nested-goal.rs:9:12 + | +LL | fn needs_a<const N: usize>(_: [u8; N]) where (): A<N> {} + | ^^^^^^^^^^^^^^ required by this const generic parameter in `needs_a` + +error[E0308]: mismatched types + --> $DIR/type-mismatch-in-nested-goal.rs:13:13 + | +LL | needs_a([]); + | ------- ^^ expected an array with a size of true, found one with a size of 0 + | | + | arguments to this function are incorrect + | + = note: expected array `[u8; true]` + found array `[_; 0]` +note: function defined here + --> $DIR/type-mismatch-in-nested-goal.rs:9:4 + | +LL | fn needs_a<const N: usize>(_: [u8; N]) where (): A<N> {} + | ^^^^^^^ ---------- + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/const-generics/type-mismatch-in-nested-goal.rs b/tests/ui/const-generics/type-mismatch-in-nested-goal.rs new file mode 100644 index 00000000000..fd29019f89b --- /dev/null +++ b/tests/ui/const-generics/type-mismatch-in-nested-goal.rs @@ -0,0 +1,17 @@ +//@ revisions: current next +//@[next] compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) + +trait A<const B: bool> {} + +impl A<true> for () {} + +fn needs_a<const N: usize>(_: [u8; N]) where (): A<N> {} +//~^ ERROR the constant `N` is not of type `bool` + +pub fn main() { + needs_a([]); + //~^ ERROR the constant `true` is not of type `usize` + //~| ERROR mismatched types + // FIXME(const_generics): we should hide this error as we've already errored above +} diff --git a/tests/ui/enum-discriminant/eval-error.rs b/tests/ui/enum-discriminant/eval-error.rs new file mode 100644 index 00000000000..f2c3b581627 --- /dev/null +++ b/tests/ui/enum-discriminant/eval-error.rs @@ -0,0 +1,37 @@ +union Foo { + a: str, + //~^ ERROR the size for values of type `str` cannot be known at compilation time + //~| ERROR field must implement `Copy` or be wrapped in `ManuallyDrop<...>` +} + +enum Bar { + Boo = { + let _: Option<Foo> = None; + 0 + }, +} + +union Foo2 {} +//~^ ERROR unions cannot have zero fields + +enum Bar2 { + Boo = { + let _: Option<Foo2> = None; + 0 + }, +} + +#[repr(u8, packed)] +//~^ ERROR attribute should be applied to a struct or union +enum Foo3 { + A +} + +enum Bar3 { + Boo = { + let _: Option<Foo3> = None; + 0 + }, +} + +fn main() {} diff --git a/tests/ui/enum-discriminant/eval-error.stderr b/tests/ui/enum-discriminant/eval-error.stderr new file mode 100644 index 00000000000..0f12308de3c --- /dev/null +++ b/tests/ui/enum-discriminant/eval-error.stderr @@ -0,0 +1,51 @@ +error: unions cannot have zero fields + --> $DIR/eval-error.rs:14:1 + | +LL | union Foo2 {} + | ^^^^^^^^^^^^^ + +error[E0517]: attribute should be applied to a struct or union + --> $DIR/eval-error.rs:24:12 + | +LL | #[repr(u8, packed)] + | ^^^^^^ +LL | +LL | / enum Foo3 { +LL | | A +LL | | } + | |_- not a struct or union + +error[E0277]: the size for values of type `str` cannot be known at compilation time + --> $DIR/eval-error.rs:2:8 + | +LL | a: str, + | ^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `str` + = note: no field of a union may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | a: &str, + | + +help: the `Box` type always has a statically known size and allocates its contents in the heap + | +LL | a: Box<str>, + | ++++ + + +error[E0740]: field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union + --> $DIR/eval-error.rs:2:5 + | +LL | a: str, + | ^^^^^^ + | + = note: union fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>` +help: wrap the field type in `ManuallyDrop<...>` + | +LL | a: std::mem::ManuallyDrop<str>, + | +++++++++++++++++++++++ + + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0277, E0517, E0740. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/invalid_dispatch_from_dyn_impls.stderr b/tests/ui/invalid_dispatch_from_dyn_impls.stderr index 168ed37d0e6..02718334c73 100644 --- a/tests/ui/invalid_dispatch_from_dyn_impls.stderr +++ b/tests/ui/invalid_dispatch_from_dyn_impls.stderr @@ -1,4 +1,4 @@ -error[E0378]: the trait `DispatchFromDyn` may only be implemented for structs containing the field being coerced, ZST fields with 1 byte alignment, and nothing else +error[E0378]: the trait `DispatchFromDyn` may only be implemented for structs containing the field being coerced, ZST fields with 1 byte alignment that don't mention type/const generics, and nothing else --> $DIR/invalid_dispatch_from_dyn_impls.rs:10:1 | LL | / impl<T, U> DispatchFromDyn<WrapperWithExtraField<U>> for WrapperWithExtraField<T> @@ -35,7 +35,7 @@ LL | | where LL | | T: Unsize<U>, | |_________________^ -error[E0378]: the trait `DispatchFromDyn` may only be implemented for structs containing the field being coerced, ZST fields with 1 byte alignment, and nothing else +error[E0378]: the trait `DispatchFromDyn` may only be implemented for structs containing the field being coerced, ZST fields with 1 byte alignment that don't mention type/const generics, and nothing else --> $DIR/invalid_dispatch_from_dyn_impls.rs:46:1 | LL | / impl<T: ?Sized, U: ?Sized> DispatchFromDyn<OverAligned<U>> for OverAligned<T> diff --git a/tests/ui/layout/base-layout-is-sized-ice-123078.rs b/tests/ui/layout/base-layout-is-sized-ice-123078.rs index b1c33e15075..15f11145f84 100644 --- a/tests/ui/layout/base-layout-is-sized-ice-123078.rs +++ b/tests/ui/layout/base-layout-is-sized-ice-123078.rs @@ -8,7 +8,6 @@ struct S { } const C: S = unsafe { std::mem::transmute(()) }; -//~^ ERROR cannot transmute between types of different sizes, or dependently-sized types const _: [(); { C; 0 diff --git a/tests/ui/layout/base-layout-is-sized-ice-123078.stderr b/tests/ui/layout/base-layout-is-sized-ice-123078.stderr index 455bd2cbf8b..9181368533a 100644 --- a/tests/ui/layout/base-layout-is-sized-ice-123078.stderr +++ b/tests/ui/layout/base-layout-is-sized-ice-123078.stderr @@ -16,16 +16,6 @@ help: the `Box` type always has a statically known size and allocates its conten LL | a: Box<[u8]>, | ++++ + -error[E0512]: cannot transmute between types of different sizes, or dependently-sized types - --> $DIR/base-layout-is-sized-ice-123078.rs:10:23 - | -LL | const C: S = unsafe { std::mem::transmute(()) }; - | ^^^^^^^^^^^^^^^^^^^ - | - = note: source type: `()` (0 bits) - = note: target type: `S` (size can vary because of [u8]) - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error -Some errors have detailed explanations: E0277, E0512. -For more information about an error, try `rustc --explain E0277`. +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/layout/debug.stderr b/tests/ui/layout/debug.stderr index 1fc55511384..319c0de26a9 100644 --- a/tests/ui/layout/debug.stderr +++ b/tests/ui/layout/debug.stderr @@ -590,7 +590,7 @@ LL | type Impossible = (str, str); = help: the trait `Sized` is not implemented for `str` = note: only the last element of a tuple may have a dynamically sized type -error: the type `EmptyUnion` has an unknown layout +error: the type has an unknown layout --> $DIR/debug.rs:83:1 | LL | union EmptyUnion {} diff --git a/tests/ui/nll/closure-requirements/escape-argument-callee.stderr b/tests/ui/nll/closure-requirements/escape-argument-callee.stderr index a7a59dccf22..a445534c8d8 100644 --- a/tests/ui/nll/closure-requirements/escape-argument-callee.stderr +++ b/tests/ui/nll/closure-requirements/escape-argument-callee.stderr @@ -17,7 +17,7 @@ LL | let mut closure = expect_sig(|p, y| *p = y); | - - ^^^^^^ assignment requires that `'1` must outlive `'2` | | | | | has type `&'1 i32` - | has type `&'?2 mut &'2 i32` + | has type `&'?1 mut &'2 i32` note: no external requirements --> $DIR/escape-argument-callee.rs:20:1 diff --git a/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr b/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr index 0094d7a50d3..621c1ea083b 100644 --- a/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr +++ b/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr @@ -20,7 +20,7 @@ LL | foo(cell, |cell_a, cell_x| { LL | cell_a.set(cell_x.get()); // forces 'x: 'a, error in closure | ^^^^^^^^^^^^^^^^^^^^^^^^ `cell_x` escapes the closure body here | - = note: requirement occurs because of the type `Cell<&'?8 u32>`, which makes the generic argument `&'?8 u32` invariant + = note: requirement occurs because of the type `Cell<&'?9 u32>`, which makes the generic argument `&'?9 u32` invariant = note: the struct `Cell<T>` is invariant over the parameter `T` = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance diff --git a/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr b/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr index 4558ff50674..f48ed2823dd 100644 --- a/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr +++ b/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr @@ -16,9 +16,9 @@ error: lifetime may not live long enough --> $DIR/propagate-fail-to-approximate-longer-no-bounds.rs:37:9 | LL | establish_relationships(&cell_a, &cell_b, |_outlives, x, y| { - | --------- - has type `&'?7 Cell<&'1 u32>` + | --------- - has type `&'?6 Cell<&'1 u32>` | | - | has type `&'?5 Cell<&'2 &'?1 u32>` + | has type `&'?4 Cell<&'2 &'?1 u32>` LL | // Only works if 'x: 'y: LL | demand_y(x, y, x.get()) | ^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'2` diff --git a/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr b/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr index 83173ae80c0..a090e94593f 100644 --- a/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr +++ b/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr @@ -16,9 +16,9 @@ error: lifetime may not live long enough --> $DIR/propagate-fail-to-approximate-longer-wrong-bounds.rs:41:9 | LL | establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| { - | ---------- ---------- has type `&'?8 Cell<&'2 &'?2 u32>` + | ---------- ---------- has type `&'?7 Cell<&'2 &'?2 u32>` | | - | has type `&'?6 Cell<&'1 &'?1 u32>` + | has type `&'?5 Cell<&'1 &'?1 u32>` LL | // Only works if 'x: 'y: LL | demand_y(x, y, x.get()) | ^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'2` diff --git a/tests/ui/self/dispatch-from-dyn-zst-transmute-zst-nonzst.rs b/tests/ui/self/dispatch-from-dyn-zst-transmute-zst-nonzst.rs new file mode 100644 index 00000000000..71f198f7dc7 --- /dev/null +++ b/tests/ui/self/dispatch-from-dyn-zst-transmute-zst-nonzst.rs @@ -0,0 +1,25 @@ +// We used to allow erroneous `DispatchFromDyn` impls whose RHS type contained +// fields that weren't ZSTs. I don't believe this was possible to abuse, but +// it's at least nice to give users better errors. + +#![feature(arbitrary_self_types)] +#![feature(unsize)] +#![feature(dispatch_from_dyn)] + +use std::marker::Unsize; +use std::ops::DispatchFromDyn; + +struct Dispatchable<T: ?Sized, Z> { + _ptr: Box<T>, + z: Z, +} + +impl<T, U> DispatchFromDyn<Dispatchable<U, i32>> for Dispatchable<T, ()> +//~^ ERROR implementing the `DispatchFromDyn` trait requires multiple coercions +where + T: Unsize<U> + ?Sized, + U: ?Sized, +{ +} + +fn main() {} diff --git a/tests/ui/self/dispatch-from-dyn-zst-transmute-zst-nonzst.stderr b/tests/ui/self/dispatch-from-dyn-zst-transmute-zst-nonzst.stderr new file mode 100644 index 00000000000..1f13c51f679 --- /dev/null +++ b/tests/ui/self/dispatch-from-dyn-zst-transmute-zst-nonzst.stderr @@ -0,0 +1,16 @@ +error[E0378]: implementing the `DispatchFromDyn` trait requires multiple coercions + --> $DIR/dispatch-from-dyn-zst-transmute-zst-nonzst.rs:17:1 + | +LL | / impl<T, U> DispatchFromDyn<Dispatchable<U, i32>> for Dispatchable<T, ()> +LL | | +LL | | where +LL | | T: Unsize<U> + ?Sized, +LL | | U: ?Sized, + | |______________^ + | + = note: the trait `DispatchFromDyn` may only be implemented for a coercion between structures with a single field being coerced + = note: currently, 2 fields need coercions: `_ptr` (`Box<T>` to `Box<U>`), `z` (`()` to `i32`) + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0378`. diff --git a/tests/ui/self/dispatch-from-dyn-zst-transmute.rs b/tests/ui/self/dispatch-from-dyn-zst-transmute.rs new file mode 100644 index 00000000000..57c255b4d7b --- /dev/null +++ b/tests/ui/self/dispatch-from-dyn-zst-transmute.rs @@ -0,0 +1,34 @@ +#![feature(arbitrary_self_types)] +#![feature(unsize)] +#![feature(dispatch_from_dyn)] + +use std::marker::PhantomData; +use std::marker::Unsize; +use std::ops::DispatchFromDyn; +use std::ops::Deref; + +struct IsSendToken<T: ?Sized>(PhantomData<fn(T) -> T>); + +struct Foo<'a, U: ?Sized> { + token: IsSendToken<U>, + ptr: &'a U, +} + +impl<'a, T, U> DispatchFromDyn<Foo<'a, U>> for Foo<'a, T> +//~^ ERROR implementing the `DispatchFromDyn` trait requires multiple coercions +where + T: Unsize<U> + ?Sized, + U: ?Sized {} + +trait Bar { + fn f(self: Foo<'_, Self>); +} + +impl<U: ?Sized> Deref for Foo<'_, U> { + type Target = U; + fn deref(&self) -> &U { + self.ptr + } +} + +fn main() {} diff --git a/tests/ui/self/dispatch-from-dyn-zst-transmute.stderr b/tests/ui/self/dispatch-from-dyn-zst-transmute.stderr new file mode 100644 index 00000000000..5a8ae88b5f1 --- /dev/null +++ b/tests/ui/self/dispatch-from-dyn-zst-transmute.stderr @@ -0,0 +1,16 @@ +error[E0378]: implementing the `DispatchFromDyn` trait requires multiple coercions + --> $DIR/dispatch-from-dyn-zst-transmute.rs:17:1 + | +LL | / impl<'a, T, U> DispatchFromDyn<Foo<'a, U>> for Foo<'a, T> +LL | | +LL | | where +LL | | T: Unsize<U> + ?Sized, +LL | | U: ?Sized {} + | |_____________^ + | + = note: the trait `DispatchFromDyn` may only be implemented for a coercion between structures with a single field being coerced + = note: currently, 2 fields need coercions: `token` (`IsSendToken<T>` to `IsSendToken<U>`), `ptr` (`&'a T` to `&'a U`) + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0378`. diff --git a/tests/ui/self/phantomdata-in-coerce-and-dispatch-impls.rs b/tests/ui/self/phantomdata-in-coerce-and-dispatch-impls.rs new file mode 100644 index 00000000000..9c7e33830f5 --- /dev/null +++ b/tests/ui/self/phantomdata-in-coerce-and-dispatch-impls.rs @@ -0,0 +1,25 @@ +//@ check-pass + +#![feature(coerce_unsized, dispatch_from_dyn, unsize)] + +use std::marker::Unsize; +use std::ops::{CoerceUnsized, DispatchFromDyn}; +use std::marker::PhantomData; + +trait Mirror { + type Assoc; +} +impl<T> Mirror for T { + type Assoc = T; +} + +struct W<T: 'static> { + t: &'static T, + f: <PhantomData<T> as Mirror>::Assoc, +} + +impl<T, U> CoerceUnsized<W<U>> for W<T> where T: Unsize<U> {} + +impl<T, U> DispatchFromDyn<W<U>> for W<T> where T: Unsize<U> {} + +fn main() {} diff --git a/tests/ui/traits/next-solver/known-type-outlives-has-constraints.rs b/tests/ui/traits/next-solver/known-type-outlives-has-constraints.rs new file mode 100644 index 00000000000..55fea005ea1 --- /dev/null +++ b/tests/ui/traits/next-solver/known-type-outlives-has-constraints.rs @@ -0,0 +1,13 @@ +//@ compile-flags: -Znext-solver +//@ check-pass + +trait Norm { + type Out; +} +impl<'a, T: 'a> Norm for &'a T { + type Out = T; +} + +fn hello<'a, T: 'a>() where <&'a T as Norm>::Out: 'a {} + +fn main() {} diff --git a/tests/ui/traits/trait-upcasting/impossible-method-modulo-binders-2.rs b/tests/ui/traits/trait-upcasting/impossible-method-modulo-binders-2.rs new file mode 100644 index 00000000000..c03b5145aa7 --- /dev/null +++ b/tests/ui/traits/trait-upcasting/impossible-method-modulo-binders-2.rs @@ -0,0 +1,39 @@ +//@ build-pass +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver +// Regression test for #135462. +#![allow(coherence_leak_check)] + +type A = fn(&'static ()); +type B = fn(&()); + +trait Bound<P: WithAssoc>: From<GetAssoc<P>> { +} +impl Bound<B> for String {} + +trait Trt<T> { + fn __(&self, x: T) where T: Bound<A> { + T::from(()); + } +} + +impl<T, S> Trt<T> for S {} + +type GetAssoc<T> = <T as WithAssoc>::Ty; + +trait WithAssoc { + type Ty; +} + +impl WithAssoc for B { + type Ty = String; +} + +impl WithAssoc for A { + type Ty = (); +} + +fn main() { + let x: &'static dyn Trt<String> = &(); +} diff --git a/tests/ui/traits/trait-upcasting/impossible-method-modulo-binders.rs b/tests/ui/traits/trait-upcasting/impossible-method-modulo-binders.rs new file mode 100644 index 00000000000..63ad1c0a060 --- /dev/null +++ b/tests/ui/traits/trait-upcasting/impossible-method-modulo-binders.rs @@ -0,0 +1,40 @@ +//@ build-pass +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver + +trait Foo {} +impl Foo for fn(&'static ()) {} + +trait Bar { + type Assoc: Default; +} +impl<T: Foo> Bar for T { + type Assoc = usize; +} +impl Bar for fn(&()) { + type Assoc = (); +} + +fn needs_foo<T: Foo>() -> usize { + needs_bar::<T>() +} + +fn needs_bar<T: Bar>() -> <T as Bar>::Assoc { + Default::default() +} + +trait Evil<T> { + fn bad(&self) + where + T: Foo, + { + needs_foo::<T>(); + } +} + +impl Evil<fn(&())> for () {} + +fn main() { + let x: &dyn Evil<fn(&())> = &(); +} |
