diff options
435 files changed, 5078 insertions, 2731 deletions
diff --git a/Cargo.lock b/Cargo.lock index 2b08aab41ed..449f0c73588 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4523,6 +4523,7 @@ dependencies = [ "rustc_index", "rustc_macros", "rustc_serialize", + "serde_json", "smallvec", "stable_deref_trait", "stacker", @@ -4826,6 +4827,7 @@ dependencies = [ "rustc_data_structures", "rustc_errors", "rustc_expand", + "rustc_fs_util", "rustc_hir", "rustc_hir_analysis", "rustc_hir_typeck", @@ -4950,6 +4952,7 @@ dependencies = [ "rustc_errors", "rustc_expand", "rustc_feature", + "rustc_fs_util", "rustc_hir", "rustc_hir_pretty", "rustc_index", @@ -5294,6 +5297,7 @@ name = "rustc_span" version = "0.0.0" dependencies = [ "cfg-if", + "indexmap", "md-5", "rustc_arena", "rustc_data_structures", @@ -5334,6 +5338,7 @@ dependencies = [ "rustc_abi", "rustc_data_structures", "rustc_feature", + "rustc_fs_util", "rustc_index", "rustc_macros", "rustc_serialize", diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index 2e83b3e623f..c4771115cac 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -180,6 +180,12 @@ impl Attribute { self.doc_str().map_or(false, |s| comments::may_have_doc_links(s.as_str())) } + pub fn is_proc_macro_attr(&self) -> bool { + [sym::proc_macro, sym::proc_macro_attribute, sym::proc_macro_derive] + .iter() + .any(|kind| self.has_name(*kind)) + } + /// Extracts the MetaItem from inside this Attribute. pub fn meta(&self) -> Option<MetaItem> { match &self.kind { @@ -627,6 +633,22 @@ pub fn mk_attr_name_value_str( mk_attr(g, style, path, args, span) } +pub fn filter_by_name(attrs: &[Attribute], name: Symbol) -> impl Iterator<Item = &Attribute> { + attrs.iter().filter(move |attr| attr.has_name(name)) +} + +pub fn find_by_name(attrs: &[Attribute], name: Symbol) -> Option<&Attribute> { + filter_by_name(attrs, name).next() +} + +pub fn first_attr_value_str_by_name(attrs: &[Attribute], name: Symbol) -> Option<Symbol> { + find_by_name(attrs, name).and_then(|attr| attr.value_str()) +} + +pub fn contains_name(attrs: &[Attribute], name: Symbol) -> bool { + find_by_name(attrs, name).is_some() +} + pub fn list_contains_name(items: &[NestedMetaItem], name: Symbol) -> bool { items.iter().any(|item| item.has_name(name)) } diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index ea7fa02521e..0b6b02ba00f 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -2185,7 +2185,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { def_id: self.local_def_id(param.id), name, span: self.lower_span(param.span()), - pure_wrt_drop: self.tcx.sess.contains_name(¶m.attrs, sym::may_dangle), + pure_wrt_drop: attr::contains_name(¶m.attrs, sym::may_dangle), kind, colon_span: param.colon_span.map(|s| self.lower_span(s)), source, diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 539c822ea09..93c854cc809 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -799,11 +799,11 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } fn visit_item(&mut self, item: &'a Item) { - if item.attrs.iter().any(|attr| self.session.is_proc_macro_attr(attr)) { + if item.attrs.iter().any(|attr| attr.is_proc_macro_attr()) { self.has_proc_macro_decls = true; } - if self.session.contains_name(&item.attrs, sym::no_mangle) { + if attr::contains_name(&item.attrs, sym::no_mangle) { self.check_nomangle_item_asciionly(item.ident, item.span); } @@ -973,7 +973,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } // Ensure that `path` attributes on modules are recorded as used (cf. issue #35584). if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _)) - && !self.session.contains_name(&item.attrs, sym::path) + && !attr::contains_name(&item.attrs, sym::path) { self.check_mod_file_item_asciionly(item.ident); } @@ -1248,7 +1248,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) { - if self.session.contains_name(&item.attrs, sym::no_mangle) { + if attr::contains_name(&item.attrs, sym::no_mangle) { self.check_nomangle_item_asciionly(item.ident, item.span); } diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 6a5d5614b1c..344a1e7f5e7 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -1,6 +1,6 @@ use rustc_ast as ast; use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor}; -use rustc_ast::{AssocConstraint, AssocConstraintKind, NodeId}; +use rustc_ast::{attr, AssocConstraint, AssocConstraintKind, NodeId}; use rustc_ast::{PatKind, RangeEnd}; use rustc_errors::{Applicability, StashKey}; use rustc_feature::{AttributeGate, BuiltinAttribute, Features, GateIssue, BUILTIN_ATTRIBUTE_MAP}; @@ -232,7 +232,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { } ast::ItemKind::Fn(..) => { - if self.sess.contains_name(&i.attrs, sym::start) { + if attr::contains_name(&i.attrs, sym::start) { gate_feature_post!( &self, start, @@ -245,7 +245,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { } ast::ItemKind::Struct(..) => { - for attr in self.sess.filter_by_name(&i.attrs, sym::repr) { + for attr in attr::filter_by_name(&i.attrs, sym::repr) { for item in attr.meta_item_list().unwrap_or_else(ThinVec::new) { if item.has_name(sym::simd) { gate_feature_post!( @@ -306,7 +306,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { fn visit_foreign_item(&mut self, i: &'a ast::ForeignItem) { match i.kind { ast::ForeignItemKind::Fn(..) | ast::ForeignItemKind::Static(..) => { - let link_name = self.sess.first_attr_value_str_by_name(&i.attrs, sym::link_name); + let link_name = attr::first_attr_value_str_by_name(&i.attrs, sym::link_name); let links_to_llvm = link_name.map_or(false, |val| val.as_str().starts_with("llvm.")); if links_to_llvm { diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index 3d240108b4a..d6dbdd3975e 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -1,6 +1,6 @@ //! Parsing and validation of builtin attributes -use rustc_ast as ast; +use rustc_ast::{self as ast, attr}; use rustc_ast::{Attribute, LitKind, MetaItem, MetaItemKind, MetaItemLit, NestedMetaItem, NodeId}; use rustc_ast_pretty::pprust; use rustc_feature::{find_gated_cfg, is_builtin_attr_name, Features, GatedCfg}; @@ -556,8 +556,8 @@ where (stab, const_stab, body_stab) } -pub fn find_crate_name(sess: &Session, attrs: &[Attribute]) -> Option<Symbol> { - sess.first_attr_value_str_by_name(attrs, sym::crate_name) +pub fn find_crate_name(attrs: &[Attribute]) -> Option<Symbol> { + attr::first_attr_value_str_by_name(attrs, sym::crate_name) } #[derive(Clone, Debug)] @@ -1177,7 +1177,7 @@ fn allow_unstable<'a>( attrs: &'a [Attribute], symbol: Symbol, ) -> impl Iterator<Item = Symbol> + 'a { - let attrs = sess.filter_by_name(attrs, symbol); + let attrs = attr::filter_by_name(attrs, symbol); let list = attrs .filter_map(move |attr| { attr.meta_item_list().or_else(|| { diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index bad08451adf..a8c216407f9 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -120,9 +120,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { && !self.upvars.is_empty() { item_msg = access_place_desc; - debug_assert!( - self.body.local_decls[ty::CAPTURE_STRUCT_LOCAL].ty.is_region_ptr() - ); + debug_assert!(self.body.local_decls[ty::CAPTURE_STRUCT_LOCAL].ty.is_ref()); debug_assert!(is_closure_or_generator( Place::ty_from( the_place_err.local, @@ -470,11 +468,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { { let local_decl = &self.body.local_decls[local]; - let (pointer_sigil, pointer_desc) = if local_decl.ty.is_region_ptr() { - ("&", "reference") - } else { - ("*const", "pointer") - }; + let (pointer_sigil, pointer_desc) = + if local_decl.ty.is_ref() { ("&", "reference") } else { ("*const", "pointer") }; match self.local_names[local] { Some(name) if !local_decl.from_compiler_desugaring() => { @@ -1258,7 +1253,7 @@ fn suggest_ampmut<'tcx>( ( suggestability, highlight_span, - if local_decl.ty.is_region_ptr() { + if local_decl.ty.is_ref() { format!("&mut {}", ty_mut.ty) } else { format!("*mut {}", ty_mut.ty) diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 5e77f6b190a..b7ce3afce7b 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -19,7 +19,6 @@ extern crate tracing; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::graph::dominators::Dominators; -use rustc_data_structures::vec_map::VecMap; use rustc_errors::{Diagnostic, DiagnosticBuilder, DiagnosticMessage, SubdiagnosticMessage}; use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; @@ -141,7 +140,7 @@ fn mir_borrowck(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> &Bor debug!("Skipping borrowck because of injected body"); // Let's make up a borrowck result! Fun times! let result = BorrowCheckResult { - concrete_opaque_types: VecMap::new(), + concrete_opaque_types: FxIndexMap::default(), closure_requirements: None, used_mut_upvars: SmallVec::new(), tainted_by_errors: None, @@ -511,16 +510,11 @@ impl<'cx, 'tcx> BorrowckInferCtxt<'cx, 'tcx> { .as_var() .unwrap_or_else(|| bug!("expected RegionKind::RegionVar on {:?}", next_region)); - if cfg!(debug_assertions) { + if cfg!(debug_assertions) && !self.inside_canonicalization_ctxt() { debug!("inserting vid {:?} with origin {:?} into var_to_origin", vid, origin); let ctxt = get_ctxt_fn(); let mut var_to_origin = self.reg_var_to_origin.borrow_mut(); - let prev = var_to_origin.insert(vid, ctxt); - - // This only makes sense if not called in a canonicalization context. If this - // ever changes we either want to get rid of `BorrowckInferContext::reg_var_to_origin` - // or modify how we track nll region vars for that map. - assert!(matches!(prev, None)); + var_to_origin.insert(vid, ctxt); } next_region @@ -540,16 +534,11 @@ impl<'cx, 'tcx> BorrowckInferCtxt<'cx, 'tcx> { .as_var() .unwrap_or_else(|| bug!("expected RegionKind::RegionVar on {:?}", next_region)); - if cfg!(debug_assertions) { + if cfg!(debug_assertions) && !self.inside_canonicalization_ctxt() { debug!("inserting vid {:?} with origin {:?} into var_to_origin", vid, origin); let ctxt = get_ctxt_fn(); let mut var_to_origin = self.reg_var_to_origin.borrow_mut(); - let prev = var_to_origin.insert(vid, ctxt); - - // This only makes sense if not called in a canonicalization context. If this - // ever changes we either want to get rid of `BorrowckInferContext::reg_var_to_origin` - // or modify how we track nll region vars for that map. - assert!(matches!(prev, None)); + var_to_origin.insert(vid, ctxt); } next_region diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index 96228338a4c..f0068fc9226 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -2,7 +2,7 @@ #![deny(rustc::diagnostic_outside_of_impl)] //! The entry point of the NLL borrow checker. -use rustc_data_structures::vec_map::VecMap; +use rustc_data_structures::fx::FxIndexMap; use rustc_hir::def_id::LocalDefId; use rustc_index::vec::IndexVec; use rustc_middle::mir::{create_dump_file, dump_enabled, dump_mir, PassWhere}; @@ -44,7 +44,7 @@ pub type PoloniusOutput = Output<RustcFacts>; /// closure requirements to propagate, and any generated errors. pub(crate) struct NllOutput<'tcx> { pub regioncx: RegionInferenceContext<'tcx>, - pub opaque_type_values: VecMap<LocalDefId, OpaqueHiddenType<'tcx>>, + pub opaque_type_values: FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>>, pub polonius_input: Option<Box<AllFacts>>, pub polonius_output: Option<Rc<PoloniusOutput>>, pub opt_closure_req: Option<ClosureRegionRequirements<'tcx>>, @@ -377,7 +377,7 @@ pub(super) fn dump_annotation<'tcx>( body: &Body<'tcx>, regioncx: &RegionInferenceContext<'tcx>, closure_region_requirements: &Option<ClosureRegionRequirements<'tcx>>, - opaque_type_values: &VecMap<LocalDefId, OpaqueHiddenType<'tcx>>, + opaque_type_values: &FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>>, errors: &mut crate::error::BorrowckErrors<'tcx>, ) { let tcx = infcx.tcx; diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index dbf15a3e05f..03f175daca9 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -256,11 +256,12 @@ fn sccs_info<'cx, 'tcx>( let mut var_to_origin_sorted = var_to_origin.clone().into_iter().collect::<Vec<_>>(); var_to_origin_sorted.sort_by_key(|vto| vto.0); - let mut debug_str = "region variables to origins:\n".to_string(); + + let mut reg_vars_to_origins_str = "region variables to origins:\n".to_string(); for (reg_var, origin) in var_to_origin_sorted.into_iter() { - debug_str.push_str(&format!("{:?}: {:?}\n", reg_var, origin)); + reg_vars_to_origins_str.push_str(&format!("{:?}: {:?}\n", reg_var, origin)); } - debug!(debug_str); + debug!("{}", reg_vars_to_origins_str); let num_components = sccs.scc_data().ranges().len(); let mut components = vec![FxIndexSet::default(); num_components]; @@ -275,12 +276,12 @@ fn sccs_info<'cx, 'tcx>( for (scc_idx, reg_vars_origins) in components.iter().enumerate() { let regions_info = reg_vars_origins.clone().into_iter().collect::<Vec<_>>(); components_str.push_str(&format!( - "{:?}: {:?})", + "{:?}: {:?},\n)", ConstraintSccIndex::from_usize(scc_idx), regions_info, )) } - debug!(components_str); + debug!("{}", components_str); // calculate the best representative for each component let components_representatives = components diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index e542a1da053..2b16655cf7d 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -1,5 +1,4 @@ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; -use rustc_data_structures::vec_map::VecMap; use rustc_errors::ErrorGuaranteed; use rustc_hir::def_id::LocalDefId; use rustc_hir::OpaqueTyOrigin; @@ -61,9 +60,9 @@ impl<'tcx> RegionInferenceContext<'tcx> { pub(crate) fn infer_opaque_types( &self, infcx: &InferCtxt<'tcx>, - opaque_ty_decls: VecMap<OpaqueTypeKey<'tcx>, (OpaqueHiddenType<'tcx>, OpaqueTyOrigin)>, - ) -> VecMap<LocalDefId, OpaqueHiddenType<'tcx>> { - let mut result: VecMap<LocalDefId, OpaqueHiddenType<'tcx>> = VecMap::new(); + opaque_ty_decls: FxIndexMap<OpaqueTypeKey<'tcx>, (OpaqueHiddenType<'tcx>, OpaqueTyOrigin)>, + ) -> FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>> { + let mut result: FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>> = FxIndexMap::default(); let member_constraints: FxIndexMap<_, _> = self .member_constraints diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 53fef4d75bf..c2a426bea09 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -10,7 +10,6 @@ use either::Either; use hir::OpaqueTyOrigin; use rustc_data_structures::frozen::Frozen; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; -use rustc_data_structures::vec_map::VecMap; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalDefId; @@ -894,7 +893,7 @@ pub(crate) struct MirTypeckResults<'tcx> { pub(crate) constraints: MirTypeckRegionConstraints<'tcx>, pub(crate) universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>, pub(crate) opaque_type_values: - VecMap<OpaqueTypeKey<'tcx>, (OpaqueHiddenType<'tcx>, OpaqueTyOrigin)>, + FxIndexMap<OpaqueTypeKey<'tcx>, (OpaqueHiddenType<'tcx>, OpaqueTyOrigin)>, } /// A collection of region constraints that must be satisfied for the @@ -2223,6 +2222,13 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } } + CastKind::Transmute => { + span_mirbug!( + self, + rvalue, + "Unexpected CastKind::Transmute, which is not permitted in Analysis MIR", + ); + } } } diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs index d96372fb99b..305e2c8fe8e 100644 --- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs +++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs @@ -132,9 +132,12 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> let reg_var = reg.as_var().unwrap_or_else(|| bug!("expected region {:?} to be of kind ReVar", reg)); - let mut var_to_origin = self.type_checker.infcx.reg_var_to_origin.borrow_mut(); - let prev = var_to_origin.insert(reg_var, RegionCtxt::Placeholder(reg_info)); - assert!(matches!(prev, None)); + + if cfg!(debug_assertions) && !self.type_checker.infcx.inside_canonicalization_ctxt() { + let mut var_to_origin = self.type_checker.infcx.reg_var_to_origin.borrow_mut(); + debug!(?reg_var); + var_to_origin.insert(reg_var, RegionCtxt::Placeholder(reg_info)); + } reg } @@ -149,14 +152,9 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> let reg_var = reg.as_var().unwrap_or_else(|| bug!("expected region {:?} to be of kind ReVar", reg)); - if cfg!(debug_assertions) { + if cfg!(debug_assertions) && !self.type_checker.infcx.inside_canonicalization_ctxt() { let mut var_to_origin = self.type_checker.infcx.reg_var_to_origin.borrow_mut(); - let prev = var_to_origin.insert(reg_var, RegionCtxt::Existential(None)); - - // It only makes sense to track region vars in non-canonicalization contexts. If this - // ever changes we either want to get rid of `BorrowckInferContext::reg_var_to_origin` - // or modify how we track nll region vars for that map. - assert!(matches!(prev, None)); + var_to_origin.insert(reg_var, RegionCtxt::Existential(None)); } reg diff --git a/compiler/rustc_builtin_macros/src/cmdline_attrs.rs b/compiler/rustc_builtin_macros/src/cmdline_attrs.rs index db05c00d211..2b6fcc169be 100644 --- a/compiler/rustc_builtin_macros/src/cmdline_attrs.rs +++ b/compiler/rustc_builtin_macros/src/cmdline_attrs.rs @@ -6,7 +6,7 @@ use rustc_ast::{self as ast, AttrItem, AttrStyle}; use rustc_session::parse::ParseSess; use rustc_span::FileName; -pub fn inject(mut krate: ast::Crate, parse_sess: &ParseSess, attrs: &[String]) -> ast::Crate { +pub fn inject(krate: &mut ast::Crate, parse_sess: &ParseSess, attrs: &[String]) { for raw_attr in attrs { let mut parser = rustc_parse::new_parser_from_source_str( parse_sess, @@ -36,6 +36,4 @@ pub fn inject(mut krate: ast::Crate, parse_sess: &ParseSess, attrs: &[String]) - start_span.to(end_span), )); } - - krate } diff --git a/compiler/rustc_builtin_macros/src/deriving/default.rs b/compiler/rustc_builtin_macros/src/deriving/default.rs index 4d753a2ed80..cc32739d083 100644 --- a/compiler/rustc_builtin_macros/src/deriving/default.rs +++ b/compiler/rustc_builtin_macros/src/deriving/default.rs @@ -1,7 +1,7 @@ use crate::deriving::generic::ty::*; use crate::deriving::generic::*; use rustc_ast as ast; -use rustc_ast::{walk_list, EnumDef, VariantData}; +use rustc_ast::{attr, walk_list, EnumDef, VariantData}; use rustc_errors::Applicability; use rustc_expand::base::{Annotatable, DummyResult, ExtCtxt}; use rustc_span::symbol::Ident; @@ -106,7 +106,7 @@ fn extract_default_variant<'a>( let default_variants: SmallVec<[_; 1]> = enum_def .variants .iter() - .filter(|variant| cx.sess.contains_name(&variant.attrs, kw::Default)) + .filter(|variant| attr::contains_name(&variant.attrs, kw::Default)) .collect(); let variant = match default_variants.as_slice() { @@ -116,7 +116,7 @@ fn extract_default_variant<'a>( .variants .iter() .filter(|variant| matches!(variant.data, VariantData::Unit(..))) - .filter(|variant| !cx.sess.contains_name(&variant.attrs, sym::non_exhaustive)); + .filter(|variant| !attr::contains_name(&variant.attrs, sym::non_exhaustive)); let mut diag = cx.struct_span_err(trait_span, "no default declared"); diag.help("make a unit variant default by placing `#[default]` above it"); @@ -146,7 +146,7 @@ fn extract_default_variant<'a>( if v.span == variant.span { None } else { - Some((cx.sess.find_by_name(&v.attrs, kw::Default)?.span, String::new())) + Some((attr::find_by_name(&v.attrs, kw::Default)?.span, String::new())) } }) .collect(); @@ -174,7 +174,7 @@ fn extract_default_variant<'a>( return Err(()); } - if let Some(non_exhaustive_attr) = cx.sess.find_by_name(&variant.attrs, sym::non_exhaustive) { + if let Some(non_exhaustive_attr) = attr::find_by_name(&variant.attrs, sym::non_exhaustive) { cx.struct_span_err(variant.ident.span, "default variant must be exhaustive") .span_label(non_exhaustive_attr.span, "declared `#[non_exhaustive]` here") .help("consider a manual implementation of `Default`") @@ -191,7 +191,7 @@ fn validate_default_attribute( default_variant: &rustc_ast::Variant, ) -> Result<(), ()> { let attrs: SmallVec<[_; 1]> = - cx.sess.filter_by_name(&default_variant.attrs, kw::Default).collect(); + attr::filter_by_name(&default_variant.attrs, kw::Default).collect(); let attr = match attrs.as_slice() { [attr] => attr, diff --git a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs index bc513607ddd..378d5f39f4a 100644 --- a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs +++ b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs @@ -1,6 +1,6 @@ use rustc_ast::ptr::P; use rustc_ast::visit::{self, Visitor}; -use rustc_ast::{self as ast, NodeId}; +use rustc_ast::{self as ast, attr, NodeId}; use rustc_ast_pretty::pprust; use rustc_expand::base::{parse_macro_name_and_helper_attrs, ExtCtxt, ResolverExpand}; use rustc_expand::expand::{AstFragment, ExpansionConfig}; @@ -34,7 +34,6 @@ enum ProcMacro { } struct CollectProcMacros<'a> { - sess: &'a Session, macros: Vec<ProcMacro>, in_root: bool, handler: &'a rustc_errors::Handler, @@ -44,19 +43,18 @@ struct CollectProcMacros<'a> { } pub fn inject( + krate: &mut ast::Crate, sess: &Session, resolver: &mut dyn ResolverExpand, - mut krate: ast::Crate, is_proc_macro_crate: bool, has_proc_macro_decls: bool, is_test_crate: bool, handler: &rustc_errors::Handler, -) -> ast::Crate { +) { let ecfg = ExpansionConfig::default("proc_macro".to_string()); let mut cx = ExtCtxt::new(sess, ecfg, resolver, None); let mut collect = CollectProcMacros { - sess, macros: Vec::new(), in_root: true, handler, @@ -66,22 +64,20 @@ pub fn inject( }; if has_proc_macro_decls || is_proc_macro_crate { - visit::walk_crate(&mut collect, &krate); + visit::walk_crate(&mut collect, krate); } let macros = collect.macros; if !is_proc_macro_crate { - return krate; + return; } if is_test_crate { - return krate; + return; } let decls = mk_decls(&mut cx, ¯os); krate.items.push(decls); - - krate } impl<'a> CollectProcMacros<'a> { @@ -160,7 +156,7 @@ impl<'a> CollectProcMacros<'a> { impl<'a> Visitor<'a> for CollectProcMacros<'a> { fn visit_item(&mut self, item: &'a ast::Item) { if let ast::ItemKind::MacroDef(..) = item.kind { - if self.is_proc_macro_crate && self.sess.contains_name(&item.attrs, sym::macro_export) { + if self.is_proc_macro_crate && attr::contains_name(&item.attrs, sym::macro_export) { let msg = "cannot export macro_rules! macros from a `proc-macro` crate type currently"; self.handler.span_err(self.source_map.guess_head_span(item.span), msg); @@ -176,7 +172,7 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> { let mut found_attr: Option<&'a ast::Attribute> = None; for attr in &item.attrs { - if self.sess.is_proc_macro_attr(&attr) { + if attr.is_proc_macro_attr() { if let Some(prev_attr) = found_attr { let prev_item = prev_attr.get_normal_item(); let item = attr.get_normal_item(); diff --git a/compiler/rustc_builtin_macros/src/standard_library_imports.rs b/compiler/rustc_builtin_macros/src/standard_library_imports.rs index e67c0dba685..6493c6f13d5 100644 --- a/compiler/rustc_builtin_macros/src/standard_library_imports.rs +++ b/compiler/rustc_builtin_macros/src/standard_library_imports.rs @@ -1,4 +1,4 @@ -use rustc_ast as ast; +use rustc_ast::{self as ast, attr}; use rustc_expand::base::{ExtCtxt, ResolverExpand}; use rustc_expand::expand::ExpansionConfig; use rustc_session::Session; @@ -9,17 +9,19 @@ use rustc_span::DUMMY_SP; use thin_vec::thin_vec; pub fn inject( - mut krate: ast::Crate, + krate: &mut ast::Crate, + pre_configured_attrs: &[ast::Attribute], resolver: &mut dyn ResolverExpand, sess: &Session, -) -> ast::Crate { +) -> usize { + let orig_num_items = krate.items.len(); let edition = sess.parse_sess.edition; // the first name in this list is the crate name of the crate with the prelude - let names: &[Symbol] = if sess.contains_name(&krate.attrs, sym::no_core) { - return krate; - } else if sess.contains_name(&krate.attrs, sym::no_std) { - if sess.contains_name(&krate.attrs, sym::compiler_builtins) { + let names: &[Symbol] = if attr::contains_name(pre_configured_attrs, sym::no_core) { + return 0; + } else if attr::contains_name(pre_configured_attrs, sym::no_std) { + if attr::contains_name(pre_configured_attrs, sym::compiler_builtins) { &[sym::core] } else { &[sym::core, sym::compiler_builtins] @@ -88,6 +90,5 @@ pub fn inject( ); krate.items.insert(0, use_item); - - krate + krate.items.len() - orig_num_items } diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs index 151afd2d458..44b9c4718a7 100644 --- a/compiler/rustc_builtin_macros/src/test.rs +++ b/compiler/rustc_builtin_macros/src/test.rs @@ -1,12 +1,11 @@ /// The expansion from a test function to the appropriate test struct for libtest /// Ideally, this code would be in libtest but for efficiency and error messages it lives here. use crate::util::{check_builtin_macro_attribute, warn_on_duplicate_attribute}; -use rustc_ast as ast; use rustc_ast::ptr::P; +use rustc_ast::{self as ast, attr}; use rustc_ast_pretty::pprust; use rustc_errors::Applicability; use rustc_expand::base::*; -use rustc_session::Session; use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::{FileNameDisplayPreference, Span}; use std::iter; @@ -291,14 +290,11 @@ pub fn expand_test_or_bench( ), ), // ignore: true | false - field( - "ignore", - cx.expr_bool(sp, should_ignore(&cx.sess, &item)), - ), + field("ignore", cx.expr_bool(sp, should_ignore(&item)),), // ignore_message: Some("...") | None field( "ignore_message", - if let Some(msg) = should_ignore_message(cx, &item) { + if let Some(msg) = should_ignore_message(&item) { cx.expr_some(sp, cx.expr_str(sp, msg)) } else { cx.expr_none(sp) @@ -425,12 +421,12 @@ enum ShouldPanic { Yes(Option<Symbol>), } -fn should_ignore(sess: &Session, i: &ast::Item) -> bool { - sess.contains_name(&i.attrs, sym::ignore) +fn should_ignore(i: &ast::Item) -> bool { + attr::contains_name(&i.attrs, sym::ignore) } -fn should_ignore_message(cx: &ExtCtxt<'_>, i: &ast::Item) -> Option<Symbol> { - match cx.sess.find_by_name(&i.attrs, sym::ignore) { +fn should_ignore_message(i: &ast::Item) -> Option<Symbol> { + match attr::find_by_name(&i.attrs, sym::ignore) { Some(attr) => { match attr.meta_item_list() { // Handle #[ignore(bar = "foo")] @@ -444,7 +440,7 @@ fn should_ignore_message(cx: &ExtCtxt<'_>, i: &ast::Item) -> Option<Symbol> { } fn should_panic(cx: &ExtCtxt<'_>, i: &ast::Item) -> ShouldPanic { - match cx.sess.find_by_name(&i.attrs, sym::should_panic) { + match attr::find_by_name(&i.attrs, sym::should_panic) { Some(attr) => { let sd = &cx.sess.parse_sess.span_diagnostic; @@ -510,7 +506,7 @@ fn test_type(cx: &ExtCtxt<'_>) -> TestType { } fn has_test_signature(cx: &ExtCtxt<'_>, i: &ast::Item) -> bool { - let has_should_panic_attr = cx.sess.contains_name(&i.attrs, sym::should_panic); + let has_should_panic_attr = attr::contains_name(&i.attrs, sym::should_panic); let sd = &cx.sess.parse_sess.span_diagnostic; match &i.kind { ast::ItemKind::Fn(box ast::Fn { sig, generics, .. }) => { diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs index d8e3db9e8ee..43ab6c04428 100644 --- a/compiler/rustc_builtin_macros/src/test_harness.rs +++ b/compiler/rustc_builtin_macros/src/test_harness.rs @@ -37,7 +37,7 @@ struct TestCtxt<'a> { /// Traverse the crate, collecting all the test functions, eliding any /// existing main functions, and synthesizing a main test harness -pub fn inject(sess: &Session, resolver: &mut dyn ResolverExpand, krate: &mut ast::Crate) { +pub fn inject(krate: &mut ast::Crate, sess: &Session, resolver: &mut dyn ResolverExpand) { let span_diagnostic = sess.diagnostic(); let panic_strategy = sess.panic_strategy(); let platform_panic_strategy = sess.target.panic_strategy; @@ -47,11 +47,11 @@ pub fn inject(sess: &Session, resolver: &mut dyn ResolverExpand, krate: &mut ast // unconditional, so that the attribute is still marked as used in // non-test builds. let reexport_test_harness_main = - sess.first_attr_value_str_by_name(&krate.attrs, sym::reexport_test_harness_main); + attr::first_attr_value_str_by_name(&krate.attrs, sym::reexport_test_harness_main); // Do this here so that the test_runner crate attribute gets marked as used // even in non-test builds - let test_runner = get_test_runner(sess, span_diagnostic, &krate); + let test_runner = get_test_runner(span_diagnostic, &krate); if sess.opts.test { let panic_strategy = match (panic_strategy, sess.opts.unstable_opts.panic_abort_tests) { @@ -123,7 +123,7 @@ impl<'a> MutVisitor for TestHarnessGenerator<'a> { fn flat_map_item(&mut self, i: P<ast::Item>) -> SmallVec<[P<ast::Item>; 1]> { let mut item = i.into_inner(); - if let Some(name) = get_test_name(&self.cx.ext_cx.sess, &item) { + if let Some(name) = get_test_name(&item) { debug!("this is a test item"); let test = Test { span: item.span, ident: item.ident, name }; @@ -145,12 +145,12 @@ impl<'a> MutVisitor for TestHarnessGenerator<'a> { // Beware, this is duplicated in librustc_passes/entry.rs (with // `rustc_hir::Item`), so make sure to keep them in sync. -fn entry_point_type(sess: &Session, item: &ast::Item, depth: usize) -> EntryPointType { +fn entry_point_type(item: &ast::Item, depth: usize) -> EntryPointType { match item.kind { ast::ItemKind::Fn(..) => { - if sess.contains_name(&item.attrs, sym::start) { + if attr::contains_name(&item.attrs, sym::start) { EntryPointType::Start - } else if sess.contains_name(&item.attrs, sym::rustc_main) { + } else if attr::contains_name(&item.attrs, sym::rustc_main) { EntryPointType::RustcMainAttr } else if item.ident.name == sym::main { if depth == 0 { @@ -184,7 +184,7 @@ impl<'a> MutVisitor for EntryPointCleaner<'a> { // Remove any #[rustc_main] or #[start] from the AST so it doesn't // clash with the one we're going to add, but mark it as // #[allow(dead_code)] to avoid printing warnings. - let item = match entry_point_type(self.sess, &item, self.depth) { + let item = match entry_point_type(&item, self.depth) { EntryPointType::MainNamed | EntryPointType::RustcMainAttr | EntryPointType::Start => { item.map(|ast::Item { id, ident, attrs, kind, vis, span, tokens }| { let allow_dead_code = attr::mk_attr_nested_word( @@ -373,16 +373,12 @@ fn mk_tests_slice(cx: &TestCtxt<'_>, sp: Span) -> P<ast::Expr> { ) } -fn get_test_name(sess: &Session, i: &ast::Item) -> Option<Symbol> { - sess.first_attr_value_str_by_name(&i.attrs, sym::rustc_test_marker) +fn get_test_name(i: &ast::Item) -> Option<Symbol> { + attr::first_attr_value_str_by_name(&i.attrs, sym::rustc_test_marker) } -fn get_test_runner( - sess: &Session, - sd: &rustc_errors::Handler, - krate: &ast::Crate, -) -> Option<ast::Path> { - let test_attr = sess.find_by_name(&krate.attrs, sym::test_runner)?; +fn get_test_runner(sd: &rustc_errors::Handler, krate: &ast::Crate) -> Option<ast::Path> { + let test_attr = attr::find_by_name(&krate.attrs, sym::test_runner)?; let meta_list = test_attr.meta_item_list()?; let span = test_attr.span; match &*meta_list { diff --git a/compiler/rustc_builtin_macros/src/util.rs b/compiler/rustc_builtin_macros/src/util.rs index 83812631c2f..9463a1418ce 100644 --- a/compiler/rustc_builtin_macros/src/util.rs +++ b/compiler/rustc_builtin_macros/src/util.rs @@ -1,4 +1,4 @@ -use rustc_ast::{AttrStyle, Attribute, MetaItem}; +use rustc_ast::{attr, AttrStyle, Attribute, MetaItem}; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_feature::AttributeTemplate; use rustc_lint_defs::builtin::DUPLICATE_MACRO_ATTRIBUTES; @@ -36,7 +36,7 @@ pub fn warn_on_duplicate_attribute(ecx: &ExtCtxt<'_>, item: &Annotatable, name: _ => None, }; if let Some(attrs) = attrs { - if let Some(attr) = ecx.sess.find_by_name(attrs, name) { + if let Some(attr) = attr::find_by_name(attrs, name) { ecx.parse_sess().buffer_lint( DUPLICATE_MACRO_ATTRIBUTES, attr.span, diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index 1b8e9312e2f..2107ae147e9 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -709,6 +709,10 @@ fn codegen_stmt<'tcx>( let operand = codegen_operand(fx, operand); operand.coerce_dyn_star(fx, lval); } + Rvalue::Cast(CastKind::Transmute, ref operand, _to_ty) => { + let operand = codegen_operand(fx, operand); + lval.write_cvalue_transmute(fx, operand); + } Rvalue::Discriminant(place) => { let place = codegen_place(fx, place); let value = place.to_cvalue(fx); diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs index fe48cac4faf..03f2a65fcca 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs @@ -557,16 +557,6 @@ fn codegen_regular_intrinsic_call<'tcx>( fx.bcx.ins().band(ptr, mask); } - sym::transmute => { - intrinsic_args!(fx, args => (from); intrinsic); - - if ret.layout().abi.is_uninhabited() { - crate::base::codegen_panic(fx, "Transmuting to uninhabited type.", source_info); - return; - } - - ret.write_cvalue_transmute(fx, from); - } sym::write_bytes | sym::volatile_set_memory => { intrinsic_args!(fx, args => (dst, val, count); intrinsic); let val = val.load_scalar(fx); diff --git a/compiler/rustc_codegen_cranelift/src/vtable.rs b/compiler/rustc_codegen_cranelift/src/vtable.rs index b7bfd8fd395..94806e0d798 100644 --- a/compiler/rustc_codegen_cranelift/src/vtable.rs +++ b/compiler/rustc_codegen_cranelift/src/vtable.rs @@ -48,9 +48,7 @@ pub(crate) fn get_ptr_and_method_ref<'tcx>( ) -> (Pointer, Value) { let (ptr, vtable) = 'block: { if let Abi::Scalar(_) = arg.layout().abi { - 'descend_newtypes: while !arg.layout().ty.is_unsafe_ptr() - && !arg.layout().ty.is_region_ptr() - { + 'descend_newtypes: while !arg.layout().ty.is_unsafe_ptr() && !arg.layout().ty.is_ref() { for i in 0..arg.layout().fields.count() { let field = arg.value_field(fx, mir::Field::new(i)); if !field.layout().is_zst() { diff --git a/compiler/rustc_codegen_llvm/src/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs index dd3268d7780..a570f2af0f0 100644 --- a/compiler/rustc_codegen_llvm/src/back/archive.rs +++ b/compiler/rustc_codegen_llvm/src/back/archive.rs @@ -189,6 +189,15 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder { path.push(lib_name); path }; + // dlltool target architecture args from: + // https://github.com/llvm/llvm-project-release-prs/blob/llvmorg-15.0.6/llvm/lib/ToolDrivers/llvm-dlltool/DlltoolDriver.cpp#L69 + let (dlltool_target_arch, dlltool_target_bitness) = match sess.target.arch.as_ref() { + "x86_64" => ("i386:x86-64", "--64"), + "x86" => ("i386", "--32"), + "aarch64" => ("arm64", "--64"), + "arm" => ("arm", "--32"), + _ => panic!("unsupported arch {}", sess.target.arch), + }; let result = std::process::Command::new(dlltool) .args([ "-d", @@ -197,6 +206,10 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder { lib_name, "-l", output_path.to_str().unwrap(), + "-m", + dlltool_target_arch, + "-f", + dlltool_target_bitness, "--no-leading-underscore", "--temp-prefix", temp_prefix.to_str().unwrap(), @@ -422,24 +435,22 @@ fn find_binutils_dlltool(sess: &Session) -> OsString { return dlltool_path.clone().into_os_string(); } - let mut tool_name: OsString = if sess.host.arch != sess.target.arch { - // We are cross-compiling, so we need the tool with the prefix matching our target - if sess.target.arch == "x86" { - "i686-w64-mingw32-dlltool" - } else { - "x86_64-w64-mingw32-dlltool" - } + let tool_name: OsString = if sess.host.options.is_like_windows { + // If we're compiling on Windows, always use "dlltool.exe". + "dlltool.exe" } else { - // We are not cross-compiling, so we just want `dlltool` - "dlltool" + // On other platforms, use the architecture-specific name. + match sess.target.arch.as_ref() { + "x86_64" => "x86_64-w64-mingw32-dlltool", + "x86" => "i686-w64-mingw32-dlltool", + "aarch64" => "aarch64-w64-mingw32-dlltool", + + // For non-standard architectures (e.g., aarch32) fallback to "dlltool". + _ => "dlltool", + } } .into(); - if sess.host.options.is_like_windows { - // If we're compiling on Windows, add the .exe suffix - tool_name.push(".exe"); - } - // NOTE: it's not clear how useful it is to explicitly search PATH. for dir in env::split_paths(&env::var_os("PATH").unwrap_or_default()) { let full_path = dir.join(&tool_name); diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs index 80fd9726fc7..ff2b005d757 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs @@ -5,12 +5,12 @@ use crate::llvm; use crate::builder::Builder; use crate::common::CodegenCx; use crate::value::Value; +use rustc_ast::attr; use rustc_codegen_ssa::base::collect_debugger_visualizers_transitive; use rustc_codegen_ssa::traits::*; use rustc_hir::def_id::LOCAL_CRATE; use rustc_middle::bug; use rustc_session::config::{CrateType, DebugInfo}; - use rustc_span::symbol::sym; use rustc_span::DebuggerVisualizerType; @@ -87,7 +87,7 @@ pub fn get_or_insert_gdb_debug_scripts_section_global<'ll>(cx: &CodegenCx<'ll, ' pub fn needs_gdb_debug_scripts_section(cx: &CodegenCx<'_, '_>) -> bool { let omit_gdb_pretty_printer_section = - cx.tcx.sess.contains_name(cx.tcx.hir().krate_attrs(), sym::omit_gdb_pretty_printer_section); + attr::contains_name(cx.tcx.hir().krate_attrs(), sym::omit_gdb_pretty_printer_section); // To ensure the section `__rustc_debug_gdb_scripts_section__` will not create // ODR violations at link time, this section will not be emitted for rlibs since diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 9c921989ca9..012e25884ca 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -378,7 +378,7 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> { } } - _ => bug!("unknown intrinsic '{}'", name), + _ => bug!("unknown intrinsic '{}' -- should it have been lowered earlier?", name), }; if !fn_abi.ret.is_ignore() { diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 8dafe1b750b..e5bae009ed6 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -361,12 +361,12 @@ impl CodegenBackend for LlvmCodegenBackend { .expect("Expected LlvmCodegenBackend's OngoingCodegen, found Box<Any>") .join(sess); - sess.time("llvm_dump_timing_file", || { - if sess.opts.unstable_opts.llvm_time_trace { + if sess.opts.unstable_opts.llvm_time_trace { + sess.time("llvm_dump_timing_file", || { let file_name = outputs.with_extension("llvm_timings.json"); llvm_util::time_trace_profiler_finish(&file_name); - } - }); + }); + } Ok((codegen_results, work_products)) } diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index ba58a2e68e9..46692fd5e8b 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -424,7 +424,7 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec<Str .filter_map(|s| { let enable_disable = match s.chars().next() { None => return None, - Some(c @ '+' | c @ '-') => c, + Some(c @ ('+' | '-')) => c, Some(_) => { if diagnostics { sess.emit_warning(UnknownCTargetFeaturePrefix { feature: s }); diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index 23e2b272410..dd117681950 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -133,6 +133,9 @@ pub fn get_linker<'a>( LinkerFlavor::Unix(Cc::No) if sess.target.os == "l4re" => { Box::new(L4Bender::new(cmd, sess)) as Box<dyn Linker> } + LinkerFlavor::Unix(Cc::No) if sess.target.os == "aix" => { + Box::new(AixLinker::new(cmd, sess)) as Box<dyn Linker> + } LinkerFlavor::WasmLld(Cc::No) => Box::new(WasmLd::new(cmd, sess)) as Box<dyn Linker>, LinkerFlavor::Gnu(cc, _) | LinkerFlavor::Darwin(cc, _) @@ -1474,6 +1477,177 @@ impl<'a> L4Bender<'a> { } } +/// Linker for AIX. +pub struct AixLinker<'a> { + cmd: Command, + sess: &'a Session, + hinted_static: bool, +} + +impl<'a> AixLinker<'a> { + pub fn new(cmd: Command, sess: &'a Session) -> AixLinker<'a> { + AixLinker { cmd: cmd, sess: sess, hinted_static: false } + } + + fn hint_static(&mut self) { + if !self.hinted_static { + self.cmd.arg("-bstatic"); + self.hinted_static = true; + } + } + + fn hint_dynamic(&mut self) { + if self.hinted_static { + self.cmd.arg("-bdynamic"); + self.hinted_static = false; + } + } + + fn build_dylib(&mut self, _out_filename: &Path) { + self.cmd.arg("-bM:SRE"); + self.cmd.arg("-bnoentry"); + // FIXME: Use CreateExportList utility to create export list + // and remove -bexpfull. + self.cmd.arg("-bexpfull"); + } +} + +impl<'a> Linker for AixLinker<'a> { + fn link_dylib(&mut self, lib: &str, _verbatim: bool, _as_needed: bool) { + self.hint_dynamic(); + self.cmd.arg(format!("-l{}", lib)); + } + + fn link_staticlib(&mut self, lib: &str, _verbatim: bool) { + self.hint_static(); + self.cmd.arg(format!("-l{}", lib)); + } + + fn link_rlib(&mut self, lib: &Path) { + self.hint_static(); + self.cmd.arg(lib); + } + + fn include_path(&mut self, path: &Path) { + self.cmd.arg("-L").arg(path); + } + + fn framework_path(&mut self, _: &Path) { + bug!("frameworks are not supported on AIX"); + } + + fn output_filename(&mut self, path: &Path) { + self.cmd.arg("-o").arg(path); + } + + fn add_object(&mut self, path: &Path) { + self.cmd.arg(path); + } + + fn full_relro(&mut self) {} + + fn partial_relro(&mut self) {} + + fn no_relro(&mut self) {} + + fn cmd(&mut self) -> &mut Command { + &mut self.cmd + } + + fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path) { + match output_kind { + LinkOutputKind::DynamicDylib => { + self.hint_dynamic(); + self.build_dylib(out_filename); + } + LinkOutputKind::StaticDylib => { + self.hint_static(); + self.build_dylib(out_filename); + } + _ => {} + } + } + + fn link_rust_dylib(&mut self, lib: &str, _: &Path) { + self.hint_dynamic(); + self.cmd.arg(format!("-l{}", lib)); + } + + fn link_framework(&mut self, _framework: &str, _as_needed: bool) { + bug!("frameworks not supported on AIX"); + } + + fn link_whole_staticlib(&mut self, lib: &str, verbatim: bool, search_path: &[PathBuf]) { + self.hint_static(); + let lib = find_native_static_library(lib, verbatim, search_path, &self.sess); + self.cmd.arg(format!("-bkeepfile:{}", lib.to_str().unwrap())); + } + + fn link_whole_rlib(&mut self, lib: &Path) { + self.hint_static(); + self.cmd.arg(format!("-bkeepfile:{}", lib.to_str().unwrap())); + } + + fn gc_sections(&mut self, _keep_metadata: bool) { + self.cmd.arg("-bgc"); + } + + fn no_gc_sections(&mut self) { + self.cmd.arg("-bnogc"); + } + + fn optimize(&mut self) {} + + fn pgo_gen(&mut self) {} + + fn control_flow_guard(&mut self) {} + + fn debuginfo(&mut self, strip: Strip, _: &[PathBuf]) { + match strip { + Strip::None => {} + // FIXME: -s strips the symbol table, line number information + // and relocation information. + Strip::Debuginfo | Strip::Symbols => { + self.cmd.arg("-s"); + } + } + } + + fn no_crt_objects(&mut self) {} + + fn no_default_libraries(&mut self) {} + + fn export_symbols(&mut self, tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) { + let path = tmpdir.join("list.exp"); + let res: io::Result<()> = try { + let mut f = BufWriter::new(File::create(&path)?); + // TODO: use llvm-nm to generate export list. + for symbol in symbols { + debug!(" _{}", symbol); + writeln!(f, " {}", symbol)?; + } + }; + if let Err(e) = res { + self.sess.fatal(&format!("failed to write export file: {}", e)); + } + self.cmd.arg(format!("-bE:{}", path.to_str().unwrap())); + } + + fn subsystem(&mut self, _subsystem: &str) {} + + fn reset_per_library_state(&mut self) { + self.hint_dynamic(); + } + + fn linker_plugin_lto(&mut self) {} + + fn add_eh_frame_header(&mut self) {} + + fn add_no_exec(&mut self) {} + + fn add_as_needed(&mut self) {} +} + fn for_each_exported_symbols_include_dep<'tcx>( tcx: TyCtxt<'tcx>, crate_type: CrateType, diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 8508ab87532..7ce72d21727 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -8,6 +8,7 @@ use crate::{ CachedModuleCodegen, CodegenResults, CompiledModule, CrateInfo, ModuleCodegen, ModuleKind, }; use jobserver::{Acquired, Client}; +use rustc_ast::attr; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::memmap::Mmap; use rustc_data_structures::profiling::SelfProfilerRef; @@ -447,8 +448,8 @@ pub fn start_async_codegen<B: ExtraBackendMethods>( let sess = tcx.sess; let crate_attrs = tcx.hir().attrs(rustc_hir::CRATE_HIR_ID); - let no_builtins = tcx.sess.contains_name(crate_attrs, sym::no_builtins); - let is_compiler_builtins = tcx.sess.contains_name(crate_attrs, sym::compiler_builtins); + let no_builtins = attr::contains_name(crate_attrs, sym::no_builtins); + let is_compiler_builtins = attr::contains_name(crate_attrs, sym::compiler_builtins); let crate_info = CrateInfo::new(tcx, target_cpu); diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index abc510e360d..c3c8649dbff 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -786,6 +786,7 @@ pub fn codegen_crate<B: ExtraBackendMethods>( total_codegen_time, start_rss.unwrap(), end_rss, + tcx.sess.opts.unstable_opts.time_passes_format, ); } @@ -809,7 +810,7 @@ impl CrateInfo { .collect(); let local_crate_name = tcx.crate_name(LOCAL_CRATE); let crate_attrs = tcx.hir().attrs(rustc_hir::CRATE_HIR_ID); - let subsystem = tcx.sess.first_attr_value_str_by_name(crate_attrs, sym::windows_subsystem); + let subsystem = attr::first_attr_value_str_by_name(crate_attrs, sym::windows_subsystem); let windows_subsystem = subsystem.map(|subsystem| { if subsystem != sym::windows && subsystem != sym::console { tcx.sess.emit_fatal(errors::InvalidWindowsSubsystem { subsystem }); diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index bdfc0aa1c30..5da0e826c56 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -16,7 +16,7 @@ use rustc_index::vec::Idx; use rustc_middle::mir::{self, AssertKind, SwitchTargets}; use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, ValidityRequirement}; use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths}; -use rustc_middle::ty::{self, Instance, Ty, TypeVisitableExt}; +use rustc_middle::ty::{self, Instance, Ty}; use rustc_session::config::OptLevel; use rustc_span::source_map::Span; use rustc_span::{sym, Symbol}; @@ -769,23 +769,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { None => bx.fn_abi_of_fn_ptr(sig, extra_args), }; - if intrinsic == Some(sym::transmute) { - return if let Some(target) = target { - self.codegen_transmute(bx, &args[0], destination); - helper.funclet_br(self, bx, target, mergeable_succ) - } else { - // If we are trying to transmute to an uninhabited type, - // it is likely there is no allotted destination. In fact, - // transmuting to an uninhabited type is UB, which means - // we can do what we like. Here, we declare that transmuting - // into an uninhabited type is impossible, so anything following - // it must be unreachable. - assert_eq!(fn_abi.ret.layout.abi, abi::Abi::Uninhabited); - bx.unreachable(); - MergingSucc::False - }; - } - if let Some(merging_succ) = self.codegen_panic_intrinsic( &helper, bx, @@ -828,7 +811,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { match intrinsic { None | Some(sym::drop_in_place) => {} - Some(sym::copy_nonoverlapping) => unreachable!(), Some(intrinsic) => { let dest = match ret_dest { _ if fn_abi.ret.is_indirect() => llargs[0], @@ -917,7 +899,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // // This is also relevant for `Pin<&mut Self>`, where we need to peel the `Pin`. 'descend_newtypes: while !op.layout.ty.is_unsafe_ptr() - && !op.layout.ty.is_region_ptr() + && !op.layout.ty.is_ref() { for i in 0..op.layout.fields.count() { let field = op.extract_field(bx, i); @@ -959,7 +941,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { Immediate(_) => { // See comment above explaining why we peel these newtypes 'descend_newtypes: while !op.layout.ty.is_unsafe_ptr() - && !op.layout.ty.is_region_ptr() + && !op.layout.ty.is_ref() { for i in 0..op.layout.fields.count() { let field = op.extract_field(bx, i); @@ -1739,71 +1721,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } - fn codegen_transmute(&mut self, bx: &mut Bx, src: &mir::Operand<'tcx>, dst: mir::Place<'tcx>) { - if let Some(index) = dst.as_local() { - match self.locals[index] { - LocalRef::Place(place) => self.codegen_transmute_into(bx, src, place), - LocalRef::UnsizedPlace(_) => bug!("transmute must not involve unsized locals"), - LocalRef::Operand(None) => { - let dst_layout = bx.layout_of(self.monomorphized_place_ty(dst.as_ref())); - assert!(!dst_layout.ty.has_erasable_regions()); - let place = PlaceRef::alloca(bx, dst_layout); - place.storage_live(bx); - self.codegen_transmute_into(bx, src, place); - let op = bx.load_operand(place); - place.storage_dead(bx); - self.locals[index] = LocalRef::Operand(Some(op)); - self.debug_introduce_local(bx, index); - } - LocalRef::Operand(Some(op)) => { - assert!(op.layout.is_zst(), "assigning to initialized SSAtemp"); - } - } - } else { - let dst = self.codegen_place(bx, dst.as_ref()); - self.codegen_transmute_into(bx, src, dst); - } - } - - fn codegen_transmute_into( - &mut self, - bx: &mut Bx, - src: &mir::Operand<'tcx>, - dst: PlaceRef<'tcx, Bx::Value>, - ) { - let src = self.codegen_operand(bx, src); - - // Special-case transmutes between scalars as simple bitcasts. - match (src.layout.abi, dst.layout.abi) { - (abi::Abi::Scalar(src_scalar), abi::Abi::Scalar(dst_scalar)) => { - // HACK(eddyb) LLVM doesn't like `bitcast`s between pointers and non-pointers. - let src_is_ptr = matches!(src_scalar.primitive(), abi::Pointer(_)); - let dst_is_ptr = matches!(dst_scalar.primitive(), abi::Pointer(_)); - if src_is_ptr == dst_is_ptr { - assert_eq!(src.layout.size, dst.layout.size); - - // NOTE(eddyb) the `from_immediate` and `to_immediate_scalar` - // conversions allow handling `bool`s the same as `u8`s. - let src = bx.from_immediate(src.immediate()); - // LLVM also doesn't like `bitcast`s between pointers in different address spaces. - let src_as_dst = if src_is_ptr { - bx.pointercast(src, bx.backend_type(dst.layout)) - } else { - bx.bitcast(src, bx.backend_type(dst.layout)) - }; - Immediate(bx.to_immediate_scalar(src_as_dst, dst_scalar)).store(bx, dst); - return; - } - } - _ => {} - } - - let llty = bx.backend_type(src.layout); - let cast_ptr = bx.pointercast(dst.llval, bx.type_ptr_to(llty)); - let align = src.layout.align.abi.min(dst.align); - src.val.store(bx, PlaceRef::new_sized_aligned(cast_ptr, src.layout, align)); - } - // Stores the return value of a function call into it's final location. fn store_return( &mut self, diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 13c4fa132d8..72d41d8c32c 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -13,7 +13,7 @@ use rustc_middle::ty::cast::{CastTy, IntTy}; use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf}; use rustc_middle::ty::{self, adjustment::PointerCast, Instance, Ty, TyCtxt}; use rustc_span::source_map::{Span, DUMMY_SP}; -use rustc_target::abi::VariantIdx; +use rustc_target::abi::{self, VariantIdx}; impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { #[instrument(level = "trace", skip(self, bx))] @@ -72,6 +72,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } + mir::Rvalue::Cast(mir::CastKind::Transmute, ref operand, _ty) => { + let src = self.codegen_operand(bx, operand); + self.codegen_transmute(bx, src, dest); + } + mir::Rvalue::Repeat(ref elem, count) => { let cg_elem = self.codegen_operand(bx, elem); @@ -143,6 +148,52 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } + fn codegen_transmute( + &mut self, + bx: &mut Bx, + src: OperandRef<'tcx, Bx::Value>, + dst: PlaceRef<'tcx, Bx::Value>, + ) { + // The MIR validator enforces no unsized transmutes. + debug_assert!(src.layout.is_sized()); + debug_assert!(dst.layout.is_sized()); + + if src.layout.size != dst.layout.size + || src.layout.abi == abi::Abi::Uninhabited + || dst.layout.abi == abi::Abi::Uninhabited + { + // In all of these cases it's UB to run this transmute, but that's + // known statically so might as well trap for it, rather than just + // making it unreachable. + bx.abort(); + return; + } + + let size_in_bytes = src.layout.size.bytes(); + if size_in_bytes == 0 { + // Nothing to write + return; + } + + match src.val { + OperandValue::Ref(src_llval, meta, src_align) => { + debug_assert_eq!(meta, None); + // For a place-to-place transmute, call `memcpy` directly so that + // both arguments get the best-available alignment information. + let bytes = bx.cx().const_usize(size_in_bytes); + let flags = MemFlags::empty(); + bx.memcpy(dst.llval, dst.align, src_llval, src_align, bytes, flags); + } + OperandValue::Immediate(_) | OperandValue::Pair(_, _) => { + // When we have immediate(s), the alignment of the source is irrelevant, + // so we can store them using the destination's alignment. + let llty = bx.backend_type(src.layout); + let cast_ptr = bx.pointercast(dst.llval, bx.type_ptr_to(llty)); + src.val.store(bx, PlaceRef::new_sized_aligned(cast_ptr, src.layout, dst.align)); + } + } + } + pub fn codegen_rvalue_unsized( &mut self, bx: &mut Bx, @@ -344,6 +395,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { }; OperandValue::Immediate(newval) } + mir::CastKind::Transmute => { + bug!("Transmute operand {:?} in `codegen_rvalue_operand`", operand); + } }; OperandRef { val, layout: cast } } @@ -673,6 +727,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { pub fn rvalue_creates_operand(&self, rvalue: &mir::Rvalue<'tcx>, span: Span) -> bool { match *rvalue { + mir::Rvalue::Cast(mir::CastKind::Transmute, ..) => + // FIXME: Now that transmute is an Rvalue, it would be nice if + // it could create `Immediate`s for scalars, where possible. + false, mir::Rvalue::Ref(..) | mir::Rvalue::CopyForDeref(..) | mir::Rvalue::AddressOf(..) | diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index a44f70ed059..350ce529ef5 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -2,7 +2,7 @@ use rustc_hir::def::DefKind; use rustc_hir::{LangItem, CRATE_HIR_ID}; use rustc_middle::mir; use rustc_middle::mir::interpret::PointerArithmetic; -use rustc_middle::ty::layout::FnAbiOf; +use rustc_middle::ty::layout::{FnAbiOf, TyAndLayout}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_session::lint::builtin::INVALID_ALIGNMENT; use std::borrow::Borrow; @@ -335,8 +335,8 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, } #[inline(always)] - fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool { - ecx.tcx.sess.opts.unstable_opts.extra_const_ub_checks + fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>, layout: TyAndLayout<'tcx>) -> bool { + ecx.tcx.sess.opts.unstable_opts.extra_const_ub_checks || layout.abi.is_uninhabited() } fn alignment_check_failed( diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs index c14152a916a..163e3f86993 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -133,6 +133,22 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { bug!() } } + + Transmute => { + assert!(src.layout.is_sized()); + assert!(dest.layout.is_sized()); + if src.layout.size != dest.layout.size { + throw_ub_format!( + "transmuting from {}-byte type to {}-byte type: `{}` -> `{}`", + src.layout.size.bytes(), + dest.layout.size.bytes(), + src.layout.ty, + dest.layout.ty, + ); + } + + self.copy_op(src, dest, /*allow_transmute*/ true)?; + } } Ok(()) } diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index a29cdade023..26fb041b455 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -127,7 +127,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // First handle intrinsics without return place. let ret = match ret { None => match intrinsic_name { - sym::transmute => throw_ub_format!("transmuting to uninhabited type"), sym::abort => M::abort(self, "the program aborted execution".to_owned())?, // Unsupported diverging intrinsic. _ => return Ok(false), @@ -411,9 +410,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.exact_div(&val, &size, dest)?; } - sym::transmute => { - self.copy_op(&args[0], dest, /*allow_transmute*/ true)?; - } sym::assert_inhabited | sym::assert_zero_valid | sym::assert_mem_uninitialized_valid => { diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs index c134d3a6b2f..aca68dc454b 100644 --- a/compiler/rustc_const_eval/src/interpret/machine.rs +++ b/compiler/rustc_const_eval/src/interpret/machine.rs @@ -8,6 +8,7 @@ use std::hash::Hash; use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_middle::mir; +use rustc_middle::ty::layout::TyAndLayout; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::def_id::DefId; use rustc_target::abi::{Align, Size}; @@ -145,8 +146,8 @@ pub trait Machine<'mir, 'tcx>: Sized { check: CheckAlignment, ) -> InterpResult<'tcx, ()>; - /// Whether to enforce the validity invariant - fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool; + /// Whether to enforce the validity invariant for a specific layout. + fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>, layout: TyAndLayout<'tcx>) -> bool; /// Whether function calls should be [ABI](CallAbi)-checked. fn enforce_abi(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool { diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index 3c463500a60..ff6db143ddf 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -461,7 +461,7 @@ where ) -> InterpResult<'tcx> { self.write_immediate_no_validate(src, dest)?; - if M::enforce_validity(self) { + if M::enforce_validity(self, dest.layout) { // Data got changed, better make sure it matches the type! self.validate_operand(&self.place_to_op(dest)?)?; } @@ -616,7 +616,7 @@ where ) -> InterpResult<'tcx> { self.copy_op_no_validate(src, dest, allow_transmute)?; - if M::enforce_validity(self) { + if M::enforce_validity(self, dest.layout) { // Data got changed, better make sure it matches the type! self.validate_operand(&self.place_to_op(dest)?)?; } diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index e0939d1d1ba..66fc1c07e20 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -621,6 +621,33 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { ); } } + CastKind::Transmute => { + if let MirPhase::Runtime(..) = self.mir_phase { + // Unlike `mem::transmute`, a MIR `Transmute` is well-formed + // for any two `Sized` types, just potentially UB to run. + + if !op_ty.is_sized(self.tcx, self.param_env) { + self.fail( + location, + format!("Cannot transmute from non-`Sized` type {op_ty:?}"), + ); + } + if !target_type.is_sized(self.tcx, self.param_env) { + self.fail( + location, + format!("Cannot transmute to non-`Sized` type {target_type:?}"), + ); + } + } else { + self.fail( + location, + format!( + "Transmute is not supported in non-runtime phase {:?}.", + self.mir_phase + ), + ); + } + } } } Rvalue::Repeat(_, _) diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml index 24cf9812a25..056ee1f63be 100644 --- a/compiler/rustc_data_structures/Cargo.toml +++ b/compiler/rustc_data_structures/Cargo.toml @@ -21,6 +21,7 @@ rustc-hash = "1.1.0" rustc_index = { path = "../rustc_index", package = "rustc_index" } rustc_macros = { path = "../rustc_macros" } rustc_serialize = { path = "../rustc_serialize" } +serde_json = "1.0.59" smallvec = { version = "1.8.1", features = [ "const_generics", "union", diff --git a/compiler/rustc_data_structures/src/graph/scc/tests.rs b/compiler/rustc_data_structures/src/graph/scc/tests.rs index 820a70fc8e4..513df666d0d 100644 --- a/compiler/rustc_data_structures/src/graph/scc/tests.rs +++ b/compiler/rustc_data_structures/src/graph/scc/tests.rs @@ -56,7 +56,7 @@ fn test_three_sccs() { assert_eq!(sccs.scc(1), 0); assert_eq!(sccs.scc(2), 0); assert_eq!(sccs.scc(3), 2); - assert_eq!(sccs.successors(0), &[]); + assert_eq!(sccs.successors(0), &[] as &[usize]); assert_eq!(sccs.successors(1), &[0]); assert_eq!(sccs.successors(2), &[0]); } @@ -113,7 +113,7 @@ fn test_find_state_2() { assert_eq!(sccs.scc(2), 0); assert_eq!(sccs.scc(3), 0); assert_eq!(sccs.scc(4), 0); - assert_eq!(sccs.successors(0), &[]); + assert_eq!(sccs.successors(0), &[] as &[usize]); } #[test] @@ -138,7 +138,7 @@ fn test_find_state_3() { assert_eq!(sccs.scc(3), 0); assert_eq!(sccs.scc(4), 0); assert_eq!(sccs.scc(5), 1); - assert_eq!(sccs.successors(0), &[]); + assert_eq!(sccs.successors(0), &[] as &[usize]); assert_eq!(sccs.successors(1), &[0]); } diff --git a/compiler/rustc_data_structures/src/graph/vec_graph/tests.rs b/compiler/rustc_data_structures/src/graph/vec_graph/tests.rs index c8f97926717..7c866da6009 100644 --- a/compiler/rustc_data_structures/src/graph/vec_graph/tests.rs +++ b/compiler/rustc_data_structures/src/graph/vec_graph/tests.rs @@ -27,11 +27,11 @@ fn successors() { let graph = create_graph(); assert_eq!(graph.successors(0), &[1]); assert_eq!(graph.successors(1), &[2, 3]); - assert_eq!(graph.successors(2), &[]); + assert_eq!(graph.successors(2), &[] as &[usize]); assert_eq!(graph.successors(3), &[4]); - assert_eq!(graph.successors(4), &[]); + assert_eq!(graph.successors(4), &[] as &[usize]); assert_eq!(graph.successors(5), &[1]); - assert_eq!(graph.successors(6), &[]); + assert_eq!(graph.successors(6), &[] as &[usize]); } #[test] diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index c595bf830a3..0339fb925d4 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -79,7 +79,6 @@ pub mod sync; pub mod tiny_list; pub mod transitive_relation; pub mod vec_linked_list; -pub mod vec_map; pub mod work_queue; pub use atomic_ref::AtomicRef; pub mod frozen; diff --git a/compiler/rustc_data_structures/src/profiling.rs b/compiler/rustc_data_structures/src/profiling.rs index 3d9c7f6eae2..58a0609e296 100644 --- a/compiler/rustc_data_structures/src/profiling.rs +++ b/compiler/rustc_data_structures/src/profiling.rs @@ -97,6 +97,7 @@ use std::time::{Duration, Instant}; pub use measureme::EventId; use measureme::{EventIdBuilder, Profiler, SerializableString, StringId}; use parking_lot::RwLock; +use serde_json::json; use smallvec::SmallVec; bitflags::bitflags! { @@ -145,6 +146,15 @@ const EVENT_FILTERS_BY_NAME: &[(&str, EventFilter)] = &[ /// Something that uniquely identifies a query invocation. pub struct QueryInvocationId(pub u32); +/// Which format to use for `-Z time-passes` +#[derive(Clone, Copy, PartialEq, Hash, Debug)] +pub enum TimePassesFormat { + /// Emit human readable text + Text, + /// Emit structured JSON + Json, +} + /// A reference to the SelfProfiler. It can be cloned and sent across thread /// boundaries at will. #[derive(Clone)] @@ -158,14 +168,14 @@ pub struct SelfProfilerRef { // actually enabled. event_filter_mask: EventFilter, - // Print verbose generic activities to stderr? - print_verbose_generic_activities: bool, + // Print verbose generic activities to stderr. + print_verbose_generic_activities: Option<TimePassesFormat>, } impl SelfProfilerRef { pub fn new( profiler: Option<Arc<SelfProfiler>>, - print_verbose_generic_activities: bool, + print_verbose_generic_activities: Option<TimePassesFormat>, ) -> SelfProfilerRef { // If there is no SelfProfiler then the filter mask is set to NONE, // ensuring that nothing ever tries to actually access it. @@ -207,9 +217,10 @@ impl SelfProfilerRef { /// a measureme event, "verbose" generic activities also print a timing entry to /// stderr if the compiler is invoked with -Ztime-passes. pub fn verbose_generic_activity(&self, event_label: &'static str) -> VerboseTimingGuard<'_> { - let message = self.print_verbose_generic_activities.then(|| event_label.to_owned()); + let message_and_format = + self.print_verbose_generic_activities.map(|format| (event_label.to_owned(), format)); - VerboseTimingGuard::start(message, self.generic_activity(event_label)) + VerboseTimingGuard::start(message_and_format, self.generic_activity(event_label)) } /// Like `verbose_generic_activity`, but with an extra arg. @@ -221,11 +232,14 @@ impl SelfProfilerRef { where A: Borrow<str> + Into<String>, { - let message = self + let message_and_format = self .print_verbose_generic_activities - .then(|| format!("{}({})", event_label, event_arg.borrow())); + .map(|format| (format!("{}({})", event_label, event_arg.borrow()), format)); - VerboseTimingGuard::start(message, self.generic_activity_with_arg(event_label, event_arg)) + VerboseTimingGuard::start( + message_and_format, + self.generic_activity_with_arg(event_label, event_arg), + ) } /// Start profiling a generic activity. Profiling continues until the @@ -703,17 +717,32 @@ impl<'a> TimingGuard<'a> { } } +struct VerboseInfo { + start_time: Instant, + start_rss: Option<usize>, + message: String, + format: TimePassesFormat, +} + #[must_use] pub struct VerboseTimingGuard<'a> { - start_and_message: Option<(Instant, Option<usize>, String)>, + info: Option<VerboseInfo>, _guard: TimingGuard<'a>, } impl<'a> VerboseTimingGuard<'a> { - pub fn start(message: Option<String>, _guard: TimingGuard<'a>) -> Self { + pub fn start( + message_and_format: Option<(String, TimePassesFormat)>, + _guard: TimingGuard<'a>, + ) -> Self { VerboseTimingGuard { _guard, - start_and_message: message.map(|msg| (Instant::now(), get_resident_set_size(), msg)), + info: message_and_format.map(|(message, format)| VerboseInfo { + start_time: Instant::now(), + start_rss: get_resident_set_size(), + message, + format, + }), } } @@ -726,10 +755,10 @@ impl<'a> VerboseTimingGuard<'a> { impl Drop for VerboseTimingGuard<'_> { fn drop(&mut self) { - if let Some((start_time, start_rss, ref message)) = self.start_and_message { + if let Some(info) = &self.info { let end_rss = get_resident_set_size(); - let dur = start_time.elapsed(); - print_time_passes_entry(message, dur, start_rss, end_rss); + let dur = info.start_time.elapsed(); + print_time_passes_entry(&info.message, dur, info.start_rss, end_rss, info.format); } } } @@ -739,7 +768,22 @@ pub fn print_time_passes_entry( dur: Duration, start_rss: Option<usize>, end_rss: Option<usize>, + format: TimePassesFormat, ) { + match format { + TimePassesFormat::Json => { + let json = json!({ + "pass": what, + "time": dur.as_secs_f64(), + "rss_start": start_rss, + "rss_end": end_rss, + }); + eprintln!("time: {}", json.to_string()); + return; + } + TimePassesFormat::Text => (), + } + // Print the pass if its duration is greater than 5 ms, or it changed the // measured RSS. let is_notable = || { diff --git a/compiler/rustc_data_structures/src/vec_map.rs b/compiler/rustc_data_structures/src/vec_map.rs deleted file mode 100644 index d1a99bcaeb7..00000000000 --- a/compiler/rustc_data_structures/src/vec_map.rs +++ /dev/null @@ -1,192 +0,0 @@ -use std::borrow::Borrow; -use std::fmt::Debug; -use std::slice::Iter; -use std::vec::IntoIter; - -use crate::stable_hasher::{HashStable, StableHasher}; - -/// A map type implemented as a vector of pairs `K` (key) and `V` (value). -/// It currently provides a subset of all the map operations, the rest could be added as needed. -#[derive(Clone, Encodable, Decodable, Debug)] -pub struct VecMap<K, V>(Vec<(K, V)>); - -impl<K, V> VecMap<K, V> -where - K: Debug + PartialEq, - V: Debug, -{ - pub fn new() -> Self { - VecMap(Default::default()) - } - - /// Sets the value of the entry, and returns the entry's old value. - pub fn insert(&mut self, k: K, v: V) -> Option<V> { - if let Some(elem) = self.0.iter_mut().find(|(key, _)| *key == k) { - Some(std::mem::replace(&mut elem.1, v)) - } else { - self.0.push((k, v)); - None - } - } - - /// Removes the entry from the map and returns the removed value - pub fn remove(&mut self, k: &K) -> Option<V> { - self.0.iter().position(|(k2, _)| k2 == k).map(|pos| self.0.remove(pos).1) - } - - /// Gets a reference to the value in the entry. - pub fn get<Q: ?Sized>(&self, k: &Q) -> Option<&V> - where - K: Borrow<Q>, - Q: Eq, - { - self.0.iter().find(|(key, _)| k == key.borrow()).map(|elem| &elem.1) - } - - /// Gets a mutable reference to the value in the entry. - pub fn get_mut<Q: ?Sized>(&mut self, k: &Q) -> Option<&mut V> - where - K: Borrow<Q>, - Q: Eq, - { - self.0.iter_mut().find(|(key, _)| k == key.borrow()).map(|elem| &mut elem.1) - } - - /// Returns the any value corresponding to the supplied predicate filter. - /// - /// The supplied predicate will be applied to each (key, value) pair and it will return a - /// reference to the values where the predicate returns `true`. - pub fn any_value_matching(&self, mut predicate: impl FnMut(&(K, V)) -> bool) -> Option<&V> { - self.0.iter().find(|kv| predicate(kv)).map(|elem| &elem.1) - } - - /// Returns the value corresponding to the supplied predicate filter. It crashes if there's - /// more than one matching element. - /// - /// The supplied predicate will be applied to each (key, value) pair and it will return a - /// reference to the value where the predicate returns `true`. - pub fn get_value_matching(&self, mut predicate: impl FnMut(&(K, V)) -> bool) -> Option<&V> { - let mut filter = self.0.iter().filter(|kv| predicate(kv)); - let (_, value) = filter.next()?; - // This should return just one element, otherwise it's a bug - assert!( - filter.next().is_none(), - "Collection {self:#?} should have just one matching element" - ); - Some(value) - } - - /// Returns `true` if the map contains a value for the specified key. - /// - /// The key may be any borrowed form of the map's key type, - /// [`Eq`] on the borrowed form *must* match those for - /// the key type. - pub fn contains_key<Q: ?Sized>(&self, k: &Q) -> bool - where - K: Borrow<Q>, - Q: Eq, - { - self.get(k).is_some() - } - - /// Returns `true` if the map contains no elements. - pub fn is_empty(&self) -> bool { - self.0.is_empty() - } - - pub fn iter(&self) -> Iter<'_, (K, V)> { - self.into_iter() - } - - pub fn iter_mut(&mut self) -> impl Iterator<Item = (&K, &mut V)> { - self.into_iter() - } - - pub fn retain(&mut self, f: impl Fn(&(K, V)) -> bool) { - self.0.retain(f) - } -} - -impl<K, V> Default for VecMap<K, V> { - #[inline] - fn default() -> Self { - Self(Default::default()) - } -} - -impl<K, V> From<Vec<(K, V)>> for VecMap<K, V> { - fn from(vec: Vec<(K, V)>) -> Self { - Self(vec) - } -} - -impl<K, V> Into<Vec<(K, V)>> for VecMap<K, V> { - fn into(self) -> Vec<(K, V)> { - self.0 - } -} - -impl<K, V> FromIterator<(K, V)> for VecMap<K, V> { - fn from_iter<I: IntoIterator<Item = (K, V)>>(iter: I) -> Self { - Self(iter.into_iter().collect()) - } -} - -impl<'a, K, V> IntoIterator for &'a VecMap<K, V> { - type Item = &'a (K, V); - type IntoIter = Iter<'a, (K, V)>; - - #[inline] - fn into_iter(self) -> Self::IntoIter { - self.0.iter() - } -} - -impl<'a, K: 'a, V: 'a> IntoIterator for &'a mut VecMap<K, V> { - type Item = (&'a K, &'a mut V); - type IntoIter = impl Iterator<Item = Self::Item>; - - #[inline] - fn into_iter(self) -> Self::IntoIter { - self.0.iter_mut().map(|(k, v)| (&*k, v)) - } -} - -impl<K, V> IntoIterator for VecMap<K, V> { - type Item = (K, V); - type IntoIter = IntoIter<(K, V)>; - - #[inline] - fn into_iter(self) -> Self::IntoIter { - self.0.into_iter() - } -} - -impl<K: PartialEq + Debug, V: Debug> Extend<(K, V)> for VecMap<K, V> { - fn extend<I: IntoIterator<Item = (K, V)>>(&mut self, iter: I) { - for (k, v) in iter { - self.insert(k, v); - } - } - - fn extend_one(&mut self, (k, v): (K, V)) { - self.insert(k, v); - } - - fn extend_reserve(&mut self, additional: usize) { - self.0.extend_reserve(additional); - } -} - -impl<K, V, CTX> HashStable<CTX> for VecMap<K, V> -where - K: HashStable<CTX> + Eq, - V: HashStable<CTX>, -{ - fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { - self.0.hash_stable(hcx, hasher) - } -} - -#[cfg(test)] -mod tests; diff --git a/compiler/rustc_data_structures/src/vec_map/tests.rs b/compiler/rustc_data_structures/src/vec_map/tests.rs deleted file mode 100644 index 458b60077dc..00000000000 --- a/compiler/rustc_data_structures/src/vec_map/tests.rs +++ /dev/null @@ -1,48 +0,0 @@ -use super::*; - -impl<K, V> VecMap<K, V> { - fn into_vec(self) -> Vec<(K, V)> { - self.0.into() - } -} - -#[test] -fn test_from_iterator() { - assert_eq!( - std::iter::empty().collect::<VecMap<i32, bool>>().into_vec(), - Vec::<(i32, bool)>::new() - ); - assert_eq!(std::iter::once((42, true)).collect::<VecMap<_, _>>().into_vec(), vec![(42, true)]); - assert_eq!( - [(1, true), (2, false)].into_iter().collect::<VecMap<_, _>>().into_vec(), - vec![(1, true), (2, false)] - ); -} - -#[test] -fn test_into_iterator_owned() { - assert_eq!(VecMap::new().into_iter().collect::<Vec<(i32, bool)>>(), Vec::<(i32, bool)>::new()); - assert_eq!(VecMap::from(vec![(1, true)]).into_iter().collect::<Vec<_>>(), vec![(1, true)]); - assert_eq!( - VecMap::from(vec![(1, true), (2, false)]).into_iter().collect::<Vec<_>>(), - vec![(1, true), (2, false)] - ); -} - -#[test] -fn test_insert() { - let mut v = VecMap::new(); - assert_eq!(v.insert(1, true), None); - assert_eq!(v.insert(2, false), None); - assert_eq!(v.clone().into_vec(), vec![(1, true), (2, false)]); - assert_eq!(v.insert(1, false), Some(true)); - assert_eq!(v.into_vec(), vec![(1, false), (2, false)]); -} - -#[test] -fn test_get() { - let v = [(1, true), (2, false)].into_iter().collect::<VecMap<_, _>>(); - assert_eq!(v.get(&1), Some(&true)); - assert_eq!(v.get(&2), Some(&false)); - assert_eq!(v.get(&3), None); -} diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 8634c644176..1e835f6065a 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -20,7 +20,9 @@ pub extern crate rustc_plugin_impl as plugin; use rustc_ast as ast; use rustc_codegen_ssa::{traits::CodegenBackend, CodegenErrors, CodegenResults}; -use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry}; +use rustc_data_structures::profiling::{ + get_resident_set_size, print_time_passes_entry, TimePassesFormat, +}; use rustc_data_structures::sync::SeqCst; use rustc_errors::registry::{InvalidErrorCode, Registry}; use rustc_errors::{ @@ -161,7 +163,7 @@ pub trait Callbacks { #[derive(Default)] pub struct TimePassesCallbacks { - time_passes: bool, + time_passes: Option<TimePassesFormat>, } impl Callbacks for TimePassesCallbacks { @@ -171,7 +173,8 @@ impl Callbacks for TimePassesCallbacks { // If a --print=... option has been given, we don't print the "total" // time because it will mess up the --print output. See #64339. // - self.time_passes = config.opts.prints.is_empty() && config.opts.unstable_opts.time_passes; + self.time_passes = (config.opts.prints.is_empty() && config.opts.unstable_opts.time_passes) + .then(|| config.opts.unstable_opts.time_passes_format); config.opts.trimmed_def_paths = TrimmedDefPaths::GoodPath; } } @@ -353,7 +356,7 @@ fn run_compiler( { let plugins = queries.register_plugins()?; - let (_, lint_store) = &*plugins.borrow(); + let (.., lint_store) = &*plugins.borrow(); // Lint plugins are registered; now we can process command line flags. if sess.opts.describe_lints { @@ -1354,9 +1357,9 @@ pub fn main() -> ! { RunCompiler::new(&args, &mut callbacks).run() }); - if callbacks.time_passes { + if let Some(format) = callbacks.time_passes { let end_rss = get_resident_set_size(); - print_time_passes_entry("total", start_time.elapsed(), start_rss, end_rss); + print_time_passes_entry("total", start_time.elapsed(), start_rss, end_rss, format); } process::exit(exit_code) diff --git a/compiler/rustc_error_codes/src/error_codes/E0080.md b/compiler/rustc_error_codes/src/error_codes/E0080.md index 7b1bbde6140..71d6c6fe2ef 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0080.md +++ b/compiler/rustc_error_codes/src/error_codes/E0080.md @@ -15,9 +15,8 @@ or causing an integer overflow are two ways to induce this error. Ensure that the expressions given can be evaluated as the desired integer type. -See the [Custom Discriminants][custom-discriminants] section of the Reference -for more information about setting custom integer types on fieldless enums -using the [`repr` attribute][repr-attribute]. +See the [Discriminants] section of the Reference for more information about +setting custom integer types on enums using the [`repr` attribute][repr-attribute]. -[custom-discriminants]: https://doc.rust-lang.org/reference/items/enumerations.html#custom-discriminant-values-for-field-less-enumerations -[repr-attribute]: https://doc.rust-lang.org/reference/type-layout.html#reprc-enums +[discriminants]: https://doc.rust-lang.org/reference/items/enumerations.html#discriminants +[repr-attribute]: https://doc.rust-lang.org/reference/type-layout.html#representations diff --git a/compiler/rustc_error_codes/src/error_codes/E0794.md b/compiler/rustc_error_codes/src/error_codes/E0794.md index a33802885c0..4377a292473 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0794.md +++ b/compiler/rustc_error_codes/src/error_codes/E0794.md @@ -59,6 +59,6 @@ In the definition of `bar`, the lifetime parameter `'a` is late-bound, while where `'a` is universally quantified and `'b` is substituted by a specific lifetime. It is not allowed to explicitly specify early-bound lifetime arguments when late-bound lifetime parameters are present (as for `bar_fn2`, -see issue #42868: https://github.com/rust-lang/rust/issues/42868), although the +see [issue #42868](https://github.com/rust-lang/rust/issues/42868)), although the types that are constrained by early-bound parameters can be specified (as for `bar_fn3`). diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 713e4fbbdce..d32af10914e 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -776,16 +776,14 @@ impl SyntaxExtension { let allow_internal_unstable = attr::allow_internal_unstable(sess, &attrs).collect::<Vec<Symbol>>(); - let allow_internal_unsafe = sess.contains_name(attrs, sym::allow_internal_unsafe); - let local_inner_macros = sess - .find_by_name(attrs, sym::macro_export) + let allow_internal_unsafe = attr::contains_name(attrs, sym::allow_internal_unsafe); + let local_inner_macros = attr::find_by_name(attrs, sym::macro_export) .and_then(|macro_export| macro_export.meta_item_list()) .map_or(false, |l| attr::list_contains_name(&l, sym::local_inner_macros)); - let collapse_debuginfo = sess.contains_name(attrs, sym::collapse_debuginfo); + let collapse_debuginfo = attr::contains_name(attrs, sym::collapse_debuginfo); tracing::debug!(?local_inner_macros, ?collapse_debuginfo, ?allow_internal_unsafe); - let (builtin_name, helper_attrs) = sess - .find_by_name(attrs, sym::rustc_builtin_macro) + let (builtin_name, helper_attrs) = attr::find_by_name(attrs, sym::rustc_builtin_macro) .map(|attr| { // Override `helper_attrs` passed above if it's a built-in macro, // marking `proc_macro_derive` macros as built-in is not a realistic use case. @@ -1004,6 +1002,7 @@ pub struct ExpansionData { pub struct ExtCtxt<'a> { pub sess: &'a Session, pub ecfg: expand::ExpansionConfig<'a>, + pub num_standard_library_imports: usize, pub reduced_recursion_limit: Option<Limit>, pub root_path: PathBuf, pub resolver: &'a mut dyn ResolverExpand, @@ -1032,6 +1031,7 @@ impl<'a> ExtCtxt<'a> { ExtCtxt { sess, ecfg, + num_standard_library_imports: 0, reduced_recursion_limit: None, resolver, lint_store, diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index d6cb173ba9b..a78dc0678d5 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -24,7 +24,6 @@ use rustc_session::Session; use rustc_span::edition::{Edition, ALL_EDITIONS}; use rustc_span::symbol::{sym, Symbol}; use rustc_span::{Span, DUMMY_SP}; -use thin_vec::ThinVec; /// A folder that strips out items that do not belong in the current configuration. pub struct StripUnconfigured<'a> { @@ -37,7 +36,7 @@ pub struct StripUnconfigured<'a> { pub lint_node_id: NodeId, } -fn get_features(sess: &Session, krate_attrs: &[ast::Attribute]) -> Features { +pub fn features(sess: &Session, krate_attrs: &[Attribute]) -> Features { fn feature_removed(sess: &Session, span: Span, reason: Option<&str>) { sess.emit_err(FeatureRemoved { span, @@ -191,39 +190,16 @@ fn get_features(sess: &Session, krate_attrs: &[ast::Attribute]) -> Features { features } -/// `cfg_attr`-process the crate's attributes and compute the crate's features. -pub fn features( - sess: &Session, - mut krate: ast::Crate, - lint_node_id: NodeId, -) -> (ast::Crate, Features) { - let mut strip_unconfigured = - StripUnconfigured { sess, features: None, config_tokens: false, lint_node_id }; - - let unconfigured_attrs = krate.attrs.clone(); - let diag = &sess.parse_sess.span_diagnostic; - let err_count = diag.err_count(); - let features = match strip_unconfigured.configure_krate_attrs(krate.attrs) { - None => { - // The entire crate is unconfigured. - krate.attrs = ast::AttrVec::new(); - krate.items = ThinVec::new(); - Features::default() - } - Some(attrs) => { - krate.attrs = attrs; - let features = get_features(sess, &krate.attrs); - if err_count == diag.err_count() { - // Avoid reconfiguring malformed `cfg_attr`s. - strip_unconfigured.features = Some(&features); - // Run configuration again, this time with features available - // so that we can perform feature-gating. - strip_unconfigured.configure_krate_attrs(unconfigured_attrs); - } - features - } +pub fn pre_configure_attrs(sess: &Session, attrs: &[Attribute]) -> ast::AttrVec { + let strip_unconfigured = StripUnconfigured { + sess, + features: None, + config_tokens: false, + lint_node_id: ast::CRATE_NODE_ID, }; - (krate, features) + let attrs: ast::AttrVec = + attrs.iter().flat_map(|attr| strip_unconfigured.process_cfg_attr(attr)).collect(); + if strip_unconfigured.in_cfg(&attrs) { attrs } else { ast::AttrVec::new() } } #[macro_export] @@ -254,11 +230,6 @@ impl<'a> StripUnconfigured<'a> { } } - fn configure_krate_attrs(&self, mut attrs: ast::AttrVec) -> Option<ast::AttrVec> { - attrs.flat_map_in_place(|attr| self.process_cfg_attr(attr)); - self.in_cfg(&attrs).then_some(attrs) - } - /// Performs cfg-expansion on `stream`, producing a new `AttrTokenStream`. /// This is only used during the invocation of `derive` proc-macros, /// which require that we cfg-expand their entire input. @@ -281,7 +252,7 @@ impl<'a> StripUnconfigured<'a> { .iter() .flat_map(|tree| match tree.clone() { AttrTokenTree::Attributes(mut data) => { - data.attrs.flat_map_in_place(|attr| self.process_cfg_attr(attr)); + data.attrs.flat_map_in_place(|attr| self.process_cfg_attr(&attr)); if self.in_cfg(&data.attrs) { data.tokens = LazyAttrTokenStream::new( @@ -319,12 +290,16 @@ impl<'a> StripUnconfigured<'a> { /// the syntax of any `cfg_attr` is incorrect. fn process_cfg_attrs<T: HasAttrs>(&self, node: &mut T) { node.visit_attrs(|attrs| { - attrs.flat_map_in_place(|attr| self.process_cfg_attr(attr)); + attrs.flat_map_in_place(|attr| self.process_cfg_attr(&attr)); }); } - fn process_cfg_attr(&self, attr: Attribute) -> Vec<Attribute> { - if attr.has_name(sym::cfg_attr) { self.expand_cfg_attr(attr, true) } else { vec![attr] } + fn process_cfg_attr(&self, attr: &Attribute) -> Vec<Attribute> { + if attr.has_name(sym::cfg_attr) { + self.expand_cfg_attr(attr, true) + } else { + vec![attr.clone()] + } } /// Parse and expand a single `cfg_attr` attribute into a list of attributes @@ -334,9 +309,9 @@ impl<'a> StripUnconfigured<'a> { /// Gives a compiler warning when the `cfg_attr` contains no attributes and /// is in the original source file. Gives a compiler error if the syntax of /// the attribute is incorrect. - pub(crate) fn expand_cfg_attr(&self, attr: Attribute, recursive: bool) -> Vec<Attribute> { + pub(crate) fn expand_cfg_attr(&self, attr: &Attribute, recursive: bool) -> Vec<Attribute> { let Some((cfg_predicate, expanded_attrs)) = - rustc_parse::parse_cfg_attr(&attr, &self.sess.parse_sess) else { + rustc_parse::parse_cfg_attr(attr, &self.sess.parse_sess) else { return vec![]; }; @@ -365,10 +340,10 @@ impl<'a> StripUnconfigured<'a> { // `#[cfg_attr(false, cfg_attr(true, some_attr))]`. expanded_attrs .into_iter() - .flat_map(|item| self.process_cfg_attr(self.expand_cfg_attr_item(&attr, item))) + .flat_map(|item| self.process_cfg_attr(&self.expand_cfg_attr_item(attr, item))) .collect() } else { - expanded_attrs.into_iter().map(|item| self.expand_cfg_attr_item(&attr, item)).collect() + expanded_attrs.into_iter().map(|item| self.expand_cfg_attr_item(attr, item)).collect() } } diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 4092a192e0c..ec40911545f 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -1038,6 +1038,9 @@ trait InvocationCollectorNode: HasAttrs + HasNodeId + Sized { ) -> Result<Self::OutputTy, Self> { Ok(noop_flat_map(node, collector)) } + fn expand_cfg_false(&mut self, collector: &mut InvocationCollector<'_, '_>, span: Span) { + collector.cx.emit_err(RemoveNodeNotSupported { span, descr: Self::descr() }); + } } impl InvocationCollectorNode for P<ast::Item> { @@ -1378,6 +1381,11 @@ impl InvocationCollectorNode for ast::Crate { fn noop_visit<V: MutVisitor>(&mut self, visitor: &mut V) { noop_visit_crate(self, visitor) } + fn expand_cfg_false(&mut self, collector: &mut InvocationCollector<'_, '_>, _span: Span) { + self.attrs.clear(); + // Standard prelude imports are left in the crate for backward compatibility. + self.items.truncate(collector.cx.num_standard_library_imports); + } } impl InvocationCollectorNode for P<ast::Ty> { @@ -1688,7 +1696,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { res } - fn expand_cfg_attr(&self, node: &mut impl HasAttrs, attr: ast::Attribute, pos: usize) { + fn expand_cfg_attr(&self, node: &mut impl HasAttrs, attr: &ast::Attribute, pos: usize) { node.visit_attrs(|attrs| { // Repeated `insert` calls is inefficient, but the number of // insertions is almost always 0 or 1 in practice. @@ -1712,7 +1720,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { Default::default() } sym::cfg_attr => { - self.expand_cfg_attr(&mut node, attr, pos); + self.expand_cfg_attr(&mut node, &attr, pos); continue; } _ => { @@ -1756,11 +1764,11 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { continue; } - self.cx.emit_err(RemoveNodeNotSupported { span, descr: Node::descr() }); + node.expand_cfg_false(self, span); continue; } sym::cfg_attr => { - self.expand_cfg_attr(node, attr, pos); + self.expand_cfg_attr(node, &attr, pos); continue; } _ => visit_clobber(node, |node| { diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index e0a7c864b94..b7d280b8751 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -160,6 +160,8 @@ declare_features! ( (active, intrinsics, "1.0.0", None, None), /// Allows using `#[lang = ".."]` attribute for linking items to special compiler logic. (active, lang_items, "1.0.0", None, None), + /// Allows `#[link(..., cfg(..))]`; perma-unstable per #37406 + (active, link_cfg, "1.14.0", None, None), /// Allows the `multiple_supertrait_upcastable` lint. (active, multiple_supertrait_upcastable, "1.69.0", None, None), /// Allows using `#[omit_gdb_pretty_printer_section]`. @@ -432,8 +434,6 @@ declare_features! ( (active, large_assignments, "1.52.0", Some(83518), None), /// Allows `if/while p && let q = r && ...` chains. (active, let_chains, "1.37.0", Some(53667), None), - /// Allows `#[link(..., cfg(..))]`. - (active, link_cfg, "1.14.0", Some(37406), None), /// Allows using `reason` in lint attributes and the `#[expect(lint)]` lint check. (active, lint_reasons, "1.31.0", Some(54503), None), /// Give access to additional metadata about declarative macro meta-variables. diff --git a/compiler/rustc_fs_util/src/lib.rs b/compiler/rustc_fs_util/src/lib.rs index a7dfce3b9b8..81d63338145 100644 --- a/compiler/rustc_fs_util/src/lib.rs +++ b/compiler/rustc_fs_util/src/lib.rs @@ -1,10 +1,11 @@ +#![feature(absolute_path)] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] use std::ffi::CString; use std::fs; use std::io; -use std::path::{Path, PathBuf}; +use std::path::{absolute, Path, PathBuf}; // Unfortunately, on windows, it looks like msvcrt.dll is silently translating // verbatim paths under the hood to non-verbatim paths! This manifests itself as @@ -91,3 +92,8 @@ pub fn path_to_c_string(p: &Path) -> CString { pub fn path_to_c_string(p: &Path) -> CString { CString::new(p.to_str().unwrap()).unwrap() } + +#[inline] +pub fn try_canonicalize<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> { + fs::canonicalize(&path).or_else(|_| absolute(&path)) +} diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 72ff317d45d..0863d65d8f9 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -301,6 +301,7 @@ language_item_table! { Context, sym::Context, context, Target::Struct, GenericRequirement::None; FuturePoll, sym::poll, future_poll_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None; + Option, sym::Option, option_type, Target::Enum, GenericRequirement::None; OptionSome, sym::Some, option_some_variant, Target::Variant, GenericRequirement::None; OptionNone, sym::None, option_none_variant, Target::Variant, GenericRequirement::None; diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 8a9aac14fb6..6d9dfe9697c 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -31,6 +31,7 @@ use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::ObligationCause; use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; use rustc_middle::middle::stability::AllowUnstable; +use rustc_middle::ty::fold::FnMutDelegate; use rustc_middle::ty::subst::{self, GenericArgKind, InternalSubsts, SubstsRef}; use rustc_middle::ty::DynKind; use rustc_middle::ty::GenericParamDefKind; @@ -1335,7 +1336,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ty::Clause::RegionOutlives(_) | ty::Clause::ConstArgHasType(..) => bug!(), }, ty::PredicateKind::WellFormed(_) - | ty::PredicateKind::AliasEq(..) + | ty::PredicateKind::AliasRelate(..) | ty::PredicateKind::ObjectSafe(_) | ty::PredicateKind::ClosureKind(_, _, _) | ty::PredicateKind::Subtype(_) @@ -2225,47 +2226,66 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let param_env = tcx.param_env(block.owner.to_def_id()); let cause = ObligationCause::misc(span, block.owner.def_id); + let mut fulfillment_errors = Vec::new(); - let mut applicable_candidates: Vec<_> = candidates - .iter() - .filter_map(|&(impl_, (assoc_item, def_scope))| { - infcx.probe(|_| { - let ocx = ObligationCtxt::new_in_snapshot(&infcx); + let mut applicable_candidates: Vec<_> = infcx.probe(|_| { + let universe = infcx.create_next_universe(); + + // Regions are not considered during selection. + let self_ty = tcx.replace_escaping_bound_vars_uncached( + self_ty, + FnMutDelegate { + regions: &mut |_| tcx.lifetimes.re_erased, + types: &mut |bv| { + tcx.mk_placeholder(ty::PlaceholderType { universe, name: bv.kind }) + }, + consts: &mut |bv, ty| { + tcx.mk_const(ty::PlaceholderConst { universe, name: bv }, ty) + }, + }, + ); - let impl_ty = tcx.type_of(impl_); - let impl_substs = infcx.fresh_item_substs(impl_); - let impl_ty = impl_ty.subst(tcx, impl_substs); - let impl_ty = ocx.normalize(&cause, param_env, impl_ty); + candidates + .iter() + .filter_map(|&(impl_, (assoc_item, def_scope))| { + infcx.probe(|_| { + let ocx = ObligationCtxt::new_in_snapshot(&infcx); - // Check that the Self-types can be related. - // FIXME(fmease): Should we use `eq` here? - ocx.sup(&ObligationCause::dummy(), param_env, impl_ty, self_ty).ok()?; + let impl_ty = tcx.type_of(impl_); + let impl_substs = infcx.fresh_item_substs(impl_); + let impl_ty = impl_ty.subst(tcx, impl_substs); + let impl_ty = ocx.normalize(&cause, param_env, impl_ty); - // Check whether the impl imposes obligations we have to worry about. - let impl_bounds = tcx.predicates_of(impl_); - let impl_bounds = impl_bounds.instantiate(tcx, impl_substs); + // Check that the Self-types can be related. + // FIXME(fmease): Should we use `eq` here? + ocx.sup(&ObligationCause::dummy(), param_env, impl_ty, self_ty).ok()?; - let impl_bounds = ocx.normalize(&cause, param_env, impl_bounds); + // Check whether the impl imposes obligations we have to worry about. + let impl_bounds = tcx.predicates_of(impl_); + let impl_bounds = impl_bounds.instantiate(tcx, impl_substs); - let impl_obligations = traits::predicates_for_generics( - |_, _| cause.clone(), - param_env, - impl_bounds, - ); + let impl_bounds = ocx.normalize(&cause, param_env, impl_bounds); - ocx.register_obligations(impl_obligations); + let impl_obligations = traits::predicates_for_generics( + |_, _| cause.clone(), + param_env, + impl_bounds, + ); - let mut errors = ocx.select_where_possible(); - if !errors.is_empty() { - fulfillment_errors.append(&mut errors); - return None; - } + ocx.register_obligations(impl_obligations); + + let mut errors = ocx.select_where_possible(); + if !errors.is_empty() { + fulfillment_errors.append(&mut errors); + return None; + } - // FIXME(fmease): Unsolved vars can escape this InferCtxt snapshot. - Some((assoc_item, def_scope, infcx.resolve_vars_if_possible(impl_substs))) + // FIXME(fmease): Unsolved vars can escape this InferCtxt snapshot. + Some((assoc_item, def_scope, infcx.resolve_vars_if_possible(impl_substs))) + }) }) - }) - .collect(); + .collect() + }); if applicable_candidates.len() > 1 { return Err(self.complain_about_ambiguous_inherent_assoc_type( diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 4082759006d..d8dda7a93be 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -305,7 +305,7 @@ pub(super) fn check_opaque_for_inheriting_lifetimes( }) = item.kind { let substs = InternalSubsts::identity_for_item(tcx, def_id); - let opaque_identity_ty = if in_trait { + let opaque_identity_ty = if in_trait && !tcx.lower_impl_trait_in_trait_to_assoc_ty() { tcx.mk_projection(def_id.to_def_id(), substs) } else { tcx.mk_opaque(def_id.to_def_id(), substs) @@ -554,7 +554,15 @@ fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) { check_union(tcx, id.owner_id.def_id); } DefKind::OpaqueTy => { - check_opaque(tcx, id); + let opaque = tcx.hir().expect_item(id.owner_id.def_id).expect_opaque_ty(); + if let hir::OpaqueTyOrigin::FnReturn(fn_def_id) | hir::OpaqueTyOrigin::AsyncFn(fn_def_id) = opaque.origin + && let hir::Node::TraitItem(trait_item) = tcx.hir().get_by_def_id(fn_def_id) + && let (_, hir::TraitFn::Required(..)) = trait_item.expect_fn() + { + // Skip opaques from RPIT in traits with no default body. + } else { + check_opaque(tcx, id); + } } DefKind::ImplTraitPlaceholder => { let parent = tcx.impl_trait_in_trait_parent_fn(id.owner_id.to_def_id()); diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index f7aaa7a159f..1b7475486dc 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -223,6 +223,21 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { ], tcx.mk_ptr(ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }), ), + sym::option_payload_ptr => { + let option_def_id = tcx.require_lang_item(hir::LangItem::Option, None); + let p0 = param(0); + ( + 1, + vec![tcx.mk_ptr(ty::TypeAndMut { + ty: tcx.mk_adt( + tcx.adt_def(option_def_id), + tcx.mk_substs_from_iter([ty::GenericArg::from(p0)].into_iter()), + ), + mutbl: hir::Mutability::Not, + })], + tcx.mk_ptr(ty::TypeAndMut { ty: p0, mutbl: hir::Mutability::Not }), + ) + } sym::ptr_mask => ( 1, vec![ diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index 1e2b37bd50c..8fe4c44fca4 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -202,8 +202,11 @@ fn missing_items_err( missing_items: &[ty::AssocItem], full_impl_span: Span, ) { + let missing_items = + missing_items.iter().filter(|trait_item| tcx.opt_rpitit_info(trait_item.def_id).is_none()); + let missing_items_msg = missing_items - .iter() + .clone() .map(|trait_item| trait_item.name.to_string()) .collect::<Vec<_>>() .join("`, `"); diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs index d4dfe455b29..3d37e0ce0c6 100644 --- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs +++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs @@ -11,7 +11,7 @@ use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_middle::ty::fast_reject::{simplify_type, SimplifiedType, TreatParams, TreatProjections}; +use rustc_middle::ty::fast_reject::{simplify_type, SimplifiedType, TreatParams}; use rustc_middle::ty::{self, CrateInherentImpls, Ty, TyCtxt}; use rustc_span::symbol::sym; @@ -97,12 +97,7 @@ impl<'tcx> InherentCollect<'tcx> { } } - if let Some(simp) = simplify_type( - self.tcx, - self_ty, - TreatParams::AsCandidateKey, - TreatProjections::AsCandidateKey, - ) { + if let Some(simp) = simplify_type(self.tcx, self_ty, TreatParams::AsCandidateKey) { self.impls_map.incoherent_impls.entry(simp).or_default().push(impl_def_id); } else { bug!("unexpected self type: {:?}", self_ty); @@ -162,12 +157,7 @@ impl<'tcx> InherentCollect<'tcx> { } } - if let Some(simp) = simplify_type( - self.tcx, - ty, - TreatParams::AsCandidateKey, - TreatProjections::AsCandidateKey, - ) { + if let Some(simp) = simplify_type(self.tcx, ty, TreatParams::AsCandidateKey) { self.impls_map.incoherent_impls.entry(simp).or_default().push(impl_def_id); } else { bug!("unexpected primitive type: {:?}", ty); diff --git a/compiler/rustc_hir_analysis/src/coherence/mod.rs b/compiler/rustc_hir_analysis/src/coherence/mod.rs index 23490bc091c..465e787c92a 100644 --- a/compiler/rustc_hir_analysis/src/coherence/mod.rs +++ b/compiler/rustc_hir_analysis/src/coherence/mod.rs @@ -133,8 +133,8 @@ fn coherent_trait(tcx: TyCtxt<'_>, def_id: DefId) { check_impl(tcx, impl_def_id, trait_ref); check_object_overlap(tcx, impl_def_id, trait_ref); - tcx.sess.time("unsafety_checking", || unsafety::check_item(tcx, impl_def_id)); - tcx.sess.time("orphan_checking", || tcx.ensure().orphan_check_impl(impl_def_id)); + unsafety::check_item(tcx, impl_def_id); + tcx.ensure().orphan_check_impl(impl_def_id); } builtin::check_trait(tcx, def_id); diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index db58f4af8ec..c41e96290df 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -1208,7 +1208,7 @@ fn infer_return_ty_for_fn_sig<'tcx>( fn_sig, Applicability::MachineApplicable, ); - } else if let Some(sugg) = suggest_impl_trait(tcx, ret_ty, ty.span, hir_id, def_id) { + } else if let Some(sugg) = suggest_impl_trait(tcx, ret_ty, ty.span, def_id) { diag.span_suggestion( ty.span, "replace with an appropriate return type", @@ -1240,12 +1240,10 @@ fn infer_return_ty_for_fn_sig<'tcx>( } } -// FIXME(vincenzopalazzo): remove the hir item when the refactoring is stable fn suggest_impl_trait<'tcx>( tcx: TyCtxt<'tcx>, ret_ty: Ty<'tcx>, span: Span, - _hir_id: hir::HirId, def_id: LocalDefId, ) -> Option<String> { let format_as_assoc: fn(_, _, _, _, _) -> _ = diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index 9bbca9b4e96..225b1550580 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -778,7 +778,7 @@ fn find_opaque_ty_constraints_for_rpit( // Use borrowck to get the type with unerased regions. let concrete_opaque_types = &self.tcx.mir_borrowck(def_id).concrete_opaque_types; debug!(?concrete_opaque_types); - for &(def_id, concrete_type) in concrete_opaque_types { + for (&def_id, &concrete_type) in concrete_opaque_types { if def_id != self.def_id { // Ignore constraints for other opaque types. continue; diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs index 91c64eeec1e..7f1e4ccc964 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs @@ -528,7 +528,7 @@ fn trait_predicate_kind<'tcx>( | ty::PredicateKind::Clause(ty::Clause::TypeOutlives(_)) | ty::PredicateKind::Clause(ty::Clause::Projection(_)) | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) - | ty::PredicateKind::AliasEq(..) + | ty::PredicateKind::AliasRelate(..) | ty::PredicateKind::WellFormed(_) | ty::PredicateKind::Subtype(_) | ty::PredicateKind::Coerce(_) diff --git a/compiler/rustc_hir_analysis/src/outlives/explicit.rs b/compiler/rustc_hir_analysis/src/outlives/explicit.rs index 9ee6785970c..357deb07b8f 100644 --- a/compiler/rustc_hir_analysis/src/outlives/explicit.rs +++ b/compiler/rustc_hir_analysis/src/outlives/explicit.rs @@ -56,7 +56,7 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> { | ty::PredicateKind::Clause(ty::Clause::Projection(..)) | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) | ty::PredicateKind::WellFormed(..) - | ty::PredicateKind::AliasEq(..) + | ty::PredicateKind::AliasRelate(..) | ty::PredicateKind::ObjectSafe(..) | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::Subtype(..) diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index 06e857ec3ca..4846579b980 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -1487,7 +1487,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { let deref_kind = if checked_ty.is_box() { "unboxing the value" - } else if checked_ty.is_region_ptr() { + } else if checked_ty.is_ref() { "dereferencing the borrow" } else { "dereferencing the type" diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 29db16849dd..fb7cb86d734 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -231,7 +231,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ty = ensure_sufficient_stack(|| match &expr.kind { hir::ExprKind::Path( - qpath @ hir::QPath::Resolved(..) | qpath @ hir::QPath::TypeRelative(..), + qpath @ (hir::QPath::Resolved(..) | hir::QPath::TypeRelative(..)), ) => self.check_expr_path(qpath, expr, args), _ => self.check_expr_kind(expr, expected), }); diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 8455076de56..3def97bca47 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -666,7 +666,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | ty::PredicateKind::Clause(ty::Clause::TypeOutlives(..)) | ty::PredicateKind::WellFormed(..) | ty::PredicateKind::ObjectSafe(..) - | ty::PredicateKind::AliasEq(..) + | ty::PredicateKind::AliasRelate(..) | ty::PredicateKind::ConstEvaluatable(..) | ty::PredicateKind::ConstEquate(..) // N.B., this predicate is created by breaking down a diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs index ec14bd3c6f4..e0ddb90c33b 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs @@ -4,7 +4,7 @@ use rustc_hir::def::Res; use rustc_hir::def_id::DefId; use rustc_infer::traits::ObligationCauseCode; use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor}; -use rustc_span::{self, Span}; +use rustc_span::{self, symbol::kw, Span}; use rustc_trait_selection::traits; use std::ops::ControlFlow; @@ -25,17 +25,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let generics = self.tcx.generics_of(def_id); let predicate_substs = match unsubstituted_pred.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(pred)) => pred.trait_ref.substs, - ty::PredicateKind::Clause(ty::Clause::Projection(pred)) => pred.projection_ty.substs, - _ => ty::List::empty(), + ty::PredicateKind::Clause(ty::Clause::Trait(pred)) => pred.trait_ref.substs.to_vec(), + ty::PredicateKind::Clause(ty::Clause::Projection(pred)) => { + pred.projection_ty.substs.to_vec() + } + ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(arg, ty)) => { + vec![ty.into(), arg.into()] + } + ty::PredicateKind::ConstEvaluatable(e) => vec![e.into()], + _ => return false, }; - let find_param_matching = |matches: &dyn Fn(&ty::ParamTy) -> bool| { - predicate_substs.types().find_map(|ty| { - ty.walk().find_map(|arg| { + let find_param_matching = |matches: &dyn Fn(ty::ParamTerm) -> bool| { + predicate_substs.iter().find_map(|arg| { + arg.walk().find_map(|arg| { if let ty::GenericArgKind::Type(ty) = arg.unpack() - && let ty::Param(param_ty) = ty.kind() - && matches(param_ty) + && let ty::Param(param_ty) = *ty.kind() + && matches(ty::ParamTerm::Ty(param_ty)) + { + Some(arg) + } else if let ty::GenericArgKind::Const(ct) = arg.unpack() + && let ty::ConstKind::Param(param_ct) = ct.kind() + && matches(ty::ParamTerm::Const(param_ct)) { Some(arg) } else { @@ -47,21 +58,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Prefer generics that are local to the fn item, since these are likely // to be the cause of the unsatisfied predicate. - let mut param_to_point_at = find_param_matching(&|param_ty| { - self.tcx.parent(generics.type_param(param_ty, self.tcx).def_id) == def_id + let mut param_to_point_at = find_param_matching(&|param_term| { + self.tcx.parent(generics.param_at(param_term.index(), self.tcx).def_id) == def_id }); // Fall back to generic that isn't local to the fn item. This will come // from a trait or impl, for example. - let mut fallback_param_to_point_at = find_param_matching(&|param_ty| { - self.tcx.parent(generics.type_param(param_ty, self.tcx).def_id) != def_id - && param_ty.name != rustc_span::symbol::kw::SelfUpper + let mut fallback_param_to_point_at = find_param_matching(&|param_term| { + self.tcx.parent(generics.param_at(param_term.index(), self.tcx).def_id) != def_id + && !matches!(param_term, ty::ParamTerm::Ty(ty) if ty.name == kw::SelfUpper) }); // Finally, the `Self` parameter is possibly the reason that the predicate // is unsatisfied. This is less likely to be true for methods, because // method probe means that we already kinda check that the predicates due // to the `Self` type are true. - let mut self_param_to_point_at = - find_param_matching(&|param_ty| param_ty.name == rustc_span::symbol::kw::SelfUpper); + let mut self_param_to_point_at = find_param_matching( + &|param_term| matches!(param_term, ty::ParamTerm::Ty(ty) if ty.name == kw::SelfUpper), + ); // Finally, for ambiguity-related errors, we actually want to look // for a parameter that is the source of the inference type left @@ -225,14 +237,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .own_substs(ty::InternalSubsts::identity_for_item(self.tcx, def_id)); let Some((index, _)) = own_substs .iter() - .filter(|arg| matches!(arg.unpack(), ty::GenericArgKind::Type(_))) .enumerate() .find(|(_, arg)| **arg == param_to_point_at) else { return false }; let Some(arg) = segment .args() .args .iter() - .filter(|arg| matches!(arg, hir::GenericArg::Type(_))) .nth(index) else { return false; }; error.obligation.cause.span = arg .span() diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 7273b93b676..18a49ef2f01 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -165,8 +165,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, ty: Ty<'tcx>, ) -> Option<(DefIdOrName, Ty<'tcx>, Vec<Ty<'tcx>>)> { - let body_hir_id = self.tcx.hir().local_def_id_to_hir_id(self.body_id); - self.err_ctxt().extract_callable_info(body_hir_id, self.param_env, ty) + self.err_ctxt().extract_callable_info(self.body_id, self.param_env, ty) } pub fn suggest_two_fn_call( diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index b6d39341fe7..dab709e17f0 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -16,7 +16,6 @@ use rustc_infer::infer::canonical::{Canonical, QueryResponse}; use rustc_infer::infer::DefineOpaqueTypes; use rustc_infer::infer::{self, InferOk, TyCtxtInferExt}; use rustc_middle::middle::stability; -use rustc_middle::ty::fast_reject::TreatProjections; use rustc_middle::ty::fast_reject::{simplify_type, TreatParams}; use rustc_middle::ty::AssocItem; use rustc_middle::ty::GenericParamDefKind; @@ -701,7 +700,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } fn assemble_inherent_candidates_for_incoherent_ty(&mut self, self_ty: Ty<'tcx>) { - let Some(simp) = simplify_type(self.tcx, self_ty, TreatParams::AsCandidateKey, TreatProjections::AsCandidateKey) else { + let Some(simp) = simplify_type(self.tcx, self_ty, TreatParams::AsCandidateKey) else { bug!("unexpected incoherent type: {:?}", self_ty) }; for &impl_def_id in self.tcx.incoherent_impls(simp) { @@ -838,7 +837,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { | ty::PredicateKind::ConstEvaluatable(..) | ty::PredicateKind::ConstEquate(..) | ty::PredicateKind::Ambiguous - | ty::PredicateKind::AliasEq(..) + | ty::PredicateKind::AliasRelate(..) | ty::PredicateKind::TypeWellFormedFromEnv(..) => None, } }); diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 50f2b71250c..55f684599e7 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -25,7 +25,6 @@ use rustc_infer::infer::{ use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; use rustc_middle::traits::util::supertraits; use rustc_middle::ty::fast_reject::DeepRejectCtxt; -use rustc_middle::ty::fast_reject::TreatProjections; use rustc_middle::ty::fast_reject::{simplify_type, TreatParams}; use rustc_middle::ty::print::{with_crate_prefix, with_forced_trimmed_paths}; use rustc_middle::ty::{self, GenericArgKind, Ty, TyCtxt, TypeVisitableExt}; @@ -1182,7 +1181,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .inputs() .skip_binder() .get(0) - .filter(|ty| ty.is_region_ptr() && !rcvr_ty.is_region_ptr()) + .filter(|ty| ty.is_ref() && !rcvr_ty.is_ref()) .copied() .unwrap_or(rcvr_ty), }; @@ -1524,7 +1523,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .into_iter() .any(|info| self.associated_value(info.def_id, item_name).is_some()); let found_assoc = |ty: Ty<'tcx>| { - simplify_type(tcx, ty, TreatParams::AsCandidateKey, TreatProjections::AsCandidateKey) + simplify_type(tcx, ty, TreatParams::AsCandidateKey) .and_then(|simp| { tcx.incoherent_impls(simp) .iter() @@ -2653,12 +2652,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // FIXME: Even though negative bounds are not implemented, we could maybe handle // cases where a positive bound implies a negative impl. (candidates, Vec::new()) - } else if let Some(simp_rcvr_ty) = simplify_type( - self.tcx, - rcvr_ty, - TreatParams::ForLookup, - TreatProjections::ForLookup, - ) { + } else if let Some(simp_rcvr_ty) = + simplify_type(self.tcx, rcvr_ty, TreatParams::ForLookup) + { let mut potential_candidates = Vec::new(); let mut explicitly_negative = Vec::new(); for candidate in candidates { @@ -2671,12 +2667,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }) .any(|imp_did| { let imp = self.tcx.impl_trait_ref(imp_did).unwrap().subst_identity(); - let imp_simp = simplify_type( - self.tcx, - imp.self_ty(), - TreatParams::ForLookup, - TreatProjections::ForLookup, - ); + let imp_simp = + simplify_type(self.tcx, imp.self_ty(), TreatParams::ForLookup); imp_simp.map_or(false, |s| s == simp_rcvr_ty) }) { diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index d5d260d7138..eadc30a799b 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -712,10 +712,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - unreachable!( - "we captured two identical projections: capture1 = {:?}, capture2 = {:?}", - capture1, capture2 + self.tcx.sess.delay_span_bug( + closure_span, + &format!( + "two identical projections: ({:?}, {:?})", + capture1.place.projections, capture2.place.projections + ), ); + std::cmp::Ordering::Equal }); } diff --git a/compiler/rustc_incremental/src/persist/fs.rs b/compiler/rustc_incremental/src/persist/fs.rs index 4deae9f41c7..d6f83838a04 100644 --- a/compiler/rustc_incremental/src/persist/fs.rs +++ b/compiler/rustc_incremental/src/persist/fs.rs @@ -108,7 +108,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::svh::Svh; use rustc_data_structures::{base_n, flock}; use rustc_errors::ErrorGuaranteed; -use rustc_fs_util::{link_or_copy, LinkOrCopy}; +use rustc_fs_util::{link_or_copy, try_canonicalize, LinkOrCopy}; use rustc_session::{Session, StableCrateId}; use rustc_span::Symbol; @@ -223,7 +223,7 @@ pub fn prepare_session_directory( // because, on windows, long paths can cause problems; // canonicalization inserts this weird prefix that makes windows // tolerate long paths. - let crate_dir = match crate_dir.canonicalize() { + let crate_dir = match try_canonicalize(&crate_dir) { Ok(v) => v, Err(err) => { return Err(sess.emit_err(errors::CanonicalizePath { path: crate_dir, err })); @@ -867,7 +867,7 @@ fn all_except_most_recent( /// before passing it to std::fs::remove_dir_all(). This will convert the path /// into the '\\?\' format, which supports much longer paths. fn safe_remove_dir_all(p: &Path) -> io::Result<()> { - let canonicalized = match std_fs::canonicalize(p) { + let canonicalized = match try_canonicalize(p) { Ok(canonicalized) => canonicalized, Err(err) if err.kind() == io::ErrorKind::NotFound => return Ok(()), Err(err) => return Err(err), @@ -877,7 +877,7 @@ fn safe_remove_dir_all(p: &Path) -> io::Result<()> { } fn safe_remove_file(p: &Path) -> io::Result<()> { - let canonicalized = match std_fs::canonicalize(p) { + let canonicalized = match try_canonicalize(p) { Ok(canonicalized) => canonicalized, Err(err) if err.kind() == io::ErrorKind::NotFound => return Ok(()), Err(err) => return Err(err), diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs index 0c8854e962a..d240d8e491f 100644 --- a/compiler/rustc_infer/src/infer/at.rs +++ b/compiler/rustc_infer/src/infer/at.rs @@ -30,6 +30,8 @@ use super::*; use rustc_middle::ty::relate::{Relate, TypeRelation}; use rustc_middle::ty::{Const, ImplSubject}; +use std::cell::Cell; + /// Whether we should define opaque types or just treat them opaquely. /// /// Currently only used to prevent predicate matching from matching anything @@ -82,6 +84,7 @@ impl<'tcx> InferCtxt<'tcx> { in_snapshot: self.in_snapshot.clone(), universe: self.universe.clone(), intercrate: self.intercrate, + inside_canonicalization_ctxt: Cell::new(self.inside_canonicalization_ctxt()), } } } diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs index 8ac82653c0e..96a5f6532fe 100644 --- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs +++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs @@ -561,6 +561,8 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { where V: TypeFoldable<TyCtxt<'tcx>>, { + let _inside_canonical_ctxt_guard = infcx.set_canonicalization_ctxt(); + let needs_canonical_flags = if canonicalize_region_mode.any() { TypeFlags::NEEDS_INFER | TypeFlags::HAS_FREE_REGIONS | // `HAS_RE_PLACEHOLDER` implies `HAS_FREE_REGIONS` diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index 156a7e68ed1..268896b671a 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -159,9 +159,7 @@ impl<'tcx> InferCtxt<'tcx> { .opaque_type_storage .opaque_types .iter() - .map(|&(k, ref v)| { - (self.tcx.mk_opaque(k.def_id.to_def_id(), k.substs), v.hidden_type.ty) - }) + .map(|(k, v)| (self.tcx.mk_opaque(k.def_id.to_def_id(), k.substs), v.hidden_type.ty)) .collect() } diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs index 4503af03ca3..88a28e26005 100644 --- a/compiler/rustc_infer/src/infer/combine.rs +++ b/compiler/rustc_infer/src/infer/combine.rs @@ -128,7 +128,7 @@ impl<'tcx> InferCtxt<'tcx> { (_, ty::Alias(AliasKind::Projection, _)) | (ty::Alias(AliasKind::Projection, _), _) if self.tcx.trait_solver_next() => { - relation.register_type_equate_obligation(a, b); + relation.register_type_relate_obligation(a, b); Ok(a) } @@ -842,23 +842,25 @@ pub trait ObligationEmittingRelation<'tcx>: TypeRelation<'tcx> { let (a, b) = if self.a_is_expected() { (a, b) } else { (b, a) }; self.register_predicates([ty::Binder::dummy(if self.tcx().trait_solver_next() { - ty::PredicateKind::AliasEq(a.into(), b.into()) + ty::PredicateKind::AliasRelate(a.into(), b.into(), ty::AliasRelationDirection::Equate) } else { ty::PredicateKind::ConstEquate(a, b) })]); } - /// Register an obligation that both types must be equal to each other. - /// - /// If they aren't equal then the relation doesn't hold. - fn register_type_equate_obligation(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) { - let (a, b) = if self.a_is_expected() { (a, b) } else { (b, a) }; - - self.register_predicates([ty::Binder::dummy(ty::PredicateKind::AliasEq( + /// Register an obligation that both types must be related to each other according to + /// the [`ty::AliasRelationDirection`] given by [`ObligationEmittingRelation::alias_relate_direction`] + fn register_type_relate_obligation(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) { + self.register_predicates([ty::Binder::dummy(ty::PredicateKind::AliasRelate( a.into(), b.into(), + self.alias_relate_direction(), ))]); } + + /// Relation direction emitted for `AliasRelate` predicates, corresponding to the direction + /// of the relation. + fn alias_relate_direction(&self) -> ty::AliasRelationDirection; } fn int_unification_error<'tcx>( diff --git a/compiler/rustc_infer/src/infer/equate.rs b/compiler/rustc_infer/src/infer/equate.rs index c92a74b6241..38002357cde 100644 --- a/compiler/rustc_infer/src/infer/equate.rs +++ b/compiler/rustc_infer/src/infer/equate.rs @@ -210,4 +210,8 @@ impl<'tcx> ObligationEmittingRelation<'tcx> for Equate<'_, '_, 'tcx> { fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) { self.fields.register_obligations(obligations); } + + fn alias_relate_direction(&self) -> ty::AliasRelationDirection { + ty::AliasRelationDirection::Equate + } } diff --git a/compiler/rustc_infer/src/infer/glb.rs b/compiler/rustc_infer/src/infer/glb.rs index 5c12351226a..6395c4d4b20 100644 --- a/compiler/rustc_infer/src/infer/glb.rs +++ b/compiler/rustc_infer/src/infer/glb.rs @@ -155,4 +155,9 @@ impl<'tcx> ObligationEmittingRelation<'tcx> for Glb<'_, '_, 'tcx> { fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) { self.fields.register_obligations(obligations); } + + fn alias_relate_direction(&self) -> ty::AliasRelationDirection { + // FIXME(deferred_projection_equality): This isn't right, I think? + ty::AliasRelationDirection::Equate + } } diff --git a/compiler/rustc_infer/src/infer/lub.rs b/compiler/rustc_infer/src/infer/lub.rs index dbef42db8f1..98cbd4c561c 100644 --- a/compiler/rustc_infer/src/infer/lub.rs +++ b/compiler/rustc_infer/src/infer/lub.rs @@ -155,4 +155,9 @@ impl<'tcx> ObligationEmittingRelation<'tcx> for Lub<'_, '_, 'tcx> { fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) { self.fields.register_obligations(obligations) } + + fn alias_relate_direction(&self) -> ty::AliasRelationDirection { + // FIXME(deferred_projection_equality): This isn't right, I think? + ty::AliasRelationDirection::Equate + } } diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index aeb4ddb4212..9afe9cc1e76 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -39,6 +39,7 @@ use rustc_span::Span; use std::cell::{Cell, RefCell}; use std::fmt; +use std::ops::Drop; use self::combine::CombineFields; use self::error_reporting::TypeErrCtxt; @@ -342,6 +343,11 @@ pub struct InferCtxt<'tcx> { /// there is no type that the user could *actually name* that /// would satisfy it. This avoids crippling inference, basically. pub intercrate: bool, + + /// Flag that is set when we enter canonicalization. Used for debugging to ensure + /// that we only collect region information for `BorrowckInferCtxt::reg_var_to_origin` + /// inside non-canonicalization contexts. + inside_canonicalization_ctxt: Cell<bool>, } /// See the `error_reporting` module for more details. @@ -585,8 +591,8 @@ impl<'tcx> InferCtxtBuilder<'tcx> { self } - pub fn intercrate(mut self) -> Self { - self.intercrate = true; + pub fn intercrate(mut self, intercrate: bool) -> Self { + self.intercrate = intercrate; self } @@ -633,6 +639,7 @@ impl<'tcx> InferCtxtBuilder<'tcx> { skip_leak_check: Cell::new(false), universe: Cell::new(ty::UniverseIndex::ROOT), intercrate, + inside_canonicalization_ctxt: Cell::new(false), } } } @@ -1728,6 +1735,31 @@ impl<'tcx> InferCtxt<'tcx> { } } } + + pub fn inside_canonicalization_ctxt(&self) -> bool { + self.inside_canonicalization_ctxt.get() + } + + pub fn set_canonicalization_ctxt(&self) -> CanonicalizationCtxtGuard<'_, 'tcx> { + let prev_ctxt = self.inside_canonicalization_ctxt(); + self.inside_canonicalization_ctxt.set(true); + CanonicalizationCtxtGuard { prev_ctxt, infcx: self } + } + + fn set_canonicalization_ctxt_to(&self, ctxt: bool) { + self.inside_canonicalization_ctxt.set(ctxt); + } +} + +pub struct CanonicalizationCtxtGuard<'cx, 'tcx> { + prev_ctxt: bool, + infcx: &'cx InferCtxt<'tcx>, +} + +impl<'cx, 'tcx> Drop for CanonicalizationCtxtGuard<'cx, 'tcx> { + fn drop(&mut self) { + self.infcx.set_canonicalization_ctxt_to(self.prev_ctxt) + } } impl<'tcx> TypeErrCtxt<'_, 'tcx> { diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs index 573cd91a2a2..f5d20cb7ebf 100644 --- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs +++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs @@ -28,6 +28,7 @@ use crate::traits::{Obligation, PredicateObligations}; use rustc_data_structures::fx::FxHashMap; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::error::TypeError; +use rustc_middle::ty::fold::FnMutDelegate; use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation}; use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor}; use rustc_middle::ty::{self, InferConst, Ty, TyCtxt}; @@ -55,21 +56,6 @@ where ambient_variance: ty::Variance, ambient_variance_info: ty::VarianceDiagInfo<'tcx>, - - /// When we pass through a set of binders (e.g., when looking into - /// a `fn` type), we push a new bound region scope onto here. This - /// will contain the instantiated region for each region in those - /// binders. When we then encounter a `ReLateBound(d, br)`, we can - /// use the De Bruijn index `d` to find the right scope, and then - /// bound region name `br` to find the specific instantiation from - /// within that scope. See `replace_bound_region`. - /// - /// This field stores the instantiations for late-bound regions in - /// the `a` type. - a_scopes: Vec<BoundRegionScope<'tcx>>, - - /// Same as `a_scopes`, but for the `b` type. - b_scopes: Vec<BoundRegionScope<'tcx>>, } pub trait TypeRelatingDelegate<'tcx> { @@ -147,8 +133,6 @@ where delegate, ambient_variance, ambient_variance_info: ty::VarianceDiagInfo::default(), - a_scopes: vec![], - b_scopes: vec![], } } @@ -166,88 +150,6 @@ where } } - fn create_scope( - &mut self, - value: ty::Binder<'tcx, impl Relate<'tcx>>, - universally_quantified: UniversallyQuantified, - ) -> BoundRegionScope<'tcx> { - let mut scope = BoundRegionScope::default(); - - // Create a callback that creates (via the delegate) either an - // existential or placeholder region as needed. - let mut next_region = { - let delegate = &mut self.delegate; - let mut lazy_universe = None; - move |br: ty::BoundRegion| { - if universally_quantified.0 { - // The first time this closure is called, create a - // new universe for the placeholders we will make - // from here out. - let universe = lazy_universe.unwrap_or_else(|| { - let universe = delegate.create_next_universe(); - lazy_universe = Some(universe); - universe - }); - - let placeholder = ty::PlaceholderRegion { universe, name: br.kind }; - delegate.next_placeholder_region(placeholder) - } else { - delegate.next_existential_region_var(true, br.kind.get_name()) - } - } - }; - - value.skip_binder().visit_with(&mut ScopeInstantiator { - next_region: &mut next_region, - target_index: ty::INNERMOST, - bound_region_scope: &mut scope, - }); - - scope - } - - /// When we encounter binders during the type traversal, we record - /// the value to substitute for each of the things contained in - /// that binder. (This will be either a universal placeholder or - /// an existential inference variable.) Given the De Bruijn index - /// `debruijn` (and name `br`) of some binder we have now - /// encountered, this routine finds the value that we instantiated - /// the region with; to do so, it indexes backwards into the list - /// of ambient scopes `scopes`. - fn lookup_bound_region( - debruijn: ty::DebruijnIndex, - br: &ty::BoundRegion, - first_free_index: ty::DebruijnIndex, - scopes: &[BoundRegionScope<'tcx>], - ) -> ty::Region<'tcx> { - // The debruijn index is a "reverse index" into the - // scopes listing. So when we have INNERMOST (0), we - // want the *last* scope pushed, and so forth. - let debruijn_index = debruijn.index() - first_free_index.index(); - let scope = &scopes[scopes.len() - debruijn_index - 1]; - - // Find this bound region in that scope to map to a - // particular region. - scope.map[br] - } - - /// If `r` is a bound region, find the scope in which it is bound - /// (from `scopes`) and return the value that we instantiated it - /// with. Otherwise just return `r`. - fn replace_bound_region( - &self, - r: ty::Region<'tcx>, - first_free_index: ty::DebruijnIndex, - scopes: &[BoundRegionScope<'tcx>], - ) -> ty::Region<'tcx> { - debug!("replace_bound_regions(scopes={:?})", scopes); - if let ty::ReLateBound(debruijn, br) = *r { - Self::lookup_bound_region(debruijn, &br, first_free_index, scopes) - } else { - r - } - } - /// Push a new outlives requirement into our output set of /// constraints. fn push_outlives( @@ -314,18 +216,9 @@ where self.infcx.inner.borrow_mut().type_variables().instantiate(vid, generalized_ty); - // The generalized values we extract from `canonical_var_values` have - // been fully instantiated and hence the set of scopes we have - // doesn't matter -- just to be sure, put an empty vector - // in there. - let old_a_scopes = std::mem::take(pair.vid_scopes(self)); - // Relate the generalized kind to the original one. let result = pair.relate_generalized_ty(self, generalized_ty); - // Restore the old scopes now. - *pair.vid_scopes(self) = old_a_scopes; - debug!("relate_ty_var: complete, result = {:?}", result); result } @@ -379,6 +272,97 @@ where trace!(a = ?a.kind(), b = ?b.kind(), "opaque type instantiated"); Ok(a) } + + #[instrument(skip(self), level = "debug")] + fn instantiate_binder_with_placeholders<T>(&mut self, binder: ty::Binder<'tcx, T>) -> T + where + T: ty::TypeFoldable<TyCtxt<'tcx>> + Copy, + { + if let Some(inner) = binder.no_bound_vars() { + return inner; + } + + let mut next_region = { + let nll_delegate = &mut self.delegate; + let mut lazy_universe = None; + + move |br: ty::BoundRegion| { + // The first time this closure is called, create a + // new universe for the placeholders we will make + // from here out. + let universe = lazy_universe.unwrap_or_else(|| { + let universe = nll_delegate.create_next_universe(); + lazy_universe = Some(universe); + universe + }); + + let placeholder = ty::PlaceholderRegion { universe, name: br.kind }; + debug!(?placeholder); + let placeholder_reg = nll_delegate.next_placeholder_region(placeholder); + debug!(?placeholder_reg); + + placeholder_reg + } + }; + + let delegate = FnMutDelegate { + regions: &mut next_region, + types: &mut |_bound_ty: ty::BoundTy| { + unreachable!("we only replace regions in nll_relate, not types") + }, + consts: &mut |_bound_var: ty::BoundVar, _ty| { + unreachable!("we only replace regions in nll_relate, not consts") + }, + }; + + let replaced = self.infcx.tcx.replace_bound_vars_uncached(binder, delegate); + debug!(?replaced); + + replaced + } + + #[instrument(skip(self), level = "debug")] + fn instantiate_binder_with_existentials<T>(&mut self, binder: ty::Binder<'tcx, T>) -> T + where + T: ty::TypeFoldable<TyCtxt<'tcx>> + Copy, + { + if let Some(inner) = binder.no_bound_vars() { + return inner; + } + + let mut next_region = { + let nll_delegate = &mut self.delegate; + let mut reg_map = FxHashMap::default(); + + move |br: ty::BoundRegion| { + if let Some(ex_reg_var) = reg_map.get(&br) { + return *ex_reg_var; + } else { + let ex_reg_var = + nll_delegate.next_existential_region_var(true, br.kind.get_name()); + debug!(?ex_reg_var); + reg_map.insert(br, ex_reg_var); + + ex_reg_var + } + } + }; + + let delegate = FnMutDelegate { + regions: &mut next_region, + types: &mut |_bound_ty: ty::BoundTy| { + unreachable!("we only replace regions in nll_relate, not types") + }, + consts: &mut |_bound_var: ty::BoundVar, _ty| { + unreachable!("we only replace regions in nll_relate, not consts") + }, + }; + + let replaced = self.infcx.tcx.replace_bound_vars_uncached(binder, delegate); + debug!(?replaced); + + replaced + } } /// When we instantiate an inference variable with a value in @@ -396,14 +380,6 @@ trait VidValuePair<'tcx>: Debug { /// opposite part of the tuple from the vid). fn value_ty(&self) -> Ty<'tcx>; - /// Extract the scopes that apply to whichever side of the tuple - /// the vid was found on. See the comment where this is called - /// for more details on why we want them. - fn vid_scopes<'r, D: TypeRelatingDelegate<'tcx>>( - &self, - relate: &'r mut TypeRelating<'_, 'tcx, D>, - ) -> &'r mut Vec<BoundRegionScope<'tcx>>; - /// Given a generalized type G that should replace the vid, relate /// G to the value, putting G on whichever side the vid would have /// appeared. @@ -425,16 +401,6 @@ impl<'tcx> VidValuePair<'tcx> for (ty::TyVid, Ty<'tcx>) { self.1 } - fn vid_scopes<'r, D>( - &self, - relate: &'r mut TypeRelating<'_, 'tcx, D>, - ) -> &'r mut Vec<BoundRegionScope<'tcx>> - where - D: TypeRelatingDelegate<'tcx>, - { - &mut relate.a_scopes - } - fn relate_generalized_ty<D>( &self, relate: &mut TypeRelating<'_, 'tcx, D>, @@ -457,16 +423,6 @@ impl<'tcx> VidValuePair<'tcx> for (Ty<'tcx>, ty::TyVid) { self.0 } - fn vid_scopes<'r, D>( - &self, - relate: &'r mut TypeRelating<'_, 'tcx, D>, - ) -> &'r mut Vec<BoundRegionScope<'tcx>> - where - D: TypeRelatingDelegate<'tcx>, - { - &mut relate.b_scopes - } - fn relate_generalized_ty<D>( &self, relate: &mut TypeRelating<'_, 'tcx, D>, @@ -602,20 +558,14 @@ where ) -> RelateResult<'tcx, ty::Region<'tcx>> { debug!(?self.ambient_variance); - let v_a = self.replace_bound_region(a, ty::INNERMOST, &self.a_scopes); - let v_b = self.replace_bound_region(b, ty::INNERMOST, &self.b_scopes); - - debug!(?v_a); - debug!(?v_b); - if self.ambient_covariance() { // Covariant: &'a u8 <: &'b u8. Hence, `'a: 'b`. - self.push_outlives(v_a, v_b, self.ambient_variance_info); + self.push_outlives(a, b, self.ambient_variance_info); } if self.ambient_contravariance() { // Contravariant: &'b u8 <: &'a u8. Hence, `'b: 'a`. - self.push_outlives(v_b, v_a, self.ambient_variance_info); + self.push_outlives(b, a, self.ambient_variance_info); } Ok(a) @@ -689,15 +639,6 @@ where // instantiation of B (i.e., B instantiated with // universals). - let b_scope = self.create_scope(b, UniversallyQuantified(true)); - let a_scope = self.create_scope(a, UniversallyQuantified(false)); - - debug!(?a_scope, "(existential)"); - debug!(?b_scope, "(universal)"); - - self.b_scopes.push(b_scope); - self.a_scopes.push(a_scope); - // Reset the ambient variance to covariant. This is needed // to correctly handle cases like // @@ -718,12 +659,14 @@ where // subtyping (i.e., `&'b u32 <: &{P} u32`). let variance = std::mem::replace(&mut self.ambient_variance, ty::Variance::Covariant); - self.relate(a.skip_binder(), b.skip_binder())?; + // Note: the order here is important. Create the placeholders first, otherwise + // we assign the wrong universe to the existential! + let b_replaced = self.instantiate_binder_with_placeholders(b); + let a_replaced = self.instantiate_binder_with_existentials(a); - self.ambient_variance = variance; + self.relate(a_replaced, b_replaced)?; - self.b_scopes.pop().unwrap(); - self.a_scopes.pop().unwrap(); + self.ambient_variance = variance; } if self.ambient_contravariance() { @@ -733,26 +676,17 @@ where // instantiation of B (i.e., B instantiated with // existentials). Opposite of above. - let a_scope = self.create_scope(a, UniversallyQuantified(true)); - let b_scope = self.create_scope(b, UniversallyQuantified(false)); - - debug!(?a_scope, "(universal)"); - debug!(?b_scope, "(existential)"); - - self.a_scopes.push(a_scope); - self.b_scopes.push(b_scope); - // Reset ambient variance to contravariance. See the // covariant case above for an explanation. let variance = std::mem::replace(&mut self.ambient_variance, ty::Variance::Contravariant); - self.relate(a.skip_binder(), b.skip_binder())?; + let a_replaced = self.instantiate_binder_with_placeholders(a); + let b_replaced = self.instantiate_binder_with_existentials(b); - self.ambient_variance = variance; + self.relate(a_replaced, b_replaced)?; - self.b_scopes.pop().unwrap(); - self.a_scopes.pop().unwrap(); + self.ambient_variance = variance; } Ok(a) @@ -777,6 +711,34 @@ where fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) { self.delegate.register_obligations(obligations); } + + fn alias_relate_direction(&self) -> ty::AliasRelationDirection { + unreachable!("manually overridden to handle ty::Variance::Contravariant ambient variance") + } + + fn register_type_relate_obligation(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) { + self.register_predicates([ty::Binder::dummy(match self.ambient_variance { + ty::Variance::Covariant => ty::PredicateKind::AliasRelate( + a.into(), + b.into(), + ty::AliasRelationDirection::Subtype, + ), + // a :> b is b <: a + ty::Variance::Contravariant => ty::PredicateKind::AliasRelate( + b.into(), + a.into(), + ty::AliasRelationDirection::Subtype, + ), + ty::Variance::Invariant => ty::PredicateKind::AliasRelate( + a.into(), + b.into(), + ty::AliasRelationDirection::Equate, + ), + // FIXME(deferred_projection_equality): Implement this when we trigger it. + // Probably just need to do nothing here. + ty::Variance::Bivariant => unreachable!(), + })]); + } } /// When we encounter a binder like `for<..> fn(..)`, we actually have diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs index 49f823a47b8..3a0a0494a7e 100644 --- a/compiler/rustc_infer/src/infer/opaque_types.rs +++ b/compiler/rustc_infer/src/infer/opaque_types.rs @@ -5,8 +5,8 @@ use crate::infer::{DefiningAnchor, InferCtxt, InferOk}; use crate::traits; use hir::def_id::{DefId, LocalDefId}; use hir::OpaqueTyOrigin; +use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::sync::Lrc; -use rustc_data_structures::vec_map::VecMap; use rustc_hir as hir; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::error::{ExpectedFound, TypeError}; @@ -21,7 +21,7 @@ use std::ops::ControlFlow; mod table; -pub type OpaqueTypeMap<'tcx> = VecMap<OpaqueTypeKey<'tcx>, OpaqueTypeDecl<'tcx>>; +pub type OpaqueTypeMap<'tcx> = FxIndexMap<OpaqueTypeKey<'tcx>, OpaqueTypeDecl<'tcx>>; pub use table::{OpaqueTypeStorage, OpaqueTypeTable}; /// Information about the opaque types whose values we diff --git a/compiler/rustc_infer/src/infer/outlives/mod.rs b/compiler/rustc_infer/src/infer/outlives/mod.rs index 83f3d5a74fb..048dad3a48b 100644 --- a/compiler/rustc_infer/src/infer/outlives/mod.rs +++ b/compiler/rustc_infer/src/infer/outlives/mod.rs @@ -22,7 +22,7 @@ pub fn explicit_outlives_bounds<'tcx>( ty::PredicateKind::Clause(ty::Clause::Projection(..)) | ty::PredicateKind::Clause(ty::Clause::Trait(..)) | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) - | ty::PredicateKind::AliasEq(..) + | ty::PredicateKind::AliasRelate(..) | ty::PredicateKind::Coerce(..) | ty::PredicateKind::Subtype(..) | ty::PredicateKind::WellFormed(..) diff --git a/compiler/rustc_infer/src/infer/projection.rs b/compiler/rustc_infer/src/infer/projection.rs index f795047709e..fa6529dfa93 100644 --- a/compiler/rustc_infer/src/infer/projection.rs +++ b/compiler/rustc_infer/src/infer/projection.rs @@ -26,7 +26,7 @@ impl<'tcx> InferCtxt<'tcx> { // completely change the normalization routine with the new solver. // // The new solver correctly handles projection equality so this hack - // is not necessary. if re-enabled it should emit `PredicateKind::AliasEq` + // is not necessary. if re-enabled it should emit `PredicateKind::AliasRelate` // not `PredicateKind::Clause(Clause::Projection(..))` as in the new solver // `Projection` is used as `normalizes-to` which will fail for `<T as Trait>::Assoc eq ?0`. return projection_ty.to_ty(self.tcx); diff --git a/compiler/rustc_infer/src/infer/sub.rs b/compiler/rustc_infer/src/infer/sub.rs index 230cadb1184..fc73ca7606d 100644 --- a/compiler/rustc_infer/src/infer/sub.rs +++ b/compiler/rustc_infer/src/infer/sub.rs @@ -236,4 +236,8 @@ impl<'tcx> ObligationEmittingRelation<'tcx> for Sub<'_, '_, 'tcx> { fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) { self.fields.register_obligations(obligations); } + + fn alias_relate_direction(&self) -> ty::AliasRelationDirection { + ty::AliasRelationDirection::Subtype + } } diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs index c07ff516579..0d2faeba5fc 100644 --- a/compiler/rustc_infer/src/traits/util.rs +++ b/compiler/rustc_infer/src/traits/util.rs @@ -293,7 +293,7 @@ impl<'tcx> Elaborator<'tcx> { // Nothing to elaborate } ty::PredicateKind::Ambiguous => {} - ty::PredicateKind::AliasEq(..) => { + ty::PredicateKind::AliasRelate(..) => { // No } ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) => { diff --git a/compiler/rustc_interface/Cargo.toml b/compiler/rustc_interface/Cargo.toml index ac6e8fca695..96d6a1cb062 100644 --- a/compiler/rustc_interface/Cargo.toml +++ b/compiler/rustc_interface/Cargo.toml @@ -16,6 +16,7 @@ rustc_attr = { path = "../rustc_attr" } rustc_borrowck = { path = "../rustc_borrowck" } rustc_builtin_macros = { path = "../rustc_builtin_macros" } rustc_expand = { path = "../rustc_expand" } +rustc_fs_util = { path = "../rustc_fs_util" } rustc_macros = { path = "../rustc_macros" } rustc_parse = { path = "../rustc_parse" } rustc_session = { path = "../rustc_session" } diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 71bdd4df95b..413b40ab808 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -3,7 +3,6 @@ use crate::interface::{Compiler, Result}; use crate::proc_macro_decls; use crate::util; -use ast::CRATE_NODE_ID; use rustc_ast::{self as ast, visit}; use rustc_borrowck as mir_borrowck; use rustc_codegen_ssa::traits::CodegenBackend; @@ -12,6 +11,7 @@ use rustc_data_structures::steal::Steal; use rustc_data_structures::sync::{Lrc, OnceCell, WorkerLocal}; use rustc_errors::PResult; use rustc_expand::base::{ExtCtxt, LintStoreExpand}; +use rustc_fs_util::try_canonicalize; use rustc_hir::def_id::{StableCrateId, LOCAL_CRATE}; use rustc_lint::{unerased_lint_store, BufferedEarlyLint, EarlyCheckNode, LintStore}; use rustc_metadata::creader::CStore; @@ -76,22 +76,14 @@ pub fn register_plugins<'a>( sess: &'a Session, metadata_loader: &'a dyn MetadataLoader, register_lints: impl Fn(&Session, &mut LintStore), - mut krate: ast::Crate, + pre_configured_attrs: &[ast::Attribute], crate_name: Symbol, -) -> Result<(ast::Crate, LintStore)> { - krate = sess.time("attributes_injection", || { - rustc_builtin_macros::cmdline_attrs::inject( - krate, - &sess.parse_sess, - &sess.opts.unstable_opts.crate_attr, - ) - }); - - let (krate, features) = rustc_expand::config::features(sess, krate, CRATE_NODE_ID); +) -> Result<LintStore> { // these need to be set "early" so that expansion sees `quote` if enabled. + let features = rustc_expand::config::features(sess, pre_configured_attrs); sess.init_features(features); - let crate_types = util::collect_crate_types(sess, &krate.attrs); + let crate_types = util::collect_crate_types(sess, pre_configured_attrs); sess.init_crate_types(crate_types); let stable_crate_id = StableCrateId::new( @@ -117,8 +109,9 @@ pub fn register_plugins<'a>( let mut lint_store = rustc_lint::new_lint_store(sess.enable_internal_lints()); register_lints(sess, &mut lint_store); - let registrars = - sess.time("plugin_loading", || plugin::load::load_plugins(sess, metadata_loader, &krate)); + let registrars = sess.time("plugin_loading", || { + plugin::load::load_plugins(sess, metadata_loader, pre_configured_attrs) + }); sess.time("plugin_registration", || { let mut registry = plugin::Registry { lint_store: &mut lint_store }; for registrar in registrars { @@ -126,7 +119,7 @@ pub fn register_plugins<'a>( } }); - Ok((krate, lint_store)) + Ok(lint_store) } fn pre_expansion_lint<'a>( @@ -173,19 +166,29 @@ impl LintStoreExpand for LintStoreExpandImpl<'_> { /// harness if one is to be provided, injection of a dependency on the /// standard library and prelude, and name resolution. #[instrument(level = "trace", skip(krate, resolver))] -fn configure_and_expand(mut krate: ast::Crate, resolver: &mut Resolver<'_, '_>) -> ast::Crate { +fn configure_and_expand( + mut krate: ast::Crate, + pre_configured_attrs: &[ast::Attribute], + resolver: &mut Resolver<'_, '_>, +) -> ast::Crate { let tcx = resolver.tcx(); let sess = tcx.sess; let lint_store = unerased_lint_store(tcx); let crate_name = tcx.crate_name(LOCAL_CRATE); - pre_expansion_lint(sess, lint_store, tcx.registered_tools(()), &krate, crate_name); + let lint_check_node = (&krate, pre_configured_attrs); + pre_expansion_lint(sess, lint_store, tcx.registered_tools(()), lint_check_node, crate_name); rustc_builtin_macros::register_builtin_macros(resolver); - krate = sess.time("crate_injection", || { - rustc_builtin_macros::standard_library_imports::inject(krate, resolver, sess) + let num_standard_library_imports = sess.time("crate_injection", || { + rustc_builtin_macros::standard_library_imports::inject( + &mut krate, + pre_configured_attrs, + resolver, + sess, + ) }); - util::check_attr_crate_type(sess, &krate.attrs, &mut resolver.lint_buffer()); + util::check_attr_crate_type(sess, pre_configured_attrs, &mut resolver.lint_buffer()); // Expand all macros krate = sess.time("macro_expand_crate", || { @@ -222,7 +225,7 @@ fn configure_and_expand(mut krate: ast::Crate, resolver: &mut Resolver<'_, '_>) // Create the config for macro expansion let features = sess.features_untracked(); - let recursion_limit = get_recursion_limit(&krate.attrs, sess); + let recursion_limit = get_recursion_limit(pre_configured_attrs, sess); let cfg = rustc_expand::expand::ExpansionConfig { features: Some(features), recursion_limit, @@ -235,6 +238,7 @@ fn configure_and_expand(mut krate: ast::Crate, resolver: &mut Resolver<'_, '_>) let lint_store = LintStoreExpandImpl(lint_store); let mut ecx = ExtCtxt::new(sess, cfg, resolver, Some(&lint_store)); + ecx.num_standard_library_imports = num_standard_library_imports; // Expand macros now! let krate = sess.time("expand_crate", || ecx.monotonic_expander().expand_crate(krate)); @@ -263,7 +267,7 @@ fn configure_and_expand(mut krate: ast::Crate, resolver: &mut Resolver<'_, '_>) }); sess.time("maybe_building_test_harness", || { - rustc_builtin_macros::test_harness::inject(sess, resolver, &mut krate) + rustc_builtin_macros::test_harness::inject(&mut krate, sess, resolver) }); let has_proc_macro_decls = sess.time("AST_validation", || { @@ -287,12 +291,12 @@ fn configure_and_expand(mut krate: ast::Crate, resolver: &mut Resolver<'_, '_>) sess.emit_warning(errors::ProcMacroCratePanicAbort); } - krate = sess.time("maybe_create_a_macro_crate", || { + sess.time("maybe_create_a_macro_crate", || { let is_test_crate = sess.opts.test; rustc_builtin_macros::proc_macro_harness::inject( + &mut krate, sess, resolver, - krate, is_proc_macro_crate, has_proc_macro_decls, is_test_crate, @@ -356,7 +360,7 @@ fn early_lint_checks(tcx: TyCtxt<'_>, (): ()) { tcx.registered_tools(()), Some(lint_buffer), rustc_lint::BuiltinCombinedEarlyLintPass::new(), - &**krate, + (&**krate, &*krate.attrs), ) } @@ -405,12 +409,12 @@ where } fn output_contains_path(output_paths: &[PathBuf], input_path: &Path) -> bool { - let input_path = input_path.canonicalize().ok(); + let input_path = try_canonicalize(input_path).ok(); if input_path.is_none() { return false; } let check = |output_path: &PathBuf| { - if output_path.canonicalize().ok() == input_path { Some(()) } else { None } + if try_canonicalize(output_path).ok() == input_path { Some(()) } else { None } }; check_output(output_paths, check).is_some() } @@ -557,9 +561,9 @@ fn resolver_for_lowering<'tcx>( ) -> &'tcx Steal<(ty::ResolverAstLowering, Lrc<ast::Crate>)> { let arenas = Resolver::arenas(); let _ = tcx.registered_tools(()); // Uses `crate_for_resolver`. - let krate = tcx.crate_for_resolver(()).steal(); - let mut resolver = Resolver::new(tcx, &krate, &arenas); - let krate = configure_and_expand(krate, &mut resolver); + let (krate, pre_configured_attrs) = tcx.crate_for_resolver(()).steal(); + let mut resolver = Resolver::new(tcx, &pre_configured_attrs, krate.spans.inner_span, &arenas); + let krate = configure_and_expand(krate, &pre_configured_attrs, &mut resolver); // Make sure we don't mutate the cstore from here on. tcx.untracked().cstore.leak(); diff --git a/compiler/rustc_interface/src/proc_macro_decls.rs b/compiler/rustc_interface/src/proc_macro_decls.rs index 9bf7778bfb2..1c58caa0353 100644 --- a/compiler/rustc_interface/src/proc_macro_decls.rs +++ b/compiler/rustc_interface/src/proc_macro_decls.rs @@ -1,3 +1,4 @@ +use rustc_ast::attr; use rustc_hir::def_id::LocalDefId; use rustc_middle::ty::query::Providers; use rustc_middle::ty::TyCtxt; @@ -8,7 +9,7 @@ fn proc_macro_decls_static(tcx: TyCtxt<'_>, (): ()) -> Option<LocalDefId> { for id in tcx.hir().items() { let attrs = tcx.hir().attrs(id.hir_id()); - if tcx.sess.contains_name(attrs, sym::rustc_proc_macro_decls) { + if attr::contains_name(attrs, sym::rustc_proc_macro_decls) { decls = Some(id.owner_id.def_id); } } diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index 58ad044b399..d2293780836 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -88,8 +88,9 @@ pub struct Queries<'tcx> { dep_graph_future: Query<Option<DepGraphFuture>>, parse: Query<ast::Crate>, + pre_configure: Query<(ast::Crate, ast::AttrVec)>, crate_name: Query<Symbol>, - register_plugins: Query<(ast::Crate, Lrc<LintStore>)>, + register_plugins: Query<(ast::Crate, ast::AttrVec, Lrc<LintStore>)>, dep_graph: Query<DepGraph>, // This just points to what's in `gcx_cell`. gcx: Query<&'tcx GlobalCtxt<'tcx>>, @@ -106,6 +107,7 @@ impl<'tcx> Queries<'tcx> { hir_arena: WorkerLocal::new(|_| rustc_hir::Arena::default()), dep_graph_future: Default::default(), parse: Default::default(), + pre_configure: Default::default(), crate_name: Default::default(), register_plugins: Default::default(), dep_graph: Default::default(), @@ -133,17 +135,36 @@ impl<'tcx> Queries<'tcx> { .compute(|| passes::parse(self.session()).map_err(|mut parse_error| parse_error.emit())) } - pub fn register_plugins(&self) -> Result<QueryResult<'_, (ast::Crate, Lrc<LintStore>)>> { + pub fn pre_configure(&self) -> Result<QueryResult<'_, (ast::Crate, ast::AttrVec)>> { + self.pre_configure.compute(|| { + let mut krate = self.parse()?.steal(); + + let sess = self.session(); + rustc_builtin_macros::cmdline_attrs::inject( + &mut krate, + &sess.parse_sess, + &sess.opts.unstable_opts.crate_attr, + ); + + let pre_configured_attrs = + rustc_expand::config::pre_configure_attrs(sess, &krate.attrs); + Ok((krate, pre_configured_attrs)) + }) + } + + pub fn register_plugins( + &self, + ) -> Result<QueryResult<'_, (ast::Crate, ast::AttrVec, Lrc<LintStore>)>> { self.register_plugins.compute(|| { let crate_name = *self.crate_name()?.borrow(); - let krate = self.parse()?.steal(); + let (krate, pre_configured_attrs) = self.pre_configure()?.steal(); let empty: &(dyn Fn(&Session, &mut LintStore) + Sync + Send) = &|_, _| {}; - let (krate, lint_store) = passes::register_plugins( + let lint_store = passes::register_plugins( self.session(), &*self.codegen_backend().metadata_loader(), self.compiler.register_lints.as_deref().unwrap_or_else(|| empty), - krate, + &pre_configured_attrs, crate_name, )?; @@ -154,17 +175,17 @@ impl<'tcx> Queries<'tcx> { // called, which happens within passes::register_plugins(). self.dep_graph_future().ok(); - Ok((krate, Lrc::new(lint_store))) + Ok((krate, pre_configured_attrs, Lrc::new(lint_store))) }) } fn crate_name(&self) -> Result<QueryResult<'_, Symbol>> { self.crate_name.compute(|| { Ok({ - let parse_result = self.parse()?; - let krate = parse_result.borrow(); + let pre_configure_result = self.pre_configure()?; + let (_, pre_configured_attrs) = &*pre_configure_result.borrow(); // parse `#[crate_name]` even if `--crate-name` was passed, to make sure it matches. - find_crate_name(self.session(), &krate.attrs) + find_crate_name(self.session(), pre_configured_attrs) }) }) } @@ -188,7 +209,7 @@ impl<'tcx> Queries<'tcx> { pub fn global_ctxt(&'tcx self) -> Result<QueryResult<'_, &'tcx GlobalCtxt<'tcx>>> { self.gcx.compute(|| { let crate_name = *self.crate_name()?.borrow(); - let (krate, lint_store) = self.register_plugins()?.steal(); + let (krate, pre_configured_attrs, lint_store) = self.register_plugins()?.steal(); let sess = self.session(); @@ -215,7 +236,7 @@ impl<'tcx> Queries<'tcx> { feed.crate_name(crate_name); let feed = tcx.feed_unit_query(); - feed.crate_for_resolver(tcx.arena.alloc(Steal::new(krate))); + feed.crate_for_resolver(tcx.arena.alloc(Steal::new((krate, pre_configured_attrs)))); feed.metadata_loader( tcx.arena.alloc(Steal::new(self.codegen_backend().metadata_loader())), ); diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 014810dba9c..eb5990507fb 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -2,6 +2,7 @@ use crate::interface::parse_cfgspecs; use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::profiling::TimePassesFormat; use rustc_errors::{emitter::HumanReadableErrorType, registry, ColorConfig}; use rustc_session::config::rustc_optgroups; use rustc_session::config::Input; @@ -699,6 +700,7 @@ fn test_unstable_options_tracking_hash() { untracked!(threads, 99); untracked!(time_llvm_passes, true); untracked!(time_passes, true); + untracked!(time_passes_format, TimePassesFormat::Json); untracked!(trace_macros, true); untracked!(track_diagnostics, true); untracked!(trim_diagnostic_paths, false); diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index 043892410ce..8abdcebb751 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -505,7 +505,7 @@ pub fn build_output_filenames(attrs: &[ast::Attribute], sess: &Session) -> Outpu .opts .crate_name .clone() - .or_else(|| rustc_attr::find_crate_name(sess, attrs).map(|n| n.to_string())) + .or_else(|| rustc_attr::find_crate_name(attrs).map(|n| n.to_string())) .unwrap_or_else(|| sess.io.input.filestem().to_owned()); OutputFilenames::new( diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index c822237413c..68e62c9789a 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -508,6 +508,3 @@ lint_opaque_hidden_inferred_bound = opaque type `{$ty}` does not satisfy its ass .specifically = this associated type bound is unsatisfied for `{$proj_ty}` lint_opaque_hidden_inferred_bound_sugg = add this bound - -lint_useless_anonymous_reexport = useless anonymous re-export - .note = only anonymous re-exports of traits are useful, this is {$article} `{$desc}` diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 8af1a663ef5..64c3ef45137 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -358,29 +358,29 @@ impl EarlyLintPass for UnsafeCode { } ast::ItemKind::Fn(..) => { - if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::no_mangle) { + if let Some(attr) = attr::find_by_name(&it.attrs, sym::no_mangle) { self.report_unsafe(cx, attr.span, BuiltinUnsafe::NoMangleFn); } - if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::export_name) { + if let Some(attr) = attr::find_by_name(&it.attrs, sym::export_name) { self.report_unsafe(cx, attr.span, BuiltinUnsafe::ExportNameFn); } - if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::link_section) { + if let Some(attr) = attr::find_by_name(&it.attrs, sym::link_section) { self.report_unsafe(cx, attr.span, BuiltinUnsafe::LinkSectionFn); } } ast::ItemKind::Static(..) => { - if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::no_mangle) { + if let Some(attr) = attr::find_by_name(&it.attrs, sym::no_mangle) { self.report_unsafe(cx, attr.span, BuiltinUnsafe::NoMangleStatic); } - if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::export_name) { + if let Some(attr) = attr::find_by_name(&it.attrs, sym::export_name) { self.report_unsafe(cx, attr.span, BuiltinUnsafe::ExportNameStatic); } - if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::link_section) { + if let Some(attr) = attr::find_by_name(&it.attrs, sym::link_section) { self.report_unsafe(cx, attr.span, BuiltinUnsafe::LinkSectionStatic); } } @@ -391,10 +391,10 @@ impl EarlyLintPass for UnsafeCode { fn check_impl_item(&mut self, cx: &EarlyContext<'_>, it: &ast::AssocItem) { if let ast::AssocItemKind::Fn(..) = it.kind { - if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::no_mangle) { + if let Some(attr) = attr::find_by_name(&it.attrs, sym::no_mangle) { self.report_unsafe(cx, attr.span, BuiltinUnsafe::NoMangleMethod); } - if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::export_name) { + if let Some(attr) = attr::find_by_name(&it.attrs, sym::export_name) { self.report_unsafe(cx, attr.span, BuiltinUnsafe::ExportNameMethod); } } @@ -1123,12 +1123,12 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems { }; match it.kind { hir::ItemKind::Fn(.., ref generics, _) => { - if let Some(no_mangle_attr) = cx.sess().find_by_name(attrs, sym::no_mangle) { + if let Some(no_mangle_attr) = attr::find_by_name(attrs, sym::no_mangle) { check_no_mangle_on_generic_fn(no_mangle_attr, None, generics, it.span); } } hir::ItemKind::Const(..) => { - if cx.sess().contains_name(attrs, sym::no_mangle) { + if attr::contains_name(attrs, sym::no_mangle) { // account for "pub const" (#45562) let start = cx .tcx @@ -1152,9 +1152,8 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems { hir::ItemKind::Impl(hir::Impl { generics, items, .. }) => { for it in *items { if let hir::AssocItemKind::Fn { .. } = it.kind { - if let Some(no_mangle_attr) = cx - .sess() - .find_by_name(cx.tcx.hir().attrs(it.id.hir_id()), sym::no_mangle) + if let Some(no_mangle_attr) = + attr::find_by_name(cx.tcx.hir().attrs(it.id.hir_id()), sym::no_mangle) { check_no_mangle_on_generic_fn( no_mangle_attr, @@ -1601,7 +1600,7 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints { // Ignore projections, as they can only be global // if the trait bound is global Clause(Clause::Projection(..)) | - AliasEq(..) | + AliasRelate(..) | // Ignore bounds that a user can't type WellFormed(..) | ObjectSafe(..) | @@ -1836,7 +1835,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnameableTestItems { } let attrs = cx.tcx.hir().attrs(it.hir_id()); - if let Some(attr) = cx.sess().find_by_name(attrs, sym::rustc_test_marker) { + if let Some(attr) = attr::find_by_name(attrs, sym::rustc_test_marker) { cx.emit_spanned_lint(UNNAMEABLE_TEST_ITEMS, attr.span, BuiltinUnnameableTestItems); } } diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index f5a711315ea..626c09fea07 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -910,6 +910,10 @@ pub trait LintContext: Sized { Applicability::MachineApplicable, ); } + BuiltinLintDiagnostics::AmbiguousGlobReexports { name, namespace, first_reexport_span, duplicate_reexport_span } => { + db.span_label(first_reexport_span, format!("the name `{}` in the {} namespace is first re-exported here", name, namespace)); + db.span_label(duplicate_reexport_span, format!("but the name `{}` in the {} namespace is also re-exported here", name, namespace)); + } } // Rewrap `db`, and pass control to the user. decorate(db) diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs index 337a19dd024..9b0d8d6c072 100644 --- a/compiler/rustc_lint/src/early.rs +++ b/compiler/rustc_lint/src/early.rs @@ -341,7 +341,7 @@ pub trait EarlyCheckNode<'a>: Copy { 'a: 'b; } -impl<'a> EarlyCheckNode<'a> for &'a ast::Crate { +impl<'a> EarlyCheckNode<'a> for (&'a ast::Crate, &'a [ast::Attribute]) { fn id(self) -> ast::NodeId { ast::CRATE_NODE_ID } @@ -349,15 +349,15 @@ impl<'a> EarlyCheckNode<'a> for &'a ast::Crate { where 'a: 'b, { - &self.attrs + &self.1 } fn check<'b, T: EarlyLintPass>(self, cx: &mut EarlyContextAndPass<'b, T>) where 'a: 'b, { - lint_callback!(cx, check_crate, self); - ast_visit::walk_crate(cx, self); - lint_callback!(cx, check_crate_post, self); + lint_callback!(cx, check_crate, self.0); + ast_visit::walk_crate(cx, self.0); + lint_callback!(cx, check_crate_post, self.0); } } diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index c2cc2fcdf55..b3578540516 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -74,7 +74,6 @@ mod opaque_hidden_inferred_bound; mod pass_by_value; mod passes; mod redundant_semicolon; -mod reexports; mod traits; mod types; mod unused; @@ -112,7 +111,6 @@ use noop_method_call::*; use opaque_hidden_inferred_bound::*; use pass_by_value::*; use redundant_semicolon::*; -use reexports::*; use traits::*; use types::*; use unused::*; @@ -244,7 +242,6 @@ late_lint_methods!( OpaqueHiddenInferredBound: OpaqueHiddenInferredBound, MultipleSupertraitUpcastable: MultipleSupertraitUpcastable, MapUnitFn: MapUnitFn, - UselessAnonymousReexport: UselessAnonymousReexport, ] ] ); diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 46a025f41e0..308c02929ca 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -1528,11 +1528,3 @@ pub struct UnusedAllocationDiag; #[derive(LintDiagnostic)] #[diag(lint_unused_allocation_mut)] pub struct UnusedAllocationMutDiag; - -#[derive(LintDiagnostic)] -#[diag(lint_useless_anonymous_reexport)] -#[note] -pub struct UselessAnonymousReexportDiag { - pub article: &'static str, - pub desc: &'static str, -} diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index 0f44dde5948..9efc14849c7 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -328,8 +328,7 @@ impl<'tcx> LateLintPass<'tcx> for NonSnakeCase { let crate_ident = if let Some(name) = &cx.tcx.sess.opts.crate_name { Some(Ident::from_str(name)) } else { - cx.sess() - .find_by_name(&cx.tcx.hir().attrs(hir::CRATE_HIR_ID), sym::crate_name) + attr::find_by_name(&cx.tcx.hir().attrs(hir::CRATE_HIR_ID), sym::crate_name) .and_then(|attr| attr.meta()) .and_then(|meta| { meta.name_value_literal().and_then(|lit| { @@ -489,7 +488,7 @@ impl<'tcx> LateLintPass<'tcx> for NonUpperCaseGlobals { fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) { let attrs = cx.tcx.hir().attrs(it.hir_id()); match it.kind { - hir::ItemKind::Static(..) if !cx.sess().contains_name(attrs, sym::no_mangle) => { + hir::ItemKind::Static(..) if !attr::contains_name(attrs, sym::no_mangle) => { NonUpperCaseGlobals::check_upper_case(cx, "static variable", &it.ident); } hir::ItemKind::Const(..) => { diff --git a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs index 883a56cb3ce..f9d43fe2200 100644 --- a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs +++ b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs @@ -27,6 +27,8 @@ declare_lint! { /// ### Example /// /// ```rust + /// #![feature(type_alias_impl_trait)] + /// /// trait Duh {} /// /// impl Duh for i32 {} @@ -41,7 +43,9 @@ declare_lint! { /// type Assoc = F; /// } /// - /// fn test() -> impl Trait<Assoc = impl Sized> { + /// type Tait = impl Sized; + /// + /// fn test() -> impl Trait<Assoc = Tait> { /// 42 /// } /// ``` @@ -54,7 +58,7 @@ declare_lint! { /// /// Although the hidden type, `i32` does satisfy this bound, we do not /// consider the return type to be well-formed with this lint. It can be - /// fixed by changing `impl Sized` into `impl Sized + Send`. + /// fixed by changing `Tait = impl Sized` into `Tait = impl Sized + Send`. pub OPAQUE_HIDDEN_INFERRED_BOUND, Warn, "detects the use of nested `impl Trait` types in associated type bounds that are not general enough" @@ -64,7 +68,7 @@ declare_lint_pass!(OpaqueHiddenInferredBound => [OPAQUE_HIDDEN_INFERRED_BOUND]); impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) { - let hir::ItemKind::OpaqueTy(_) = &item.kind else { return; }; + let hir::ItemKind::OpaqueTy(opaque) = &item.kind else { return; }; let def_id = item.owner_id.def_id.to_def_id(); let infcx = &cx.tcx.infer_ctxt().build(); // For every projection predicate in the opaque type's explicit bounds, @@ -81,6 +85,17 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound { // have opaques in them anyways. let Some(proj_term) = proj.term.ty() else { continue }; + // HACK: `impl Trait<Assoc = impl Trait2>` from an RPIT is "ok"... + if let ty::Alias(ty::Opaque, opaque_ty) = *proj_term.kind() + && cx.tcx.parent(opaque_ty.def_id) == def_id + && matches!( + opaque.origin, + hir::OpaqueTyOrigin::FnReturn(_) | hir::OpaqueTyOrigin::AsyncFn(_) + ) + { + continue; + } + let proj_ty = cx.tcx.mk_projection(proj.projection_ty.def_id, proj.projection_ty.substs); // For every instance of the projection type in the bounds, diff --git a/compiler/rustc_lint/src/reexports.rs b/compiler/rustc_lint/src/reexports.rs deleted file mode 100644 index 8737a57ea02..00000000000 --- a/compiler/rustc_lint/src/reexports.rs +++ /dev/null @@ -1,82 +0,0 @@ -use crate::lints::UselessAnonymousReexportDiag; -use crate::{LateContext, LateLintPass, LintContext}; -use rustc_hir::def::DefKind; -use rustc_hir::def_id::DefId; -use rustc_hir::{Item, ItemKind, UseKind}; -use rustc_middle::ty::Visibility; -use rustc_span::symbol::kw; -use rustc_span::Span; - -declare_lint! { - /// The `useless_anonymous_reexport` lint checks if anonymous re-exports - /// are re-exports of traits. - /// - /// ### Example - /// - /// ```rust,compile_fail - /// #![deny(useless_anonymous_reexport)] - /// - /// mod sub { - /// pub struct Bar; - /// } - /// - /// pub use self::sub::Bar as _; - /// # fn main() {} - /// ``` - /// - /// {{produces}} - /// - /// ### Explanation - /// - /// Anonymous re-exports are only useful if it's a re-export of a trait - /// in case you want to give access to it. If you re-export any other kind, - /// you won't be able to use it since its name won't be accessible. - pub USELESS_ANONYMOUS_REEXPORT, - Warn, - "useless anonymous re-export" -} - -declare_lint_pass!(UselessAnonymousReexport => [USELESS_ANONYMOUS_REEXPORT]); - -fn emit_err(cx: &LateContext<'_>, span: Span, def_id: DefId) { - let article = cx.tcx.def_descr_article(def_id); - let desc = cx.tcx.def_descr(def_id); - cx.emit_spanned_lint( - USELESS_ANONYMOUS_REEXPORT, - span, - UselessAnonymousReexportDiag { article, desc }, - ); -} - -impl<'tcx> LateLintPass<'tcx> for UselessAnonymousReexport { - fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { - if let ItemKind::Use(path, kind) = item.kind && - !matches!(kind, UseKind::Glob) && - item.ident.name == kw::Underscore && - // We only want re-exports. If it's just a `use X;`, then we ignore it. - match cx.tcx.local_visibility(item.owner_id.def_id) { - Visibility::Public => true, - Visibility::Restricted(level) => { - level != cx.tcx.parent_module_from_def_id(item.owner_id.def_id) - } - } - { - for def_id in path.res.iter().filter_map(|r| r.opt_def_id()) { - match cx.tcx.def_kind(def_id) { - DefKind::Trait | DefKind::TraitAlias => {} - DefKind::TyAlias => { - let ty = cx.tcx.type_of(def_id); - if !ty.0.is_trait() { - emit_err(cx, item.span, def_id); - break; - } - } - _ => { - emit_err(cx, item.span, def_id); - break; - } - } - } - } - } -} diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 91966e75b5f..9d6ab0b75df 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -3230,6 +3230,45 @@ declare_lint! { }; } +declare_lint! { + /// The `ambiguous_glob_reexports` lint detects cases where names re-exported via globs + /// collide. Downstream users trying to use the same name re-exported from multiple globs + /// will receive a warning pointing out redefinition of the same name. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(ambiguous_glob_reexports)] + /// pub mod foo { + /// pub type X = u8; + /// } + /// + /// pub mod bar { + /// pub type Y = u8; + /// pub type X = u8; + /// } + /// + /// pub use foo::*; + /// pub use bar::*; + /// + /// + /// pub fn main() {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// This was previously accepted but it could silently break a crate's downstream users code. + /// For example, if `foo::*` and `bar::*` were re-exported before `bar::X` was added to the + /// re-exports, down stream users could use `this_crate::X` without problems. However, adding + /// `bar::X` would cause compilation errors in downstream crates because `X` is defined + /// multiple times in the same namespace of `this_crate`. + pub AMBIGUOUS_GLOB_REEXPORTS, + Warn, + "ambiguous glob re-exports", +} + declare_lint_pass! { /// Does nothing as a lint pass, but registers some `Lint`s /// that are used by other parts of the compiler. @@ -3337,6 +3376,7 @@ declare_lint_pass! { NAMED_ARGUMENTS_USED_POSITIONALLY, IMPLIED_BOUNDS_ENTAILMENT, BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE, + AMBIGUOUS_GLOB_REEXPORTS, ] } @@ -3968,14 +4008,9 @@ declare_lint! { /// /// ### Example /// - /// ```rust,ignore (need FFI) - /// #![feature(ffi_unwind_calls)] + /// ```rust /// #![feature(c_unwind)] - /// - /// # mod impl { - /// # #[no_mangle] - /// # pub fn "C-unwind" fn foo() {} - /// # } + /// #![warn(ffi_unwind_calls)] /// /// extern "C-unwind" { /// fn foo(); diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 6f22bdabff4..69a8b691ab2 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -529,6 +529,16 @@ pub enum BuiltinLintDiagnostics { vis_span: Span, ident_span: Span, }, + AmbiguousGlobReexports { + /// The name for which collision(s) have occurred. + name: String, + /// The name space for whihc the collision(s) occurred in. + namespace: String, + /// Span where the name is first re-exported. + first_reexport_span: Span, + /// Span where the same name is also re-exported. + duplicate_reexport_span: Span, + }, } /// Lints that are buffered up early on in the `Session` before the diff --git a/compiler/rustc_metadata/Cargo.toml b/compiler/rustc_metadata/Cargo.toml index bee5c8541d6..4d7c133e09b 100644 --- a/compiler/rustc_metadata/Cargo.toml +++ b/compiler/rustc_metadata/Cargo.toml @@ -18,6 +18,7 @@ rustc_attr = { path = "../rustc_attr" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_feature = { path = "../rustc_feature" } +rustc_fs_util = { path = "../rustc_fs_util" } rustc_hir = { path = "../rustc_hir" } rustc_hir_pretty = { path = "../rustc_hir_pretty" } rustc_target = { path = "../rustc_target" } diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index f870a1db82d..23c1aebb8ae 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -6,11 +6,11 @@ use crate::rmeta::{CrateDep, CrateMetadata, CrateNumMap, CrateRoot, MetadataBlob use rustc_ast::expand::allocator::AllocatorKind; use rustc_ast::{self as ast, *}; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::{MappedReadGuard, MappedWriteGuard, ReadGuard, WriteGuard}; use rustc_expand::base::SyntaxExtension; -use rustc_hir::def_id::{CrateNum, LocalDefId, StableCrateId, LOCAL_CRATE}; +use rustc_hir::def_id::{CrateNum, LocalDefId, StableCrateId, StableCrateIdMap, LOCAL_CRATE}; use rustc_hir::definitions::Definitions; use rustc_index::vec::IndexVec; use rustc_middle::ty::TyCtxt; @@ -46,9 +46,8 @@ pub struct CStore { /// This crate has a `#[alloc_error_handler]` item. has_alloc_error_handler: bool, - /// This map is used to verify we get no hash conflicts between - /// `StableCrateId` values. - pub(crate) stable_crate_ids: FxHashMap<StableCrateId, CrateNum>, + /// The interned [StableCrateId]s. + pub(crate) stable_crate_ids: StableCrateIdMap, /// Unused externs of the crate unused_externs: Vec<Symbol>, @@ -144,9 +143,21 @@ impl CStore { }) } - fn alloc_new_crate_num(&mut self) -> CrateNum { - self.metas.push(None); - CrateNum::new(self.metas.len() - 1) + fn intern_stable_crate_id(&mut self, root: &CrateRoot) -> Result<CrateNum, CrateError> { + assert_eq!(self.metas.len(), self.stable_crate_ids.len()); + let num = CrateNum::new(self.stable_crate_ids.len()); + if let Some(&existing) = self.stable_crate_ids.get(&root.stable_crate_id()) { + let crate_name0 = root.name(); + if let Some(crate_name1) = self.metas[existing].as_ref().map(|data| data.name()) { + Err(CrateError::StableCrateIdCollision(crate_name0, crate_name1)) + } else { + Err(CrateError::SymbolConflictsCurrent(crate_name0)) + } + } else { + self.metas.push(None); + self.stable_crate_ids.insert(root.stable_crate_id(), num); + Ok(num) + } } pub fn has_crate_data(&self, cnum: CrateNum) -> bool { @@ -247,7 +258,7 @@ impl CStore { } pub fn new(sess: &Session) -> CStore { - let mut stable_crate_ids = FxHashMap::default(); + let mut stable_crate_ids = StableCrateIdMap::default(); stable_crate_ids.insert(sess.local_stable_crate_id(), LOCAL_CRATE); CStore { // We add an empty entry for LOCAL_CRATE (which maps to zero) in @@ -342,42 +353,6 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { None } - fn verify_no_symbol_conflicts(&self, root: &CrateRoot) -> Result<(), CrateError> { - // Check for (potential) conflicts with the local crate - if self.sess.local_stable_crate_id() == root.stable_crate_id() { - return Err(CrateError::SymbolConflictsCurrent(root.name())); - } - - // Check for conflicts with any crate loaded so far - for (_, other) in self.cstore.iter_crate_data() { - // Same stable crate id but different SVH - if other.stable_crate_id() == root.stable_crate_id() && other.hash() != root.hash() { - bug!( - "Previously returned E0523 here. \ - See https://github.com/rust-lang/rust/pull/100599 for additional discussion.\ - root.name() = {}.", - root.name() - ); - } - } - - Ok(()) - } - - fn verify_no_stable_crate_id_hash_conflicts( - &mut self, - root: &CrateRoot, - cnum: CrateNum, - ) -> Result<(), CrateError> { - if let Some(existing) = self.cstore.stable_crate_ids.insert(root.stable_crate_id(), cnum) { - let crate_name0 = root.name(); - let crate_name1 = self.cstore.get_crate_data(existing).name(); - return Err(CrateError::StableCrateIdCollision(crate_name0, crate_name1)); - } - - Ok(()) - } - fn register_crate( &mut self, host_lib: Option<Library>, @@ -396,7 +371,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { self.sess.opts.externs.get(name.as_str()).map_or(false, |e| e.is_private_dep); // Claim this crate number and cache it - let cnum = self.cstore.alloc_new_crate_num(); + let cnum = self.cstore.intern_stable_crate_id(&crate_root)?; info!( "register crate `{}` (cnum = {}. private_dep = {})", @@ -432,14 +407,6 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { None }; - // Perform some verification *after* resolve_crate_deps() above is - // known to have been successful. It seems that - in error cases - the - // cstore can be in a temporarily invalid state between cnum allocation - // and dependency resolution and the verification code would produce - // ICEs in that case (see #83045). - self.verify_no_symbol_conflicts(&crate_root)?; - self.verify_no_stable_crate_id_hash_conflicts(&crate_root, cnum)?; - let crate_metadata = CrateMetadata::new( self.sess, &self.cstore, @@ -720,8 +687,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { // compilation mode also comes into play. let desired_strategy = self.sess.panic_strategy(); let mut runtime_found = false; - let mut needs_panic_runtime = - self.sess.contains_name(&krate.attrs, sym::needs_panic_runtime); + let mut needs_panic_runtime = attr::contains_name(&krate.attrs, sym::needs_panic_runtime); for (cnum, data) in self.cstore.iter_crate_data() { needs_panic_runtime = needs_panic_runtime || data.needs_panic_runtime(); @@ -789,7 +755,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { info!("loading profiler"); let name = Symbol::intern(&self.sess.opts.unstable_opts.profiler_runtime); - if name == sym::profiler_builtins && self.sess.contains_name(&krate.attrs, sym::no_core) { + if name == sym::profiler_builtins && attr::contains_name(&krate.attrs, sym::no_core) { self.sess.emit_err(errors::ProfilerBuiltinsNeedsCore); } @@ -803,14 +769,14 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { } fn inject_allocator_crate(&mut self, krate: &ast::Crate) { - self.cstore.has_global_allocator = match &*global_allocator_spans(&self.sess, krate) { + self.cstore.has_global_allocator = match &*global_allocator_spans(krate) { [span1, span2, ..] => { self.sess.emit_err(errors::NoMultipleGlobalAlloc { span2: *span2, span1: *span1 }); true } spans => !spans.is_empty(), }; - self.cstore.has_alloc_error_handler = match &*alloc_error_handler_spans(&self.sess, krate) { + self.cstore.has_alloc_error_handler = match &*alloc_error_handler_spans(krate) { [span1, span2, ..] => { self.sess .emit_err(errors::NoMultipleAllocErrorHandler { span2: *span2, span1: *span1 }); @@ -822,7 +788,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { // Check to see if we actually need an allocator. This desire comes // about through the `#![needs_allocator]` attribute and is typically // written down in liballoc. - if !self.sess.contains_name(&krate.attrs, sym::needs_allocator) + if !attr::contains_name(&krate.attrs, sym::needs_allocator) && !self.cstore.iter_crate_data().any(|(_, data)| data.needs_allocator()) { return; @@ -881,7 +847,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { // allocator. At this point our allocator request is typically fulfilled // by the standard library, denoted by the `#![default_lib_allocator]` // attribute. - if !self.sess.contains_name(&krate.attrs, sym::default_lib_allocator) + if !attr::contains_name(&krate.attrs, sym::default_lib_allocator) && !self.cstore.iter_crate_data().any(|(_, data)| data.has_default_lib_allocator()) { self.sess.emit_err(errors::GlobalAllocRequired); @@ -1003,7 +969,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { } None => item.ident.name, }; - let dep_kind = if self.sess.contains_name(&item.attrs, sym::no_link) { + let dep_kind = if attr::contains_name(&item.attrs, sym::no_link) { CrateDepKind::MacrosOnly } else { CrateDepKind::Explicit @@ -1049,16 +1015,15 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { } } -fn global_allocator_spans(sess: &Session, krate: &ast::Crate) -> Vec<Span> { - struct Finder<'a> { - sess: &'a Session, +fn global_allocator_spans(krate: &ast::Crate) -> Vec<Span> { + struct Finder { name: Symbol, spans: Vec<Span>, } - impl<'ast, 'a> visit::Visitor<'ast> for Finder<'a> { + impl<'ast> visit::Visitor<'ast> for Finder { fn visit_item(&mut self, item: &'ast ast::Item) { if item.ident.name == self.name - && self.sess.contains_name(&item.attrs, sym::rustc_std_internal_symbol) + && attr::contains_name(&item.attrs, sym::rustc_std_internal_symbol) { self.spans.push(item.span); } @@ -1067,21 +1032,20 @@ fn global_allocator_spans(sess: &Session, krate: &ast::Crate) -> Vec<Span> { } let name = Symbol::intern(&AllocatorKind::Global.fn_name(sym::alloc)); - let mut f = Finder { sess, name, spans: Vec::new() }; + let mut f = Finder { name, spans: Vec::new() }; visit::walk_crate(&mut f, krate); f.spans } -fn alloc_error_handler_spans(sess: &Session, krate: &ast::Crate) -> Vec<Span> { - struct Finder<'a> { - sess: &'a Session, +fn alloc_error_handler_spans(krate: &ast::Crate) -> Vec<Span> { + struct Finder { name: Symbol, spans: Vec<Span>, } - impl<'ast, 'a> visit::Visitor<'ast> for Finder<'a> { + impl<'ast> visit::Visitor<'ast> for Finder { fn visit_item(&mut self, item: &'ast ast::Item) { if item.ident.name == self.name - && self.sess.contains_name(&item.attrs, sym::rustc_std_internal_symbol) + && attr::contains_name(&item.attrs, sym::rustc_std_internal_symbol) { self.spans.push(item.span); } @@ -1090,7 +1054,7 @@ fn alloc_error_handler_spans(sess: &Session, krate: &ast::Crate) -> Vec<Span> { } let name = Symbol::intern(&AllocatorKind::Global.fn_name(sym::oom)); - let mut f = Finder { sess, name, spans: Vec::new() }; + let mut f = Finder { name, spans: Vec::new() }; visit::walk_crate(&mut f, krate); f.spans } diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs index c48e681eb94..79c42a128e7 100644 --- a/compiler/rustc_metadata/src/locator.rs +++ b/compiler/rustc_metadata/src/locator.rs @@ -222,6 +222,7 @@ use rustc_data_structures::owning_ref::OwningRef; use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::MetadataRef; use rustc_errors::{DiagnosticArgValue, FatalError, IntoDiagnosticArg}; +use rustc_fs_util::try_canonicalize; use rustc_session::config::{self, CrateType}; use rustc_session::cstore::{CrateSource, MetadataLoader}; use rustc_session::filesearch::FileSearch; @@ -236,7 +237,7 @@ use snap::read::FrameDecoder; use std::borrow::Cow; use std::io::{Read, Result as IoResult, Write}; use std::path::{Path, PathBuf}; -use std::{cmp, fmt, fs}; +use std::{cmp, fmt}; #[derive(Clone)] pub(crate) struct CrateLocator<'a> { @@ -441,7 +442,7 @@ impl<'a> CrateLocator<'a> { info!("lib candidate: {}", spf.path.display()); let (rlibs, rmetas, dylibs) = candidates.entry(hash.to_string()).or_default(); - let path = fs::canonicalize(&spf.path).unwrap_or_else(|_| spf.path.clone()); + let path = try_canonicalize(&spf.path).unwrap_or_else(|_| spf.path.clone()); if seen_paths.contains(&path) { continue; }; @@ -636,7 +637,7 @@ impl<'a> CrateLocator<'a> { // as well. if let Some((prev, _)) = &ret { let sysroot = self.sysroot; - let sysroot = sysroot.canonicalize().unwrap_or_else(|_| sysroot.to_path_buf()); + let sysroot = try_canonicalize(sysroot).unwrap_or_else(|_| sysroot.to_path_buf()); if prev.starts_with(&sysroot) { continue; } diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 0070e46ffdf..06a64f0db0e 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -925,10 +925,6 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { tcx.mk_adt_def(did, adt_kind, variants, repr) } - fn get_generics(self, item_id: DefIndex, sess: &Session) -> ty::Generics { - self.root.tables.generics_of.get(self, item_id).unwrap().decode((self, sess)) - } - fn get_visibility(self, id: DefIndex) -> Visibility<DefId> { self.root .tables @@ -1045,13 +1041,6 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { self.root.tables.optimized_mir.get(self, id).is_some() } - fn module_expansion(self, id: DefIndex, sess: &Session) -> ExpnId { - match self.def_kind(id) { - DefKind::Mod | DefKind::Enum | DefKind::Trait => self.get_expn_that_defined(id, sess), - _ => panic!("Expected module, found {:?}", self.local_def_id(id)), - } - } - fn get_fn_has_self_parameter(self, id: DefIndex, sess: &'a Session) -> bool { self.root .tables @@ -1709,10 +1698,6 @@ impl CrateMetadata { self.root.name } - pub(crate) fn stable_crate_id(&self) -> StableCrateId { - self.root.stable_crate_id - } - pub(crate) fn hash(&self) -> Svh { self.root.hash } diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 9661e815623..3a50d7c9363 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -490,6 +490,9 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) { .alloc_slice(&CStore::from_tcx(tcx).crate_dependencies_in_postorder(LOCAL_CRATE)) }, crates: |tcx, ()| { + // The list of loaded crates is now frozen in query cache, + // so make sure cstore is not mutably accessed from here on. + tcx.untracked().cstore.leak(); tcx.arena.alloc_from_iter(CStore::from_tcx(tcx).iter_crate_data().map(|(cnum, _)| cnum)) }, ..*providers @@ -537,20 +540,16 @@ impl CStore { ) } - pub fn get_span_untracked(&self, def_id: DefId, sess: &Session) -> Span { + pub fn def_span_untracked(&self, def_id: DefId, sess: &Session) -> Span { self.get_crate_data(def_id.krate).get_span(def_id.index, sess) } - pub fn def_kind(&self, def: DefId) -> DefKind { + pub fn def_kind_untracked(&self, def: DefId) -> DefKind { self.get_crate_data(def.krate).def_kind(def.index) } - pub fn item_generics_num_lifetimes(&self, def_id: DefId, sess: &Session) -> usize { - self.get_crate_data(def_id.krate).get_generics(def_id.index, sess).own_counts().lifetimes - } - - pub fn module_expansion_untracked(&self, def_id: DefId, sess: &Session) -> ExpnId { - self.get_crate_data(def_id.krate).module_expansion(def_id.index, sess) + pub fn expn_that_defined_untracked(&self, def_id: DefId, sess: &Session) -> ExpnId { + self.get_crate_data(def_id.krate).get_expn_that_defined(def_id.index, sess) } /// Only public-facing way to traverse all the definitions in a non-local crate. @@ -560,14 +559,6 @@ impl CStore { self.get_crate_data(cnum).num_def_ids() } - pub fn item_attrs_untracked<'a>( - &'a self, - def_id: DefId, - sess: &'a Session, - ) -> impl Iterator<Item = ast::Attribute> + 'a { - self.get_crate_data(def_id.krate).get_item_attrs(def_id.index, sess) - } - pub fn get_proc_macro_quoted_span_untracked( &self, cnum: CrateNum, @@ -595,7 +586,10 @@ impl CrateStore for CStore { } fn stable_crate_id_to_crate_num(&self, stable_crate_id: StableCrateId) -> CrateNum { - self.stable_crate_ids[&stable_crate_id] + *self + .stable_crate_ids + .get(&stable_crate_id) + .unwrap_or_else(|| bug!("uninterned StableCrateId: {stable_crate_id:?}")) } /// Returns the `DefKey` for a given `DefId`. This indicates the diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index ef3eda584e1..2652a4280d3 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -27,7 +27,7 @@ use rustc_middle::mir::interpret; use rustc_middle::query::LocalCrate; use rustc_middle::traits::specialization_graph; use rustc_middle::ty::codec::TyEncoder; -use rustc_middle::ty::fast_reject::{self, SimplifiedType, TreatParams, TreatProjections}; +use rustc_middle::ty::fast_reject::{self, SimplifiedType, TreatParams}; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, SymbolName, Ty, TyCtxt}; use rustc_middle::util::common::to_readable_str; @@ -681,17 +681,15 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { has_global_allocator: tcx.has_global_allocator(LOCAL_CRATE), has_alloc_error_handler: tcx.has_alloc_error_handler(LOCAL_CRATE), has_panic_handler: tcx.has_panic_handler(LOCAL_CRATE), - has_default_lib_allocator: tcx - .sess - .contains_name(&attrs, sym::default_lib_allocator), + has_default_lib_allocator: attr::contains_name(&attrs, sym::default_lib_allocator), proc_macro_data, debugger_visualizers, - compiler_builtins: tcx.sess.contains_name(&attrs, sym::compiler_builtins), - needs_allocator: tcx.sess.contains_name(&attrs, sym::needs_allocator), - needs_panic_runtime: tcx.sess.contains_name(&attrs, sym::needs_panic_runtime), - no_builtins: tcx.sess.contains_name(&attrs, sym::no_builtins), - panic_runtime: tcx.sess.contains_name(&attrs, sym::panic_runtime), - profiler_runtime: tcx.sess.contains_name(&attrs, sym::profiler_runtime), + compiler_builtins: attr::contains_name(&attrs, sym::compiler_builtins), + needs_allocator: attr::contains_name(&attrs, sym::needs_allocator), + needs_panic_runtime: attr::contains_name(&attrs, sym::needs_panic_runtime), + no_builtins: attr::contains_name(&attrs, sym::no_builtins), + panic_runtime: attr::contains_name(&attrs, sym::panic_runtime), + profiler_runtime: attr::contains_name(&attrs, sym::profiler_runtime), symbol_mangling_version: tcx.sess.opts.get_symbol_mangling_version(), crate_deps, @@ -1016,7 +1014,6 @@ fn should_encode_type(tcx: TyCtxt<'_>, def_id: LocalDefId, def_kind: DefKind) -> | DefKind::Const | DefKind::Static(..) | DefKind::TyAlias - | DefKind::OpaqueTy | DefKind::ForeignTy | DefKind::Impl { .. } | DefKind::AssocFn @@ -1027,6 +1024,18 @@ fn should_encode_type(tcx: TyCtxt<'_>, def_id: LocalDefId, def_kind: DefKind) -> | DefKind::AnonConst | DefKind::InlineConst => true, + DefKind::OpaqueTy => { + let opaque = tcx.hir().expect_item(def_id).expect_opaque_ty(); + if let hir::OpaqueTyOrigin::FnReturn(fn_def_id) | hir::OpaqueTyOrigin::AsyncFn(fn_def_id) = opaque.origin + && let hir::Node::TraitItem(trait_item) = tcx.hir().get_by_def_id(fn_def_id) + && let (_, hir::TraitFn::Required(..)) = trait_item.expect_fn() + { + false + } else { + true + } + } + DefKind::ImplTraitPlaceholder => { let parent_def_id = tcx.impl_trait_in_trait_parent_fn(def_id.to_def_id()); let assoc_item = tcx.associated_item(parent_def_id); @@ -1044,7 +1053,13 @@ fn should_encode_type(tcx: TyCtxt<'_>, def_id: LocalDefId, def_kind: DefKind) -> let assoc_item = tcx.associated_item(def_id); match assoc_item.container { ty::AssocItemContainer::ImplContainer => true, - ty::AssocItemContainer::TraitContainer => assoc_item.defaultness(tcx).has_value(), + // FIXME(-Zlower-impl-trait-in-trait-to-assoc-ty) always encode RPITITs, + // since we need to be able to "project" from an RPITIT associated item + // to an opaque when installing the default projection predicates in + // default trait methods with RPITITs. + ty::AssocItemContainer::TraitContainer => { + assoc_item.defaultness(tcx).has_value() || assoc_item.opt_rpitit_info.is_some() + } } } DefKind::TyParam => { @@ -1730,11 +1745,11 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { // Proc-macros may have attributes like `#[allow_internal_unstable]`, // so downstream crates need access to them. let attrs = hir.attrs(proc_macro); - let macro_kind = if tcx.sess.contains_name(attrs, sym::proc_macro) { + let macro_kind = if attr::contains_name(attrs, sym::proc_macro) { MacroKind::Bang - } else if tcx.sess.contains_name(attrs, sym::proc_macro_attribute) { + } else if attr::contains_name(attrs, sym::proc_macro_attribute) { MacroKind::Attr - } else if let Some(attr) = tcx.sess.find_by_name(attrs, sym::proc_macro_derive) { + } else if let Some(attr) = attr::find_by_name(attrs, sym::proc_macro_derive) { // This unwrap chain should have been checked by the proc-macro harness. name = attr.meta_item_list().unwrap()[0] .meta_item() @@ -1866,7 +1881,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.tcx, trait_ref.self_ty(), TreatParams::AsCandidateKey, - TreatProjections::AsCandidateKey, ); fx_hash_map diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index 72907fba5e6..9f16ecbdaa9 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -36,7 +36,7 @@ macro_rules! arena_types { )>, [] output_filenames: std::sync::Arc<rustc_session::config::OutputFilenames>, [] metadata_loader: rustc_data_structures::steal::Steal<Box<rustc_session::cstore::MetadataLoaderDyn>>, - [] crate_for_resolver: rustc_data_structures::steal::Steal<rustc_ast::ast::Crate>, + [] crate_for_resolver: rustc_data_structures::steal::Steal<(rustc_ast::Crate, rustc_ast::AttrVec)>, [] resolutions: rustc_middle::ty::ResolverGlobalCtxt, [decode] unsafety_check_result: rustc_middle::mir::UnsafetyCheckResult, [decode] code_region: rustc_middle::mir::coverage::CodeRegion, diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index b2bae47054c..89a485b47ca 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -188,7 +188,7 @@ impl<'hir> Map<'hir> { ItemKind::Macro(_, macro_kind) => DefKind::Macro(macro_kind), ItemKind::Mod(..) => DefKind::Mod, ItemKind::OpaqueTy(ref opaque) => { - if opaque.in_trait { + if opaque.in_trait && !self.tcx.lower_impl_trait_in_trait_to_assoc_ty() { DefKind::ImplTraitPlaceholder } else { DefKind::OpaqueTy diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 638c082cc84..9c575f6eb9f 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -1967,7 +1967,8 @@ impl<'tcx> Rvalue<'tcx> { | CastKind::PtrToPtr | CastKind::Pointer(_) | CastKind::PointerFromExposedAddress - | CastKind::DynStar, + | CastKind::DynStar + | CastKind::Transmute, _, _, ) diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index d85d68870d7..786c2e9cd94 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -2,8 +2,8 @@ use crate::mir::{Body, ConstantKind, Promoted}; use crate::ty::{self, OpaqueHiddenType, Ty, TyCtxt}; +use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::unord::UnordSet; -use rustc_data_structures::vec_map::VecMap; use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; @@ -227,7 +227,7 @@ pub struct BorrowCheckResult<'tcx> { /// All the opaque types that are restricted to concrete types /// by this function. Unlike the value in `TypeckResults`, this has /// unerased regions. - pub concrete_opaque_types: VecMap<LocalDefId, OpaqueHiddenType<'tcx>>, + pub concrete_opaque_types: FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>>, pub closure_requirements: Option<ClosureRegionRequirements<'tcx>>, pub used_mut_upvars: SmallVec<[Field; 8]>, pub tainted_by_errors: Option<ErrorGuaranteed>, diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index 3a893cdabf6..bbd913d071d 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -1156,6 +1156,13 @@ pub enum CastKind { IntToFloat, PtrToPtr, FnPtrToPtr, + /// Reinterpret the bits of the input as a different type. + /// + /// MIR is well-formed if the input and output types have different sizes, + /// but running a transmute between differently-sized types is UB. + /// + /// Allowed only in [`MirPhase::Runtime`]; Earlier it's a [`TerminatorKind::Call`]. + Transmute, } #[derive(Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)] diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index f740ec51080..9203dd59a7e 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -2116,7 +2116,7 @@ rustc_queries! { desc { "raw operations for metadata file access" } } - query crate_for_resolver((): ()) -> &'tcx Steal<rustc_ast::ast::Crate> { + query crate_for_resolver((): ()) -> &'tcx Steal<(rustc_ast::Crate, rustc_ast::AttrVec)> { feedable no_hash desc { "the ast before macro expansion and name resolution" } diff --git a/compiler/rustc_middle/src/traits/solve.rs b/compiler/rustc_middle/src/traits/solve.rs index 92d3e73e683..512d67f34b9 100644 --- a/compiler/rustc_middle/src/traits/solve.rs +++ b/compiler/rustc_middle/src/traits/solve.rs @@ -63,15 +63,14 @@ impl Certainty { (Certainty::Yes, Certainty::Yes) => Certainty::Yes, (Certainty::Yes, Certainty::Maybe(_)) => other, (Certainty::Maybe(_), Certainty::Yes) => self, - (Certainty::Maybe(MaybeCause::Overflow), Certainty::Maybe(MaybeCause::Overflow)) => { - Certainty::Maybe(MaybeCause::Overflow) - } - // If at least one of the goals is ambiguous, hide the overflow as the ambiguous goal - // may still result in failure. - (Certainty::Maybe(MaybeCause::Ambiguity), Certainty::Maybe(_)) - | (Certainty::Maybe(_), Certainty::Maybe(MaybeCause::Ambiguity)) => { + (Certainty::Maybe(MaybeCause::Ambiguity), Certainty::Maybe(MaybeCause::Ambiguity)) => { Certainty::Maybe(MaybeCause::Ambiguity) } + (Certainty::Maybe(MaybeCause::Ambiguity), Certainty::Maybe(MaybeCause::Overflow)) + | (Certainty::Maybe(MaybeCause::Overflow), Certainty::Maybe(MaybeCause::Ambiguity)) + | (Certainty::Maybe(MaybeCause::Overflow), Certainty::Maybe(MaybeCause::Overflow)) => { + Certainty::Maybe(MaybeCause::Overflow) + } } } } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 65376335398..a1c1acc4a25 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -28,7 +28,7 @@ use crate::ty::{ TraitObjectVisitor, Ty, TyKind, TyVar, TyVid, TypeAndMut, TypeckResults, UintTy, Visibility, }; use crate::ty::{GenericArg, InternalSubsts, SubstsRef}; -use rustc_ast as ast; +use rustc_ast::{self as ast, attr}; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::intern::Interned; @@ -2520,9 +2520,9 @@ pub fn provide(providers: &mut ty::query::Providers) { providers.extern_mod_stmt_cnum = |tcx, id| tcx.resolutions(()).extern_crate_map.get(&id).cloned(); providers.is_panic_runtime = - |tcx, LocalCrate| tcx.sess.contains_name(tcx.hir().krate_attrs(), sym::panic_runtime); + |tcx, LocalCrate| attr::contains_name(tcx.hir().krate_attrs(), sym::panic_runtime); providers.is_compiler_builtins = - |tcx, LocalCrate| tcx.sess.contains_name(tcx.hir().krate_attrs(), sym::compiler_builtins); + |tcx, LocalCrate| attr::contains_name(tcx.hir().krate_attrs(), sym::compiler_builtins); providers.has_panic_handler = |tcx, LocalCrate| { // We want to check if the panic handler was defined in this crate tcx.lang_items().panic_impl().map_or(false, |did| did.is_local()) diff --git a/compiler/rustc_middle/src/ty/fast_reject.rs b/compiler/rustc_middle/src/ty/fast_reject.rs index ee505742be9..669d50a7fda 100644 --- a/compiler/rustc_middle/src/ty/fast_reject.rs +++ b/compiler/rustc_middle/src/ty/fast_reject.rs @@ -56,7 +56,15 @@ pub enum TreatParams { AsCandidateKey, /// Treat parameters as placeholders in the given environment. This is the /// correct mode for *lookup*, as during candidate selection. + /// + /// This also treats projections with inference variables as infer vars + /// since they could be further normalized. ForLookup, + /// Treat parameters as placeholders in the given environment. This is the + /// correct mode for *lookup*, as during candidate selection. + /// + /// N.B. during deep rejection, this acts identically to `ForLookup`. + NextSolverLookup, } /// During fast-rejection, we have the choice of treating projection types @@ -64,13 +72,6 @@ pub enum TreatParams { /// to be normalized/rigid. #[derive(PartialEq, Eq, Debug, Clone, Copy)] pub enum TreatProjections { - /// In candidates, we may be able to normalize the projection - /// after instantiating the candidate and equating it with a goal. - /// - /// We must assume that the `impl<T> Trait<T> for <T as Id>::This` - /// can apply to all self types so we don't return a simplified type - /// for `<T as Id>::This`. - AsCandidateKey, /// In the old solver we don't try to normalize projections /// when looking up impls and only access them by using the /// current self type. This means that if the self type is @@ -107,7 +108,6 @@ pub fn simplify_type<'tcx>( tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, treat_params: TreatParams, - treat_projections: TreatProjections, ) -> Option<SimplifiedType> { match *ty.kind() { ty::Bool => Some(BoolSimplifiedType), @@ -136,13 +136,20 @@ pub fn simplify_type<'tcx>( ty::FnPtr(f) => Some(FunctionSimplifiedType(f.skip_binder().inputs().len())), ty::Placeholder(..) => Some(PlaceholderSimplifiedType), ty::Param(_) => match treat_params { - TreatParams::ForLookup => Some(PlaceholderSimplifiedType), + TreatParams::ForLookup | TreatParams::NextSolverLookup => { + Some(PlaceholderSimplifiedType) + } TreatParams::AsCandidateKey => None, }, - ty::Alias(..) => match treat_projections { - TreatProjections::ForLookup if !ty.needs_infer() => Some(PlaceholderSimplifiedType), - TreatProjections::NextSolverLookup => Some(PlaceholderSimplifiedType), - TreatProjections::AsCandidateKey | TreatProjections::ForLookup => None, + ty::Alias(..) => match treat_params { + // When treating `ty::Param` as a placeholder, projections also + // don't unify with anything else as long as they are fully normalized. + // + // We will have to be careful with lazy normalization here. + // FIXME(lazy_normalization): This is probably not right... + TreatParams::ForLookup if !ty.has_non_region_infer() => Some(PlaceholderSimplifiedType), + TreatParams::NextSolverLookup => Some(PlaceholderSimplifiedType), + TreatParams::ForLookup | TreatParams::AsCandidateKey => None, }, ty::Foreign(def_id) => Some(ForeignSimplifiedType(def_id)), ty::Bound(..) | ty::Infer(_) | ty::Error(_) => None, @@ -310,7 +317,7 @@ impl DeepRejectCtxt { // Depending on the value of `treat_obligation_params`, we either // treat generic parameters like placeholders or like inference variables. ty::Param(_) => match self.treat_obligation_params { - TreatParams::ForLookup => false, + TreatParams::ForLookup | TreatParams::NextSolverLookup => false, TreatParams::AsCandidateKey => true, }, @@ -348,7 +355,7 @@ impl DeepRejectCtxt { let k = impl_ct.kind(); match obligation_ct.kind() { ty::ConstKind::Param(_) => match self.treat_obligation_params { - TreatParams::ForLookup => false, + TreatParams::ForLookup | TreatParams::NextSolverLookup => false, TreatParams::AsCandidateKey => true, }, diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs index 91241ff404f..5a6ee123811 100644 --- a/compiler/rustc_middle/src/ty/flags.rs +++ b/compiler/rustc_middle/src/ty/flags.rs @@ -288,7 +288,7 @@ impl FlagComputation { self.add_ty(ty); } ty::PredicateKind::Ambiguous => {} - ty::PredicateKind::AliasEq(t1, t2) => { + ty::PredicateKind::AliasRelate(t1, t2, _) => { self.add_term(t1); self.add_term(t2); } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index d383a413208..e3cd5cca785 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -543,7 +543,7 @@ impl<'tcx> Predicate<'tcx> { | PredicateKind::Clause(Clause::TypeOutlives(_)) | PredicateKind::Clause(Clause::Projection(_)) | PredicateKind::Clause(Clause::ConstArgHasType(..)) - | PredicateKind::AliasEq(..) + | PredicateKind::AliasRelate(..) | PredicateKind::ObjectSafe(_) | PredicateKind::ClosureKind(_, _, _) | PredicateKind::Subtype(_) @@ -640,7 +640,23 @@ pub enum PredicateKind<'tcx> { /// This predicate requires two terms to be equal to eachother. /// /// Only used for new solver - AliasEq(Term<'tcx>, Term<'tcx>), + AliasRelate(Term<'tcx>, Term<'tcx>, AliasRelationDirection), +} + +#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable)] +#[derive(HashStable, Debug)] +pub enum AliasRelationDirection { + Equate, + Subtype, +} + +impl std::fmt::Display for AliasRelationDirection { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + AliasRelationDirection::Equate => write!(f, " == "), + AliasRelationDirection::Subtype => write!(f, " <: "), + } + } } /// The crate outlives map is computed during typeck and contains the @@ -976,11 +992,11 @@ impl<'tcx> Term<'tcx> { } } - /// This function returns `None` for `AliasKind::Opaque`. + /// This function returns the inner `AliasTy` if this term is a projection. /// /// FIXME: rename `AliasTy` to `AliasTerm` and make sure we correctly /// deal with constants. - pub fn to_alias_term_no_opaque(&self, tcx: TyCtxt<'tcx>) -> Option<AliasTy<'tcx>> { + pub fn to_projection_term(&self, tcx: TyCtxt<'tcx>) -> Option<AliasTy<'tcx>> { match self.unpack() { TermKind::Ty(ty) => match ty.kind() { ty::Alias(kind, alias_ty) => match kind { @@ -1035,6 +1051,21 @@ impl<'tcx> TermKind<'tcx> { } } +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub enum ParamTerm { + Ty(ParamTy), + Const(ParamConst), +} + +impl ParamTerm { + pub fn index(self) -> usize { + match self { + ParamTerm::Ty(ty) => ty.index as usize, + ParamTerm::Const(ct) => ct.index as usize, + } + } +} + /// This kind of predicate has no *direct* correspondent in the /// syntax, but it roughly corresponds to the syntactic forms: /// @@ -1206,7 +1237,7 @@ impl<'tcx> Predicate<'tcx> { PredicateKind::Clause(Clause::Trait(t)) => Some(predicate.rebind(t)), PredicateKind::Clause(Clause::Projection(..)) | PredicateKind::Clause(Clause::ConstArgHasType(..)) - | PredicateKind::AliasEq(..) + | PredicateKind::AliasRelate(..) | PredicateKind::Subtype(..) | PredicateKind::Coerce(..) | PredicateKind::Clause(Clause::RegionOutlives(..)) @@ -1227,7 +1258,7 @@ impl<'tcx> Predicate<'tcx> { PredicateKind::Clause(Clause::Projection(t)) => Some(predicate.rebind(t)), PredicateKind::Clause(Clause::Trait(..)) | PredicateKind::Clause(Clause::ConstArgHasType(..)) - | PredicateKind::AliasEq(..) + | PredicateKind::AliasRelate(..) | PredicateKind::Subtype(..) | PredicateKind::Coerce(..) | PredicateKind::Clause(Clause::RegionOutlives(..)) @@ -1249,7 +1280,7 @@ impl<'tcx> Predicate<'tcx> { PredicateKind::Clause(Clause::Trait(..)) | PredicateKind::Clause(Clause::ConstArgHasType(..)) | PredicateKind::Clause(Clause::Projection(..)) - | PredicateKind::AliasEq(..) + | PredicateKind::AliasRelate(..) | PredicateKind::Subtype(..) | PredicateKind::Coerce(..) | PredicateKind::Clause(Clause::RegionOutlives(..)) @@ -2525,7 +2556,7 @@ impl<'tcx> TyCtxt<'tcx> { ident } - // FIXME(vincenzoapalzzo): move the HirId to a LocalDefId + // FIXME(vincenzopalazzo): move the HirId to a LocalDefId pub fn adjust_ident_and_get_scope( self, mut ident: Ident, diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index fffdbfc9660..de4c703107e 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -704,7 +704,11 @@ pub trait PrettyPrinter<'tcx>: ty::BoundTyKind::Anon(bv) => { self.pretty_print_bound_var(debruijn, ty::BoundVar::from_u32(bv))? } - ty::BoundTyKind::Param(_, s) => p!(write("{}", s)), + ty::BoundTyKind::Param(_, s) => match self.should_print_verbose() { + true if debruijn == ty::INNERMOST => p!(write("^{}", s)), + true => p!(write("^{}_{}", debruijn.index(), s)), + false => p!(write("{}", s)), + }, }, ty::Adt(def, substs) => { p!(print_def_path(def.did(), substs)); @@ -2847,7 +2851,7 @@ define_print_and_forward_display! { p!("the type `", print(ty), "` is found in the environment") } ty::PredicateKind::Ambiguous => p!("ambiguous"), - ty::PredicateKind::AliasEq(t1, t2) => p!(print(t1), " == ", print(t2)), + ty::PredicateKind::AliasRelate(t1, t2, dir) => p!(print(t1), write(" {} ", dir), print(t2)), } } diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index ef643531bb2..c6bb8146795 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -177,7 +177,9 @@ impl<'tcx> fmt::Debug for ty::PredicateKind<'tcx> { write!(f, "TypeWellFormedFromEnv({:?})", ty) } ty::PredicateKind::Ambiguous => write!(f, "Ambiguous"), - ty::PredicateKind::AliasEq(t1, t2) => write!(f, "AliasEq({t1:?}, {t2:?})"), + ty::PredicateKind::AliasRelate(t1, t2, dir) => { + write!(f, "AliasRelate({t1:?}, {dir:?}, {t2:?})") + } } } } @@ -250,6 +252,7 @@ TrivialTypeTraversalAndLiftImpls! { crate::ty::AssocItem, crate::ty::AssocKind, crate::ty::AliasKind, + crate::ty::AliasRelationDirection, crate::ty::Placeholder<crate::ty::BoundRegionKind>, crate::ty::Placeholder<crate::ty::BoundTyKind>, crate::ty::ClosureKind, diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 2a0536a1af7..35a581d314c 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1926,11 +1926,6 @@ impl<'tcx> Ty<'tcx> { } #[inline] - pub fn is_region_ptr(self) -> bool { - matches!(self.kind(), Ref(..)) - } - - #[inline] pub fn is_mutable_ptr(self) -> bool { matches!( self.kind(), @@ -1956,7 +1951,7 @@ impl<'tcx> Ty<'tcx> { /// Tests if this is any kind of primitive pointer type (reference, raw pointer, fn pointer). #[inline] pub fn is_any_ptr(self) -> bool { - self.is_region_ptr() || self.is_unsafe_ptr() || self.is_fn_ptr() + self.is_ref() || self.is_unsafe_ptr() || self.is_fn_ptr() } #[inline] diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs index bf2b121f704..6747da7abd3 100644 --- a/compiler/rustc_middle/src/ty/trait_def.rs +++ b/compiler/rustc_middle/src/ty/trait_def.rs @@ -153,12 +153,7 @@ impl<'tcx> TyCtxt<'tcx> { self_ty: Ty<'tcx>, ) -> impl Iterator<Item = DefId> + 'tcx { let impls = self.trait_impls_of(trait_def_id); - if let Some(simp) = fast_reject::simplify_type( - self, - self_ty, - TreatParams::AsCandidateKey, - TreatProjections::AsCandidateKey, - ) { + if let Some(simp) = fast_reject::simplify_type(self, self_ty, TreatParams::AsCandidateKey) { if let Some(impls) = impls.non_blanket_impls.get(&simp) { return impls.iter().copied(); } @@ -191,13 +186,17 @@ impl<'tcx> TyCtxt<'tcx> { } } + // Note that we're using `TreatParams::ForLookup` to query `non_blanket_impls` while using + // `TreatParams::AsCandidateKey` while actually adding them. + let treat_params = match treat_projections { + TreatProjections::NextSolverLookup => TreatParams::NextSolverLookup, + TreatProjections::ForLookup => TreatParams::ForLookup, + }; // This way, when searching for some impl for `T: Trait`, we do not look at any impls // whose outer level is not a parameter or projection. Especially for things like // `T: Clone` this is incredibly useful as we would otherwise look at all the impls // of `Clone` for `Option<T>`, `Vec<T>`, `ConcreteType` and so on. - if let Some(simp) = - fast_reject::simplify_type(self, self_ty, TreatParams::ForLookup, treat_projections) - { + if let Some(simp) = fast_reject::simplify_type(self, self_ty, treat_params) { if let Some(impls) = impls.non_blanket_impls.get(&simp) { for &impl_def_id in impls { if let result @ Some(_) = f(impl_def_id) { @@ -258,12 +257,9 @@ pub(super) fn trait_impls_of_provider(tcx: TyCtxt<'_>, trait_id: DefId) -> Trait continue; } - if let Some(simplified_self_ty) = fast_reject::simplify_type( - tcx, - impl_self_ty, - TreatParams::AsCandidateKey, - TreatProjections::AsCandidateKey, - ) { + if let Some(simplified_self_ty) = + fast_reject::simplify_type(tcx, impl_self_ty, TreatParams::AsCandidateKey) + { impls.non_blanket_impls.entry(simplified_self_ty).or_default().push(impl_def_id); } else { impls.blanket_impls.push(impl_def_id); diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs index 586958247fc..2b0fb4dc2b7 100644 --- a/compiler/rustc_middle/src/ty/typeck_results.rs +++ b/compiler/rustc_middle/src/ty/typeck_results.rs @@ -8,10 +8,9 @@ use crate::{ }, }; use rustc_data_structures::{ - fx::FxHashMap, + fx::{FxHashMap, FxIndexMap}, sync::Lrc, unord::{UnordItems, UnordSet}, - vec_map::VecMap, }; use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; @@ -155,7 +154,7 @@ pub struct TypeckResults<'tcx> { /// by this function. We also store the /// type here, so that mir-borrowck can use it as a hint for figuring out hidden types, /// even if they are only set in dead code (which doesn't show up in MIR). - pub concrete_opaque_types: VecMap<LocalDefId, ty::OpaqueHiddenType<'tcx>>, + pub concrete_opaque_types: FxIndexMap<LocalDefId, ty::OpaqueHiddenType<'tcx>>, /// Tracks the minimum captures required for a closure; /// see `MinCaptureInformationMap` for more details. diff --git a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs index adbd37a7cd9..bf58b3090fb 100644 --- a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs +++ b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs @@ -137,6 +137,10 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> { fn parse_rvalue(&self, expr_id: ExprId) -> PResult<Rvalue<'tcx>> { parse_by_kind!(self, expr_id, expr, "rvalue", @call("mir_discriminant", args) => self.parse_place(args[0]).map(Rvalue::Discriminant), + @call("mir_cast_transmute", args) => { + let source = self.parse_operand(args[0])?; + Ok(Rvalue::Cast(CastKind::Transmute, source, expr.ty)) + }, @call("mir_checked", args) => { parse_by_kind!(self, args[0], _, "binary op", ExprKind::Binary { op, lhs, rhs } => Ok(Rvalue::CheckedBinaryOp( diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs index 140d1154718..3b775f590a4 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs @@ -566,41 +566,51 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Rvalue::Use(Operand::Move(val)) } BinOp::Shl | BinOp::Shr if self.check_overflow && ty.is_integral() => { - // Consider that the shift overflows if `rhs < 0` or `rhs >= bits`. - // This can be encoded as a single operation as `(rhs & -bits) != 0`. - let (size, _) = ty.int_size_and_signed(self.tcx); - let bits = size.bits(); - debug_assert!(bits.is_power_of_two()); - let mask = !((bits - 1) as u128); - + // For an unsigned RHS, the shift is in-range for `rhs < bits`. + // For a signed RHS, `IntToInt` cast to the equivalent unsigned + // type and do that same comparison. Because the type is the + // same size, there's no negative shift amount that ends up + // overlapping with valid ones, thus it catches negatives too. + let (lhs_size, _) = ty.int_size_and_signed(self.tcx); let rhs_ty = rhs.ty(&self.local_decls, self.tcx); let (rhs_size, _) = rhs_ty.int_size_and_signed(self.tcx); - let mask = Operand::const_from_scalar( + + let (unsigned_rhs, unsigned_ty) = match rhs_ty.kind() { + ty::Uint(_) => (rhs.to_copy(), rhs_ty), + ty::Int(int_width) => { + let uint_ty = self.tcx.mk_mach_uint(int_width.to_unsigned()); + let rhs_temp = self.temp(uint_ty, span); + self.cfg.push_assign( + block, + source_info, + rhs_temp, + Rvalue::Cast(CastKind::IntToInt, rhs.to_copy(), uint_ty), + ); + (Operand::Move(rhs_temp), uint_ty) + } + _ => unreachable!("only integers are shiftable"), + }; + + // This can't overflow because the largest shiftable types are 128-bit, + // which fits in `u8`, the smallest possible `unsigned_ty`. + // (And `from_uint` will `bug!` if that's ever no longer true.) + let lhs_bits = Operand::const_from_scalar( self.tcx, - rhs_ty, - Scalar::from_uint(rhs_size.truncate(mask), rhs_size), + unsigned_ty, + Scalar::from_uint(lhs_size.bits(), rhs_size), span, ); - let outer_bits = self.temp(rhs_ty, span); - self.cfg.push_assign( - block, - source_info, - outer_bits, - Rvalue::BinaryOp(BinOp::BitAnd, Box::new((rhs.to_copy(), mask))), - ); - - let overflows = self.temp(bool_ty, span); - let zero = self.zero_literal(span, rhs_ty); + let inbounds = self.temp(bool_ty, span); self.cfg.push_assign( block, source_info, - overflows, - Rvalue::BinaryOp(BinOp::Ne, Box::new((Operand::Move(outer_bits), zero))), + inbounds, + Rvalue::BinaryOp(BinOp::Lt, Box::new((unsigned_rhs, lhs_bits))), ); let overflow_err = AssertKind::Overflow(op, lhs.to_copy(), rhs.to_copy()); - block = self.assert(block, Operand::Move(overflows), false, overflow_err, span); + block = self.assert(block, Operand::Move(inbounds), true, overflow_err, span); Rvalue::BinaryOp(op, Box::new((lhs, rhs))) } BinOp::Div | BinOp::Rem if ty.is_integral() => { diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index 80d8b27336c..1923e10ddb5 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -3,6 +3,7 @@ use crate::build::expr::as_place::PlaceBuilder; use crate::build::scope::DropKind; use rustc_apfloat::ieee::{Double, Single}; use rustc_apfloat::Float; +use rustc_ast::attr; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sorted_map::SortedIndexMultiMap; use rustc_errors::ErrorGuaranteed; @@ -680,7 +681,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Some functions always have overflow checks enabled, // however, they may not get codegen'd, depending on // the settings for the crate they are codegened in. - let mut check_overflow = tcx.sess.contains_name(attrs, sym::rustc_inherit_overflow_checks); + let mut check_overflow = attr::contains_name(attrs, sym::rustc_inherit_overflow_checks); // Respect -C overflow-checks. check_overflow |= tcx.sess.overflow_checks(); // Constants always need overflow checks. diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index cecb8a61aa2..6fd9b9dbb57 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -185,7 +185,7 @@ impl<'tcx> Cx<'tcx> { if self.typeck_results().is_coercion_cast(source.hir_id) { // Convert the lexpr to a vexpr. ExprKind::Use { source: self.mirror_expr(source) } - } else if self.typeck_results().expr_ty(source).is_region_ptr() { + } else if self.typeck_results().expr_ty(source).is_ref() { // Special cased so that we can type check that the element // type of the source matches the pointed to type of the // destination. diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs index bebd9723740..c1cf6ee0f9e 100644 --- a/compiler/rustc_mir_transform/src/const_prop.rs +++ b/compiler/rustc_mir_transform/src/const_prop.rs @@ -180,7 +180,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx> } #[inline(always)] - fn enforce_validity(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool { + fn enforce_validity(_ecx: &InterpCx<'mir, 'tcx, Self>, _layout: TyAndLayout<'tcx>) -> bool { false // for now, we don't enforce validity } fn alignment_check_failed( @@ -504,6 +504,15 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { return None; } + // Do not try creating references, nor any types with potentially-complex + // invariants. This avoids an issue where checking validity would do a + // bunch of work generating a nice message about the invariant violation, + // only to not show it to anyone (since this isn't the lint). + Rvalue::Cast(CastKind::Transmute, op, dst_ty) if !dst_ty.is_primitive() => { + trace!("skipping Transmute of {:?} to {:?}", op, dst_ty); + + return None; + } // There's no other checking to do at this time. Rvalue::Aggregate(..) diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index 49ded10ba1f..a7218a4f250 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -8,6 +8,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_hir::def::DefKind; use rustc_middle::mir::visit::{MutVisitor, Visitor}; use rustc_middle::mir::*; +use rustc_middle::ty::layout::TyAndLayout; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_mir_dataflow::value_analysis::{Map, State, TrackElem, ValueAnalysis, ValueOrPlace}; use rustc_mir_dataflow::{lattice::FlatSet, Analysis, ResultsVisitor, SwitchIntEdgeEffects}; @@ -548,7 +549,7 @@ impl<'mir, 'tcx> rustc_const_eval::interpret::Machine<'mir, 'tcx> for DummyMachi unimplemented!() } - fn enforce_validity(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool { + fn enforce_validity(_ecx: &InterpCx<'mir, 'tcx, Self>, _layout: TyAndLayout<'tcx>) -> bool { unimplemented!() } fn alignment_check_failed( diff --git a/compiler/rustc_mir_transform/src/lower_intrinsics.rs b/compiler/rustc_mir_transform/src/lower_intrinsics.rs index 5d7382305ae..6a7ceb8fef7 100644 --- a/compiler/rustc_mir_transform/src/lower_intrinsics.rs +++ b/compiler/rustc_mir_transform/src/lower_intrinsics.rs @@ -6,6 +6,7 @@ use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::symbol::{sym, Symbol}; use rustc_span::Span; +use rustc_target::abi::VariantIdx; pub struct LowerIntrinsics; @@ -191,6 +192,61 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics { terminator.kind = TerminatorKind::Goto { target }; } } + sym::option_payload_ptr => { + if let (Some(target), Some(arg)) = (*target, args[0].place()) { + let ty::RawPtr(ty::TypeAndMut { ty: dest_ty, .. }) = + destination.ty(local_decls, tcx).ty.kind() + else { bug!(); }; + + block.statements.push(Statement { + source_info: terminator.source_info, + kind: StatementKind::Assign(Box::new(( + *destination, + Rvalue::AddressOf( + Mutability::Not, + arg.project_deeper( + &[ + PlaceElem::Deref, + PlaceElem::Downcast( + Some(sym::Some), + VariantIdx::from_u32(1), + ), + PlaceElem::Field(Field::from_u32(0), *dest_ty), + ], + tcx, + ), + ), + ))), + }); + terminator.kind = TerminatorKind::Goto { target }; + } + } + sym::transmute => { + let dst_ty = destination.ty(local_decls, tcx).ty; + let Ok([arg]) = <[_; 1]>::try_from(std::mem::take(args)) else { + span_bug!( + terminator.source_info.span, + "Wrong number of arguments for transmute intrinsic", + ); + }; + + // Always emit the cast, even if we transmute to an uninhabited type, + // because that lets CTFE and codegen generate better error messages + // when such a transmute actually ends up reachable. + block.statements.push(Statement { + source_info: terminator.source_info, + kind: StatementKind::Assign(Box::new(( + *destination, + Rvalue::Cast(CastKind::Transmute, arg, dst_ty), + ))), + }); + + if let Some(target) = *target { + terminator.kind = TerminatorKind::Goto { target }; + } else { + terminator.kind = TerminatorKind::Unreachable; + } + } _ if intrinsic_name.as_str().starts_with("simd_shuffle") => { validate_simd_shuffle(tcx, args, terminator.source_info.span); } diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index c39ada95a4e..96765c296e7 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -336,7 +336,7 @@ parse_expected_identifier_found_reserved_keyword = expected identifier, found re parse_expected_identifier_found_doc_comment = expected identifier, found doc comment parse_expected_identifier = expected identifier -parse_sugg_escape_to_use_as_identifier = escape `{$ident_name}` to use it as an identifier +parse_sugg_escape_identifier = escape `{$ident_name}` to use it as an identifier parse_sugg_remove_comma = remove this comma diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index af0c3026c66..a9d116012ae 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -888,12 +888,12 @@ pub(crate) struct InvalidMetaItem { #[derive(Subdiagnostic)] #[suggestion( - parse_sugg_escape_to_use_as_identifier, + parse_sugg_escape_identifier, style = "verbose", applicability = "maybe-incorrect", code = "r#" )] -pub(crate) struct SuggEscapeToUseAsIdentifier { +pub(crate) struct SuggEscapeIdentifier { #[primary_span] pub span: Span, pub ident_name: String, @@ -937,7 +937,7 @@ impl ExpectedIdentifierFound { pub(crate) struct ExpectedIdentifier { pub span: Span, pub token: Token, - pub suggest_raw: Option<SuggEscapeToUseAsIdentifier>, + pub suggest_raw: Option<SuggEscapeIdentifier>, pub suggest_remove_comma: Option<SuggRemoveComma>, pub help_cannot_start_number: Option<HelpIdentifierStartsWithNumber>, } @@ -986,7 +986,10 @@ impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for ExpectedIdentifier { #[derive(Subdiagnostic)] #[help(parse_invalid_identifier_with_leading_number)] -pub(crate) struct HelpIdentifierStartsWithNumber; +pub(crate) struct HelpIdentifierStartsWithNumber { + #[primary_span] + pub num_span: Span, +} pub(crate) struct ExpectedSemi { pub span: Span, diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 5b12bcc1822..9544afd3d6d 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -6,14 +6,14 @@ use super::{ use crate::errors::{ AmbiguousPlus, AttributeOnParamType, BadQPathStage2, BadTypePlus, BadTypePlusSub, ComparisonOperatorsCannotBeChained, ComparisonOperatorsCannotBeChainedSugg, - ConstGenericWithoutBraces, ConstGenericWithoutBracesSugg, DocCommentOnParamType, - DoubleColonInBound, ExpectedIdentifier, ExpectedSemi, ExpectedSemiSugg, + ConstGenericWithoutBraces, ConstGenericWithoutBracesSugg, DocCommentDoesNotDocumentAnything, + DocCommentOnParamType, DoubleColonInBound, ExpectedIdentifier, ExpectedSemi, ExpectedSemiSugg, GenericParamsWithoutAngleBrackets, GenericParamsWithoutAngleBracketsSugg, HelpIdentifierStartsWithNumber, InInTypo, IncorrectAwait, IncorrectSemicolon, IncorrectUseOfAwait, ParenthesesInForHead, ParenthesesInForHeadSugg, PatternMethodParamWithoutBody, QuestionMarkInType, QuestionMarkInTypeSugg, SelfParamNotFirst, StructLiteralBodyWithoutPath, StructLiteralBodyWithoutPathSugg, StructLiteralNeedingParens, - StructLiteralNeedingParensSugg, SuggEscapeToUseAsIdentifier, SuggRemoveComma, + StructLiteralNeedingParensSugg, SuggEscapeIdentifier, SuggRemoveComma, UnexpectedConstInGenericParam, UnexpectedConstParamDeclaration, UnexpectedConstParamDeclarationSugg, UnmatchedAngleBrackets, UseEqInstead, }; @@ -38,7 +38,7 @@ use rustc_errors::{ use rustc_session::errors::ExprParenthesesNeeded; use rustc_span::source_map::Spanned; use rustc_span::symbol::{kw, sym, Ident}; -use rustc_span::{Span, SpanSnippetError, DUMMY_SP}; +use rustc_span::{Span, SpanSnippetError, Symbol, DUMMY_SP}; use std::mem::take; use std::ops::{Deref, DerefMut}; use thin_vec::{thin_vec, ThinVec}; @@ -268,7 +268,21 @@ impl<'a> Parser<'a> { self.sess.source_map().span_to_snippet(span) } - pub(super) fn expected_ident_found(&mut self) -> DiagnosticBuilder<'a, ErrorGuaranteed> { + /// Emits an error with suggestions if an identifier was expected but not found. + /// + /// Returns a possibly recovered identifier. + pub(super) fn expected_ident_found( + &mut self, + recover: bool, + ) -> PResult<'a, (Ident, /* is_raw */ bool)> { + if let TokenKind::DocComment(..) = self.prev_token.kind { + return Err(DocCommentDoesNotDocumentAnything { + span: self.prev_token.span, + missing_comma: None, + } + .into_diagnostic(&self.sess.span_diagnostic)); + } + let valid_follow = &[ TokenKind::Eq, TokenKind::Colon, @@ -281,31 +295,51 @@ impl<'a> Parser<'a> { TokenKind::CloseDelim(Delimiter::Parenthesis), ]; - let suggest_raw = match self.token.ident() { - Some((ident, false)) - if ident.is_raw_guess() - && self.look_ahead(1, |t| valid_follow.contains(&t.kind)) => - { - Some(SuggEscapeToUseAsIdentifier { - span: ident.span.shrink_to_lo(), - // `Symbol::to_string()` is different from `Symbol::into_diagnostic_arg()`, - // which uses `Symbol::to_ident_string()` and "helpfully" adds an implicit `r#` - ident_name: ident.name.to_string(), - }) - } - _ => None, - }; + let mut recovered_ident = None; + // we take this here so that the correct original token is retained in + // the diagnostic, regardless of eager recovery. + let bad_token = self.token.clone(); + + // suggest prepending a keyword in identifier position with `r#` + let suggest_raw = if let Some((ident, false)) = self.token.ident() + && ident.is_raw_guess() + && self.look_ahead(1, |t| valid_follow.contains(&t.kind)) + { + recovered_ident = Some((ident, true)); + + // `Symbol::to_string()` is different from `Symbol::into_diagnostic_arg()`, + // which uses `Symbol::to_ident_string()` and "helpfully" adds an implicit `r#` + let ident_name = ident.name.to_string(); + + Some(SuggEscapeIdentifier { + span: ident.span.shrink_to_lo(), + ident_name + }) + } else { None }; + + let suggest_remove_comma = + if self.token == token::Comma && self.look_ahead(1, |t| t.is_ident()) { + if recover { + self.bump(); + recovered_ident = self.ident_or_err(false).ok(); + }; - let suggest_remove_comma = (self.token == token::Comma - && self.look_ahead(1, |t| t.is_ident())) - .then_some(SuggRemoveComma { span: self.token.span }); + Some(SuggRemoveComma { span: bad_token.span }) + } else { + None + }; - let help_cannot_start_number = - self.is_lit_bad_ident().then_some(HelpIdentifierStartsWithNumber); + let help_cannot_start_number = self.is_lit_bad_ident().map(|(len, valid_portion)| { + let (invalid, valid) = self.token.span.split_at(len as u32); + + recovered_ident = Some((Ident::new(valid_portion, valid), false)); + + HelpIdentifierStartsWithNumber { num_span: invalid } + }); let err = ExpectedIdentifier { - span: self.token.span, - token: self.token.clone(), + span: bad_token.span, + token: bad_token, suggest_raw, suggest_remove_comma, help_cannot_start_number, @@ -314,6 +348,7 @@ impl<'a> Parser<'a> { // if the token we have is a `<` // it *might* be a misplaced generic + // FIXME: could we recover with this? if self.token == token::Lt { // all keywords that could have generic applied let valid_prev_keywords = @@ -364,18 +399,38 @@ impl<'a> Parser<'a> { } } - err + if let Some(recovered_ident) = recovered_ident && recover { + err.emit(); + Ok(recovered_ident) + } else { + Err(err) + } + } + + pub(super) fn expected_ident_found_err(&mut self) -> DiagnosticBuilder<'a, ErrorGuaranteed> { + self.expected_ident_found(false).unwrap_err() } /// Checks if the current token is a integer or float literal and looks like /// it could be a invalid identifier with digits at the start. - pub(super) fn is_lit_bad_ident(&mut self) -> bool { - matches!(self.token.uninterpolate().kind, token::Literal(Lit { kind: token::LitKind::Integer | token::LitKind::Float, .. }) - // ensure that the integer literal is followed by a *invalid* - // suffix: this is how we know that it is a identifier with an - // invalid beginning. - if rustc_ast::MetaItemLit::from_token(&self.token).is_none() - ) + /// + /// Returns the number of characters (bytes) composing the invalid portion + /// of the identifier and the valid portion of the identifier. + pub(super) fn is_lit_bad_ident(&mut self) -> Option<(usize, Symbol)> { + // ensure that the integer literal is followed by a *invalid* + // suffix: this is how we know that it is a identifier with an + // invalid beginning. + if let token::Literal(Lit { + kind: token::LitKind::Integer | token::LitKind::Float, + symbol, + suffix, + }) = self.token.kind + && rustc_ast::MetaItemLit::from_token(&self.token).is_none() + { + Some((symbol.as_str().len(), suffix.unwrap())) + } else { + None + } } pub(super) fn expected_one_of_not_found( diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 85cc8ca02a9..ae8fe90e9d6 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1181,7 +1181,7 @@ impl<'a> Parser<'a> { defaultness: Defaultness, ) -> PResult<'a, ItemInfo> { let impl_span = self.token.span; - let mut err = self.expected_ident_found(); + let mut err = self.expected_ident_found_err(); // Only try to recover if this is implementing a trait for a type let mut impl_info = match self.parse_item_impl(attrs, defaultness) { @@ -1744,7 +1744,7 @@ impl<'a> Parser<'a> { /// Parses a field identifier. Specialized version of `parse_ident_common` /// for better diagnostics and suggestions. fn parse_field_ident(&mut self, adt_ty: &str, lo: Span) -> PResult<'a, Ident> { - let (ident, is_raw) = self.ident_or_err()?; + let (ident, is_raw) = self.ident_or_err(true)?; if !is_raw && ident.is_reserved() { let snapshot = self.create_snapshot_for_diagnostic(); let err = if self.check_fn_front_matter(false, Case::Sensitive) { @@ -1776,7 +1776,7 @@ impl<'a> Parser<'a> { Err(err) => { err.cancel(); self.restore_snapshot(snapshot); - self.expected_ident_found() + self.expected_ident_found_err() } } } else if self.eat_keyword(kw::Struct) { @@ -1792,11 +1792,11 @@ impl<'a> Parser<'a> { Err(err) => { err.cancel(); self.restore_snapshot(snapshot); - self.expected_ident_found() + self.expected_ident_found_err() } } } else { - let mut err = self.expected_ident_found(); + let mut err = self.expected_ident_found_err(); if self.eat_keyword_noexpect(kw::Let) && let removal_span = self.prev_token.span.until(self.token.span) && let Ok(ident) = self.parse_ident_common(false) diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 3251dd6d0c6..53c25a80c4b 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -42,8 +42,7 @@ use thin_vec::ThinVec; use tracing::debug; use crate::errors::{ - DocCommentDoesNotDocumentAnything, IncorrectVisibilityRestriction, MismatchedClosingDelimiter, - NonStringAbiLiteral, + IncorrectVisibilityRestriction, MismatchedClosingDelimiter, NonStringAbiLiteral, }; bitflags::bitflags! { @@ -552,21 +551,11 @@ impl<'a> Parser<'a> { self.parse_ident_common(true) } - fn ident_or_err(&mut self) -> PResult<'a, (Ident, /* is_raw */ bool)> { - self.token.ident().ok_or_else(|| match self.prev_token.kind { - TokenKind::DocComment(..) => DocCommentDoesNotDocumentAnything { - span: self.prev_token.span, - missing_comma: None, - } - .into_diagnostic(&self.sess.span_diagnostic), - _ => self.expected_ident_found(), - }) - } - fn parse_ident_common(&mut self, recover: bool) -> PResult<'a, Ident> { - let (ident, is_raw) = self.ident_or_err()?; + let (ident, is_raw) = self.ident_or_err(recover)?; + if !is_raw && ident.is_reserved() { - let mut err = self.expected_ident_found(); + let mut err = self.expected_ident_found_err(); if recover { err.emit(); } else { @@ -577,6 +566,21 @@ impl<'a> Parser<'a> { Ok(ident) } + fn ident_or_err(&mut self, recover: bool) -> PResult<'a, (Ident, /* is_raw */ bool)> { + let result = self.token.ident().ok_or_else(|| self.expected_ident_found(recover)); + + let (ident, is_raw) = match result { + Ok(ident) => ident, + Err(err) => match err { + // we recovered! + Ok(ident) => ident, + Err(err) => return Err(err), + }, + }; + + Ok((ident, is_raw)) + } + /// Checks if the next token is `tok`, and returns `true` if so. /// /// This method will automatically add `tok` to `expected_tokens` if `tok` is not diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index fc9f1d1330a..2246002f5d3 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -348,10 +348,6 @@ impl<'a> Parser<'a> { lo = self.token.span; } - if self.is_lit_bad_ident() { - return Err(self.expected_ident_found()); - } - let pat = if self.check(&token::BinOp(token::And)) || self.token.kind == token::AndAnd { self.parse_pat_deref(expected)? } else if self.check(&token::OpenDelim(Delimiter::Parenthesis)) { @@ -395,7 +391,13 @@ impl<'a> Parser<'a> { } else { PatKind::Lit(const_expr) } - } else if self.can_be_ident_pat() { + // Don't eagerly error on semantically invalid tokens when matching + // declarative macros, as the input to those doesn't have to be + // semantically valid. For attribute/derive proc macros this is not the + // case, so doing the recovery for them is fine. + } else if self.can_be_ident_pat() + || (self.is_lit_bad_ident().is_some() && self.may_recover()) + { // Parse `ident @ pat` // This can give false positives and parse nullary enums, // they are dealt with later in resolve. @@ -594,7 +596,7 @@ impl<'a> Parser<'a> { // Make sure we don't allow e.g. `let mut $p;` where `$p:pat`. if let token::Interpolated(nt) = &self.token.kind { if let token::NtPat(_) = **nt { - self.expected_ident_found().emit(); + self.expected_ident_found_err().emit(); } } diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 8bed7888142..1c459edabb8 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -1907,7 +1907,7 @@ impl CheckAttrVisitor<'_> { match target { Target::Fn => { for attr in attrs { - if self.tcx.sess.is_proc_macro_attr(attr) { + if attr.is_proc_macro_attr() { debug!("Is proc macro attr"); return true; } diff --git a/compiler/rustc_passes/src/entry.rs b/compiler/rustc_passes/src/entry.rs index b7e6a11998b..f3e683f4b3a 100644 --- a/compiler/rustc_passes/src/entry.rs +++ b/compiler/rustc_passes/src/entry.rs @@ -1,3 +1,4 @@ +use rustc_ast::attr; use rustc_ast::entry::EntryPointType; use rustc_errors::error_code; use rustc_hir::def::DefKind; @@ -37,7 +38,7 @@ fn entry_fn(tcx: TyCtxt<'_>, (): ()) -> Option<(DefId, EntryFnType)> { } // If the user wants no main function at all, then stop here. - if tcx.sess.contains_name(&tcx.hir().attrs(CRATE_HIR_ID), sym::no_main) { + if attr::contains_name(&tcx.hir().attrs(CRATE_HIR_ID), sym::no_main) { return None; } @@ -57,9 +58,9 @@ fn entry_fn(tcx: TyCtxt<'_>, (): ()) -> Option<(DefId, EntryFnType)> { // An equivalent optimization was not applied to the duplicated code in test_harness.rs. fn entry_point_type(ctxt: &EntryContext<'_>, id: ItemId, at_root: bool) -> EntryPointType { let attrs = ctxt.tcx.hir().attrs(id.hir_id()); - if ctxt.tcx.sess.contains_name(attrs, sym::start) { + if attr::contains_name(attrs, sym::start) { EntryPointType::Start - } else if ctxt.tcx.sess.contains_name(attrs, sym::rustc_main) { + } else if attr::contains_name(attrs, sym::rustc_main) { EntryPointType::RustcMainAttr } else { if let Some(name) = ctxt.tcx.opt_item_name(id.owner_id.to_def_id()) @@ -78,7 +79,7 @@ fn entry_point_type(ctxt: &EntryContext<'_>, id: ItemId, at_root: bool) -> Entry fn attr_span_by_symbol(ctxt: &EntryContext<'_>, id: ItemId, sym: Symbol) -> Option<Span> { let attrs = ctxt.tcx.hir().attrs(id.hir_id()); - ctxt.tcx.sess.find_by_name(attrs, sym).map(|attr| attr.span) + attr::find_by_name(attrs, sym).map(|attr| attr.span) } fn find_item(id: ItemId, ctxt: &mut EntryContext<'_>) { diff --git a/compiler/rustc_plugin_impl/src/load.rs b/compiler/rustc_plugin_impl/src/load.rs index 8e75e969ae0..27e5cb9f0d0 100644 --- a/compiler/rustc_plugin_impl/src/load.rs +++ b/compiler/rustc_plugin_impl/src/load.rs @@ -3,7 +3,7 @@ use crate::errors::{LoadPluginError, MalformedPluginAttribute}; use crate::Registry; use libloading::Library; -use rustc_ast::Crate; +use rustc_ast::Attribute; use rustc_metadata::locator; use rustc_session::cstore::MetadataLoader; use rustc_session::Session; @@ -20,11 +20,11 @@ type PluginRegistrarFn = fn(&mut Registry<'_>); pub fn load_plugins( sess: &Session, metadata_loader: &dyn MetadataLoader, - krate: &Crate, + attrs: &[Attribute], ) -> Vec<PluginRegistrarFn> { let mut plugins = Vec::new(); - for attr in &krate.attrs { + for attr in attrs { if !attr.has_name(sym::plugin) { continue; } diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index d884ebd9acc..3be0160d561 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -180,7 +180,7 @@ where | ty::PredicateKind::ConstEquate(_, _) | ty::PredicateKind::TypeWellFormedFromEnv(_) | ty::PredicateKind::Ambiguous - | ty::PredicateKind::AliasEq(_, _) => bug!("unexpected predicate: {:?}", predicate), + | ty::PredicateKind::AliasRelate(..) => bug!("unexpected predicate: {:?}", predicate), } } diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 362ef693c48..19ccb3a6484 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -27,7 +27,6 @@ use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID}; use rustc_metadata::creader::LoadedMacro; use rustc_middle::metadata::ModChild; use rustc_middle::{bug, ty}; -use rustc_session::cstore::CrateStore; use rustc_span::hygiene::{ExpnId, LocalExpnId, MacroKind}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::Span; @@ -115,34 +114,28 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } if !def_id.is_local() { - let def_kind = self.cstore().def_kind(def_id); - match def_kind { - DefKind::Mod | DefKind::Enum | DefKind::Trait => { - let def_key = self.cstore().def_key(def_id); - let parent = def_key.parent.map(|index| { - self.get_nearest_non_block_module(DefId { index, krate: def_id.krate }) - }); - let name = if let Some(cnum) = def_id.as_crate_root() { - self.cstore().crate_name(cnum) - } else { - def_key.disambiguated_data.data.get_opt_name().expect("module without name") - }; - - let expn_id = self.cstore().module_expansion_untracked(def_id, &self.tcx.sess); - Some(self.new_module( - parent, - ModuleKind::Def(def_kind, def_id, name), - expn_id, - self.def_span(def_id), - // FIXME: Account for `#[no_implicit_prelude]` attributes. - parent.map_or(false, |module| module.no_implicit_prelude), - )) - } - _ => None, + // Query `def_kind` is not used because query system overhead is too expensive here. + let def_kind = self.cstore().def_kind_untracked(def_id); + if let DefKind::Mod | DefKind::Enum | DefKind::Trait = def_kind { + let parent = self + .tcx + .opt_parent(def_id) + .map(|parent_id| self.get_nearest_non_block_module(parent_id)); + // Query `expn_that_defined` is not used because + // hashing spans in its result is expensive. + let expn_id = self.cstore().expn_that_defined_untracked(def_id, &self.tcx.sess); + return Some(self.new_module( + parent, + ModuleKind::Def(def_kind, def_id, self.tcx.item_name(def_id)), + expn_id, + self.def_span(def_id), + // FIXME: Account for `#[no_implicit_prelude]` attributes. + parent.map_or(false, |module| module.no_implicit_prelude), + )); } - } else { - None } + + None } pub(crate) fn expn_def_scope(&mut self, expn_id: ExpnId) -> Module<'a> { @@ -204,6 +197,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } pub(crate) fn build_reduced_graph_external(&mut self, module: Module<'a>) { + // Query `module_children` is not used because hashing spans in its result is expensive. let children = Vec::from_iter(self.cstore().module_children_untracked(module.def_id(), self.tcx.sess)); for child in children { @@ -570,7 +564,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { } ast::UseTreeKind::Glob => { let kind = ImportKind::Glob { - is_prelude: self.r.tcx.sess.contains_name(&item.attrs, sym::prelude_import), + is_prelude: attr::contains_name(&item.attrs, sym::prelude_import), max_vis: Cell::new(None), id, }; @@ -685,7 +679,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { expansion.to_expn_id(), item.span, parent.no_implicit_prelude - || self.r.tcx.sess.contains_name(&item.attrs, sym::no_implicit_prelude), + || attr::contains_name(&item.attrs, sym::no_implicit_prelude), ); self.r.define(parent, ident, TypeNS, (module, vis, sp, expansion)); @@ -750,7 +744,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { // If the structure is marked as non_exhaustive then lower the visibility // to within the crate. let mut ctor_vis = if vis.is_public() - && self.r.tcx.sess.contains_name(&item.attrs, sym::non_exhaustive) + && attr::contains_name(&item.attrs, sym::non_exhaustive) { ty::Visibility::Restricted(CRATE_DEF_ID) } else { @@ -1168,12 +1162,11 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { } fn proc_macro_stub(&self, item: &ast::Item) -> Option<(MacroKind, Ident, Span)> { - if self.r.tcx.sess.contains_name(&item.attrs, sym::proc_macro) { + if attr::contains_name(&item.attrs, sym::proc_macro) { return Some((MacroKind::Bang, item.ident, item.span)); - } else if self.r.tcx.sess.contains_name(&item.attrs, sym::proc_macro_attribute) { + } else if attr::contains_name(&item.attrs, sym::proc_macro_attribute) { return Some((MacroKind::Attr, item.ident, item.span)); - } else if let Some(attr) = self.r.tcx.sess.find_by_name(&item.attrs, sym::proc_macro_derive) - { + } else if let Some(attr) = attr::find_by_name(&item.attrs, sym::proc_macro_derive) { if let Some(nested_meta) = attr.meta_item_list().and_then(|list| list.get(0).cloned()) { if let Some(ident) = nested_meta.ident() { return Some((MacroKind::Derive, ident, ident.span)); @@ -1228,7 +1221,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { if macro_rules { let ident = ident.normalize_to_macros_2_0(); self.r.macro_names.insert(ident); - let is_macro_export = self.r.tcx.sess.contains_name(&item.attrs, sym::macro_export); + let is_macro_export = attr::contains_name(&item.attrs, sym::macro_export); let vis = if is_macro_export { ty::Visibility::Public } else { @@ -1488,13 +1481,12 @@ impl<'a, 'b, 'tcx> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b, 'tcx> { self.r.visibilities.insert(def_id, vis); // If the variant is marked as non_exhaustive then lower the visibility to within the crate. - let ctor_vis = if vis.is_public() - && self.r.tcx.sess.contains_name(&variant.attrs, sym::non_exhaustive) - { - ty::Visibility::Restricted(CRATE_DEF_ID) - } else { - vis - }; + let ctor_vis = + if vis.is_public() && attr::contains_name(&variant.attrs, sym::non_exhaustive) { + ty::Visibility::Restricted(CRATE_DEF_ID) + } else { + vis + }; // Define a constructor name in the value namespace. if let Some((ctor_kind, ctor_node_id)) = CtorKind::from_ast(&variant.data) { diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs index b2578e4c4b4..dbf6cec788b 100644 --- a/compiler/rustc_resolve/src/check_unused.rs +++ b/compiler/rustc_resolve/src/check_unused.rs @@ -32,9 +32,10 @@ use rustc_ast::visit::{self, Visitor}; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_data_structures::unord::UnordSet; use rustc_errors::{pluralize, MultiSpan}; +use rustc_hir::def::{DefKind, Res}; use rustc_session::lint::builtin::{MACRO_USE_EXTERN_CRATE, UNUSED_EXTERN_CRATES, UNUSED_IMPORTS}; use rustc_session::lint::BuiltinLintDiagnostics; -use rustc_span::symbol::Ident; +use rustc_span::symbol::{kw, Ident}; use rustc_span::{Span, DUMMY_SP}; struct UnusedImport<'a> { @@ -58,6 +59,7 @@ struct UnusedImportCheckVisitor<'a, 'b, 'tcx> { base_use_tree: Option<&'a ast::UseTree>, base_id: ast::NodeId, item_span: Span, + base_use_is_pub: bool, } struct ExternCrateToLint { @@ -110,6 +112,35 @@ impl<'a, 'b, 'tcx> UnusedImportCheckVisitor<'a, 'b, 'tcx> { unused: Default::default(), }) } + + fn check_import_as_underscore(&mut self, item: &ast::UseTree, id: ast::NodeId) { + match item.kind { + ast::UseTreeKind::Simple(Some(ident)) => { + if ident.name == kw::Underscore + && !self + .r + .import_res_map + .get(&id) + .map(|per_ns| { + per_ns.iter().filter_map(|res| res.as_ref()).any(|res| { + matches!(res, Res::Def(DefKind::Trait | DefKind::TraitAlias, _)) + }) + }) + .unwrap_or(false) + { + self.unused_import(self.base_id).add(id); + } + } + ast::UseTreeKind::Nested(ref items) => self.check_imports_as_underscore(items), + _ => {} + } + } + + fn check_imports_as_underscore(&mut self, items: &[(ast::UseTree, ast::NodeId)]) { + for (item, id) in items { + self.check_import_as_underscore(item, *id); + } + } } impl<'a, 'b, 'tcx> Visitor<'a> for UnusedImportCheckVisitor<'a, 'b, 'tcx> { @@ -119,7 +150,8 @@ impl<'a, 'b, 'tcx> Visitor<'a> for UnusedImportCheckVisitor<'a, 'b, 'tcx> { // whether they're used or not. Also ignore imports with a dummy span // because this means that they were generated in some fashion by the // compiler and we don't need to consider them. - ast::ItemKind::Use(..) if item.vis.kind.is_pub() || item.span.is_dummy() => return, + ast::ItemKind::Use(..) if item.span.is_dummy() => return, + ast::ItemKind::Use(..) => self.base_use_is_pub = item.vis.kind.is_pub(), ast::ItemKind::ExternCrate(orig_name) => { self.extern_crate_items.push(ExternCrateToLint { id: item.id, @@ -146,6 +178,11 @@ impl<'a, 'b, 'tcx> Visitor<'a> for UnusedImportCheckVisitor<'a, 'b, 'tcx> { self.base_use_tree = Some(use_tree); } + if self.base_use_is_pub { + self.check_import_as_underscore(use_tree, id); + return; + } + if let ast::UseTreeKind::Nested(ref items) = use_tree.kind { if items.is_empty() { self.unused_import(self.base_id).add(id); @@ -300,6 +337,7 @@ impl Resolver<'_, '_> { base_use_tree: None, base_id: ast::DUMMY_NODE_ID, item_span: DUMMY_SP, + base_use_is_pub: false, }; visit::walk_crate(&mut visitor, krate); diff --git a/compiler/rustc_resolve/src/effective_visibilities.rs b/compiler/rustc_resolve/src/effective_visibilities.rs index 4bb252bfb29..a1ae9b8a521 100644 --- a/compiler/rustc_resolve/src/effective_visibilities.rs +++ b/compiler/rustc_resolve/src/effective_visibilities.rs @@ -4,6 +4,7 @@ use rustc_ast::visit; use rustc_ast::visit::Visitor; use rustc_ast::Crate; use rustc_ast::EnumDef; +use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::intern::Interned; use rustc_hir::def_id::LocalDefId; use rustc_hir::def_id::CRATE_DEF_ID; @@ -70,11 +71,11 @@ impl Resolver<'_, '_> { impl<'r, 'a, 'tcx> EffectiveVisibilitiesVisitor<'r, 'a, 'tcx> { /// Fills the `Resolver::effective_visibilities` table with public & exported items /// For now, this doesn't resolve macros (FIXME) and cannot resolve Impl, as we - /// need access to a TyCtxt for that. + /// need access to a TyCtxt for that. Returns the set of ambiguous re-exports. pub(crate) fn compute_effective_visibilities<'c>( r: &'r mut Resolver<'a, 'tcx>, krate: &'c Crate, - ) { + ) -> FxHashSet<Interned<'a, NameBinding<'a>>> { let mut visitor = EffectiveVisibilitiesVisitor { r, def_effective_visibilities: Default::default(), @@ -93,18 +94,26 @@ impl<'r, 'a, 'tcx> EffectiveVisibilitiesVisitor<'r, 'a, 'tcx> { } visitor.r.effective_visibilities = visitor.def_effective_visibilities; + let mut exported_ambiguities = FxHashSet::default(); + // Update visibilities for import def ids. These are not used during the // `EffectiveVisibilitiesVisitor` pass, because we have more detailed binding-based // information, but are used by later passes. Effective visibility of an import def id // is the maximum value among visibilities of bindings corresponding to that def id. for (binding, eff_vis) in visitor.import_effective_visibilities.iter() { let NameBindingKind::Import { import, .. } = binding.kind else { unreachable!() }; - if let Some(node_id) = import.id() { - r.effective_visibilities.update_eff_vis(r.local_def_id(node_id), eff_vis, r.tcx) + if !binding.is_ambiguity() { + if let Some(node_id) = import.id() { + r.effective_visibilities.update_eff_vis(r.local_def_id(node_id), eff_vis, r.tcx) + } + } else if binding.ambiguity.is_some() && eff_vis.is_public_at_level(Level::Reexported) { + exported_ambiguities.insert(*binding); } } info!("resolve::effective_visibilities: {:#?}", r.effective_visibilities); + + exported_ambiguities } /// Update effective visibilities of bindings in the given module, @@ -115,21 +124,44 @@ impl<'r, 'a, 'tcx> EffectiveVisibilitiesVisitor<'r, 'a, 'tcx> { let resolutions = self.r.resolutions(module); for (_, name_resolution) in resolutions.borrow().iter() { - if let Some(mut binding) = name_resolution.borrow().binding() && !binding.is_ambiguity() { - // Set the given effective visibility level to `Level::Direct` and - // sets the rest of the `use` chain to `Level::Reexported` until - // we hit the actual exported item. - let mut parent_id = ParentId::Def(module_id); - while let NameBindingKind::Import { binding: nested_binding, .. } = binding.kind { - let binding_id = ImportId::new_unchecked(binding); - self.update_import(binding_id, parent_id); - - parent_id = ParentId::Import(binding_id); - binding = nested_binding; - } + if let Some(mut binding) = name_resolution.borrow().binding() { + if !binding.is_ambiguity() { + // Set the given effective visibility level to `Level::Direct` and + // sets the rest of the `use` chain to `Level::Reexported` until + // we hit the actual exported item. + let mut parent_id = ParentId::Def(module_id); + while let NameBindingKind::Import { binding: nested_binding, .. } = binding.kind + { + let binding_id = ImportId::new_unchecked(binding); + self.update_import(binding_id, parent_id); + + parent_id = ParentId::Import(binding_id); + binding = nested_binding; + } + + if let Some(def_id) = binding.res().opt_def_id().and_then(|id| id.as_local()) { + self.update_def(def_id, binding.vis.expect_local(), parent_id); + } + } else { + // Put the root ambiguity binding and all reexports leading to it into the + // table. They are used by the `ambiguous_glob_reexports` lint. For all + // bindings added to the table here `is_ambiguity` returns true. + let mut parent_id = ParentId::Def(module_id); + while let NameBindingKind::Import { binding: nested_binding, .. } = binding.kind + { + let binding_id = ImportId::new_unchecked(binding); + self.update_import(binding_id, parent_id); - if let Some(def_id) = binding.res().opt_def_id().and_then(|id| id.as_local()) { - self.update_def(def_id, binding.vis.expect_local(), parent_id); + if binding.ambiguity.is_some() { + // Stop at the root ambiguity, further bindings in the chain should not + // be reexported because the root ambiguity blocks any access to them. + // (Those further bindings are most likely not ambiguities themselves.) + break; + } + + parent_id = ParentId::Import(binding_id); + binding = nested_binding; + } } } } diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 4d4bc1be349..bc17ce571a7 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -19,7 +19,9 @@ use rustc_hir::def::{self, DefKind, PartialRes}; use rustc_middle::metadata::ModChild; use rustc_middle::span_bug; use rustc_middle::ty; -use rustc_session::lint::builtin::{PUB_USE_OF_PRIVATE_EXTERN_CRATE, UNUSED_IMPORTS}; +use rustc_session::lint::builtin::{ + AMBIGUOUS_GLOB_REEXPORTS, PUB_USE_OF_PRIVATE_EXTERN_CRATE, UNUSED_IMPORTS, +}; use rustc_session::lint::BuiltinLintDiagnostics; use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::hygiene::LocalExpnId; @@ -510,6 +512,34 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } } + pub(crate) fn check_reexport_ambiguities( + &mut self, + exported_ambiguities: FxHashSet<Interned<'a, NameBinding<'a>>>, + ) { + for module in self.arenas.local_modules().iter() { + module.for_each_child(self, |this, ident, ns, binding| { + if let NameBindingKind::Import { import, .. } = binding.kind + && let Some((amb_binding, _)) = binding.ambiguity + && binding.res() != Res::Err + && exported_ambiguities.contains(&Interned::new_unchecked(binding)) + { + this.lint_buffer.buffer_lint_with_diagnostic( + AMBIGUOUS_GLOB_REEXPORTS, + import.root_id, + import.root_span, + "ambiguous glob re-exports", + BuiltinLintDiagnostics::AmbiguousGlobReexports { + name: ident.to_string(), + namespace: ns.descr().to_string(), + first_reexport_span: import.root_span, + duplicate_reexport_span: amb_binding.span, + }, + ); + } + }); + } + } + fn throw_unresolved_import_error(&self, errors: Vec<(&Import<'_>, UnresolvedImportError)>) { if errors.is_empty() { return; diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 1afd8851ce0..6af9dc89e56 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -590,7 +590,6 @@ struct LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { parent_scope: ParentScope<'a>, /// The current set of local scopes for types and values. - /// FIXME #4948: Reuse ribs to avoid allocation. ribs: PerNS<Vec<Rib<'a>>>, /// Previous poped `rib`, only used for diagnostic. diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index cd90fd3ef84..0e84432a5b4 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -23,7 +23,7 @@ extern crate tracing; use rustc_arena::{DroplessArena, TypedArena}; use rustc_ast::node_id::NodeMap; -use rustc_ast::{self as ast, NodeId, CRATE_NODE_ID}; +use rustc_ast::{self as ast, attr, NodeId, CRATE_NODE_ID}; use rustc_ast::{AngleBracketedArg, Crate, Expr, ExprKind, GenericArg, GenericArgs, LitKind, Path}; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::intern::Interned; @@ -1168,7 +1168,7 @@ impl<'tcx> Resolver<'_, 'tcx> { if let Some(def_id) = def_id.as_local() { self.item_generics_num_lifetimes[&def_id] } else { - self.cstore().item_generics_num_lifetimes(def_id, self.tcx.sess) + self.tcx.generics_of(def_id).own_counts().lifetimes } } @@ -1180,7 +1180,8 @@ impl<'tcx> Resolver<'_, 'tcx> { impl<'a, 'tcx> Resolver<'a, 'tcx> { pub fn new( tcx: TyCtxt<'tcx>, - krate: &Crate, + attrs: &[ast::Attribute], + crate_span: Span, arenas: &'a ResolverArenas<'a>, ) -> Resolver<'a, 'tcx> { let root_def_id = CRATE_DEF_ID.to_def_id(); @@ -1189,8 +1190,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { None, ModuleKind::Def(DefKind::Mod, root_def_id, kw::Empty), ExpnId::root(), - krate.spans.inner_span, - tcx.sess.contains_name(&krate.attrs, sym::no_implicit_prelude), + crate_span, + attr::contains_name(attrs, sym::no_implicit_prelude), &mut module_map, ); let empty_module = arenas.new_module( @@ -1222,9 +1223,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { .map(|(name, _)| (Ident::from_str(name), Default::default())) .collect(); - if !tcx.sess.contains_name(&krate.attrs, sym::no_core) { + if !attr::contains_name(attrs, sym::no_core) { extern_prelude.insert(Ident::with_dummy_span(sym::core), Default::default()); - if !tcx.sess.contains_name(&krate.attrs, sym::no_std) { + if !attr::contains_name(attrs, sym::no_std) { extern_prelude.insert(Ident::with_dummy_span(sym::std), Default::default()); } } @@ -1474,9 +1475,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { pub fn resolve_crate(&mut self, krate: &Crate) { self.tcx.sess.time("resolve_crate", || { self.tcx.sess.time("finalize_imports", || self.finalize_imports()); - self.tcx.sess.time("compute_effective_visibilities", || { + let exported_ambiguities = self.tcx.sess.time("compute_effective_visibilities", || { EffectiveVisibilitiesVisitor::compute_effective_visibilities(self, krate) }); + self.tcx.sess.time("check_reexport_ambiguities", || { + self.check_reexport_ambiguities(exported_ambiguities) + }); self.tcx.sess.time("finalize_macro_resolutions", || self.finalize_macro_resolutions()); self.tcx.sess.time("late_resolve_crate", || self.late_resolve_crate(krate)); self.tcx.sess.time("resolve_main", || self.resolve_main()); @@ -1871,7 +1875,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { fn def_span(&self, def_id: DefId) -> Span { match def_id.as_local() { Some(def_id) => self.tcx.source_span(def_id), - None => self.cstore().get_span_untracked(def_id, self.tcx.sess), + // Query `def_span` is not used because hashing its result span is expensive. + None => self.cstore().def_span_untracked(def_id, self.tcx.sess), } } @@ -1906,10 +1911,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { return v.clone(); } - let attr = self - .cstore() - .item_attrs_untracked(def_id, self.tcx.sess) - .find(|a| a.has_name(sym::rustc_legacy_const_generics))?; + let attr = self.tcx.get_attr(def_id, sym::rustc_legacy_const_generics)?; let mut ret = Vec::new(); for meta in attr.meta_item_list()? { match meta.lit()?.kind { diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 37153854f7e..48707d37a10 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -5,7 +5,7 @@ use crate::Namespace::*; use crate::{BuiltinMacroState, Determinacy}; use crate::{DeriveData, Finalize, ParentScope, ResolutionError, Resolver, ScopeSet}; use crate::{ModuleKind, ModuleOrUniformRoot, NameBinding, PathResult, Segment}; -use rustc_ast::{self as ast, Inline, ItemKind, ModKind, NodeId}; +use rustc_ast::{self as ast, attr, Inline, ItemKind, ModKind, NodeId}; use rustc_ast_pretty::pprust; use rustc_attr::StabilityLevel; use rustc_data_structures::intern::Interned; @@ -112,8 +112,8 @@ fn fast_print_path(path: &ast::Path) -> Symbol { pub(crate) fn registered_tools(tcx: TyCtxt<'_>, (): ()) -> RegisteredTools { let mut registered_tools = RegisteredTools::default(); - let krate = tcx.crate_for_resolver(()).borrow(); - for attr in tcx.sess.filter_by_name(&krate.attrs, sym::register_tool) { + let (_, pre_configured_attrs) = &*tcx.crate_for_resolver(()).borrow(); + for attr in attr::filter_by_name(pre_configured_attrs, sym::register_tool) { for nested_meta in attr.meta_item_list().unwrap_or_default() { match nested_meta.ident() { Some(ident) => { @@ -703,7 +703,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { PathResult::NonModule(path_res) if let Some(res) = path_res.full_res() => { check_consistency(self, &path, path_span, kind, initial_res, res) } - path_res @ PathResult::NonModule(..) | path_res @ PathResult::Failed { .. } => { + path_res @ (PathResult::NonModule(..) | PathResult::Failed { .. }) => { let mut suggestion = None; let (span, label) = if let PathResult::Failed { span, label, .. } = path_res { // try to suggest if it's not a macro, maybe a function diff --git a/compiler/rustc_resolve/src/rustdoc.rs b/compiler/rustc_resolve/src/rustdoc.rs index b8853c1744c..0e40f794f18 100644 --- a/compiler/rustc_resolve/src/rustdoc.rs +++ b/compiler/rustc_resolve/src/rustdoc.rs @@ -26,11 +26,13 @@ pub enum DocFragmentKind { #[derive(Clone, PartialEq, Eq, Debug)] pub struct DocFragment { pub span: Span, - /// The module this doc-comment came from. - /// - /// This allows distinguishing between the original documentation and a pub re-export. - /// If it is `None`, the item was not re-exported. - pub parent_module: Option<DefId>, + /// The item this doc-comment came from. + /// Used to determine the scope in which doc links in this fragment are resolved. + /// Typically filled for reexport docs when they are merged into the docs of the + /// original reexported item. + /// If the id is not filled, which happens for the original reexported item, then + /// it has to be taken from somewhere else during doc link resolution. + pub item_id: Option<DefId>, pub doc: Symbol, pub kind: DocFragmentKind, pub indent: usize, @@ -186,7 +188,7 @@ pub fn attrs_to_doc_fragments<'a>( ) -> (Vec<DocFragment>, ast::AttrVec) { let mut doc_fragments = Vec::new(); let mut other_attrs = ast::AttrVec::new(); - for (attr, parent_module) in attrs { + for (attr, item_id) in attrs { if let Some((doc_str, comment_kind)) = attr.doc_str_and_comment_kind() { let doc = beautify_doc_string(doc_str, comment_kind); let kind = if attr.is_doc_comment() { @@ -194,7 +196,7 @@ pub fn attrs_to_doc_fragments<'a>( } else { DocFragmentKind::RawDoc }; - let fragment = DocFragment { span: attr.span, doc, kind, parent_module, indent: 0 }; + let fragment = DocFragment { span: attr.span, doc, kind, item_id, indent: 0 }; doc_fragments.push(fragment); } else if !doc_only { other_attrs.push(attr.clone()); @@ -216,7 +218,7 @@ pub fn prepare_to_doc_link_resolution( ) -> FxHashMap<Option<DefId>, String> { let mut res = FxHashMap::default(); for fragment in doc_fragments { - let out_str = res.entry(fragment.parent_module).or_default(); + let out_str = res.entry(fragment.item_id).or_default(); add_doc_fragment(out_str, fragment); } res diff --git a/compiler/rustc_session/src/filesearch.rs b/compiler/rustc_session/src/filesearch.rs index e734599cbfc..2404928b254 100644 --- a/compiler/rustc_session/src/filesearch.rs +++ b/compiler/rustc_session/src/filesearch.rs @@ -1,5 +1,6 @@ //! A module for searching for libraries +use rustc_fs_util::try_canonicalize; use smallvec::{smallvec, SmallVec}; use std::env; use std::fs; @@ -125,7 +126,7 @@ pub fn sysroot_candidates() -> SmallVec<[PathBuf; 2]> { let target = crate::config::host_triple(); let mut sysroot_candidates: SmallVec<[PathBuf; 2]> = smallvec![get_or_default_sysroot().expect("Failed finding sysroot")]; - let path = current_dll_path().and_then(|s| s.canonicalize().map_err(|e| e.to_string())); + let path = current_dll_path().and_then(|s| try_canonicalize(s).map_err(|e| e.to_string())); if let Ok(dll) = path { // use `parent` twice to chop off the file name and then also the // directory containing the dll which should be either `lib` or `bin`. @@ -160,7 +161,7 @@ pub fn sysroot_candidates() -> SmallVec<[PathBuf; 2]> { pub fn get_or_default_sysroot() -> Result<PathBuf, String> { // Follow symlinks. If the resolved path is relative, make it absolute. fn canonicalize(path: PathBuf) -> PathBuf { - let path = fs::canonicalize(&path).unwrap_or(path); + let path = try_canonicalize(&path).unwrap_or(path); // See comments on this target function, but the gist is that // gcc chokes on verbatim paths which fs::canonicalize generates // so we try to avoid those kinds of paths. diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 0548379dc2f..c75af48e80a 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -4,6 +4,7 @@ use crate::early_error; use crate::lint; use crate::search_paths::SearchPath; use crate::utils::NativeLib; +use rustc_data_structures::profiling::TimePassesFormat; use rustc_errors::{LanguageIdentifier, TerminalUrl}; use rustc_target::spec::{CodeModel, LinkerFlavorCli, MergeFunctions, PanicStrategy, SanitizerSet}; use rustc_target::spec::{ @@ -365,6 +366,7 @@ mod desc { pub const parse_number: &str = "a number"; pub const parse_opt_number: &str = parse_number; pub const parse_threads: &str = parse_number; + pub const parse_time_passes_format: &str = "`text` (default) or `json`"; pub const parse_passes: &str = "a space-separated list of passes, or `all`"; pub const parse_panic_strategy: &str = "either `unwind` or `abort`"; pub const parse_opt_panic_strategy: &str = parse_panic_strategy; @@ -829,6 +831,21 @@ mod parse { true } + pub(crate) fn parse_time_passes_format(slot: &mut TimePassesFormat, v: Option<&str>) -> bool { + match v { + None => true, + Some("json") => { + *slot = TimePassesFormat::Json; + true + } + Some("text") => { + *slot = TimePassesFormat::Text; + true + } + Some(_) => false, + } + } + pub(crate) fn parse_dump_mono_stats(slot: &mut DumpMonoStatsFormat, v: Option<&str>) -> bool { match v { None => true, @@ -1709,6 +1726,8 @@ options! { "measure time of each LLVM pass (default: no)"), time_passes: bool = (false, parse_bool, [UNTRACKED], "measure time of each rustc pass (default: no)"), + time_passes_format: TimePassesFormat = (TimePassesFormat::Text, parse_time_passes_format, [UNTRACKED], + "the format to use for -Z time-passes (`text` (default) or `json`)"), tiny_const_eval_limit: bool = (false, parse_bool, [TRACKED], "sets a tiny, non-configurable limit for const eval; useful for compiler tests"), #[rustc_lint_opt_deny_field_access("use `Session::tls_model` instead of this field")] diff --git a/compiler/rustc_session/src/output.rs b/compiler/rustc_session/src/output.rs index c3f0c4b58f5..fdb9fae44e1 100644 --- a/compiler/rustc_session/src/output.rs +++ b/compiler/rustc_session/src/output.rs @@ -5,7 +5,7 @@ use crate::errors::{ InvalidCharacterInCrateName, }; use crate::Session; -use rustc_ast as ast; +use rustc_ast::{self as ast, attr}; use rustc_span::symbol::sym; use rustc_span::{Span, Symbol}; use std::path::{Path, PathBuf}; @@ -56,7 +56,7 @@ pub fn find_crate_name(sess: &Session, attrs: &[ast::Attribute]) -> Symbol { // the command line over one found in the #[crate_name] attribute. If we // find both we ensure that they're the same later on as well. let attr_crate_name = - sess.find_by_name(attrs, sym::crate_name).and_then(|at| at.value_str().map(|s| (at, s))); + attr::find_by_name(attrs, sym::crate_name).and_then(|at| at.value_str().map(|s| (at, s))); if let Some(ref s) = sess.opts.crate_name { let s = Symbol::intern(s); diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index fdacf814dd6..5730df9d5c6 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -30,7 +30,7 @@ use rustc_macros::HashStable_Generic; pub use rustc_span::def_id::StableCrateId; use rustc_span::edition::Edition; use rustc_span::source_map::{FileLoader, RealFileLoader, SourceMap, Span}; -use rustc_span::{sym, SourceFileHashAlgorithm, Symbol}; +use rustc_span::{SourceFileHashAlgorithm, Symbol}; use rustc_target::asm::InlineAsmArch; use rustc_target::spec::{CodeModel, PanicStrategy, RelocModel, RelroLevel}; use rustc_target::spec::{ @@ -1003,40 +1003,6 @@ impl Session { || self.opts.unstable_opts.sanitizer.intersects(SanitizerSet::ADDRESS | SanitizerSet::KERNELADDRESS | SanitizerSet::MEMORY | SanitizerSet::HWADDRESS) } - pub fn is_proc_macro_attr(&self, attr: &Attribute) -> bool { - [sym::proc_macro, sym::proc_macro_attribute, sym::proc_macro_derive] - .iter() - .any(|kind| attr.has_name(*kind)) - } - - pub fn contains_name(&self, attrs: &[Attribute], name: Symbol) -> bool { - attrs.iter().any(|item| item.has_name(name)) - } - - pub fn find_by_name<'a>( - &'a self, - attrs: &'a [Attribute], - name: Symbol, - ) -> Option<&'a Attribute> { - attrs.iter().find(|attr| attr.has_name(name)) - } - - pub fn filter_by_name<'a>( - &'a self, - attrs: &'a [Attribute], - name: Symbol, - ) -> impl Iterator<Item = &'a Attribute> { - attrs.iter().filter(move |attr| attr.has_name(name)) - } - - pub fn first_attr_value_str_by_name( - &self, - attrs: &[Attribute], - name: Symbol, - ) -> Option<Symbol> { - attrs.iter().find(|at| at.has_name(name)).and_then(|at| at.value_str()) - } - pub fn diagnostic_width(&self) -> usize { let default_column_width = 140; if let Some(width) = self.opts.diagnostic_width { @@ -1487,7 +1453,10 @@ pub fn build_session( CguReuseTracker::new_disabled() }; - let prof = SelfProfilerRef::new(self_profiler, sopts.unstable_opts.time_passes); + let prof = SelfProfilerRef::new( + self_profiler, + sopts.unstable_opts.time_passes.then(|| sopts.unstable_opts.time_passes_format), + ); let ctfe_backtrace = Lock::new(match env::var("RUSTC_CTFE_BACKTRACE") { Ok(ref val) if val == "immediate" => CtfeBacktrace::Immediate, diff --git a/compiler/rustc_session/src/utils.rs b/compiler/rustc_session/src/utils.rs index 3b3d4ca5d6b..1d15e2c28d8 100644 --- a/compiler/rustc_session/src/utils.rs +++ b/compiler/rustc_session/src/utils.rs @@ -1,5 +1,6 @@ use crate::session::Session; use rustc_data_structures::profiling::VerboseTimingGuard; +use rustc_fs_util::try_canonicalize; use std::path::{Path, PathBuf}; impl Session { @@ -98,7 +99,7 @@ pub struct CanonicalizedPath { impl CanonicalizedPath { pub fn new(path: &Path) -> Self { - Self { original: path.to_owned(), canonicalized: std::fs::canonicalize(path).ok() } + Self { original: path.to_owned(), canonicalized: try_canonicalize(path).ok() } } pub fn canonicalized(&self) -> &PathBuf { diff --git a/compiler/rustc_span/Cargo.toml b/compiler/rustc_span/Cargo.toml index ae81d95e279..98d6e0ab117 100644 --- a/compiler/rustc_span/Cargo.toml +++ b/compiler/rustc_span/Cargo.toml @@ -18,3 +18,4 @@ tracing = "0.1" sha1 = "0.10.0" sha2 = "0.10.1" md5 = { package = "md-5", version = "0.10.0" } +indexmap = { version = "1.9.1" } diff --git a/compiler/rustc_span/src/def_id.rs b/compiler/rustc_span/src/def_id.rs index 162c15574b5..b2c58caff2e 100644 --- a/compiler/rustc_span/src/def_id.rs +++ b/compiler/rustc_span/src/def_id.rs @@ -1,13 +1,17 @@ use crate::{HashStableContext, Symbol}; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey}; +use rustc_data_structures::unhash::Unhasher; use rustc_data_structures::AtomicRef; use rustc_index::vec::Idx; use rustc_macros::HashStable_Generic; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use std::borrow::Borrow; use std::fmt; -use std::hash::{Hash, Hasher}; +use std::hash::{BuildHasherDefault, Hash, Hasher}; + +pub type StableCrateIdMap = + indexmap::IndexMap<StableCrateId, CrateNum, BuildHasherDefault<Unhasher>>; rustc_index::newtype_index! { #[custom_encodable] diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 873cd33f6a4..02cffc762be 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -795,6 +795,18 @@ impl Span { }) } + /// Splits a span into two composite spans around a certain position. + pub fn split_at(self, pos: u32) -> (Span, Span) { + let len = self.hi().0 - self.lo().0; + debug_assert!(pos <= len); + + let split_pos = BytePos(self.lo().0 + pos); + ( + Span::new(self.lo(), split_pos, self.ctxt(), self.parent()), + Span::new(split_pos, self.hi(), self.ctxt(), self.parent()), + ) + } + /// Returns a `Span` that would enclose both `self` and `end`. /// /// Note that this can also be used to extend the span "backwards": diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index abe5af8f9e0..4a1abdf6318 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1044,6 +1044,7 @@ symbols! { optin_builtin_traits, option, option_env, + option_payload_ptr, options, or, or_patterns, diff --git a/compiler/rustc_target/Cargo.toml b/compiler/rustc_target/Cargo.toml index 568c916a163..4e7a8d166ae 100644 --- a/compiler/rustc_target/Cargo.toml +++ b/compiler/rustc_target/Cargo.toml @@ -7,6 +7,7 @@ edition = "2021" bitflags = "1.2.1" tracing = "0.1" serde_json = "1.0.59" +rustc_fs_util = { path = "../rustc_fs_util" } rustc_abi = { path = "../rustc_abi" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_feature = { path = "../rustc_feature" } diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index f3304e91429..2553b11d878 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -40,6 +40,7 @@ use crate::json::{Json, ToJson}; use crate::spec::abi::{lookup as lookup_abi, Abi}; use crate::spec::crt_objects::{CrtObjects, LinkSelfContainedDefault}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +use rustc_fs_util::try_canonicalize; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use rustc_span::symbol::{sym, Symbol}; use serde_json::Value; @@ -2949,7 +2950,7 @@ impl TargetTriple { /// Creates a target triple from the passed target path. pub fn from_path(path: &Path) -> Result<Self, io::Error> { - let canonicalized_path = path.canonicalize()?; + let canonicalized_path = try_canonicalize(path)?; let contents = std::fs::read_to_string(&canonicalized_path).map_err(|err| { io::Error::new( io::ErrorKind::InvalidInput, diff --git a/compiler/rustc_trait_selection/src/solve/assembly.rs b/compiler/rustc_trait_selection/src/solve/assembly.rs index f9cb56655ae..995fec78c40 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly.rs @@ -2,7 +2,8 @@ #[cfg(doc)] use super::trait_goals::structural_traits::*; -use super::EvalCtxt; +use super::{EvalCtxt, SolverMode}; +use crate::traits::coherence; use itertools::Itertools; use rustc_hir::def_id::DefId; use rustc_infer::traits::query::NoSolution; @@ -87,6 +88,8 @@ pub(super) enum CandidateSource { pub(super) trait GoalKind<'tcx>: TypeFoldable<TyCtxt<'tcx>> + Copy + Eq { fn self_ty(self) -> Ty<'tcx>; + fn trait_ref(self, tcx: TyCtxt<'tcx>) -> ty::TraitRef<'tcx>; + fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self; fn trait_def_id(self, tcx: TyCtxt<'tcx>) -> DefId; @@ -249,15 +252,16 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { self.assemble_object_bound_candidates(goal, &mut candidates); + self.assemble_coherence_unknowable_candidates(goal, &mut candidates); + candidates } /// If the self type of a goal is a projection, computing the relevant candidates is difficult. /// /// To deal with this, we first try to normalize the self type and add the candidates for the normalized - /// self type to the list of candidates in case that succeeds. Note that we can't just eagerly return in - /// this case as projections as self types add - // FIXME complete the unfinished sentence above + /// self type to the list of candidates in case that succeeds. We also have to consider candidates with the + /// projection as a self type as well fn assemble_candidates_after_normalizing_self_ty<G: GoalKind<'tcx>>( &mut self, goal: Goal<'tcx, G>, @@ -475,14 +479,40 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { } } + fn assemble_coherence_unknowable_candidates<G: GoalKind<'tcx>>( + &mut self, + goal: Goal<'tcx, G>, + candidates: &mut Vec<Candidate<'tcx>>, + ) { + match self.solver_mode() { + SolverMode::Normal => return, + SolverMode::Coherence => { + let trait_ref = goal.predicate.trait_ref(self.tcx()); + match coherence::trait_ref_is_knowable(self.tcx(), trait_ref) { + Ok(()) => {} + Err(_) => match self + .evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) + { + Ok(result) => candidates + .push(Candidate { source: CandidateSource::BuiltinImpl, result }), + // FIXME: This will be reachable at some point if we're in + // `assemble_candidates_after_normalizing_self_ty` and we get a + // universe error. We'll deal with it at this point. + Err(NoSolution) => bug!("coherence candidate resulted in NoSolution"), + }, + } + } + } + } + #[instrument(level = "debug", skip(self), ret)] - pub(super) fn merge_candidates_and_discard_reservation_impls( + pub(super) fn merge_candidates( &mut self, mut candidates: Vec<Candidate<'tcx>>, ) -> QueryResult<'tcx> { match candidates.len() { 0 => return Err(NoSolution), - 1 => return Ok(self.discard_reservation_impl(candidates.pop().unwrap()).result), + 1 => return Ok(candidates.pop().unwrap().result), _ => {} } @@ -490,10 +520,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { let mut i = 0; 'outer: while i < candidates.len() { for j in (0..candidates.len()).filter(|&j| i != j) { - if self.trait_candidate_should_be_dropped_in_favor_of( - &candidates[i], - &candidates[j], - ) { + if self.candidate_should_be_dropped_in_favor_of(&candidates[i], &candidates[j]) + { debug!(candidate = ?candidates[i], "Dropping candidate #{}/{}", i, candidates.len()); candidates.swap_remove(i); continue 'outer; @@ -518,11 +546,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { } } - // FIXME: What if there are >1 candidates left with the same response, and one is a reservation impl? - Ok(self.discard_reservation_impl(candidates.pop().unwrap()).result) + Ok(candidates.pop().unwrap().result) } - fn trait_candidate_should_be_dropped_in_favor_of( + fn candidate_should_be_dropped_in_favor_of( &self, candidate: &Candidate<'tcx>, other: &Candidate<'tcx>, @@ -535,20 +562,4 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { | (CandidateSource::BuiltinImpl, _) => false, } } - - fn discard_reservation_impl(&mut self, mut candidate: Candidate<'tcx>) -> Candidate<'tcx> { - if let CandidateSource::Impl(def_id) = candidate.source { - if let ty::ImplPolarity::Reservation = self.tcx().impl_polarity(def_id) { - debug!("Selected reservation impl"); - // We assemble all candidates inside of a probe so by - // making a new canonical response here our result will - // have no constraints. - candidate.result = self - .evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) - .unwrap(); - } - } - - candidate - } } diff --git a/compiler/rustc_trait_selection/src/solve/canonical/mod.rs b/compiler/rustc_trait_selection/src/solve/canonical/mod.rs index 9d45e78ebab..efecaf33ef9 100644 --- a/compiler/rustc_trait_selection/src/solve/canonical/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/canonical/mod.rs @@ -99,20 +99,20 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { param_env: ty::ParamEnv<'tcx>, original_values: Vec<ty::GenericArg<'tcx>>, response: CanonicalResponse<'tcx>, - ) -> Result<Certainty, NoSolution> { + ) -> Result<(Certainty, Vec<Goal<'tcx, ty::Predicate<'tcx>>>), NoSolution> { let substitution = self.compute_query_response_substitution(&original_values, &response); let Response { var_values, external_constraints, certainty } = response.substitute(self.tcx(), &substitution); - self.unify_query_var_values(param_env, &original_values, var_values)?; + let nested_goals = self.unify_query_var_values(param_env, &original_values, var_values)?; // FIXME: implement external constraints. let ExternalConstraintsData { region_constraints, opaque_types: _ } = external_constraints.deref(); self.register_region_constraints(region_constraints); - Ok(certainty) + Ok((certainty, nested_goals)) } /// This returns the substitutions to instantiate the bound variables of @@ -205,21 +205,15 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { param_env: ty::ParamEnv<'tcx>, original_values: &[ty::GenericArg<'tcx>], var_values: CanonicalVarValues<'tcx>, - ) -> Result<(), NoSolution> { + ) -> Result<Vec<Goal<'tcx, ty::Predicate<'tcx>>>, NoSolution> { assert_eq!(original_values.len(), var_values.len()); + + let mut nested_goals = vec![]; for (&orig, response) in iter::zip(original_values, var_values.var_values) { - // This can fail due to the occurs check, see - // `tests/ui/typeck/lazy-norm/equating-projection-cyclically.rs` for an example - // where that can happen. - // - // FIXME: To deal with #105787 I also expect us to emit nested obligations here at - // some point. We can figure out how to deal with this once we actually have - // an ICE. - let nested_goals = self.eq_and_get_goals(param_env, orig, response)?; - assert!(nested_goals.is_empty(), "{nested_goals:?}"); + nested_goals.extend(self.eq_and_get_goals(param_env, orig, response)?); } - Ok(()) + Ok(nested_goals) } fn register_region_constraints(&mut self, region_constraints: &QueryRegionConstraints<'tcx>) { diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs index 95412922357..e47b5ae21b5 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs @@ -17,6 +17,7 @@ use rustc_span::DUMMY_SP; use std::ops::ControlFlow; use super::search_graph::{self, OverflowHandler}; +use super::SolverMode; use super::{search_graph::SearchGraph, Goal}; pub struct EvalCtxt<'a, 'tcx> { @@ -69,7 +70,7 @@ pub trait InferCtxtEvalExt<'tcx> { fn evaluate_root_goal( &self, goal: Goal<'tcx, ty::Predicate<'tcx>>, - ) -> Result<(bool, Certainty), NoSolution>; + ) -> Result<(bool, Certainty, Vec<Goal<'tcx, ty::Predicate<'tcx>>>), NoSolution>; } impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> { @@ -77,8 +78,9 @@ impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> { fn evaluate_root_goal( &self, goal: Goal<'tcx, ty::Predicate<'tcx>>, - ) -> Result<(bool, Certainty), NoSolution> { - let mut search_graph = search_graph::SearchGraph::new(self.tcx); + ) -> Result<(bool, Certainty, Vec<Goal<'tcx, ty::Predicate<'tcx>>>), NoSolution> { + let mode = if self.intercrate { SolverMode::Coherence } else { SolverMode::Normal }; + let mut search_graph = search_graph::SearchGraph::new(self.tcx, mode); let mut ecx = EvalCtxt { search_graph: &mut search_graph, @@ -101,6 +103,10 @@ impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> { } impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { + pub(super) fn solver_mode(&self) -> SolverMode { + self.search_graph.solver_mode() + } + /// The entry point of the solver. /// /// This function deals with (coinductive) cycles, overflow, and caching @@ -120,8 +126,14 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { // // The actual solver logic happens in `ecx.compute_goal`. search_graph.with_new_goal(tcx, canonical_goal, |search_graph| { - let (ref infcx, goal, var_values) = - tcx.infer_ctxt().build_with_canonical(DUMMY_SP, &canonical_goal); + let intercrate = match search_graph.solver_mode() { + SolverMode::Normal => false, + SolverMode::Coherence => true, + }; + let (ref infcx, goal, var_values) = tcx + .infer_ctxt() + .intercrate(intercrate) + .build_with_canonical(DUMMY_SP, &canonical_goal); let mut ecx = EvalCtxt { infcx, var_values, @@ -139,13 +151,13 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { &mut self, is_normalizes_to_hack: IsNormalizesToHack, goal: Goal<'tcx, ty::Predicate<'tcx>>, - ) -> Result<(bool, Certainty), NoSolution> { + ) -> Result<(bool, Certainty, Vec<Goal<'tcx, ty::Predicate<'tcx>>>), NoSolution> { let (orig_values, canonical_goal) = self.canonicalize_goal(goal); let canonical_response = EvalCtxt::evaluate_canonical_goal(self.tcx(), self.search_graph, canonical_goal)?; let has_changed = !canonical_response.value.var_values.is_identity(); - let certainty = self.instantiate_and_apply_query_response( + let (certainty, nested_goals) = self.instantiate_and_apply_query_response( goal.param_env, orig_values, canonical_response, @@ -173,7 +185,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { assert_eq!(certainty, canonical_response.value.certainty); } - Ok((has_changed, certainty)) + Ok((has_changed, certainty, nested_goals)) } fn compute_goal(&mut self, goal: Goal<'tcx, ty::Predicate<'tcx>>) -> QueryResult<'tcx> { @@ -223,9 +235,11 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { ty::PredicateKind::TypeWellFormedFromEnv(..) => { bug!("TypeWellFormedFromEnv is only used for Chalk") } - ty::PredicateKind::AliasEq(lhs, rhs) => { - self.compute_alias_eq_goal(Goal { param_env, predicate: (lhs, rhs) }) - } + ty::PredicateKind::AliasRelate(lhs, rhs, direction) => self + .compute_alias_relate_goal(Goal { + param_env, + predicate: (lhs, rhs, direction), + }), } } else { let kind = self.infcx.instantiate_binder_with_placeholders(kind); @@ -248,13 +262,14 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { let mut has_changed = Err(Certainty::Yes); if let Some(goal) = goals.normalizes_to_hack_goal.take() { - let (_, certainty) = match this.evaluate_goal( + let (_, certainty, nested_goals) = match this.evaluate_goal( IsNormalizesToHack::Yes, goal.with(this.tcx(), ty::Binder::dummy(goal.predicate)), ) { Ok(r) => r, Err(NoSolution) => return Some(Err(NoSolution)), }; + new_goals.goals.extend(nested_goals); if goal.predicate.projection_ty != this.resolve_vars_if_possible(goal.predicate.projection_ty) @@ -293,11 +308,12 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { } for nested_goal in goals.goals.drain(..) { - let (changed, certainty) = + let (changed, certainty, nested_goals) = match this.evaluate_goal(IsNormalizesToHack::No, nested_goal) { Ok(result) => result, Err(NoSolution) => return Some(Err(NoSolution)), }; + new_goals.goals.extend(nested_goals); if changed { has_changed = Ok(()); @@ -457,6 +473,25 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { }) } + #[instrument(level = "debug", skip(self, param_env), ret)] + pub(super) fn sub<T: ToTrace<'tcx>>( + &mut self, + param_env: ty::ParamEnv<'tcx>, + sub: T, + sup: T, + ) -> Result<(), NoSolution> { + self.infcx + .at(&ObligationCause::dummy(), param_env) + .sub(DefineOpaqueTypes::No, sub, sup) + .map(|InferOk { value: (), obligations }| { + self.add_goals(obligations.into_iter().map(|o| o.into())); + }) + .map_err(|e| { + debug!(?e, "failed to subtype"); + NoSolution + }) + } + /// Equates two values returning the nested goals without adding them /// to the nested goals of the `EvalCtxt`. /// diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index 38120b9760f..76a2a587911 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -1,6 +1,7 @@ use std::mem; use rustc_infer::infer::InferCtxt; +use rustc_infer::traits::Obligation; use rustc_infer::traits::{ query::NoSolution, FulfillmentError, FulfillmentErrorCode, MismatchedProjectionTypes, PredicateObligation, SelectionError, TraitEngine, @@ -61,7 +62,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> { let mut has_changed = false; for obligation in mem::take(&mut self.obligations) { let goal = obligation.clone().into(); - let (changed, certainty) = match infcx.evaluate_root_goal(goal) { + let (changed, certainty, nested_goals) = match infcx.evaluate_root_goal(goal) { Ok(result) => result, Err(NoSolution) => { errors.push(FulfillmentError { @@ -73,7 +74,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> { MismatchedProjectionTypes { err: TypeError::Mismatch }, ) } - ty::PredicateKind::AliasEq(_, _) => { + ty::PredicateKind::AliasRelate(_, _, _) => { FulfillmentErrorCode::CodeProjectionError( MismatchedProjectionTypes { err: TypeError::Mismatch }, ) @@ -125,7 +126,16 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> { continue; } }; - + // Push any nested goals that we get from unifying our canonical response + // with our obligation onto the fulfillment context. + self.obligations.extend(nested_goals.into_iter().map(|goal| { + Obligation::new( + infcx.tcx, + obligation.cause.clone(), + goal.param_env, + goal.predicate, + ) + })); has_changed |= changed; match certainty { Certainty::Yes => {} diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index 606c2eaa510..6a64dfdedd4 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -9,15 +9,10 @@ //! FIXME(@lcnr): Write that section. If you read this before then ask me //! about it on zulip. -// FIXME: Instead of using `infcx.canonicalize_query` we have to add a new routine which -// preserves universes and creates a unique var (in the highest universe) for each -// appearance of a region. - // FIXME: uses of `infcx.at` need to enable deferred projection equality once that's implemented. use rustc_hir::def_id::DefId; use rustc_infer::infer::canonical::{Canonical, CanonicalVarValues}; -use rustc_infer::infer::{DefineOpaqueTypes, InferOk}; use rustc_infer::traits::query::NoSolution; use rustc_middle::traits::solve::{ CanonicalGoal, CanonicalResponse, Certainty, ExternalConstraints, ExternalConstraintsData, @@ -41,6 +36,19 @@ mod trait_goals; pub use eval_ctxt::{EvalCtxt, InferCtxtEvalExt}; pub use fulfill::FulfillmentCtxt; +#[derive(Debug, Clone, Copy)] +enum SolverMode { + /// Ordinary trait solving, using everywhere except for coherence. + Normal, + /// Trait solving during coherence. There are a few notable differences + /// between coherence and ordinary trait solving. + /// + /// Most importantly, trait solving during coherence must not be incomplete, + /// i.e. return `Err(NoSolution)` for goals for which a solution exists. + /// This means that we must not make any guesses or arbitrary choices. + Coherence, +} + trait CanonicalResponseExt { fn has_no_inference_or_external_constraints(&self) -> bool; } @@ -101,11 +109,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { // That won't actually reflect in the query response, so it seems moot. self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) } else { - let InferOk { value: (), obligations } = self - .infcx - .at(&ObligationCause::dummy(), goal.param_env) - .sub(DefineOpaqueTypes::No, goal.predicate.a, goal.predicate.b)?; - self.add_goals(obligations.into_iter().map(|pred| pred.into())); + self.sub(goal.param_env, goal.predicate.a, goal.predicate.b)?; self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } } @@ -156,55 +160,94 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { } #[instrument(level = "debug", skip(self), ret)] - fn compute_alias_eq_goal( + fn compute_alias_relate_goal( &mut self, - goal: Goal<'tcx, (ty::Term<'tcx>, ty::Term<'tcx>)>, + goal: Goal<'tcx, (ty::Term<'tcx>, ty::Term<'tcx>, ty::AliasRelationDirection)>, ) -> QueryResult<'tcx> { let tcx = self.tcx(); + // We may need to invert the alias relation direction if dealing an alias on the RHS. + enum Invert { + No, + Yes, + } + let evaluate_normalizes_to = + |ecx: &mut EvalCtxt<'_, 'tcx>, alias, other, direction, invert| { + debug!("evaluate_normalizes_to(alias={:?}, other={:?})", alias, other); + let result = ecx.probe(|ecx| { + let other = match direction { + // This is purely an optimization. + ty::AliasRelationDirection::Equate => other, + + ty::AliasRelationDirection::Subtype => { + let fresh = ecx.next_term_infer_of_kind(other); + let (sub, sup) = match invert { + Invert::No => (fresh, other), + Invert::Yes => (other, fresh), + }; + ecx.sub(goal.param_env, sub, sup)?; + fresh + } + }; + ecx.add_goal(goal.with( + tcx, + ty::Binder::dummy(ty::ProjectionPredicate { + projection_ty: alias, + term: other, + }), + )); + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + }); + debug!("evaluate_normalizes_to({alias}, {other}, {direction:?}) -> {result:?}"); + result + }; - let evaluate_normalizes_to = |ecx: &mut EvalCtxt<'_, 'tcx>, alias, other| { - debug!("evaluate_normalizes_to(alias={:?}, other={:?})", alias, other); - let r = ecx.probe(|ecx| { - ecx.add_goal(goal.with( - tcx, - ty::Binder::dummy(ty::ProjectionPredicate { - projection_ty: alias, - term: other, - }), - )); - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) - }); - debug!("evaluate_normalizes_to(..) -> {:?}", r); - r - }; + let (lhs, rhs, direction) = goal.predicate; - if goal.predicate.0.is_infer() || goal.predicate.1.is_infer() { + if lhs.is_infer() || rhs.is_infer() { bug!( - "`AliasEq` goal with an infer var on lhs or rhs which should have been instantiated" + "`AliasRelate` goal with an infer var on lhs or rhs which should have been instantiated" ); } - match ( - goal.predicate.0.to_alias_term_no_opaque(tcx), - goal.predicate.1.to_alias_term_no_opaque(tcx), - ) { - (None, None) => bug!("`AliasEq` goal without an alias on either lhs or rhs"), - (Some(alias), None) => evaluate_normalizes_to(self, alias, goal.predicate.1), - (None, Some(alias)) => evaluate_normalizes_to(self, alias, goal.predicate.0), - (Some(alias_lhs), Some(alias_rhs)) => { - debug!("compute_alias_eq_goal: both sides are aliases"); + match (lhs.to_projection_term(tcx), rhs.to_projection_term(tcx)) { + (None, None) => bug!("`AliasRelate` goal without an alias on either lhs or rhs"), - let mut candidates = Vec::with_capacity(3); + // RHS is not a projection, only way this is true is if LHS normalizes-to RHS + (Some(alias_lhs), None) => { + evaluate_normalizes_to(self, alias_lhs, rhs, direction, Invert::No) + } - // Evaluate all 3 potential candidates for the alias' being equal - candidates.push(evaluate_normalizes_to(self, alias_lhs, goal.predicate.1)); - candidates.push(evaluate_normalizes_to(self, alias_rhs, goal.predicate.0)); - candidates.push(self.probe(|ecx| { - debug!("compute_alias_eq_goal: alias defids are equal, equating substs"); - ecx.eq(goal.param_env, alias_lhs, alias_rhs)?; - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) - })); + // LHS is not a projection, only way this is true is if RHS normalizes-to LHS + (None, Some(alias_rhs)) => { + evaluate_normalizes_to(self, alias_rhs, lhs, direction, Invert::Yes) + } + (Some(alias_lhs), Some(alias_rhs)) => { + debug!("compute_alias_relate_goal: both sides are aliases"); + + let candidates = vec![ + // LHS normalizes-to RHS + evaluate_normalizes_to(self, alias_lhs, rhs, direction, Invert::No), + // RHS normalizes-to RHS + evaluate_normalizes_to(self, alias_rhs, lhs, direction, Invert::Yes), + // Relate via substs + self.probe(|ecx| { + debug!( + "compute_alias_relate_goal: alias defids are equal, equating substs" + ); + + match direction { + ty::AliasRelationDirection::Equate => { + ecx.eq(goal.param_env, alias_lhs, alias_rhs)?; + } + ty::AliasRelationDirection::Subtype => { + ecx.sub(goal.param_env, alias_lhs, alias_rhs)?; + } + } + + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + }), + ]; debug!(?candidates); self.try_merge_responses(candidates.into_iter()) @@ -255,7 +298,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { return Err(NoSolution); } - // FIXME(-Ztreat-solver=next): We should instead try to find a `Certainty::Yes` response with + // FIXME(-Ztrait-solver=next): We should instead try to find a `Certainty::Yes` response with // a subset of the constraints that all the other responses have. let one = candidates[0]; if candidates[1..].iter().all(|resp| resp == &one) { diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs index df821a2913a..525b3105538 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs @@ -34,7 +34,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { // projection cache in the solver. if self.term_is_fully_unconstrained(goal) { let candidates = self.assemble_and_evaluate_candidates(goal); - self.merge_candidates_and_discard_reservation_impls(candidates) + self.merge_candidates(candidates) } else { let predicate = goal.predicate; let unconstrained_rhs = self.next_term_infer_of_kind(predicate.term); @@ -56,6 +56,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { self.self_ty() } + fn trait_ref(self, tcx: TyCtxt<'tcx>) -> ty::TraitRef<'tcx> { + self.projection_ty.trait_ref(tcx) + } + fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self { self.with_self_ty(tcx, self_ty) } diff --git a/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs b/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs index 83d77a69c00..219890b9dc4 100644 --- a/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs @@ -1,8 +1,9 @@ mod cache; mod overflow; +pub(super) use overflow::OverflowHandler; + use self::cache::ProvisionalEntry; -pub(super) use crate::solve::search_graph::overflow::OverflowHandler; use cache::ProvisionalCache; use overflow::OverflowData; use rustc_index::vec::IndexVec; @@ -11,6 +12,8 @@ use rustc_middle::traits::solve::{CanonicalGoal, Certainty, MaybeCause, QueryRes use rustc_middle::ty::TyCtxt; use std::{collections::hash_map::Entry, mem}; +use super::SolverMode; + rustc_index::newtype_index! { pub struct StackDepth {} } @@ -21,6 +24,7 @@ struct StackElem<'tcx> { } pub(super) struct SearchGraph<'tcx> { + mode: SolverMode, /// The stack of goals currently being computed. /// /// An element is *deeper* in the stack if its index is *lower*. @@ -30,14 +34,19 @@ pub(super) struct SearchGraph<'tcx> { } impl<'tcx> SearchGraph<'tcx> { - pub(super) fn new(tcx: TyCtxt<'tcx>) -> SearchGraph<'tcx> { + pub(super) fn new(tcx: TyCtxt<'tcx>, mode: SolverMode) -> SearchGraph<'tcx> { Self { + mode, stack: Default::default(), overflow_data: OverflowData::new(tcx), provisional_cache: ProvisionalCache::empty(), } } + pub(super) fn solver_mode(&self) -> SolverMode { + self.mode + } + pub(super) fn is_empty(&self) -> bool { self.stack.is_empty() && self.provisional_cache.is_empty() } @@ -245,7 +254,8 @@ impl<'tcx> SearchGraph<'tcx> { // dependencies, our non-root goal may no longer appear as child of the root goal. // // See https://github.com/rust-lang/rust/pull/108071 for some additional context. - let should_cache_globally = !self.overflow_data.did_overflow() || self.stack.is_empty(); + let should_cache_globally = matches!(self.solver_mode(), SolverMode::Normal) + && (!self.overflow_data.did_overflow() || self.stack.is_empty()); if should_cache_globally { tcx.new_solver_evaluation_cache.insert( current_goal.goal, diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index 29b7ab61c7c..ade45d199f0 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -2,7 +2,7 @@ use std::iter; -use super::{assembly, EvalCtxt}; +use super::{assembly, EvalCtxt, SolverMode}; use rustc_hir::def_id::DefId; use rustc_hir::LangItem; use rustc_infer::traits::query::NoSolution; @@ -20,6 +20,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { self.self_ty() } + fn trait_ref(self, _: TyCtxt<'tcx>) -> ty::TraitRef<'tcx> { + self.trait_ref + } + fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self { self.with_self_ty(tcx, self_ty) } @@ -43,6 +47,22 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { return Err(NoSolution); } + let impl_polarity = tcx.impl_polarity(impl_def_id); + // An upper bound of the certainty of this goal, used to lower the certainty + // of reservation impl to ambiguous during coherence. + let maximal_certainty = match impl_polarity { + ty::ImplPolarity::Positive | ty::ImplPolarity::Negative => { + match impl_polarity == goal.predicate.polarity { + true => Certainty::Yes, + false => return Err(NoSolution), + } + } + ty::ImplPolarity::Reservation => match ecx.solver_mode() { + SolverMode::Normal => return Err(NoSolution), + SolverMode::Coherence => Certainty::AMBIGUOUS, + }, + }; + ecx.probe(|ecx| { let impl_substs = ecx.fresh_substs_for_item(impl_def_id); let impl_trait_ref = impl_trait_ref.subst(tcx, impl_substs); @@ -55,7 +75,8 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { .into_iter() .map(|pred| goal.with(tcx, pred)); ecx.add_goals(where_clause_bounds); - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + + ecx.evaluate_added_goals_and_make_canonical_response(maximal_certainty) }) } @@ -561,6 +582,6 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { goal: Goal<'tcx, TraitPredicate<'tcx>>, ) -> QueryResult<'tcx> { let candidates = self.assemble_and_evaluate_candidates(goal); - self.merge_candidates_and_discard_reservation_impls(candidates) + self.merge_candidates(candidates) } } diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index dbf6775afc2..6b3a59b1ed5 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -832,7 +832,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { // the `ParamEnv`. ty::PredicateKind::WellFormed(..) | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) - | ty::PredicateKind::AliasEq(..) + | ty::PredicateKind::AliasRelate(..) | ty::PredicateKind::ObjectSafe(..) | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::Subtype(..) diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index 572d20b5368..98e00e8223b 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -95,8 +95,11 @@ pub fn overlapping_impls( return None; } - let infcx = - tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bubble).intercrate().build(); + let infcx = tcx + .infer_ctxt() + .with_opaque_type_inference(DefiningAnchor::Bubble) + .intercrate(true) + .build(); let selcx = &mut SelectionContext::new(&infcx); let overlaps = overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id, overlap_mode).is_some(); @@ -107,8 +110,11 @@ pub fn overlapping_impls( // In the case where we detect an error, run the check again, but // this time tracking intercrate ambiguity causes for better // diagnostics. (These take time and can lead to false errors.) - let infcx = - tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bubble).intercrate().build(); + let infcx = tcx + .infer_ctxt() + .with_opaque_type_inference(DefiningAnchor::Bubble) + .intercrate(true) + .build(); let selcx = &mut SelectionContext::new(&infcx); selcx.enable_tracking_intercrate_ambiguity_causes(); Some(overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id, overlap_mode).unwrap()) diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/method_chain.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/method_chain.rs index 1174efdbfa8..13607b9079a 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/method_chain.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/method_chain.rs @@ -92,6 +92,11 @@ impl<'a, 'tcx> TypeRelation<'tcx> for CollectAllMismatches<'a, 'tcx> { } impl<'tcx> ObligationEmittingRelation<'tcx> for CollectAllMismatches<'_, 'tcx> { + fn alias_relate_direction(&self) -> ty::AliasRelationDirection { + // FIXME(deferred_projection_equality): We really should get rid of this relation. + ty::AliasRelationDirection::Equate + } + fn register_obligations(&mut self, _obligations: PredicateObligations<'tcx>) { // FIXME(deferred_projection_equality) } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 41ffaeeac1c..296fd1ed524 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -1276,16 +1276,26 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { "TypeWellFormedFromEnv predicate should only exist in the environment" ), - ty::PredicateKind::AliasEq(..) => span_bug!( + ty::PredicateKind::AliasRelate(..) => span_bug!( span, - "AliasEq predicate should never be the predicate cause of a SelectionError" + "AliasRelate predicate should never be the predicate cause of a SelectionError" ), ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(ct, ty)) => { - self.tcx.sess.struct_span_err( + let mut diag = self.tcx.sess.struct_span_err( span, &format!("the constant `{}` is not of type `{}`", ct, ty), - ) + ); + self.note_type_err( + &mut diag, + &obligation.cause, + None, + None, + TypeError::Sorts(ty::error::ExpectedFound::new(true, ty, ct.ty())), + false, + false, + ); + diag } } } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index b501840b926..be0817472ea 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -212,7 +212,7 @@ pub trait TypeErrCtxtExt<'tcx> { fn extract_callable_info( &self, - hir_id: HirId, + body_id: LocalDefId, param_env: ty::ParamEnv<'tcx>, found: Ty<'tcx>, ) -> Option<(DefIdOrName, Ty<'tcx>, Vec<Ty<'tcx>>)>; @@ -909,9 +909,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { trait_pred.self_ty(), ); - let body_hir_id = self.tcx.hir().local_def_id_to_hir_id(obligation.cause.body_id); let Some((def_id_or_name, output, inputs)) = self.extract_callable_info( - body_hir_id, + obligation.cause.body_id, obligation.param_env, self_ty, ) else { return false; }; @@ -1113,10 +1112,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { /// Extracts information about a callable type for diagnostics. This is a /// heuristic -- it doesn't necessarily mean that a type is always callable, /// because the callable type must also be well-formed to be called. - // FIXME(vincenzopalazzo): move the HirId to a LocalDefId fn extract_callable_info( &self, - hir_id: HirId, + body_id: LocalDefId, param_env: ty::ParamEnv<'tcx>, found: Ty<'tcx>, ) -> Option<(DefIdOrName, Ty<'tcx>, Vec<Ty<'tcx>>)> { @@ -1168,7 +1166,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { }) } ty::Param(param) => { - let generics = self.tcx.generics_of(hir_id.owner.to_def_id()); + let generics = self.tcx.generics_of(body_id); let name = if generics.count() > param.index as usize && let def = generics.param_at(param.index as usize, self.tcx) && matches!(def.kind, ty::GenericParamDefKind::Type { .. }) @@ -1358,6 +1356,31 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { Applicability::MaybeIncorrect, ); } else { + let is_mut = mut_ref_self_ty_satisfies_pred || ref_inner_ty_mut; + let sugg_prefix = format!("&{}", if is_mut { "mut " } else { "" }); + let sugg_msg = &format!( + "consider{} borrowing here", + if is_mut { " mutably" } else { "" } + ); + + // Issue #109436, we need to add parentheses properly for method calls + // for example, `foo.into()` should be `(&foo).into()` + if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet( + self.tcx.sess.source_map().span_look_ahead(span, Some("."), Some(50)), + ) { + if snippet == "." { + err.multipart_suggestion_verbose( + sugg_msg, + vec![ + (span.shrink_to_lo(), format!("({}", sugg_prefix)), + (span.shrink_to_hi(), ")".to_string()), + ], + Applicability::MaybeIncorrect, + ); + return true; + } + } + // Issue #104961, we need to add parentheses properly for compond expressions // for example, `x.starts_with("hi".to_string() + "you")` // should be `x.starts_with(&("hi".to_string() + "you"))` @@ -1374,14 +1397,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { _ => false, }; - let is_mut = mut_ref_self_ty_satisfies_pred || ref_inner_ty_mut; let span = if needs_parens { span } else { span.shrink_to_lo() }; - let sugg_prefix = format!("&{}", if is_mut { "mut " } else { "" }); - let sugg_msg = &format!( - "consider{} borrowing here", - if is_mut { " mutably" } else { "" } - ); - let suggestions = if !needs_parens { vec![(span.shrink_to_lo(), format!("{}", sugg_prefix))] } else { diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 23754480fcf..07e31e87bfb 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -361,8 +361,8 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { ty::PredicateKind::TypeWellFormedFromEnv(..) => { bug!("TypeWellFormedFromEnv is only used for Chalk") } - ty::PredicateKind::AliasEq(..) => { - bug!("AliasEq is only used for new solver") + ty::PredicateKind::AliasRelate(..) => { + bug!("AliasRelate is only used for new solver") } }, Some(pred) => match pred { @@ -630,8 +630,8 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { ty::PredicateKind::TypeWellFormedFromEnv(..) => { bug!("TypeWellFormedFromEnv is only used for Chalk") } - ty::PredicateKind::AliasEq(..) => { - bug!("AliasEq is only used for new solver") + ty::PredicateKind::AliasRelate(..) => { + bug!("AliasRelate is only used for new solver") } ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(ct, ty)) => { match self.selcx.infcx.at(&obligation.cause, obligation.param_env).eq( diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index b27a3929078..e8970606704 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -4,7 +4,7 @@ pub mod auto_trait; mod chalk_fulfill; -mod coherence; +pub(crate) mod coherence; pub mod const_evaluatable; mod engine; pub mod error_reporting; diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 038f8964471..5d2af5ff33c 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -335,7 +335,7 @@ fn predicate_references_self<'tcx>( has_self_ty(&ty.into()).then_some(sp) } - ty::PredicateKind::AliasEq(..) => bug!("`AliasEq` not allowed as assumption"), + ty::PredicateKind::AliasRelate(..) => bug!("`AliasRelate` not allowed as assumption"), ty::PredicateKind::WellFormed(..) | ty::PredicateKind::ObjectSafe(..) @@ -395,7 +395,7 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool { | ty::PredicateKind::Clause(ty::Clause::TypeOutlives(..)) | ty::PredicateKind::ConstEvaluatable(..) | ty::PredicateKind::ConstEquate(..) - | ty::PredicateKind::AliasEq(..) + | ty::PredicateKind::AliasRelate(..) | ty::PredicateKind::Ambiguous | ty::PredicateKind::TypeWellFormedFromEnv(..) => false, } diff --git a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs index f84b2f4428d..edbe2de8105 100644 --- a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs +++ b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs @@ -1,9 +1,8 @@ -use rustc_middle::traits::solve::{Certainty, Goal, MaybeCause}; +use rustc_infer::traits::{TraitEngine, TraitEngineExt}; use rustc_middle::ty; use crate::infer::canonical::OriginalQueryValues; use crate::infer::InferCtxt; -use crate::solve::InferCtxtEvalExt; use crate::traits::{EvaluationResult, OverflowError, PredicateObligation, SelectionContext}; pub trait InferCtxtExt<'tcx> { @@ -81,27 +80,20 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { if self.tcx.trait_solver_next() { self.probe(|snapshot| { - if let Ok((_, certainty)) = - self.evaluate_root_goal(Goal::new(self.tcx, param_env, obligation.predicate)) - { - match certainty { - Certainty::Yes => { - if self.opaque_types_added_in_snapshot(snapshot) { - Ok(EvaluationResult::EvaluatedToOkModuloOpaqueTypes) - } else if self.region_constraints_added_in_snapshot(snapshot).is_some() - { - Ok(EvaluationResult::EvaluatedToOkModuloRegions) - } else { - Ok(EvaluationResult::EvaluatedToOk) - } - } - Certainty::Maybe(MaybeCause::Ambiguity) => { - Ok(EvaluationResult::EvaluatedToAmbig) - } - Certainty::Maybe(MaybeCause::Overflow) => Err(OverflowError::Canonical), - } - } else { + let mut fulfill_cx = crate::solve::FulfillmentCtxt::new(); + fulfill_cx.register_predicate_obligation(self, obligation.clone()); + // True errors + // FIXME(-Ztrait-solver=next): Overflows are reported as ambig here, is that OK? + if !fulfill_cx.select_where_possible(self).is_empty() { Ok(EvaluationResult::EvaluatedToErr) + } else if !fulfill_cx.select_all_or_error(self).is_empty() { + Ok(EvaluationResult::EvaluatedToAmbig) + } else if self.opaque_types_added_in_snapshot(snapshot) { + Ok(EvaluationResult::EvaluatedToOkModuloOpaqueTypes) + } else if self.region_constraints_added_in_snapshot(snapshot).is_some() { + Ok(EvaluationResult::EvaluatedToOkModuloRegions) + } else { + Ok(EvaluationResult::EvaluatedToOk) } }) } else { diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index b8758ad9323..4f429f018ed 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -618,6 +618,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let mut fulfill_cx = crate::solve::FulfillmentCtxt::new(); fulfill_cx.register_predicate_obligations(self.infcx, predicates); // True errors + // FIXME(-Ztrait-solver=next): Overflows are reported as ambig here, is that OK? if !fulfill_cx.select_where_possible(self.infcx).is_empty() { return Ok(EvaluatedToErr); } @@ -977,8 +978,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ty::PredicateKind::TypeWellFormedFromEnv(..) => { bug!("TypeWellFormedFromEnv is only used for chalk") } - ty::PredicateKind::AliasEq(..) => { - bug!("AliasEq is only used for new solver") + ty::PredicateKind::AliasRelate(..) => { + bug!("AliasRelate is only used for new solver") } ty::PredicateKind::Ambiguous => Ok(EvaluatedToAmbig), ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(ct, ty)) => { diff --git a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs index cd665d9471d..11eb968a415 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs @@ -3,7 +3,7 @@ use super::OverlapError; use crate::traits; use rustc_errors::ErrorGuaranteed; use rustc_hir::def_id::DefId; -use rustc_middle::ty::fast_reject::{self, SimplifiedType, TreatParams, TreatProjections}; +use rustc_middle::ty::fast_reject::{self, SimplifiedType, TreatParams}; use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt}; pub use rustc_middle::traits::specialization_graph::*; @@ -49,12 +49,9 @@ impl<'tcx> ChildrenExt<'tcx> for Children { /// Insert an impl into this set of children without comparing to any existing impls. fn insert_blindly(&mut self, tcx: TyCtxt<'tcx>, impl_def_id: DefId) { let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().skip_binder(); - if let Some(st) = fast_reject::simplify_type( - tcx, - trait_ref.self_ty(), - TreatParams::AsCandidateKey, - TreatProjections::AsCandidateKey, - ) { + if let Some(st) = + fast_reject::simplify_type(tcx, trait_ref.self_ty(), TreatParams::AsCandidateKey) + { debug!("insert_blindly: impl_def_id={:?} st={:?}", impl_def_id, st); self.non_blanket_impls.entry(st).or_default().push(impl_def_id) } else { @@ -69,12 +66,9 @@ impl<'tcx> ChildrenExt<'tcx> for Children { fn remove_existing(&mut self, tcx: TyCtxt<'tcx>, impl_def_id: DefId) { let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().skip_binder(); let vec: &mut Vec<DefId>; - if let Some(st) = fast_reject::simplify_type( - tcx, - trait_ref.self_ty(), - TreatParams::AsCandidateKey, - TreatProjections::AsCandidateKey, - ) { + if let Some(st) = + fast_reject::simplify_type(tcx, trait_ref.self_ty(), TreatParams::AsCandidateKey) + { debug!("remove_existing: impl_def_id={:?} st={:?}", impl_def_id, st); vec = self.non_blanket_impls.get_mut(&st).unwrap(); } else { @@ -310,12 +304,8 @@ impl<'tcx> GraphExt<'tcx> for Graph { let mut parent = trait_def_id; let mut last_lint = None; - let simplified = fast_reject::simplify_type( - tcx, - trait_ref.self_ty(), - TreatParams::AsCandidateKey, - TreatProjections::AsCandidateKey, - ); + let simplified = + fast_reject::simplify_type(tcx, trait_ref.self_ty(), TreatParams::AsCandidateKey); // Descend the specialization tree, where `parent` is the current parent node. loop { diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index d498af359c5..ec5bd982a3c 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -191,8 +191,8 @@ pub fn predicate_obligations<'tcx>( ty::PredicateKind::TypeWellFormedFromEnv(..) => { bug!("TypeWellFormedFromEnv is only used for Chalk") } - ty::PredicateKind::AliasEq(..) => { - bug!("We should only wf check where clauses and `AliasEq` is not a `Clause`") + ty::PredicateKind::AliasRelate(..) => { + bug!("We should only wf check where clauses and `AliasRelate` is not a `Clause`") } } @@ -936,7 +936,7 @@ pub(crate) fn required_region_bounds<'tcx>( | ty::PredicateKind::ConstEvaluatable(..) | ty::PredicateKind::ConstEquate(..) | ty::PredicateKind::Ambiguous - | ty::PredicateKind::AliasEq(..) + | ty::PredicateKind::AliasRelate(..) | ty::PredicateKind::TypeWellFormedFromEnv(..) => None, ty::PredicateKind::Clause(ty::Clause::TypeOutlives(ty::OutlivesPredicate( ref t, diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs index 60e22d1001c..0e9bccba8d4 100644 --- a/compiler/rustc_traits/src/chalk/lowering.rs +++ b/compiler/rustc_traits/src/chalk/lowering.rs @@ -119,7 +119,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::InEnvironment<chalk_ir::Goal<RustInterner<' }, ty::PredicateKind::ObjectSafe(..) | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) - | ty::PredicateKind::AliasEq(..) + | ty::PredicateKind::AliasRelate(..) | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::Subtype(..) | ty::PredicateKind::Coerce(..) @@ -215,7 +215,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::GoalData<RustInterner<'tcx>>> for ty::Predi // some of these in terms of chalk operations. ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) - | ty::PredicateKind::AliasEq(..) + | ty::PredicateKind::AliasRelate(..) | ty::PredicateKind::Coerce(..) | ty::PredicateKind::ConstEvaluatable(..) | ty::PredicateKind::Ambiguous @@ -652,7 +652,7 @@ impl<'tcx> LowerInto<'tcx, Option<chalk_ir::QuantifiedWhereClause<RustInterner<' ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) => None, ty::PredicateKind::ObjectSafe(..) - | ty::PredicateKind::AliasEq(..) + | ty::PredicateKind::AliasRelate(..) | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::Subtype(..) | ty::PredicateKind::Coerce(..) @@ -787,7 +787,7 @@ impl<'tcx> LowerInto<'tcx, Option<chalk_solve::rust_ir::QuantifiedInlineBound<Ru ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) => None, ty::PredicateKind::Clause(ty::Clause::RegionOutlives(..)) - | ty::PredicateKind::AliasEq(..) + | ty::PredicateKind::AliasRelate(..) | ty::PredicateKind::ObjectSafe(..) | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::Subtype(..) diff --git a/compiler/rustc_traits/src/implied_outlives_bounds.rs b/compiler/rustc_traits/src/implied_outlives_bounds.rs index ddd4ca1436c..f5bba14d2fb 100644 --- a/compiler/rustc_traits/src/implied_outlives_bounds.rs +++ b/compiler/rustc_traits/src/implied_outlives_bounds.rs @@ -86,7 +86,7 @@ fn compute_implied_outlives_bounds<'tcx>( if obligation.predicate.has_non_region_infer() { match obligation.predicate.kind().skip_binder() { ty::PredicateKind::Clause(ty::Clause::Projection(..)) - | ty::PredicateKind::AliasEq(..) => { + | ty::PredicateKind::AliasRelate(..) => { ocx.register_obligation(obligation.clone()); } _ => {} @@ -110,7 +110,7 @@ fn compute_implied_outlives_bounds<'tcx>( | ty::PredicateKind::ConstEvaluatable(..) | ty::PredicateKind::ConstEquate(..) | ty::PredicateKind::Ambiguous - | ty::PredicateKind::AliasEq(..) + | ty::PredicateKind::AliasRelate(..) | ty::PredicateKind::TypeWellFormedFromEnv(..) => {} // We need to search through *all* WellFormed predicates diff --git a/compiler/rustc_traits/src/normalize_erasing_regions.rs b/compiler/rustc_traits/src/normalize_erasing_regions.rs index f0597f19225..126a494f34f 100644 --- a/compiler/rustc_traits/src/normalize_erasing_regions.rs +++ b/compiler/rustc_traits/src/normalize_erasing_regions.rs @@ -61,7 +61,7 @@ fn not_outlives_predicate(p: ty::Predicate<'_>) -> bool { ty::PredicateKind::Clause(ty::Clause::Trait(..)) | ty::PredicateKind::Clause(ty::Clause::Projection(..)) | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) - | ty::PredicateKind::AliasEq(..) + | ty::PredicateKind::AliasRelate(..) | ty::PredicateKind::WellFormed(..) | ty::PredicateKind::ObjectSafe(..) | ty::PredicateKind::ClosureKind(..) diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index 35c9f95eb03..ee5a7909ba3 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -539,7 +539,7 @@ fn make_thin_self_ptr<'tcx>( // get a built-in pointer type let mut fat_pointer_layout = layout; 'descend_newtypes: while !fat_pointer_layout.ty.is_unsafe_ptr() - && !fat_pointer_layout.ty.is_region_ptr() + && !fat_pointer_layout.ty.is_ref() { for i in 0..fat_pointer_layout.fields.count() { let field_layout = fat_pointer_layout.field(cx, i); diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs index 6d9ad96fa74..bf0bc202852 100644 --- a/compiler/rustc_ty_utils/src/assoc.rs +++ b/compiler/rustc_ty_utils/src/assoc.rs @@ -254,13 +254,16 @@ fn associated_type_for_impl_trait_in_trait( tcx: TyCtxt<'_>, opaque_ty_def_id: LocalDefId, ) -> LocalDefId { - let fn_def_id = tcx.impl_trait_in_trait_parent_fn(opaque_ty_def_id.to_def_id()); - let trait_def_id = tcx.parent(fn_def_id); + let (hir::OpaqueTyOrigin::FnReturn(fn_def_id) | hir::OpaqueTyOrigin::AsyncFn(fn_def_id)) = + tcx.hir().expect_item(opaque_ty_def_id).expect_opaque_ty().origin + else { + bug!("expected opaque for {opaque_ty_def_id:?}"); + }; + let trait_def_id = tcx.local_parent(fn_def_id); assert_eq!(tcx.def_kind(trait_def_id), DefKind::Trait); let span = tcx.def_span(opaque_ty_def_id); - let trait_assoc_ty = - tcx.at(span).create_def(trait_def_id.expect_local(), DefPathData::ImplTraitAssocTy); + let trait_assoc_ty = tcx.at(span).create_def(trait_def_id, DefPathData::ImplTraitAssocTy); let local_def_id = trait_assoc_ty.def_id(); let def_id = local_def_id.to_def_id(); @@ -282,7 +285,7 @@ fn associated_type_for_impl_trait_in_trait( container: ty::TraitContainer, fn_has_self_parameter: false, opt_rpitit_info: Some(ImplTraitInTraitData::Trait { - fn_def_id, + fn_def_id: fn_def_id.to_def_id(), opaque_def_id: opaque_ty_def_id.to_def_id(), }), }); @@ -324,7 +327,7 @@ fn associated_type_for_impl_trait_in_trait( params.iter().map(|param| (param.def_id, param.index)).collect(); ty::Generics { - parent: Some(trait_def_id), + parent: Some(trait_def_id.to_def_id()), parent_count, params, param_def_id_to_index, @@ -335,7 +338,7 @@ fn associated_type_for_impl_trait_in_trait( // There are no predicates for the synthesized associated type. trait_assoc_ty.explicit_predicates_of(ty::GenericPredicates { - parent: Some(trait_def_id), + parent: Some(trait_def_id.to_def_id()), predicates: &[], }); @@ -356,7 +359,6 @@ fn associated_type_for_impl_trait_in_impl( impl_fn_def_id: LocalDefId, ) -> LocalDefId { let impl_local_def_id = tcx.local_parent(impl_fn_def_id); - let impl_def_id = impl_local_def_id.to_def_id(); // FIXME fix the span, we probably want the def_id of the return type of the function let span = tcx.def_span(impl_fn_def_id); @@ -384,10 +386,6 @@ fn associated_type_for_impl_trait_in_impl( opt_rpitit_info: Some(ImplTraitInTraitData::Impl { fn_def_id: impl_fn_def_id.to_def_id() }), }); - // Copy param_env of the containing function. The synthesized associated type doesn't have - // extra predicates to assume. - impl_assoc_ty.param_env(tcx.param_env(impl_fn_def_id)); - // Copy visility of the containing function. impl_assoc_ty.visibility(tcx.visibility(impl_fn_def_id)); @@ -402,7 +400,7 @@ fn associated_type_for_impl_trait_in_impl( let trait_assoc_parent_count = trait_assoc_generics.parent_count; let mut params = trait_assoc_generics.params.clone(); - let parent_generics = tcx.generics_of(impl_def_id); + let parent_generics = tcx.generics_of(impl_local_def_id.to_def_id()); let parent_count = parent_generics.parent_count + parent_generics.params.len(); for param in &mut params { @@ -413,7 +411,7 @@ fn associated_type_for_impl_trait_in_impl( params.iter().map(|param| (param.def_id, param.index)).collect(); ty::Generics { - parent: Some(impl_def_id), + parent: Some(impl_local_def_id.to_def_id()), parent_count, params, param_def_id_to_index, @@ -424,7 +422,7 @@ fn associated_type_for_impl_trait_in_impl( // There are no predicates for the synthesized associated type. impl_assoc_ty.explicit_predicates_of(ty::GenericPredicates { - parent: Some(impl_def_id), + parent: Some(impl_local_def_id.to_def_id()), predicates: &[], }); diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index 70686eefbca..50aeb7f440f 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -130,7 +130,9 @@ fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> { // FIXME(-Zlower-impl-trait-in-trait-to-assoc-ty): I don't like this, we should // at least be making sure that the generics in RPITITs and their parent fn don't // get out of alignment, or else we do actually need to substitute these predicates. - if let Some(ImplTraitInTraitData::Trait { fn_def_id, .. }) = tcx.opt_rpitit_info(def_id) { + if let Some(ImplTraitInTraitData::Trait { fn_def_id, .. }) + | Some(ImplTraitInTraitData::Impl { fn_def_id, .. }) = tcx.opt_rpitit_info(def_id) + { predicates = tcx.predicates_of(fn_def_id).instantiate_identity(tcx).predicates; } diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index 5a991e03dee..8b23fbc7583 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -432,6 +432,17 @@ impl IntTy { _ => *self, } } + + pub fn to_unsigned(self) -> UintTy { + match self { + IntTy::Isize => UintTy::Usize, + IntTy::I8 => UintTy::U8, + IntTy::I16 => UintTy::U16, + IntTy::I32 => UintTy::U32, + IntTy::I64 => UintTy::U64, + IntTy::I128 => UintTy::U128, + } + } } #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, Debug)] @@ -479,6 +490,17 @@ impl UintTy { _ => *self, } } + + pub fn to_signed(self) -> IntTy { + match self { + UintTy::Usize => IntTy::Isize, + UintTy::U8 => IntTy::I8, + UintTy::U16 => IntTy::I16, + UintTy::U32 => IntTy::I32, + UintTy::U64 => IntTy::I64, + UintTy::U128 => IntTy::I128, + } + } } #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] diff --git a/library/alloc/src/collections/btree/mod.rs b/library/alloc/src/collections/btree/mod.rs index 7552f2fc04c..c7d0144de30 100644 --- a/library/alloc/src/collections/btree/mod.rs +++ b/library/alloc/src/collections/btree/mod.rs @@ -13,7 +13,6 @@ pub mod set; mod set_val; mod split; -#[doc(hidden)] trait Recover<Q: ?Sized> { type Key; diff --git a/library/alloc/src/collections/btree/set.rs b/library/alloc/src/collections/btree/set.rs index 4ddb2119252..4de30d40825 100644 --- a/library/alloc/src/collections/btree/set.rs +++ b/library/alloc/src/collections/btree/set.rs @@ -1,6 +1,3 @@ -// This is pretty much entirely stolen from TreeSet, since BTreeMap has an identical interface -// to TreeMap - use crate::vec::Vec; use core::borrow::Borrow; use core::cmp::Ordering::{self, Equal, Greater, Less}; @@ -18,8 +15,6 @@ use super::Recover; use crate::alloc::{Allocator, Global}; -// FIXME(conventions): implement bounded iterators - /// An ordered set based on a B-Tree. /// /// See [`BTreeMap`]'s documentation for a detailed discussion of this collection's performance diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 089b6b6418d..1e9cf404f77 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -692,10 +692,10 @@ impl<T> Rc<T> { /// it is guaranteed that exactly one of the calls returns the inner value. /// This means in particular that the inner value is not dropped. /// - /// This is equivalent to `Rc::try_unwrap(...).ok()`. (Note that these are not equivalent for - /// `Arc`, due to race conditions that do not apply to `Rc`.) + /// This is equivalent to `Rc::try_unwrap(this).ok()`. (Note that these are not equivalent for + /// [`Arc`](crate::sync::Arc), due to race conditions that do not apply to `Rc`.) #[inline] - #[unstable(feature = "rc_into_inner", issue = "106894")] + #[stable(feature = "rc_into_inner", since = "CURRENT_RUSTC_VERSION")] pub fn into_inner(this: Self) -> Option<T> { Rc::try_unwrap(this).ok() } diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 8a27a7ecdf6..150924851d2 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -662,20 +662,17 @@ impl<T> Arc<T> { /// /// This will succeed even if there are outstanding weak references. /// - // FIXME: when `Arc::into_inner` is stabilized, add this paragraph: - /* /// It is strongly recommended to use [`Arc::into_inner`] instead if you don't /// want to keep the `Arc` in the [`Err`] case. /// Immediately dropping the [`Err`] payload, like in the expression /// `Arc::try_unwrap(this).ok()`, can still cause the strong count to /// drop to zero and the inner value of the `Arc` to be dropped: - /// For instance if two threads execute this expression in parallel, then + /// For instance if two threads each execute this expression in parallel, then /// there is a race condition. The threads could first both check whether they /// have the last clone of their `Arc` via `Arc::try_unwrap`, and then /// both drop their `Arc` in the call to [`ok`][`Result::ok`], /// taking the strong count from two down to zero. /// - */ /// # Examples /// /// ``` @@ -719,20 +716,13 @@ impl<T> Arc<T> { /// This means in particular that the inner value is not dropped. /// /// The similar expression `Arc::try_unwrap(this).ok()` does not - /// offer such a guarantee. See the last example below. - // - // FIXME: when `Arc::into_inner` is stabilized, add this to end - // of the previous sentence: - /* + /// offer such a guarantee. See the last example below /// and the documentation of [`Arc::try_unwrap`]. - */ /// /// # Examples /// /// Minimal example demonstrating the guarantee that `Arc::into_inner` gives. /// ``` - /// #![feature(arc_into_inner)] - /// /// use std::sync::Arc; /// /// let x = Arc::new(3); @@ -756,8 +746,6 @@ impl<T> Arc<T> { /// /// A more practical example demonstrating the need for `Arc::into_inner`: /// ``` - /// #![feature(arc_into_inner)] - /// /// use std::sync::Arc; /// /// // Definition of a simple singly linked list using `Arc`: @@ -807,13 +795,8 @@ impl<T> Arc<T> { /// x_thread.join().unwrap(); /// y_thread.join().unwrap(); /// ``` - - // FIXME: when `Arc::into_inner` is stabilized, adjust above documentation - // and the documentation of `Arc::try_unwrap` according to the `FIXME`s. Also - // open an issue on rust-lang/rust-clippy, asking for a lint against - // `Arc::try_unwrap(...).ok()`. #[inline] - #[unstable(feature = "arc_into_inner", issue = "106894")] + #[stable(feature = "arc_into_inner", since = "CURRENT_RUSTC_VERSION")] pub fn into_inner(this: Self) -> Option<T> { // Make sure that the ordinary `Drop` implementation isn’t called as well let mut this = mem::ManuallyDrop::new(this); diff --git a/library/alloc/tests/str.rs b/library/alloc/tests/str.rs index 4d182be02c9..c1dbbde08b6 100644 --- a/library/alloc/tests/str.rs +++ b/library/alloc/tests/str.rs @@ -1499,13 +1499,25 @@ fn test_split_whitespace() { #[test] fn test_lines() { - let data = "\nMäry häd ä little lämb\n\r\nLittle lämb\n"; - let lines: Vec<&str> = data.lines().collect(); - assert_eq!(lines, ["", "Märy häd ä little lämb", "", "Little lämb"]); - - let data = "\r\nMäry häd ä little lämb\n\nLittle lämb"; // no trailing \n - let lines: Vec<&str> = data.lines().collect(); - assert_eq!(lines, ["", "Märy häd ä little lämb", "", "Little lämb"]); + fn t(data: &str, expected: &[&str]) { + let lines: Vec<&str> = data.lines().collect(); + assert_eq!(lines, expected); + } + t("", &[]); + t("\n", &[""]); + t("\n2nd", &["", "2nd"]); + t("\r\n", &[""]); + t("bare\r", &["bare\r"]); + t("bare\rcr", &["bare\rcr"]); + t("Text\n\r", &["Text", "\r"]); + t( + "\nMäry häd ä little lämb\n\r\nLittle lämb\n", + &["", "Märy häd ä little lämb", "", "Little lämb"], + ); + t( + "\r\nMäry häd ä little lämb\n\nLittle lämb", + &["", "Märy häd ä little lämb", "", "Little lämb"], + ); } #[test] diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index ee8846675ce..7482b8b0862 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -2214,6 +2214,12 @@ extern "rust-intrinsic" { where G: FnOnce<ARG, Output = RET>, F: FnOnce<ARG, Output = RET>; + + #[cfg(not(bootstrap))] + /// This method creates a pointer to any `Some` value. If the argument is + /// `None`, an invalid within-bounds pointer (that is still acceptable for + /// constructing an empty slice) is returned. + pub fn option_payload_ptr<T>(arg: *const Option<T>) -> *const T; } // Some functions are defined here because they accidentally got made diff --git a/library/core/src/intrinsics/mir.rs b/library/core/src/intrinsics/mir.rs index 64fc1c0c277..6690c1a76d5 100644 --- a/library/core/src/intrinsics/mir.rs +++ b/library/core/src/intrinsics/mir.rs @@ -49,6 +49,8 @@ //! //! The input to the [`mir!`] macro is: //! +//! - An optional return type annotation in the form of `type RET = ...;`. This may be required +//! if the compiler cannot infer the type of RET. //! - A possibly empty list of local declarations. Locals can also be declared inline on //! assignments via `let`. Type inference generally works. Shadowing does not. //! - A list of basic blocks. The first of these is the start block and is where execution begins. @@ -124,6 +126,18 @@ //! } //! ) //! } +//! +//! #[custom_mir(dialect = "runtime", phase = "optimized")] +//! fn annotated_return_type() -> (i32, bool) { +//! mir!( +//! type RET = (i32, bool); +//! { +//! RET.0 = 1; +//! RET.1 = true; +//! Return() +//! } +//! ) +//! } //! ``` //! //! We can also set off compilation failures that happen in sufficiently late stages of the @@ -330,6 +344,14 @@ define!( fn Variant<T>(place: T, index: u32) -> () ); define!( + "mir_cast_transmute", + /// Emits a `CastKind::Transmute` cast. + /// + /// Needed to test the UB when `sizeof(T) != sizeof(U)`, which can't be + /// generated via the normal `mem::transmute`. + fn CastTransmute<T, U>(operand: T) -> U +); +define!( "mir_make_place", #[doc(hidden)] fn __internal_make_place<T>(place: T) -> *mut T @@ -342,6 +364,7 @@ define!( #[rustc_macro_transparency = "transparent"] pub macro mir { ( + $(type RET = $ret_ty:ty ;)? $(let $local_decl:ident $(: $local_decl_ty:ty)? ;)* { @@ -362,7 +385,7 @@ pub macro mir { { // Now all locals #[allow(non_snake_case)] - let RET; + let RET $(: $ret_ty)?; $( let $local_decl $(: $local_decl_ty)? ; )* diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 1076d357070..a6b9acb576e 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -209,6 +209,7 @@ #![feature(derive_const)] #![feature(doc_cfg)] #![feature(doc_notable_trait)] +#![feature(generic_arg_infer)] #![feature(rustdoc_internals)] #![feature(exhaustive_patterns)] #![feature(doc_cfg_hide)] diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 0f2475a8bde..cba597e66aa 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -559,6 +559,7 @@ use crate::{ /// The `Option` type. See [the module level documentation](self) for more. #[derive(Copy, PartialOrd, Eq, Ord, Debug, Hash)] #[rustc_diagnostic_item = "Option"] +#[cfg_attr(not(bootstrap), lang = "Option")] #[stable(feature = "rust1", since = "1.0.0")] pub enum Option<T> { /// No value. @@ -735,48 +736,6 @@ impl<T> Option<T> { } } - /// This is a guess at how many bytes into the option the payload can be found. - /// - /// For niche-optimized types it's correct because it's pigeon-holed to only - /// one possible place. For other types, it's usually correct today, but - /// tweaks to the layout algorithm (particularly expansions of - /// `-Z randomize-layout`) might make it incorrect at any point. - /// - /// It's guaranteed to be a multiple of alignment (so will always give a - /// correctly-aligned location) and to be within the allocated object, so - /// is valid to use with `offset` and to use for a zero-sized read. - /// - /// FIXME: This is a horrible hack, but allows a nice optimization. It should - /// be replaced with `offset_of!` once that works on enum variants. - const SOME_BYTE_OFFSET_GUESS: isize = { - let some_uninit = Some(mem::MaybeUninit::<T>::uninit()); - let payload_ref = some_uninit.as_ref().unwrap(); - // SAFETY: `as_ref` gives an address inside the existing `Option`, - // so both pointers are derived from the same thing and the result - // cannot overflow an `isize`. - let offset = unsafe { <*const _>::byte_offset_from(payload_ref, &some_uninit) }; - - // The offset is into the object, so it's guaranteed to be non-negative. - assert!(offset >= 0); - - // The payload and the overall option are aligned, - // so the offset will be a multiple of the alignment too. - assert!((offset as usize) % mem::align_of::<T>() == 0); - - let max_offset = mem::size_of::<Self>() - mem::size_of::<T>(); - if offset as usize <= max_offset { - // There's enough space after this offset for a `T` to exist without - // overflowing the bounds of the object, so let's try it. - offset - } else { - // The offset guess is definitely wrong, so use the address - // of the original option since we have it already. - // This also correctly handles the case of layout-optimized enums - // where `max_offset == 0` and thus this is the only possibility. - 0 - } - }; - /// Returns a slice of the contained value, if any. If this is `None`, an /// empty slice is returned. This can be useful to have a single type of /// iterator over an `Option` or slice. @@ -809,28 +768,29 @@ impl<T> Option<T> { #[must_use] #[unstable(feature = "option_as_slice", issue = "108545")] pub fn as_slice(&self) -> &[T] { - let payload_ptr: *const T = - // The goal here is that both arms here are calculating exactly - // the same pointer, and thus it'll be folded away when the guessed - // offset is correct, but if the guess is wrong for some reason - // it'll at least still be sound, just no longer optimal. - if let Some(payload) = self { - payload - } else { - let self_ptr: *const Self = self; - // SAFETY: `SOME_BYTE_OFFSET_GUESS` guarantees that its value is - // such that this will be in-bounds of the object. - unsafe { self_ptr.byte_offset(Self::SOME_BYTE_OFFSET_GUESS).cast() } - }; - let len = usize::from(self.is_some()); + #[cfg(bootstrap)] + match self { + Some(value) => slice::from_ref(value), + None => &[], + } + #[cfg(not(bootstrap))] // SAFETY: When the `Option` is `Some`, we're using the actual pointer // to the payload, with a length of 1, so this is equivalent to // `slice::from_ref`, and thus is safe. // When the `Option` is `None`, the length used is 0, so to be safe it // just needs to be aligned, which it is because `&self` is aligned and // the offset used is a multiple of alignment. - unsafe { slice::from_raw_parts(payload_ptr, len) } + // + // In the new version, the intrinsic always returns a pointer to an + // in-bounds and correctly aligned position for a `T` (even if in the + // `None` case it's just padding). + unsafe { + slice::from_raw_parts( + crate::intrinsics::option_payload_ptr(crate::ptr::from_ref(self)), + usize::from(self.is_some()), + ) + } } /// Returns a mutable slice of the contained value, if any. If this is @@ -875,28 +835,32 @@ impl<T> Option<T> { #[must_use] #[unstable(feature = "option_as_slice", issue = "108545")] pub fn as_mut_slice(&mut self) -> &mut [T] { - let payload_ptr: *mut T = - // The goal here is that both arms here are calculating exactly - // the same pointer, and thus it'll be folded away when the guessed - // offset is correct, but if the guess is wrong for some reason - // it'll at least still be sound, just no longer optimal. - if let Some(payload) = self { - payload - } else { - let self_ptr: *mut Self = self; - // SAFETY: `SOME_BYTE_OFFSET_GUESS` guarantees that its value is - // such that this will be in-bounds of the object. - unsafe { self_ptr.byte_offset(Self::SOME_BYTE_OFFSET_GUESS).cast() } - }; - let len = usize::from(self.is_some()); + #[cfg(bootstrap)] + match self { + Some(value) => slice::from_mut(value), + None => &mut [], + } + #[cfg(not(bootstrap))] // SAFETY: When the `Option` is `Some`, we're using the actual pointer // to the payload, with a length of 1, so this is equivalent to // `slice::from_mut`, and thus is safe. // When the `Option` is `None`, the length used is 0, so to be safe it // just needs to be aligned, which it is because `&self` is aligned and // the offset used is a multiple of alignment. - unsafe { slice::from_raw_parts_mut(payload_ptr, len) } + // + // In the new version, the intrinsic creates a `*const T` from a + // mutable reference so it is safe to cast back to a mutable pointer + // here. As with `as_slice`, the intrinsic always returns a pointer to + // an in-bounds and correctly aligned position for a `T` (even if in + // the `None` case it's just padding). + unsafe { + slice::from_raw_parts_mut( + crate::intrinsics::option_payload_ptr(crate::ptr::from_mut(self).cast_const()) + .cast_mut(), + usize::from(self.is_some()), + ) + } } ///////////////////////////////////////////////////////////////////////// diff --git a/library/core/src/panicking.rs b/library/core/src/panicking.rs index dd0105c0eb4..35da9151b6f 100644 --- a/library/core/src/panicking.rs +++ b/library/core/src/panicking.rs @@ -29,6 +29,9 @@ use crate::fmt; use crate::panic::{Location, PanicInfo}; +#[cfg(feature = "panic_immediate_abort")] +const _: () = assert!(cfg!(panic = "abort"), "panic_immediate_abort requires -C panic=abort"); + // First we define the two main entry points that all panics go through. // In the end both are just convenience wrappers around `panic_impl`. diff --git a/library/core/src/str/iter.rs b/library/core/src/str/iter.rs index 95c682f42d0..772c3605562 100644 --- a/library/core/src/str/iter.rs +++ b/library/core/src/str/iter.rs @@ -13,7 +13,7 @@ use super::from_utf8_unchecked; use super::pattern::Pattern; use super::pattern::{DoubleEndedSearcher, ReverseSearcher, Searcher}; use super::validations::{next_code_point, next_code_point_reverse}; -use super::LinesAnyMap; +use super::LinesMap; use super::{BytesIsNotEmpty, UnsafeBytesToStr}; use super::{CharEscapeDebugContinue, CharEscapeDefault, CharEscapeUnicode}; use super::{IsAsciiWhitespace, IsNotEmpty, IsWhitespace}; @@ -1104,7 +1104,7 @@ generate_pattern_iterators! { #[stable(feature = "rust1", since = "1.0.0")] #[must_use = "iterators are lazy and do nothing unless consumed"] #[derive(Clone, Debug)] -pub struct Lines<'a>(pub(super) Map<SplitTerminator<'a, char>, LinesAnyMap>); +pub struct Lines<'a>(pub(super) Map<SplitInclusive<'a, char>, LinesMap>); #[stable(feature = "rust1", since = "1.0.0")] impl<'a> Iterator for Lines<'a> { diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index ab2f8520ecb..2b23f64732b 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -1011,7 +1011,7 @@ impl str { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn lines(&self) -> Lines<'_> { - Lines(self.split_terminator('\n').map(LinesAnyMap)) + Lines(self.split_inclusive('\n').map(LinesMap)) } /// An iterator over the lines of a string. @@ -2604,10 +2604,10 @@ impl Default for &mut str { impl_fn_for_zst! { /// A nameable, cloneable fn type #[derive(Clone)] - struct LinesAnyMap impl<'a> Fn = |line: &'a str| -> &'a str { - let l = line.len(); - if l > 0 && line.as_bytes()[l - 1] == b'\r' { &line[0 .. l - 1] } - else { line } + struct LinesMap impl<'a> Fn = |line: &'a str| -> &'a str { + let Some(line) = line.strip_suffix('\n') else { return line }; + let Some(line) = line.strip_suffix('\r') else { return line }; + line }; #[derive(Clone)] diff --git a/library/std/src/collections/hash/set.rs b/library/std/src/collections/hash/set.rs index b59f89d321c..837a18bff60 100644 --- a/library/std/src/collections/hash/set.rs +++ b/library/std/src/collections/hash/set.rs @@ -12,13 +12,6 @@ use crate::ops::{BitAnd, BitOr, BitXor, Sub}; use super::map::{map_try_reserve_error, RandomState}; -// Future Optimization (FIXME!) -// ============================ -// -// Iteration over zero sized values is a noop. There is no need -// for `bucket.val` in the case of HashSet. I suppose we would need HKT -// to get rid of it properly. - /// A [hash set] implemented as a `HashMap` where the value is `()`. /// /// As with the [`HashMap`] type, a `HashSet` requires that the elements diff --git a/library/std/src/io/error.rs b/library/std/src/io/error.rs index 7f07e4fddef..1cedd6eedfa 100644 --- a/library/std/src/io/error.rs +++ b/library/std/src/io/error.rs @@ -370,7 +370,7 @@ pub enum ErrorKind { // "Unusual" error kinds which do not correspond simply to (sets // of) OS error codes, should be added just above this comment. - // `Other` and `Uncategorised` should remain at the end: + // `Other` and `Uncategorized` should remain at the end: // /// A custom error that does not fall under any other I/O error kind. /// @@ -882,6 +882,13 @@ impl Error { /// Returns the corresponding [`ErrorKind`] for this error. /// + /// This may be a value set by Rust code constructing custom `io::Error`s, + /// or if this `io::Error` was sourced from the operating system, + /// it will be a value inferred from the system's error encoding. + /// See [`last_os_error`] for more details. + /// + /// [`last_os_error`]: Error::last_os_error + /// /// # Examples /// /// ``` @@ -892,7 +899,8 @@ impl Error { /// } /// /// fn main() { - /// // Will print "Uncategorized". + /// // As no error has (visibly) occurred, this may print anything! + /// // It likely prints a placeholder for unidentified (non-)errors. /// print_error(Error::last_os_error()); /// // Will print "AddrInUse". /// print_error(Error::new(ErrorKind::AddrInUse, "oh no!")); diff --git a/library/std/src/sync/mutex.rs b/library/std/src/sync/mutex.rs index 065045f4420..b8fec6902a0 100644 --- a/library/std/src/sync/mutex.rs +++ b/library/std/src/sync/mutex.rs @@ -107,8 +107,8 @@ use crate::sys::locks as sys; /// *guard += 1; /// ``` /// -/// It is sometimes necessary to manually drop the mutex guard to unlock it -/// sooner than the end of the enclosing scope. +/// To unlock a mutex guard sooner than the end of the enclosing scope, +/// either create an inner scope or drop the guard manually. /// /// ``` /// use std::sync::{Arc, Mutex}; @@ -125,11 +125,18 @@ use crate::sys::locks as sys; /// let res_mutex_clone = Arc::clone(&res_mutex); /// /// threads.push(thread::spawn(move || { -/// let mut data = data_mutex_clone.lock().unwrap(); -/// // This is the result of some important and long-ish work. -/// let result = data.iter().fold(0, |acc, x| acc + x * 2); -/// data.push(result); -/// drop(data); +/// // Here we use a block to limit the lifetime of the lock guard. +/// let result = { +/// let mut data = data_mutex_clone.lock().unwrap(); +/// // This is the result of some important and long-ish work. +/// let result = data.iter().fold(0, |acc, x| acc + x * 2); +/// data.push(result); +/// result +/// // The mutex guard gets dropped here, together with any other values +/// // created in the critical section. +/// }; +/// // The guard created here is a temporary dropped at the end of the statement, i.e. +/// // the lock would not remain being held even if the thread did some additional work. /// *res_mutex_clone.lock().unwrap() += result; /// })); /// }); @@ -146,6 +153,8 @@ use crate::sys::locks as sys; /// // It's even more important here than in the threads because we `.join` the /// // threads after that. If we had not dropped the mutex guard, a thread could /// // be waiting forever for it, causing a deadlock. +/// // As in the threads, a block could have been used instead of calling the +/// // `drop` function. /// drop(data); /// // Here the mutex guard is not assigned to a variable and so, even if the /// // scope does not end after this line, the mutex is still released: there is @@ -160,6 +169,7 @@ use crate::sys::locks as sys; /// /// assert_eq!(*res_mutex.lock().unwrap(), 800); /// ``` +/// #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "Mutex")] pub struct Mutex<T: ?Sized> { diff --git a/library/std/src/sys/hermit/fs.rs b/library/std/src/sys/hermit/fs.rs index c966f217757..cf0b271761f 100644 --- a/library/std/src/sys/hermit/fs.rs +++ b/library/std/src/sys/hermit/fs.rs @@ -202,7 +202,7 @@ impl OpenOptions { create: false, create_new: false, // system-specific - mode: 0x777, + mode: 0o777, } } diff --git a/library/stdarch b/library/stdarch -Subproject a0c30f3e3c75adcd6ee7efc94014ebcead61c50 +Subproject b655243782c18d3419439daa523782e0818ecf2 diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index cbf0f1c37a2..83a6d0ad292 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -919,9 +919,9 @@ impl<'a> Builder<'a> { host: TargetSelection, target: TargetSelection, ) -> Compiler { - if self.build.force_use_stage2() { + if self.build.force_use_stage2(stage) { self.compiler(2, self.config.build) - } else if self.build.force_use_stage1(Compiler { stage, host }, target) { + } else if self.build.force_use_stage1(stage, target) { self.compiler(1, self.config.build) } else { self.compiler(stage, host) diff --git a/src/bootstrap/download-ci-llvm-stamp b/src/bootstrap/download-ci-llvm-stamp index 94630e40f3c..36f9aaa595d 100644 --- a/src/bootstrap/download-ci-llvm-stamp +++ b/src/bootstrap/download-ci-llvm-stamp @@ -1,4 +1,4 @@ Change this file to make users of the `download-ci-llvm` configuration download a new version of LLVM from CI, even if the LLVM submodule hasn’t changed. -Last change is for: https://github.com/rust-lang/rust/pull/104748 +Last change is for: https://github.com/rust-lang/rust/pull/109373 diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 47a970c782e..54aa5a585bb 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -1204,19 +1204,20 @@ impl Build { /// /// When all of these conditions are met the build will lift artifacts from /// the previous stage forward. - fn force_use_stage1(&self, compiler: Compiler, target: TargetSelection) -> bool { + fn force_use_stage1(&self, stage: u32, target: TargetSelection) -> bool { !self.config.full_bootstrap - && compiler.stage >= 2 + && !self.config.download_rustc() + && stage >= 2 && (self.hosts.iter().any(|h| *h == target) || target == self.build) } /// Checks whether the `compiler` compiling for `target` should be forced to /// use a stage2 compiler instead. /// - /// When we download the pre-compiled version of rustc it should be forced to - /// use a stage2 compiler. - fn force_use_stage2(&self) -> bool { - self.config.download_rustc() + /// When we download the pre-compiled version of rustc and compiler stage is >= 2, + /// it should be forced to use a stage2 compiler. + fn force_use_stage2(&self, stage: u32) -> bool { + self.config.download_rustc() && stage >= 2 } /// Given `num` in the form "a.b.c" return a "release string" which diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index dff46b500e3..f27db5c91e2 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -309,6 +309,7 @@ impl Step for Llvm { cfg.out_dir(&out_dir) .profile(profile) .define("LLVM_ENABLE_ASSERTIONS", assertions) + .define("LLVM_UNREACHABLE_OPTIMIZE", "OFF") .define("LLVM_ENABLE_PLUGINS", plugins) .define("LLVM_TARGETS_TO_BUILD", llvm_targets) .define("LLVM_EXPERIMENTAL_TARGETS_TO_BUILD", llvm_exp_targets) diff --git a/src/ci/docker/host-x86_64/i686-gnu/Dockerfile b/src/ci/docker/host-x86_64/i686-gnu/Dockerfile index d9e58386256..b5abf6564a6 100644 --- a/src/ci/docker/host-x86_64/i686-gnu/Dockerfile +++ b/src/ci/docker/host-x86_64/i686-gnu/Dockerfile @@ -16,6 +16,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ zlib1g-dev \ lib32z1-dev \ xz-utils \ + mingw-w64 \ && rm -rf /var/lib/apt/lists/* diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-14-stage1/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-14-stage1/Dockerfile index b99a0886b4d..21dcf29b4a9 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-14-stage1/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-14-stage1/Dockerfile @@ -22,6 +22,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ zlib1g-dev \ xz-utils \ nodejs \ + mingw-w64 \ && rm -rf /var/lib/apt/lists/* COPY scripts/sccache.sh /scripts/ diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-14/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-14/Dockerfile index dc8a4aac768..cfb638e8b07 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-14/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-14/Dockerfile @@ -23,6 +23,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ zlib1g-dev \ xz-utils \ nodejs \ + mingw-w64 \ && rm -rf /var/lib/apt/lists/* # Install powershell (universal package) so we can test x.ps1 on Linux diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-15/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-15/Dockerfile index 5219247cc6f..fb5037e3b97 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-15/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-15/Dockerfile @@ -25,6 +25,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ zlib1g-dev \ xz-utils \ nodejs \ + mingw-w64 \ && rm -rf /var/lib/apt/lists/* # Install powershell (universal package) so we can test x.ps1 on Linux diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version b/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version index 9c550b2d728..6fd113fcfd8 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version +++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version @@ -1 +1 @@ -0.14.4 \ No newline at end of file +0.14.5 \ No newline at end of file diff --git a/src/ci/docker/host-x86_64/x86_64-gnu/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu/Dockerfile index 5b9581f72a6..fbec368c9ee 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu/Dockerfile @@ -16,6 +16,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ libssl-dev \ pkg-config \ xz-utils \ + mingw-w64 \ && rm -rf /var/lib/apt/lists/* COPY scripts/sccache.sh /scripts/ diff --git a/src/doc/rustdoc/src/how-to-read-rustdoc.md b/src/doc/rustdoc/src/how-to-read-rustdoc.md index 28a004a9253..2957916d56c 100644 --- a/src/doc/rustdoc/src/how-to-read-rustdoc.md +++ b/src/doc/rustdoc/src/how-to-read-rustdoc.md @@ -80,13 +80,20 @@ functions, and "In Return Types" shows matches in the return types of functions. Both are very useful when looking for a function whose name you can't quite bring to mind when you know the type you have or want. -When typing in the search bar, you can prefix your search term with a type -followed by a colon (such as `mod:`) to restrict the results to just that -kind of item. (The available items are listed in the help popup.) - -Searching for `println!` will search for a macro named `println`, just like +Names in the search interface can be prefixed with an item type followed by a +colon (such as `mod:`) to restrict the results to just that kind of item. Also, +searching for `println!` will search for a macro named `println`, just like searching for `macro:println` does. +Function signature searches can query generics, wrapped in angle brackets, and +traits are normalized like types in the search engine. For example, a function +with the signature `fn my_function<I: Iterator<Item=u32>>(input: I) -> usize` +can be matched with the following queries: + +* `Iterator<u32> -> usize` +* `trait:Iterator<primitive:u32> -> primitive:usize` +* `Iterator -> usize` + ### Changing displayed theme You can change the displayed theme by opening the settings menu (the gear diff --git a/src/doc/unstable-book/src/compiler-flags/sanitizer.md b/src/doc/unstable-book/src/compiler-flags/sanitizer.md index 262cef3454a..f71aceff455 100644 --- a/src/doc/unstable-book/src/compiler-flags/sanitizer.md +++ b/src/doc/unstable-book/src/compiler-flags/sanitizer.md @@ -213,7 +213,7 @@ See the [Clang ControlFlowIntegrity documentation][clang-cfi] for more details. ## Example -```text +```rust,ignore #![feature(naked_functions)] use std::arch::asm; @@ -238,7 +238,7 @@ pub extern "C" fn add_two(x: i32) { nop nop nop - lea rax, [rdi+2] + lea eax, [edi+2] ret ", options(noreturn) diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 148243683cb..768f8bb7bc8 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -36,15 +36,11 @@ use crate::formats::item_type::ItemType; /// /// The returned value is `None` if the definition could not be inlined, /// and `Some` of a vector of items if it was successfully expanded. -/// -/// `parent_module` refers to the parent of the *re-export*, not the original item. pub(crate) fn try_inline( cx: &mut DocContext<'_>, - parent_module: DefId, - import_def_id: Option<DefId>, res: Res, name: Symbol, - attrs: Option<&[ast::Attribute]>, + attrs: Option<(&[ast::Attribute], Option<DefId>)>, visited: &mut DefIdSet, ) -> Option<Vec<clean::Item>> { let did = res.opt_def_id()?; @@ -55,38 +51,17 @@ pub(crate) fn try_inline( debug!("attrs={:?}", attrs); - let attrs_without_docs = attrs.map(|attrs| { - attrs.into_iter().filter(|a| a.doc_str().is_none()).cloned().collect::<Vec<_>>() + let attrs_without_docs = attrs.map(|(attrs, def_id)| { + (attrs.into_iter().filter(|a| a.doc_str().is_none()).cloned().collect::<Vec<_>>(), def_id) }); - // We need this ugly code because: - // - // ``` - // attrs_without_docs.map(|a| a.as_slice()) - // ``` - // - // will fail because it returns a temporary slice and: - // - // ``` - // attrs_without_docs.map(|s| { - // vec = s.as_slice(); - // vec - // }) - // ``` - // - // will fail because we're moving an uninitialized variable into a closure. - let vec; - let attrs_without_docs = match attrs_without_docs { - Some(s) => { - vec = s; - Some(vec.as_slice()) - } - None => None, - }; + let attrs_without_docs = + attrs_without_docs.as_ref().map(|(attrs, def_id)| (&attrs[..], *def_id)); + let import_def_id = attrs.and_then(|(_, def_id)| def_id); let kind = match res { Res::Def(DefKind::Trait, did) => { record_extern_fqn(cx, did, ItemType::Trait); - build_impls(cx, Some(parent_module), did, attrs_without_docs, &mut ret); + build_impls(cx, did, attrs_without_docs, &mut ret); clean::TraitItem(Box::new(build_external_trait(cx, did))) } Res::Def(DefKind::Fn, did) => { @@ -95,27 +70,27 @@ pub(crate) fn try_inline( } Res::Def(DefKind::Struct, did) => { record_extern_fqn(cx, did, ItemType::Struct); - build_impls(cx, Some(parent_module), did, attrs_without_docs, &mut ret); + build_impls(cx, did, attrs_without_docs, &mut ret); clean::StructItem(build_struct(cx, did)) } Res::Def(DefKind::Union, did) => { record_extern_fqn(cx, did, ItemType::Union); - build_impls(cx, Some(parent_module), did, attrs_without_docs, &mut ret); + build_impls(cx, did, attrs_without_docs, &mut ret); clean::UnionItem(build_union(cx, did)) } Res::Def(DefKind::TyAlias, did) => { record_extern_fqn(cx, did, ItemType::Typedef); - build_impls(cx, Some(parent_module), did, attrs_without_docs, &mut ret); + build_impls(cx, did, attrs_without_docs, &mut ret); clean::TypedefItem(build_type_alias(cx, did)) } Res::Def(DefKind::Enum, did) => { record_extern_fqn(cx, did, ItemType::Enum); - build_impls(cx, Some(parent_module), did, attrs_without_docs, &mut ret); + build_impls(cx, did, attrs_without_docs, &mut ret); clean::EnumItem(build_enum(cx, did)) } Res::Def(DefKind::ForeignTy, did) => { record_extern_fqn(cx, did, ItemType::ForeignType); - build_impls(cx, Some(parent_module), did, attrs_without_docs, &mut ret); + build_impls(cx, did, attrs_without_docs, &mut ret); clean::ForeignTypeItem } // Never inline enum variants but leave them shown as re-exports. @@ -149,7 +124,7 @@ pub(crate) fn try_inline( _ => return None, }; - let (attrs, cfg) = merge_attrs(cx, Some(parent_module), load_attrs(cx, did), attrs); + let (attrs, cfg) = merge_attrs(cx, load_attrs(cx, did), attrs); cx.inlined.insert(did.into()); let mut item = clean::Item::from_def_id_and_attrs_and_parts(did, Some(name), kind, Box::new(attrs), cfg); @@ -316,9 +291,8 @@ fn build_type_alias(cx: &mut DocContext<'_>, did: DefId) -> Box<clean::Typedef> /// Builds all inherent implementations of an ADT (struct/union/enum) or Trait item/path/reexport. pub(crate) fn build_impls( cx: &mut DocContext<'_>, - parent_module: Option<DefId>, did: DefId, - attrs: Option<&[ast::Attribute]>, + attrs: Option<(&[ast::Attribute], Option<DefId>)>, ret: &mut Vec<clean::Item>, ) { let _prof_timer = cx.tcx.sess.prof.generic_activity("build_inherent_impls"); @@ -326,7 +300,7 @@ pub(crate) fn build_impls( // for each implementation of an item represented by `did`, build the clean::Item for that impl for &did in tcx.inherent_impls(did).iter() { - build_impl(cx, parent_module, did, attrs, ret); + build_impl(cx, did, attrs, ret); } // This pretty much exists expressly for `dyn Error` traits that exist in the `alloc` crate. @@ -340,28 +314,26 @@ pub(crate) fn build_impls( let type_ = if tcx.is_trait(did) { TraitSimplifiedType(did) } else { AdtSimplifiedType(did) }; for &did in tcx.incoherent_impls(type_) { - build_impl(cx, parent_module, did, attrs, ret); + build_impl(cx, did, attrs, ret); } } } -/// `parent_module` refers to the parent of the re-export, not the original item pub(crate) fn merge_attrs( cx: &mut DocContext<'_>, - parent_module: Option<DefId>, old_attrs: &[ast::Attribute], - new_attrs: Option<&[ast::Attribute]>, + new_attrs: Option<(&[ast::Attribute], Option<DefId>)>, ) -> (clean::Attributes, Option<Arc<clean::cfg::Cfg>>) { // NOTE: If we have additional attributes (from a re-export), // always insert them first. This ensure that re-export // doc comments show up before the original doc comments // when we render them. - if let Some(inner) = new_attrs { + if let Some((inner, item_id)) = new_attrs { let mut both = inner.to_vec(); both.extend_from_slice(old_attrs); ( - if let Some(new_id) = parent_module { - Attributes::from_ast_with_additional(old_attrs, (inner, new_id)) + if let Some(item_id) = item_id { + Attributes::from_ast_with_additional(old_attrs, (inner, item_id)) } else { Attributes::from_ast(&both) }, @@ -375,9 +347,8 @@ pub(crate) fn merge_attrs( /// Inline an `impl`, inherent or of a trait. The `did` must be for an `impl`. pub(crate) fn build_impl( cx: &mut DocContext<'_>, - parent_module: Option<DefId>, did: DefId, - attrs: Option<&[ast::Attribute]>, + attrs: Option<(&[ast::Attribute], Option<DefId>)>, ret: &mut Vec<clean::Item>, ) { if !cx.inlined.insert(did.into()) { @@ -539,7 +510,7 @@ pub(crate) fn build_impl( record_extern_trait(cx, did); } - let (merged_attrs, cfg) = merge_attrs(cx, parent_module, load_attrs(cx, did), attrs); + let (merged_attrs, cfg) = merge_attrs(cx, load_attrs(cx, did), attrs); trace!("merged_attrs={:?}", merged_attrs); trace!( @@ -635,7 +606,7 @@ fn build_module_items( cfg: None, inline_stmt_id: None, }); - } else if let Some(i) = try_inline(cx, did, None, res, item.ident.name, None, visited) { + } else if let Some(i) = try_inline(cx, res, item.ident.name, None, visited) { items.extend(i) } } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index e3e5454ef54..c00fa5994bf 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -324,7 +324,7 @@ pub(crate) fn clean_predicate<'tcx>( ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) => None, ty::PredicateKind::Subtype(..) - | ty::PredicateKind::AliasEq(..) + | ty::PredicateKind::AliasRelate(..) | ty::PredicateKind::Coerce(..) | ty::PredicateKind::ObjectSafe(..) | ty::PredicateKind::ClosureKind(..) @@ -2388,12 +2388,12 @@ fn clean_maybe_renamed_item<'tcx>( target_attrs.extend_from_slice(inline::load_attrs(cx, def_id)); } - let import_parent = import_id.map(|import_id| cx.tcx.local_parent(import_id).to_def_id()); - let (attrs, cfg) = merge_attrs(cx, import_parent, &target_attrs, Some(&import_attrs)); + let import_id = import_id.map(|def_id| def_id.to_def_id()); + let (attrs, cfg) = merge_attrs(cx, &target_attrs, Some((&import_attrs, import_id))); let mut item = Item::from_def_id_and_attrs_and_parts(def_id, Some(name), kind, Box::new(attrs), cfg); - item.inline_stmt_id = import_id.map(|def_id| def_id.to_def_id()); + item.inline_stmt_id = import_id; vec![item] }) } @@ -2478,18 +2478,12 @@ fn clean_extern_crate<'tcx>( let krate_owner_def_id = krate.owner_id.to_def_id(); if please_inline { - let mut visited = DefIdSet::default(); - - let res = Res::Def(DefKind::Mod, crate_def_id); - if let Some(items) = inline::try_inline( cx, - cx.tcx.parent_module(krate.hir_id()).to_def_id(), - Some(krate_owner_def_id), - res, + Res::Def(DefKind::Mod, crate_def_id), name, - Some(attrs), - &mut visited, + Some((attrs, Some(krate_owner_def_id))), + &mut Default::default(), ) { return items; } @@ -2613,17 +2607,13 @@ fn clean_use_statement_inner<'tcx>( denied = true; } if !denied { - let mut visited = DefIdSet::default(); let import_def_id = import.owner_id.to_def_id(); - if let Some(mut items) = inline::try_inline( cx, - cx.tcx.parent_module(import.hir_id()).to_def_id(), - Some(import_def_id), path.res, name, - Some(attrs), - &mut visited, + Some((attrs, Some(import_def_id))), + &mut Default::default(), ) { items.push(Item::from_def_id_and_parts( import_def_id, diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 6d8380c5fcc..7dbb3f76a0a 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -1471,27 +1471,68 @@ impl Type { result } - /// Check if two types are "potentially the same". + pub(crate) fn is_borrowed_ref(&self) -> bool { + matches!(self, Type::BorrowedRef { .. }) + } + + /// Check if two types are "the same" for documentation purposes. + /// /// This is different from `Eq`, because it knows that things like /// `Placeholder` are possible matches for everything. - pub(crate) fn is_same(&self, other: &Self, cache: &Cache) -> bool { - match (self, other) { + /// + /// This relation is not commutative when generics are involved: + /// + /// ```ignore(private) + /// # // see types/tests.rs:is_same_generic for the real test + /// use rustdoc::format::cache::Cache; + /// use rustdoc::clean::types::{Type, PrimitiveType}; + /// let cache = Cache::new(false); + /// let generic = Type::Generic(rustc_span::symbol::sym::Any); + /// let unit = Type::Primitive(PrimitiveType::Unit); + /// assert!(!generic.is_same(&unit, &cache)); + /// assert!(unit.is_same(&generic, &cache)); + /// ``` + /// + /// An owned type is also the same as its borrowed variants (this is commutative), + /// but `&T` is not the same as `&mut T`. + pub(crate) fn is_doc_subtype_of(&self, other: &Self, cache: &Cache) -> bool { + // Strip the references so that it can compare the actual types, unless both are references. + // If both are references, leave them alone and compare the mutabilities later. + let (self_cleared, other_cleared) = if !self.is_borrowed_ref() || !other.is_borrowed_ref() { + (self.without_borrowed_ref(), other.without_borrowed_ref()) + } else { + (self, other) + }; + match (self_cleared, other_cleared) { // Recursive cases. (Type::Tuple(a), Type::Tuple(b)) => { - a.len() == b.len() && a.iter().zip(b).all(|(a, b)| a.is_same(b, cache)) + a.len() == b.len() && a.iter().zip(b).all(|(a, b)| a.is_doc_subtype_of(b, cache)) } - (Type::Slice(a), Type::Slice(b)) => a.is_same(b, cache), - (Type::Array(a, al), Type::Array(b, bl)) => al == bl && a.is_same(b, cache), + (Type::Slice(a), Type::Slice(b)) => a.is_doc_subtype_of(b, cache), + (Type::Array(a, al), Type::Array(b, bl)) => al == bl && a.is_doc_subtype_of(b, cache), (Type::RawPointer(mutability, type_), Type::RawPointer(b_mutability, b_type_)) => { - mutability == b_mutability && type_.is_same(b_type_, cache) + mutability == b_mutability && type_.is_doc_subtype_of(b_type_, cache) } ( Type::BorrowedRef { mutability, type_, .. }, Type::BorrowedRef { mutability: b_mutability, type_: b_type_, .. }, - ) => mutability == b_mutability && type_.is_same(b_type_, cache), - // Placeholders and generics are equal to all other types. + ) => mutability == b_mutability && type_.is_doc_subtype_of(b_type_, cache), + // Placeholders are equal to all other types. (Type::Infer, _) | (_, Type::Infer) => true, - (Type::Generic(_), _) | (_, Type::Generic(_)) => true, + // Generics match everything on the right, but not on the left. + // If both sides are generic, this returns true. + (_, Type::Generic(_)) => true, + (Type::Generic(_), _) => false, + // Paths account for both the path itself and its generics. + (Type::Path { path: a }, Type::Path { path: b }) => { + a.def_id() == b.def_id() + && a.generics() + .zip(b.generics()) + .map(|(ag, bg)| { + ag.iter().zip(bg.iter()).all(|(at, bt)| at.is_doc_subtype_of(bt, cache)) + }) + .unwrap_or(true) + } // Other cases, such as primitives, just use recursion. (a, b) => a .def_id(cache) diff --git a/src/librustdoc/clean/types/tests.rs b/src/librustdoc/clean/types/tests.rs index 20627c2cfc1..d8c91a96804 100644 --- a/src/librustdoc/clean/types/tests.rs +++ b/src/librustdoc/clean/types/tests.rs @@ -10,7 +10,7 @@ use rustc_span::symbol::Symbol; fn create_doc_fragment(s: &str) -> Vec<DocFragment> { vec![DocFragment { span: DUMMY_SP, - parent_module: None, + item_id: None, doc: Symbol::intern(s), kind: DocFragmentKind::SugaredDoc, indent: 0, @@ -69,3 +69,14 @@ fn should_not_trim() { run_test("\t line1 \n\t line2", "line1 \nline2"); run_test(" \tline1 \n \tline2", "line1 \nline2"); } + +#[test] +fn is_same_generic() { + use crate::clean::types::{PrimitiveType, Type}; + use crate::formats::cache::Cache; + let cache = Cache::new(false); + let generic = Type::Generic(rustc_span::symbol::sym::Any); + let unit = Type::Primitive(PrimitiveType::Unit); + assert!(!generic.is_doc_subtype_of(&unit, &cache)); + assert!(unit.is_doc_subtype_of(&generic, &cache)); +} diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index cafb00df51e..cca50df0db2 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -195,12 +195,12 @@ pub(crate) fn build_deref_target_impls( if let Some(prim) = target.primitive_type() { let _prof_timer = cx.tcx.sess.prof.generic_activity("build_primitive_inherent_impls"); for did in prim.impls(tcx).filter(|did| !did.is_local()) { - inline::build_impl(cx, None, did, None, ret); + inline::build_impl(cx, did, None, ret); } } else if let Type::Path { path } = target { let did = path.def_id(); if !did.is_local() { - inline::build_impls(cx, None, did, None, ret); + inline::build_impls(cx, did, None, ret); } } } diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index 2c9fc4e3ca3..c099d0e4f3f 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -65,23 +65,6 @@ pub(crate) fn render_item_decl_with_highlighting(src: &str, out: &mut Buffer) { write!(out, "</pre>"); } -/// Highlights `src` as a source code page, returning the HTML output. -pub(crate) fn render_source_with_highlighting( - src: &str, - out: &mut Buffer, - line_numbers: Buffer, - href_context: HrefContext<'_, '_>, - decoration_info: DecorationInfo, - extra: Option<&str>, -) { - write_header(out, "", Some(line_numbers), Tooltip::None); - if let Some(extra) = extra { - out.push_str(extra); - } - write_code(out, src, Some(href_context), Some(decoration_info)); - write_footer(out, None); -} - fn write_header(out: &mut Buffer, class: &str, extra_content: Option<Buffer>, tooltip: Tooltip) { write!( out, @@ -143,8 +126,8 @@ fn can_merge(class1: Option<Class>, class2: Option<Class>, text: &str) -> bool { /// This type is used as a conveniency to prevent having to pass all its fields as arguments into /// the various functions (which became its methods). -struct TokenHandler<'a, 'tcx> { - out: &'a mut Buffer, +struct TokenHandler<'a, 'tcx, F: Write> { + out: &'a mut F, /// It contains the closing tag and the associated `Class`. closing_tags: Vec<(&'static str, Class)>, /// This is used because we don't automatically generate the closing tag on `ExitSpan` in @@ -159,7 +142,7 @@ struct TokenHandler<'a, 'tcx> { href_context: Option<HrefContext<'a, 'tcx>>, } -impl<'a, 'tcx> TokenHandler<'a, 'tcx> { +impl<'a, 'tcx, F: Write> TokenHandler<'a, 'tcx, F> { fn handle_exit_span(&mut self) { // We can't get the last `closing_tags` element using `pop()` because `closing_tags` is // being used in `write_pending_elems`. @@ -211,7 +194,7 @@ impl<'a, 'tcx> TokenHandler<'a, 'tcx> { } } -impl<'a, 'tcx> Drop for TokenHandler<'a, 'tcx> { +impl<'a, 'tcx, F: Write> Drop for TokenHandler<'a, 'tcx, F> { /// When leaving, we need to flush all pending data to not have missing content. fn drop(&mut self) { if self.pending_exit_span.is_some() { @@ -233,8 +216,8 @@ impl<'a, 'tcx> Drop for TokenHandler<'a, 'tcx> { /// item definition. /// /// More explanations about spans and how we use them here are provided in the -fn write_code( - out: &mut Buffer, +pub(super) fn write_code( + out: &mut impl Write, src: &str, href_context: Option<HrefContext<'_, '_>>, decoration_info: Option<DecorationInfo>, @@ -883,7 +866,7 @@ impl<'src> Classifier<'src> { /// Called when we start processing a span of text that should be highlighted. /// The `Class` argument specifies how it should be highlighted. fn enter_span( - out: &mut Buffer, + out: &mut impl Write, klass: Class, href_context: &Option<HrefContext<'_, '_>>, ) -> &'static str { @@ -894,8 +877,8 @@ fn enter_span( } /// Called at the end of a span of highlighted text. -fn exit_span(out: &mut Buffer, closing_tag: &str) { - out.write_str(closing_tag); +fn exit_span(out: &mut impl Write, closing_tag: &str) { + out.write_str(closing_tag).unwrap(); } /// Called for a span of text. If the text should be highlighted differently @@ -915,7 +898,7 @@ fn exit_span(out: &mut Buffer, closing_tag: &str) { /// will then try to find this `span` in the `span_correspondance_map`. If found, it'll then /// generate a link for this element (which corresponds to where its definition is located). fn string<T: Display>( - out: &mut Buffer, + out: &mut impl Write, text: T, klass: Option<Class>, href_context: &Option<HrefContext<'_, '_>>, @@ -923,7 +906,7 @@ fn string<T: Display>( ) { if let Some(closing_tag) = string_without_closing_tag(out, text, klass, href_context, open_tag) { - out.write_str(closing_tag); + out.write_str(closing_tag).unwrap(); } } @@ -937,7 +920,7 @@ fn string<T: Display>( /// in `span_map.rs::collect_spans_and_sources`. If it cannot retrieve the information, then it's /// the same as the second point (`klass` is `Some` but doesn't have a [`rustc_span::Span`]). fn string_without_closing_tag<T: Display>( - out: &mut Buffer, + out: &mut impl Write, text: T, klass: Option<Class>, href_context: &Option<HrefContext<'_, '_>>, @@ -945,16 +928,16 @@ fn string_without_closing_tag<T: Display>( ) -> Option<&'static str> { let Some(klass) = klass else { - write!(out, "{}", text); + write!(out, "{}", text).unwrap(); return None; }; let Some(def_span) = klass.get_span() else { if !open_tag { - write!(out, "{}", text); + write!(out, "{}", text).unwrap(); return None; } - write!(out, "<span class=\"{}\">{}", klass.as_html(), text); + write!(out, "<span class=\"{}\">{}", klass.as_html(), text).unwrap(); return Some("</span>"); }; @@ -1009,28 +992,28 @@ fn string_without_closing_tag<T: Display>( if !open_tag { // We're already inside an element which has the same klass, no need to give it // again. - write!(out, "<a href=\"{}\">{}", href, text_s); + write!(out, "<a href=\"{}\">{}", href, text_s).unwrap(); } else { let klass_s = klass.as_html(); if klass_s.is_empty() { - write!(out, "<a href=\"{}\">{}", href, text_s); + write!(out, "<a href=\"{}\">{}", href, text_s).unwrap(); } else { - write!(out, "<a class=\"{}\" href=\"{}\">{}", klass_s, href, text_s); + write!(out, "<a class=\"{}\" href=\"{}\">{}", klass_s, href, text_s).unwrap(); } } return Some("</a>"); } } if !open_tag { - write!(out, "{}", text_s); + write!(out, "{}", text_s).unwrap(); return None; } let klass_s = klass.as_html(); if klass_s.is_empty() { - write!(out, "{}", text_s); + out.write_str(&text_s).unwrap(); Some("") } else { - write!(out, "<span class=\"{}\">{}", klass_s, text_s); + write!(out, "<span class=\"{}\">{}", klass_s, text_s).unwrap(); Some("</span>") } } diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index da1f1cf5ecc..d75d03071f8 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -1294,7 +1294,7 @@ pub(crate) fn notable_traits_button(ty: &clean::Type, cx: &mut Context<'_>) -> O if let Some(impls) = cx.cache().impls.get(&did) { for i in impls { let impl_ = i.inner_impl(); - if !impl_.for_.without_borrowed_ref().is_same(ty.without_borrowed_ref(), cx.cache()) { + if !ty.is_doc_subtype_of(&impl_.for_, cx.cache()) { // Two different types might have the same did, // without actually being the same. continue; @@ -1330,7 +1330,7 @@ fn notable_traits_decl(ty: &clean::Type, cx: &Context<'_>) -> (String, String) { for i in impls { let impl_ = i.inner_impl(); - if !impl_.for_.without_borrowed_ref().is_same(ty.without_borrowed_ref(), cx.cache()) { + if !ty.is_doc_subtype_of(&impl_.for_, cx.cache()) { // Two different types might have the same did, // without actually being the same. continue; diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs index be9d1c408ec..1d298f52f75 100644 --- a/src/librustdoc/html/sources.rs +++ b/src/librustdoc/html/sources.rs @@ -1,12 +1,14 @@ use crate::clean; use crate::docfs::PathError; use crate::error::Error; +use crate::html::format; use crate::html::format::Buffer; use crate::html::highlight; use crate::html::layout; use crate::html::render::Context; use crate::visit::DocVisitor; +use askama::Template; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::def_id::LOCAL_CRATE; use rustc_middle::ty::TyCtxt; @@ -16,6 +18,7 @@ use rustc_span::source_map::FileName; use std::cell::RefCell; use std::ffi::OsStr; use std::fs; +use std::ops::RangeInclusive; use std::path::{Component, Path, PathBuf}; use std::rc::Rc; @@ -299,39 +302,32 @@ pub(crate) fn print_src( decoration_info: highlight::DecorationInfo, source_context: SourceContext, ) { + #[derive(Template)] + #[template(path = "source.html")] + struct Source<Code: std::fmt::Display> { + embedded: bool, + needs_expansion: bool, + lines: RangeInclusive<usize>, + code_html: Code, + } let lines = s.lines().count(); - let mut line_numbers = Buffer::empty_from(buf); - let extra; - line_numbers.write_str("<pre class=\"src-line-numbers\">"); + let (embedded, needs_expansion, lines) = match source_context { + SourceContext::Standalone => (false, false, 1..=lines), + SourceContext::Embedded { offset, needs_expansion } => { + (true, needs_expansion, (1 + offset)..=(lines + offset)) + } + }; let current_href = context .href_from_span(clean::Span::new(file_span), false) .expect("only local crates should have sources emitted"); - match source_context { - SourceContext::Standalone => { - extra = None; - for line in 1..=lines { - writeln!(line_numbers, "<a href=\"#{line}\" id=\"{line}\">{line}</a>") - } - } - SourceContext::Embedded { offset, needs_expansion } => { - extra = if needs_expansion { - Some(r#"<button class="expand">↕</button>"#) - } else { - None - }; - for line_number in 1..=lines { - let line = line_number + offset; - writeln!(line_numbers, "<span>{line}</span>") - } - } - } - line_numbers.write_str("</pre>"); - highlight::render_source_with_highlighting( - s, - buf, - line_numbers, - highlight::HrefContext { context, file_span, root_path, current_href }, - decoration_info, - extra, - ); + let code = format::display_fn(move |fmt| { + highlight::write_code( + fmt, + s, + Some(highlight::HrefContext { context, file_span, root_path, current_href }), + Some(decoration_info), + ); + Ok(()) + }); + Source { embedded, needs_expansion, lines, code_html: code }.render_into(buf).unwrap(); } diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 95528e70e35..7d578b5c775 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -217,7 +217,7 @@ ul.all-items { a.anchor, .small-section-header a, #source-sidebar a, -pre.rust a, +.rust a, .sidebar h2 a, .sidebar h3 a, .mobile-topbar h2 a, @@ -228,43 +228,43 @@ h1 a, color: var(--main-color); } -.content span.enum, .content a.enum, -.content span.struct, .content a.struct, -.content span.union, .content a.union, -.content span.primitive, .content a.primitive, -.content span.type, .content a.type, -.content span.foreigntype, .content a.foreigntype { +span.enum, a.enum, +span.struct, a.struct, +span.union, a.union, +span.primitive, a.primitive, +span.type, a.type, +span.foreigntype, a.foreigntype { color: var(--type-link-color); } -.content span.trait, .content a.trait, -.content span.traitalias, .content a.traitalias { +span.trait, a.trait, +span.traitalias, a.traitalias { color: var(--trait-link-color); } -.content span.associatedtype, .content a.associatedtype, -.content span.constant, .content a.constant, -.content span.static, .content a.static { +span.associatedtype, a.associatedtype, +span.constant, a.constant, +span.static, a.static { color: var(--assoc-item-link-color); } -.content span.fn, .content a.fn, -.content span.method, .content a.method, -.content span.tymethod, .content a.tymethod { +span.fn, a.fn, +span.method, a.method, +span.tymethod, a.tymethod { color: var(--function-link-color); } -.content span.attr, .content a.attr, -.content span.derive, .content a.derive, -.content span.macro, .content a.macro { +span.attr, a.attr, +span.derive, a.derive, +span.macro, a.macro { color: var(--macro-link-color); } -.content span.mod, .content a.mod { +span.mod, a.mod { color: var(--mod-link-color); } -.content span.keyword, .content a.keyword { +span.keyword, a.keyword { color: var(--keyword-link-color); } @@ -713,7 +713,7 @@ h2.small-section-header > .anchor { } .main-heading a:hover, -.example-wrap > pre.rust a:hover, +.example-wrap > .rust a:hover, .all-items a:hover, .docblock a:not(.test-arrow):not(.scrape-help):not(.tooltip):hover, .docblock-short a:not(.test-arrow):not(.scrape-help):not(.tooltip):hover, diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index 36ff20e299e..840ed8e1080 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -354,12 +354,15 @@ function initSearch(rawSearchIndex) { if (isInGenerics) { parserState.genericsElems += 1; } + const typeFilter = parserState.typeFilter; + parserState.typeFilter = null; return { name: name, fullPath: pathSegments, pathWithoutLast: pathSegments.slice(0, pathSegments.length - 1), pathLast: pathSegments[pathSegments.length - 1], generics: generics, + typeFilter, }; } @@ -495,6 +498,11 @@ function initSearch(rawSearchIndex) { */ function getItemsBefore(query, parserState, elems, endChar) { let foundStopChar = true; + let start = parserState.pos; + + // If this is a generic, keep the outer item's type filter around. + const oldTypeFilter = parserState.typeFilter; + parserState.typeFilter = null; while (parserState.pos < parserState.length) { const c = parserState.userQuery[parserState.pos]; @@ -506,7 +514,25 @@ function initSearch(rawSearchIndex) { continue; } else if (c === ":" && isPathStart(parserState)) { throw ["Unexpected ", "::", ": paths cannot start with ", "::"]; - } else if (c === ":" || isEndCharacter(c)) { + } else if (c === ":") { + if (parserState.typeFilter !== null) { + throw ["Unexpected ", ":"]; + } + if (elems.length === 0) { + throw ["Expected type filter before ", ":"]; + } else if (query.literalSearch) { + throw ["You cannot use quotes on type filter"]; + } + // The type filter doesn't count as an element since it's a modifier. + const typeFilterElem = elems.pop(); + checkExtraTypeFilterCharacters(start, parserState); + parserState.typeFilter = typeFilterElem.name; + parserState.pos += 1; + parserState.totalElems -= 1; + query.literalSearch = false; + foundStopChar = true; + continue; + } else if (isEndCharacter(c)) { let extra = ""; if (endChar === ">") { extra = "<"; @@ -540,15 +566,10 @@ function initSearch(rawSearchIndex) { ]; } const posBefore = parserState.pos; + start = parserState.pos; getNextElem(query, parserState, elems, endChar === ">"); - if (endChar !== "") { - if (parserState.pos >= parserState.length) { - throw ["Unclosed ", "<"]; - } - const c2 = parserState.userQuery[parserState.pos]; - if (!isSeparatorCharacter(c2) && c2 !== endChar) { - throw ["Expected ", endChar, ", found ", c2]; - } + if (endChar !== "" && parserState.pos >= parserState.length) { + throw ["Unclosed ", "<"]; } // This case can be encountered if `getNextElem` encountered a "stop character" right // from the start. For example if you have `,,` or `<>`. In this case, we simply move up @@ -564,6 +585,8 @@ function initSearch(rawSearchIndex) { // We are either at the end of the string or on the `endChar` character, let's move forward // in any case. parserState.pos += 1; + + parserState.typeFilter = oldTypeFilter; } /** @@ -572,10 +595,10 @@ function initSearch(rawSearchIndex) { * * @param {ParserState} parserState */ - function checkExtraTypeFilterCharacters(parserState) { + function checkExtraTypeFilterCharacters(start, parserState) { const query = parserState.userQuery; - for (let pos = 0; pos < parserState.pos; ++pos) { + for (let pos = start; pos < parserState.pos; ++pos) { if (!isIdentCharacter(query[pos]) && !isWhitespaceCharacter(query[pos])) { throw ["Unexpected ", query[pos], " in type filter"]; } @@ -591,6 +614,7 @@ function initSearch(rawSearchIndex) { */ function parseInput(query, parserState) { let foundStopChar = true; + let start = parserState.pos; while (parserState.pos < parserState.length) { const c = parserState.userQuery[parserState.pos]; @@ -612,16 +636,15 @@ function initSearch(rawSearchIndex) { } if (query.elems.length === 0) { throw ["Expected type filter before ", ":"]; - } else if (query.elems.length !== 1 || parserState.totalElems !== 1) { - throw ["Unexpected ", ":"]; } else if (query.literalSearch) { throw ["You cannot use quotes on type filter"]; } - checkExtraTypeFilterCharacters(parserState); // The type filter doesn't count as an element since it's a modifier. - parserState.typeFilter = query.elems.pop().name; + const typeFilterElem = query.elems.pop(); + checkExtraTypeFilterCharacters(start, parserState); + parserState.typeFilter = typeFilterElem.name; parserState.pos += 1; - parserState.totalElems = 0; + parserState.totalElems -= 1; query.literalSearch = false; foundStopChar = true; continue; @@ -653,6 +676,7 @@ function initSearch(rawSearchIndex) { ]; } const before = query.elems.length; + start = parserState.pos; getNextElem(query, parserState, query.elems, false); if (query.elems.length === before) { // Nothing was added, weird... Let's increase the position to not remain stuck. @@ -660,6 +684,9 @@ function initSearch(rawSearchIndex) { } foundStopChar = false; } + if (parserState.typeFilter !== null) { + throw ["Unexpected ", ":", " (expected path after type filter)"]; + } while (parserState.pos < parserState.length) { if (isReturnArrow(parserState)) { parserState.pos += 2; @@ -687,7 +714,6 @@ function initSearch(rawSearchIndex) { return { original: userQuery, userQuery: userQuery.toLowerCase(), - typeFilter: NO_TYPE_FILTER, elems: [], returned: [], // Total number of "top" elements (does not include generics). @@ -738,8 +764,8 @@ function initSearch(rawSearchIndex) { * * ident = *(ALPHA / DIGIT / "_") * path = ident *(DOUBLE-COLON ident) [!] - * arg = path [generics] - * arg-without-generic = path + * arg = [type-filter *WS COLON *WS] path [generics] + * arg-without-generic = [type-filter *WS COLON *WS] path * type-sep = COMMA/WS *(COMMA/WS) * nonempty-arg-list = *(type-sep) arg *(type-sep arg) *(type-sep) * nonempty-arg-list-without-generics = *(type-sep) arg-without-generic @@ -749,7 +775,7 @@ function initSearch(rawSearchIndex) { * return-args = RETURN-ARROW *(type-sep) nonempty-arg-list * * exact-search = [type-filter *WS COLON] [ RETURN-ARROW ] *WS QUOTE ident QUOTE [ generics ] - * type-search = [type-filter *WS COLON] [ nonempty-arg-list ] [ return-args ] + * type-search = [ nonempty-arg-list ] [ return-args ] * * query = *WS (exact-search / type-search) *WS * @@ -798,6 +824,20 @@ function initSearch(rawSearchIndex) { * @return {ParsedQuery} - The parsed query */ function parseQuery(userQuery) { + function convertTypeFilterOnElem(elem) { + if (elem.typeFilter !== null) { + let typeFilter = elem.typeFilter; + if (typeFilter === "const") { + typeFilter = "constant"; + } + elem.typeFilter = itemTypeFromName(typeFilter); + } else { + elem.typeFilter = NO_TYPE_FILTER; + } + for (const elem2 of elem.generics) { + convertTypeFilterOnElem(elem2); + } + } userQuery = userQuery.trim(); const parserState = { length: userQuery.length, @@ -812,17 +852,15 @@ function initSearch(rawSearchIndex) { try { parseInput(query, parserState); - if (parserState.typeFilter !== null) { - let typeFilter = parserState.typeFilter; - if (typeFilter === "const") { - typeFilter = "constant"; - } - query.typeFilter = itemTypeFromName(typeFilter); + for (const elem of query.elems) { + convertTypeFilterOnElem(elem); + } + for (const elem of query.returned) { + convertTypeFilterOnElem(elem); } } catch (err) { query = newParsedQuery(userQuery); query.error = err; - query.typeFilter = -1; return query; } @@ -1057,12 +1095,10 @@ function initSearch(rawSearchIndex) { } // The names match, but we need to be sure that all generics kinda // match as well. - let elem_name; if (elem.generics.length > 0 && row.generics.length >= elem.generics.length) { const elems = Object.create(null); for (const entry of row.generics) { - elem_name = entry.name; - if (elem_name === "") { + if (entry.name === "") { // Pure generic, needs to check into it. if (checkGenerics(entry, elem, maxEditDistance + 1, maxEditDistance) !== 0) { @@ -1070,19 +1106,19 @@ function initSearch(rawSearchIndex) { } continue; } - if (elems[elem_name] === undefined) { - elems[elem_name] = 0; + if (elems[entry.name] === undefined) { + elems[entry.name] = []; } - elems[elem_name] += 1; + elems[entry.name].push(entry.ty); } // We need to find the type that matches the most to remove it in order // to move forward. - for (const generic of elem.generics) { + const handleGeneric = generic => { let match = null; if (elems[generic.name]) { match = generic.name; } else { - for (elem_name in elems) { + for (const elem_name in elems) { if (!hasOwnPropertyRustdoc(elems, elem_name)) { continue; } @@ -1093,12 +1129,32 @@ function initSearch(rawSearchIndex) { } } if (match === null) { - return maxEditDistance + 1; + return false; } - elems[match] -= 1; - if (elems[match] === 0) { + const matchIdx = elems[match].findIndex(tmp_elem => + typePassesFilter(generic.typeFilter, tmp_elem)); + if (matchIdx === -1) { + return false; + } + elems[match].splice(matchIdx, 1); + if (elems[match].length === 0) { delete elems[match]; } + return true; + }; + // To do the right thing with type filters, we first process generics + // that have them, removing matching ones from the "bag," then do the + // ones with no type filter, which can match any entry regardless of its + // own type. + for (const generic of elem.generics) { + if (generic.typeFilter !== -1 && !handleGeneric(generic)) { + return maxEditDistance + 1; + } + } + for (const generic of elem.generics) { + if (generic.typeFilter === -1 && !handleGeneric(generic)) { + return maxEditDistance + 1; + } } return 0; } @@ -1145,14 +1201,20 @@ function initSearch(rawSearchIndex) { return maxEditDistance + 1; } - let dist = editDistance(row.name, elem.name, maxEditDistance); + let dist; + if (typePassesFilter(elem.typeFilter, row.ty)) { + dist = editDistance(row.name, elem.name, maxEditDistance); + } else { + dist = maxEditDistance + 1; + } if (literalSearch) { if (dist !== 0) { // The name didn't match, let's try to check if the generics do. if (elem.generics.length === 0) { const checkGeneric = row.generics.length > 0; if (checkGeneric && row.generics - .findIndex(tmp_elem => tmp_elem.name === elem.name) !== -1) { + .findIndex(tmp_elem => tmp_elem.name === elem.name && + typePassesFilter(elem.typeFilter, tmp_elem.ty)) !== -1) { return 0; } } @@ -1201,22 +1263,21 @@ function initSearch(rawSearchIndex) { * * @param {Row} row * @param {QueryElement} elem - The element from the parsed query. - * @param {integer} typeFilter + * @param {integer} maxEditDistance * @param {Array<integer>} skipPositions - Do not return one of these positions. * * @return {dist: integer, position: integer} - Returns an edit distance to the best match. * If there is no match, returns * `maxEditDistance + 1` and position: -1. */ - function findArg(row, elem, typeFilter, maxEditDistance, skipPositions) { + function findArg(row, elem, maxEditDistance, skipPositions) { let dist = maxEditDistance + 1; let position = -1; if (row && row.type && row.type.inputs && row.type.inputs.length > 0) { let i = 0; for (const input of row.type.inputs) { - if (!typePassesFilter(typeFilter, input.ty) || - skipPositions.indexOf(i) !== -1) { + if (skipPositions.indexOf(i) !== -1) { i += 1; continue; } @@ -1245,14 +1306,14 @@ function initSearch(rawSearchIndex) { * * @param {Row} row * @param {QueryElement} elem - The element from the parsed query. - * @param {integer} typeFilter + * @param {integer} maxEditDistance * @param {Array<integer>} skipPositions - Do not return one of these positions. * * @return {dist: integer, position: integer} - Returns an edit distance to the best match. * If there is no match, returns * `maxEditDistance + 1` and position: -1. */ - function checkReturned(row, elem, typeFilter, maxEditDistance, skipPositions) { + function checkReturned(row, elem, maxEditDistance, skipPositions) { let dist = maxEditDistance + 1; let position = -1; @@ -1260,8 +1321,7 @@ function initSearch(rawSearchIndex) { const ret = row.type.output; let i = 0; for (const ret_ty of ret) { - if (!typePassesFilter(typeFilter, ret_ty.ty) || - skipPositions.indexOf(i) !== -1) { + if (skipPositions.indexOf(i) !== -1) { i += 1; continue; } @@ -1483,15 +1543,15 @@ function initSearch(rawSearchIndex) { const fullId = row.id; const searchWord = searchWords[pos]; - const in_args = findArg(row, elem, parsedQuery.typeFilter, maxEditDistance, []); - const returned = checkReturned(row, elem, parsedQuery.typeFilter, maxEditDistance, []); + const in_args = findArg(row, elem, maxEditDistance, []); + const returned = checkReturned(row, elem, maxEditDistance, []); // path_dist is 0 because no parent path information is currently stored // in the search index addIntoResults(results_in_args, fullId, pos, -1, in_args.dist, 0, maxEditDistance); addIntoResults(results_returned, fullId, pos, -1, returned.dist, 0, maxEditDistance); - if (!typePassesFilter(parsedQuery.typeFilter, row.ty)) { + if (!typePassesFilter(elem.typeFilter, row.ty)) { return; } @@ -1568,7 +1628,6 @@ function initSearch(rawSearchIndex) { const { dist, position } = callback( row, elem, - NO_TYPE_FILTER, maxEditDistance, skipPositions ); @@ -1632,7 +1691,6 @@ function initSearch(rawSearchIndex) { in_returned = checkReturned( row, elem, - parsedQuery.typeFilter, maxEditDistance, [] ); diff --git a/src/librustdoc/html/templates/source.html b/src/librustdoc/html/templates/source.html new file mode 100644 index 00000000000..a224ff12f44 --- /dev/null +++ b/src/librustdoc/html/templates/source.html @@ -0,0 +1,19 @@ +<div class="example-wrap"> {# #} + <pre class="src-line-numbers"> + {% for line in lines.clone() %} + {% if embedded %} + <span>{{line|safe}}</span> + {%~ else %} + <a href="#{{line|safe}}" id="{{line|safe}}">{{line|safe}}</a> + {%~ endif %} + {% endfor %} + </pre> {# #} + <pre class="rust"> {# #} + <code> + {% if needs_expansion %} + <button class="expand">↕</button> + {% endif %} + {{code_html|safe}} + </code> {# #} + </pre> {# #} +</div> diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 6ed7b989999..789523c561e 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -28,7 +28,7 @@ use std::mem; use std::ops::Range; use crate::clean::{self, utils::find_nearest_parent_module}; -use crate::clean::{Crate, Item, ItemId, ItemLink, PrimitiveType}; +use crate::clean::{Crate, Item, ItemLink, PrimitiveType}; use crate::core::DocContext; use crate::html::markdown::{markdown_links, MarkdownLink}; use crate::lint::{BROKEN_INTRA_DOC_LINKS, PRIVATE_INTRA_DOC_LINKS}; @@ -42,8 +42,7 @@ pub(crate) const COLLECT_INTRA_DOC_LINKS: Pass = Pass { }; fn collect_intra_doc_links(krate: Crate, cx: &mut DocContext<'_>) -> Crate { - let mut collector = - LinkCollector { cx, mod_ids: Vec::new(), visited_links: FxHashMap::default() }; + let mut collector = LinkCollector { cx, visited_links: FxHashMap::default() }; collector.visit_crate(&krate); krate } @@ -149,7 +148,7 @@ impl TryFrom<ResolveRes> for Res { #[derive(Debug)] struct UnresolvedPath<'a> { /// Item on which the link is resolved, used for resolving `Self`. - item_id: ItemId, + item_id: DefId, /// The scope the link was resolved in. module_id: DefId, /// If part of the link resolved, this has the `Res`. @@ -225,7 +224,7 @@ impl UrlFragment { #[derive(Clone, Debug, Hash, PartialEq, Eq)] struct ResolutionInfo { - item_id: ItemId, + item_id: DefId, module_id: DefId, dis: Option<Disambiguator>, path_str: Box<str>, @@ -242,11 +241,6 @@ struct DiagnosticInfo<'a> { struct LinkCollector<'a, 'tcx> { cx: &'a mut DocContext<'tcx>, - /// A stack of modules used to decide what scope to resolve in. - /// - /// The last module will be used if the parent scope of the current item is - /// unknown. - mod_ids: Vec<DefId>, /// Cache the resolved links so we can avoid resolving (and emitting errors for) the same link. /// The link will be `None` if it could not be resolved (i.e. the error was cached). visited_links: FxHashMap<ResolutionInfo, Option<(Res, Option<UrlFragment>)>>, @@ -262,7 +256,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { fn variant_field<'path>( &self, path_str: &'path str, - item_id: ItemId, + item_id: DefId, module_id: DefId, ) -> Result<(Res, DefId), UnresolvedPath<'path>> { let tcx = self.cx.tcx; @@ -333,35 +327,33 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { }) } - fn resolve_self_ty(&self, path_str: &str, ns: Namespace, item_id: ItemId) -> Option<Res> { + fn resolve_self_ty(&self, path_str: &str, ns: Namespace, item_id: DefId) -> Option<Res> { if ns != TypeNS || path_str != "Self" { return None; } let tcx = self.cx.tcx; - item_id - .as_def_id() - .map(|def_id| match tcx.def_kind(def_id) { - def_kind @ (DefKind::AssocFn - | DefKind::AssocConst - | DefKind::AssocTy - | DefKind::Variant - | DefKind::Field) => { - let parent_def_id = tcx.parent(def_id); - if def_kind == DefKind::Field && tcx.def_kind(parent_def_id) == DefKind::Variant - { - tcx.parent(parent_def_id) - } else { - parent_def_id - } + let self_id = match tcx.def_kind(item_id) { + def_kind @ (DefKind::AssocFn + | DefKind::AssocConst + | DefKind::AssocTy + | DefKind::Variant + | DefKind::Field) => { + let parent_def_id = tcx.parent(item_id); + if def_kind == DefKind::Field && tcx.def_kind(parent_def_id) == DefKind::Variant { + tcx.parent(parent_def_id) + } else { + parent_def_id } - _ => def_id, - }) - .and_then(|self_id| match tcx.def_kind(self_id) { - DefKind::Impl { .. } => self.def_id_to_res(self_id), - DefKind::Use => None, - def_kind => Some(Res::Def(def_kind, self_id)), - }) + } + _ => item_id, + }; + + match tcx.def_kind(self_id) { + DefKind::Impl { .. } => self.def_id_to_res(self_id), + DefKind::Use => None, + def_kind => Some(Res::Def(def_kind, self_id)), + } } /// Convenience wrapper around `doc_link_resolutions`. @@ -373,7 +365,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { &self, path_str: &str, ns: Namespace, - item_id: ItemId, + item_id: DefId, module_id: DefId, ) -> Option<Res> { if let res @ Some(..) = self.resolve_self_ty(path_str, ns, item_id) { @@ -400,7 +392,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { &mut self, path_str: &'path str, ns: Namespace, - item_id: ItemId, + item_id: DefId, module_id: DefId, ) -> Result<(Res, Option<DefId>), UnresolvedPath<'path>> { if let Some(res) = self.resolve_path(path_str, ns, item_id, module_id) { @@ -779,48 +771,8 @@ fn is_derive_trait_collision<T>(ns: &PerNS<Result<(Res, T), ResolutionFailure<'_ impl<'a, 'tcx> DocVisitor for LinkCollector<'a, 'tcx> { fn visit_item(&mut self, item: &Item) { - let parent_node = - item.item_id.as_def_id().and_then(|did| find_nearest_parent_module(self.cx.tcx, did)); - if parent_node.is_some() { - trace!("got parent node for {:?} {:?}, id {:?}", item.type_(), item.name, item.item_id); - } - - let inner_docs = item.inner_docs(self.cx.tcx); - - if item.is_mod() && inner_docs { - self.mod_ids.push(item.item_id.expect_def_id()); - } - - // We want to resolve in the lexical scope of the documentation. - // In the presence of re-exports, this is not the same as the module of the item. - // Rather than merging all documentation into one, resolve it one attribute at a time - // so we know which module it came from. - for (parent_module, doc) in prepare_to_doc_link_resolution(&item.attrs.doc_strings) { - if !may_have_doc_links(&doc) { - continue; - } - debug!("combined_docs={}", doc); - // NOTE: if there are links that start in one crate and end in another, this will not resolve them. - // This is a degenerate case and it's not supported by rustdoc. - let parent_node = parent_module.or(parent_node); - for md_link in preprocessed_markdown_links(&doc) { - let link = self.resolve_link(item, &doc, parent_node, &md_link); - if let Some(link) = link { - self.cx.cache.intra_doc_links.entry(item.item_id).or_default().push(link); - } - } - } - - if item.is_mod() { - if !inner_docs { - self.mod_ids.push(item.item_id.expect_def_id()); - } - - self.visit_item_recur(item); - self.mod_ids.pop(); - } else { - self.visit_item_recur(item) - } + self.resolve_links(item); + self.visit_item_recur(item) } } @@ -946,14 +898,41 @@ fn preprocessed_markdown_links(s: &str) -> Vec<PreprocessedMarkdownLink> { } impl LinkCollector<'_, '_> { + fn resolve_links(&mut self, item: &Item) { + // We want to resolve in the lexical scope of the documentation. + // In the presence of re-exports, this is not the same as the module of the item. + // Rather than merging all documentation into one, resolve it one attribute at a time + // so we know which module it came from. + for (item_id, doc) in prepare_to_doc_link_resolution(&item.attrs.doc_strings) { + if !may_have_doc_links(&doc) { + continue; + } + debug!("combined_docs={}", doc); + // NOTE: if there are links that start in one crate and end in another, this will not resolve them. + // This is a degenerate case and it's not supported by rustdoc. + let item_id = item_id.unwrap_or_else(|| item.item_id.expect_def_id()); + let module_id = match self.cx.tcx.def_kind(item_id) { + DefKind::Mod if item.inner_docs(self.cx.tcx) => item_id, + _ => find_nearest_parent_module(self.cx.tcx, item_id).unwrap(), + }; + for md_link in preprocessed_markdown_links(&doc) { + let link = self.resolve_link(item, item_id, module_id, &doc, &md_link); + if let Some(link) = link { + self.cx.cache.intra_doc_links.entry(item.item_id).or_default().push(link); + } + } + } + } + /// This is the entry point for resolving an intra-doc link. /// /// FIXME(jynelson): this is way too many arguments fn resolve_link( &mut self, item: &Item, + item_id: DefId, + module_id: DefId, dox: &str, - parent_node: Option<DefId>, link: &PreprocessedMarkdownLink, ) -> Option<ItemLink> { let PreprocessedMarkdownLink(pp_link, ori_link) = link; @@ -970,25 +949,9 @@ impl LinkCollector<'_, '_> { pp_link.as_ref().map_err(|err| err.report(self.cx, diag_info.clone())).ok()?; let disambiguator = *disambiguator; - // In order to correctly resolve intra-doc links we need to - // pick a base AST node to work from. If the documentation for - // this module came from an inner comment (//!) then we anchor - // our name resolution *inside* the module. If, on the other - // hand it was an outer comment (///) then we anchor the name - // resolution in the parent module on the basis that the names - // used are more likely to be intended to be parent names. For - // this, we set base_node to None for inner comments since - // we've already pushed this node onto the resolution stack but - // for outer comments we explicitly try and resolve against the - // parent_node first. - let inner_docs = item.inner_docs(self.cx.tcx); - let base_node = - if item.is_mod() && inner_docs { self.mod_ids.last().copied() } else { parent_node }; - let module_id = base_node.expect("doc link without parent module"); - let (mut res, fragment) = self.resolve_with_disambiguator_cached( ResolutionInfo { - item_id: item.item_id, + item_id, module_id, dis: disambiguator, path_str: path_str.clone(), @@ -1229,11 +1192,11 @@ impl LinkCollector<'_, '_> { let disambiguator = key.dis; let path_str = &key.path_str; let item_id = key.item_id; - let base_node = key.module_id; + let module_id = key.module_id; match disambiguator.map(Disambiguator::ns) { Some(expected_ns) => { - match self.resolve(path_str, expected_ns, item_id, base_node) { + match self.resolve(path_str, expected_ns, item_id, module_id) { Ok(res) => Some(res), Err(err) => { // We only looked in one namespace. Try to give a better error if possible. @@ -1243,7 +1206,7 @@ impl LinkCollector<'_, '_> { for other_ns in [TypeNS, ValueNS, MacroNS] { if other_ns != expected_ns { if let Ok(res) = - self.resolve(path_str, other_ns, item_id, base_node) + self.resolve(path_str, other_ns, item_id, module_id) { err = ResolutionFailure::WrongNamespace { res: full_res(self.cx.tcx, res), @@ -1260,7 +1223,7 @@ impl LinkCollector<'_, '_> { None => { // Try everything! let mut candidate = |ns| { - self.resolve(path_str, ns, item_id, base_node) + self.resolve(path_str, ns, item_id, module_id) .map_err(ResolutionFailure::NotResolved) }; diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs index d32e8185d3f..8d204ddb79e 100644 --- a/src/librustdoc/passes/collect_trait_impls.rs +++ b/src/librustdoc/passes/collect_trait_impls.rs @@ -49,7 +49,7 @@ pub(crate) fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> let _prof_timer = cx.tcx.sess.prof.generic_activity("build_extern_trait_impls"); for &cnum in cx.tcx.crates(()) { for &impl_def_id in cx.tcx.trait_impls_in_crate(cnum) { - inline::build_impl(cx, None, impl_def_id, None, &mut new_items_external); + inline::build_impl(cx, impl_def_id, None, &mut new_items_external); } } } @@ -75,7 +75,7 @@ pub(crate) fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> ); parent = cx.tcx.opt_parent(did); } - inline::build_impl(cx, None, impl_def_id, Some(&attr_buf), &mut new_items_local); + inline::build_impl(cx, impl_def_id, Some((&attr_buf, None)), &mut new_items_local); attr_buf.clear(); } } @@ -84,7 +84,7 @@ pub(crate) fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> for def_id in PrimitiveType::all_impls(cx.tcx) { // Try to inline primitive impls from other crates. if !def_id.is_local() { - inline::build_impl(cx, None, def_id, None, &mut new_items_external); + inline::build_impl(cx, def_id, None, &mut new_items_external); } } for (prim, did) in PrimitiveType::primitive_locations(cx.tcx) { diff --git a/src/librustdoc/passes/propagate_doc_cfg.rs b/src/librustdoc/passes/propagate_doc_cfg.rs index f35643af637..8a33e51b3be 100644 --- a/src/librustdoc/passes/propagate_doc_cfg.rs +++ b/src/librustdoc/passes/propagate_doc_cfg.rs @@ -57,7 +57,8 @@ impl<'a, 'tcx> CfgPropagator<'a, 'tcx> { next_def_id = parent_def_id; } - let (_, cfg) = merge_attrs(self.cx, None, item.attrs.other_attrs.as_slice(), Some(&attrs)); + let (_, cfg) = + merge_attrs(self.cx, item.attrs.other_attrs.as_slice(), Some((&attrs, None))); item.cfg = cfg; } } diff --git a/src/tools/clippy/clippy_lints/src/functions/must_use.rs b/src/tools/clippy/clippy_lints/src/functions/must_use.rs index eacbf6c6ec9..67877780c0e 100644 --- a/src/tools/clippy/clippy_lints/src/functions/must_use.rs +++ b/src/tools/clippy/clippy_lints/src/functions/must_use.rs @@ -28,7 +28,7 @@ pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_> let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); if let Some(attr) = attr { check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr); - } else if is_public && !is_proc_macro(cx.sess(), attrs) && !attrs.iter().any(|a| a.has_name(sym::no_mangle)) { + } else if is_public && !is_proc_macro(attrs) && !attrs.iter().any(|a| a.has_name(sym::no_mangle)) { check_must_use_candidate( cx, sig.decl, @@ -51,7 +51,7 @@ pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Imp if let Some(attr) = attr { check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr); } else if is_public - && !is_proc_macro(cx.sess(), attrs) + && !is_proc_macro(attrs) && trait_ref_of_method(cx, item.owner_id.def_id).is_none() { check_must_use_candidate( @@ -78,7 +78,7 @@ pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Tr check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr); } else if let hir::TraitFn::Provided(eid) = *eid { let body = cx.tcx.hir().body(eid); - if attr.is_none() && is_public && !is_proc_macro(cx.sess(), attrs) { + if attr.is_none() && is_public && !is_proc_macro(attrs) { check_must_use_candidate( cx, sig.decl, diff --git a/src/tools/clippy/clippy_utils/src/attrs.rs b/src/tools/clippy/clippy_utils/src/attrs.rs index 7987a233bdc..bc3d774540a 100644 --- a/src/tools/clippy/clippy_utils/src/attrs.rs +++ b/src/tools/clippy/clippy_utils/src/attrs.rs @@ -145,8 +145,8 @@ pub fn get_unique_attr<'a>( /// Return true if the attributes contain any of `proc_macro`, /// `proc_macro_derive` or `proc_macro_attribute`, false otherwise -pub fn is_proc_macro(sess: &Session, attrs: &[ast::Attribute]) -> bool { - attrs.iter().any(|attr| sess.is_proc_macro_attr(attr)) +pub fn is_proc_macro(attrs: &[ast::Attribute]) -> bool { + attrs.iter().any(|attr| attr.is_proc_macro_attr()) } /// Return true if the attributes contain `#[doc(hidden)]` diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs index 24403e8b6f3..9f6adf3e3fa 100644 --- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs +++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs @@ -37,7 +37,7 @@ pub fn is_min_const_fn<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, msrv: &Msrv) | ty::PredicateKind::ConstEvaluatable(..) | ty::PredicateKind::ConstEquate(..) | ty::PredicateKind::TypeWellFormedFromEnv(..) => continue, - ty::PredicateKind::AliasEq(..) => panic!("alias eq predicate on function: {predicate:#?}"), + ty::PredicateKind::AliasRelate(..) => panic!("alias relate predicate on function: {predicate:#?}"), ty::PredicateKind::ObjectSafe(_) => panic!("object safe predicate on function: {predicate:#?}"), ty::PredicateKind::ClosureKind(..) => panic!("closure kind predicate on function: {predicate:#?}"), ty::PredicateKind::Subtype(_) => panic!("subtype predicate on function: {predicate:#?}"), @@ -176,6 +176,9 @@ fn check_rvalue<'tcx>( // FIXME(dyn-star) unimplemented!() }, + Rvalue::Cast(CastKind::Transmute, _, _) => { + Err((span, "transmute can attempt to turn pointers into integers, so is unstable in const fn".into())) + }, // binops are fine on integers Rvalue::BinaryOp(_, box (lhs, rhs)) | Rvalue::CheckedBinaryOp(_, box (lhs, rhs)) => { check_operand(tcx, lhs, span, body)?; diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index 22a0b1d13be..5bc9d9afcb9 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -964,6 +964,19 @@ pub fn make_test_description<R: Read>( .join(if config.host.contains("windows") { "rust-lld.exe" } else { "rust-lld" }) .exists(); + fn is_on_path(file: &'static str) -> impl Fn() -> bool { + move || env::split_paths(&env::var_os("PATH").unwrap()).any(|dir| dir.join(file).is_file()) + } + + // On Windows, dlltool.exe is used for all architectures. + #[cfg(windows)] + let (has_i686_dlltool, has_x86_64_dlltool) = + (is_on_path("dlltool.exe"), is_on_path("dlltool.exe")); + // For non-Windows, there are architecture specific dlltool binaries. + #[cfg(not(windows))] + let (has_i686_dlltool, has_x86_64_dlltool) = + (is_on_path("i686-w64-mingw32-dlltool"), is_on_path("x86_64-w64-mingw32-dlltool")); + iter_header(path, src, &mut |revision, ln| { if revision.is_some() && revision != cfg { return; @@ -1031,6 +1044,8 @@ pub fn make_test_description<R: Read>( reason!(config.debugger == Some(Debugger::Gdb) && ignore_gdb(config, ln)); reason!(config.debugger == Some(Debugger::Lldb) && ignore_lldb(config, ln)); reason!(!has_rust_lld && config.parse_name_directive(ln, "needs-rust-lld")); + reason!(config.parse_name_directive(ln, "needs-i686-dlltool") && !has_i686_dlltool()); + reason!(config.parse_name_directive(ln, "needs-x86_64-dlltool") && !has_x86_64_dlltool()); should_fail |= config.parse_name_directive(ln, "should-fail"); }); diff --git a/src/tools/lint-docs/src/lib.rs b/src/tools/lint-docs/src/lib.rs index 3842a649c6f..034c6aa0708 100644 --- a/src/tools/lint-docs/src/lib.rs +++ b/src/tools/lint-docs/src/lib.rs @@ -45,6 +45,36 @@ impl Lint { fn check_style(&self) -> Result<(), Box<dyn Error>> { for &expected in &["### Example", "### Explanation", "{{produces}}"] { if expected == "{{produces}}" && self.is_ignored() { + if self.doc_contains("{{produces}}") { + return Err(format!( + "the lint example has `ignore`, but also contains the {{{{produces}}}} marker\n\ + \n\ + The documentation generator cannot generate the example output when the \ + example is ignored.\n\ + Manually include the sample output below the example. For example:\n\ + \n\ + /// ```rust,ignore (needs command line option)\n\ + /// #[cfg(widnows)]\n\ + /// fn foo() {{}}\n\ + /// ```\n\ + ///\n\ + /// This will produce:\n\ + /// \n\ + /// ```text\n\ + /// warning: unknown condition name used\n\ + /// --> lint_example.rs:1:7\n\ + /// |\n\ + /// 1 | #[cfg(widnows)]\n\ + /// | ^^^^^^^\n\ + /// |\n\ + /// = note: `#[warn(unexpected_cfgs)]` on by default\n\ + /// ```\n\ + \n\ + Replacing the output with the text of the example you \ + compiled manually yourself.\n\ + " + ).into()); + } continue; } if !self.doc_contains(expected) { @@ -317,10 +347,10 @@ impl<'a> LintExtractor<'a> { .., &format!( "This will produce:\n\ - \n\ - ```text\n\ - {}\ - ```", + \n\ + ```text\n\ + {}\ + ```", output ), ); @@ -392,37 +422,36 @@ impl<'a> LintExtractor<'a> { .filter(|line| line.starts_with('{')) .map(serde_json::from_str) .collect::<Result<Vec<serde_json::Value>, _>>()?; - match msgs + // First try to find the messages with the `code` field set to our lint. + let matches: Vec<_> = msgs .iter() - .find(|msg| matches!(&msg["code"]["code"], serde_json::Value::String(s) if s==name)) - { - Some(msg) => { - let rendered = msg["rendered"].as_str().expect("rendered field should exist"); - Ok(rendered.to_string()) - } - None => { - match msgs.iter().find( - |msg| matches!(&msg["rendered"], serde_json::Value::String(s) if s.contains(name)), - ) { - Some(msg) => { - let rendered = msg["rendered"].as_str().expect("rendered field should exist"); - Ok(rendered.to_string()) - } - None => { - let rendered: Vec<&str> = - msgs.iter().filter_map(|msg| msg["rendered"].as_str()).collect(); - let non_json: Vec<&str> = - stderr.lines().filter(|line| !line.starts_with('{')).collect(); - Err(format!( - "did not find lint `{}` in output of example, got:\n{}\n{}", - name, - non_json.join("\n"), - rendered.join("\n") - ) - .into()) - } - } + .filter(|msg| matches!(&msg["code"]["code"], serde_json::Value::String(s) if s==name)) + .map(|msg| msg["rendered"].as_str().expect("rendered field should exist").to_string()) + .collect(); + if matches.is_empty() { + // Some lints override their code to something else (E0566). + // Try to find something that looks like it could be our lint. + let matches: Vec<_> = msgs.iter().filter(|msg| + matches!(&msg["rendered"], serde_json::Value::String(s) if s.contains(name))) + .map(|msg| msg["rendered"].as_str().expect("rendered field should exist").to_string()) + .collect(); + if matches.is_empty() { + let rendered: Vec<&str> = + msgs.iter().filter_map(|msg| msg["rendered"].as_str()).collect(); + let non_json: Vec<&str> = + stderr.lines().filter(|line| !line.starts_with('{')).collect(); + Err(format!( + "did not find lint `{}` in output of example, got:\n{}\n{}", + name, + non_json.join("\n"), + rendered.join("\n") + ) + .into()) + } else { + Ok(matches.join("\n")) } + } else { + Ok(matches.join("\n")) } } diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index c4baeb2a73b..cc1964de332 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -812,7 +812,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> { } #[inline(always)] - fn enforce_validity(ecx: &MiriInterpCx<'mir, 'tcx>) -> bool { + fn enforce_validity(ecx: &MiriInterpCx<'mir, 'tcx>, _layout: TyAndLayout<'tcx>) -> bool { ecx.machine.validate } diff --git a/src/tools/miri/tests/fail/never_transmute_humans.rs b/src/tools/miri/tests/fail/never_transmute_humans.rs index de723433dc2..cba3cc0ccf1 100644 --- a/src/tools/miri/tests/fail/never_transmute_humans.rs +++ b/src/tools/miri/tests/fail/never_transmute_humans.rs @@ -7,6 +7,6 @@ struct Human; fn main() { let _x: ! = unsafe { - std::mem::transmute::<Human, !>(Human) //~ ERROR: transmuting to uninhabited + std::mem::transmute::<Human, !>(Human) //~ ERROR: entering unreachable code }; } diff --git a/src/tools/miri/tests/fail/never_transmute_humans.stderr b/src/tools/miri/tests/fail/never_transmute_humans.stderr index e8df4739f9b..a51ca7fe7e7 100644 --- a/src/tools/miri/tests/fail/never_transmute_humans.stderr +++ b/src/tools/miri/tests/fail/never_transmute_humans.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: transmuting to uninhabited type +error: Undefined Behavior: entering unreachable code --> $DIR/never_transmute_humans.rs:LL:CC | LL | std::mem::transmute::<Human, !>(Human) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ entering unreachable code | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/never_transmute_void.rs b/src/tools/miri/tests/fail/never_transmute_void.rs index 19473e9ac21..ad67b444616 100644 --- a/src/tools/miri/tests/fail/never_transmute_void.rs +++ b/src/tools/miri/tests/fail/never_transmute_void.rs @@ -10,11 +10,13 @@ mod m { pub struct Void(VoidI); pub fn f(v: Void) -> ! { - match v.0 {} //~ ERROR: entering unreachable code + match v.0 {} + //~^ ERROR: entering unreachable code } } fn main() { let v = unsafe { std::mem::transmute::<(), m::Void>(()) }; - m::f(v); //~ NOTE: inside `main` + m::f(v); + //~^ NOTE: inside `main` } diff --git a/src/tools/rustdoc-js/tester.js b/src/tools/rustdoc-js/tester.js index 8d46a8ce7f1..6b9a9b66a7d 100644 --- a/src/tools/rustdoc-js/tester.js +++ b/src/tools/rustdoc-js/tester.js @@ -79,11 +79,18 @@ function checkNeededFields(fullPath, expected, error_text, queryName, position) "foundElems", "original", "returned", - "typeFilter", "userQuery", "error", ]; - } else if (fullPath.endsWith("elems") || fullPath.endsWith("generics")) { + } else if (fullPath.endsWith("elems") || fullPath.endsWith("returned")) { + fieldsToCheck = [ + "name", + "fullPath", + "pathWithoutLast", + "pathLast", + "generics", + ]; + } else if (fullPath.endsWith("generics")) { fieldsToCheck = [ "name", "fullPath", diff --git a/src/tools/rustfmt/src/attr.rs b/src/tools/rustfmt/src/attr.rs index 5648e1254ed..22e45082a9f 100644 --- a/src/tools/rustfmt/src/attr.rs +++ b/src/tools/rustfmt/src/attr.rs @@ -2,7 +2,7 @@ use rustc_ast::ast; use rustc_ast::HasAttrs; -use rustc_span::{symbol::sym, Span, Symbol}; +use rustc_span::{symbol::sym, Span}; use self::doc_comment::DocCommentFormatter; use crate::comment::{contains_comment, rewrite_doc_comment, CommentStyle}; @@ -19,20 +19,6 @@ use crate::utils::{count_newlines, mk_sp}; mod doc_comment; -pub(crate) fn contains_name(attrs: &[ast::Attribute], name: Symbol) -> bool { - attrs.iter().any(|attr| attr.has_name(name)) -} - -pub(crate) fn first_attr_value_str_by_name( - attrs: &[ast::Attribute], - name: Symbol, -) -> Option<Symbol> { - attrs - .iter() - .find(|attr| attr.has_name(name)) - .and_then(|attr| attr.value_str()) -} - /// Returns attributes on the given statement. pub(crate) fn get_attrs_from_stmt(stmt: &ast::Stmt) -> &[ast::Attribute] { stmt.attrs() diff --git a/src/tools/rustfmt/src/parse/parser.rs b/src/tools/rustfmt/src/parse/parser.rs index 7ab042506bd..6bc53159b38 100644 --- a/src/tools/rustfmt/src/parse/parser.rs +++ b/src/tools/rustfmt/src/parse/parser.rs @@ -2,13 +2,12 @@ use std::panic::{catch_unwind, AssertUnwindSafe}; use std::path::{Path, PathBuf}; use rustc_ast::token::TokenKind; -use rustc_ast::{ast, ptr}; +use rustc_ast::{ast, attr, ptr}; use rustc_errors::Diagnostic; use rustc_parse::{new_parser_from_file, parser::Parser as RawParser}; use rustc_span::{sym, Span}; use thin_vec::ThinVec; -use crate::attr::first_attr_value_str_by_name; use crate::parse::session::ParseSess; use crate::Input; @@ -93,7 +92,7 @@ pub(crate) enum ParserError { impl<'a> Parser<'a> { pub(crate) fn submod_path_from_attr(attrs: &[ast::Attribute], path: &Path) -> Option<PathBuf> { - let path_sym = first_attr_value_str_by_name(attrs, sym::path)?; + let path_sym = attr::first_attr_value_str_by_name(attrs, sym::path)?; let path_str = path_sym.as_str(); // On windows, the base path might have the form diff --git a/src/tools/rustfmt/src/reorder.rs b/src/tools/rustfmt/src/reorder.rs index 9e4a668aa49..3bddf4c1b6a 100644 --- a/src/tools/rustfmt/src/reorder.rs +++ b/src/tools/rustfmt/src/reorder.rs @@ -8,7 +8,7 @@ use std::cmp::{Ord, Ordering}; -use rustc_ast::ast; +use rustc_ast::{ast, attr}; use rustc_span::{symbol::sym, Span}; use crate::config::{Config, GroupImportsTactic}; @@ -167,7 +167,7 @@ fn rewrite_reorderable_or_regroupable_items( } fn contains_macro_use_attr(item: &ast::Item) -> bool { - crate::attr::contains_name(&item.attrs, sym::macro_use) + attr::contains_name(&item.attrs, sym::macro_use) } /// Divides imports into three groups, corresponding to standard, external diff --git a/src/tools/tidy/src/walk.rs b/src/tools/tidy/src/walk.rs index 2ade22c209f..67a4df19fcc 100644 --- a/src/tools/tidy/src/walk.rs +++ b/src/tools/tidy/src/walk.rs @@ -29,6 +29,7 @@ pub fn filter_dirs(path: &Path) -> bool { // Filter RLS output directories "target/rls", "src/bootstrap/target", + "vendor", ]; skip.iter().any(|p| path.ends_with(p)) } diff --git a/tests/assembly/is_aligned.rs b/tests/assembly/is_aligned.rs index 620a3da9463..148d11ee4d6 100644 --- a/tests/assembly/is_aligned.rs +++ b/tests/assembly/is_aligned.rs @@ -1,6 +1,7 @@ // assembly-output: emit-asm // min-llvm-version: 15.0 // only-x86_64 +// ignore-sgx // revisions: opt-speed opt-size // [opt-speed] compile-flags: -Copt-level=1 // [opt-size] compile-flags: -Copt-level=s diff --git a/tests/assembly/strict_provenance.rs b/tests/assembly/strict_provenance.rs index 01f1957d5f6..24a7c6b5bf1 100644 --- a/tests/assembly/strict_provenance.rs +++ b/tests/assembly/strict_provenance.rs @@ -1,6 +1,7 @@ // assembly-output: emit-asm // compile-flags: -Copt-level=1 // only-x86_64 +// ignore-sgx // min-llvm-version: 15.0 #![crate_type = "rlib"] diff --git a/tests/assembly/x86_64-floating-point-clamp.rs b/tests/assembly/x86_64-floating-point-clamp.rs index 0f3b465d08d..0bc6baad479 100644 --- a/tests/assembly/x86_64-floating-point-clamp.rs +++ b/tests/assembly/x86_64-floating-point-clamp.rs @@ -4,6 +4,7 @@ // assembly-output: emit-asm // compile-flags: --crate-type=lib -O -C llvm-args=-x86-asm-syntax=intel // only-x86_64 +// ignore-sgx // CHECK-LABEL: clamp_demo: #[no_mangle] diff --git a/tests/assembly/x86_64-fortanix-unknown-sgx-lvi-generic-load.rs b/tests/assembly/x86_64-fortanix-unknown-sgx-lvi-generic-load.rs index 79d82cf70d3..7eb3c6948ac 100644 --- a/tests/assembly/x86_64-fortanix-unknown-sgx-lvi-generic-load.rs +++ b/tests/assembly/x86_64-fortanix-unknown-sgx-lvi-generic-load.rs @@ -11,7 +11,7 @@ pub extern fn plus_one(r: &mut u64) { // CHECK: plus_one // CHECK: lfence -// CHECK-NEXT: addq +// CHECK-NEXT: incq // CHECK: popq [[REGISTER:%[a-z]+]] // CHECK-NEXT: lfence // CHECK-NEXT: jmpq *[[REGISTER]] diff --git a/tests/assembly/x86_64-fortanix-unknown-sgx-lvi-inline-assembly.rs b/tests/assembly/x86_64-fortanix-unknown-sgx-lvi-inline-assembly.rs index c316379d5b1..4745ebc4fcd 100644 --- a/tests/assembly/x86_64-fortanix-unknown-sgx-lvi-inline-assembly.rs +++ b/tests/assembly/x86_64-fortanix-unknown-sgx-lvi-inline-assembly.rs @@ -10,9 +10,7 @@ use std::arch::asm; pub extern "C" fn get(ptr: *const u64) -> u64 { let value: u64; unsafe { - asm!(".start_inline_asm:", - "mov {}, [{}]", - ".end_inline_asm:", + asm!("mov {}, [{}]", out(reg) value, in(reg) ptr); } @@ -20,24 +18,17 @@ pub extern "C" fn get(ptr: *const u64) -> u64 { } // CHECK: get -// CHECK: .start_inline_asm -// CHECK-NEXT: movq +// CHECK: movq // CHECK-NEXT: lfence -// CHECK-NEXT: .end_inline_asm #[no_mangle] pub extern "C" fn myret() { unsafe { - asm!( - ".start_myret_inline_asm:", - "ret", - ".end_myret_inline_asm:", - ); + asm!("ret"); } } // CHECK: myret -// CHECK: .start_myret_inline_asm -// CHECK-NEXT: shlq $0, (%rsp) +// CHECK: shlq $0, (%rsp) // CHECK-NEXT: lfence // CHECK-NEXT: retq diff --git a/tests/assembly/x86_64-no-jump-tables.rs b/tests/assembly/x86_64-no-jump-tables.rs index 007c3591a4a..edf4adaad41 100644 --- a/tests/assembly/x86_64-no-jump-tables.rs +++ b/tests/assembly/x86_64-no-jump-tables.rs @@ -6,6 +6,7 @@ // compile-flags: -O // [set] compile-flags: -Zno-jump-tables // only-x86_64 +// ignore-sgx #![crate_type = "lib"] diff --git a/tests/codegen/intrinsics/transmute.rs b/tests/codegen/intrinsics/transmute.rs new file mode 100644 index 00000000000..cefcf9ed9ca --- /dev/null +++ b/tests/codegen/intrinsics/transmute.rs @@ -0,0 +1,196 @@ +// compile-flags: -O -C no-prepopulate-passes +// only-64bit (so I don't need to worry about usize) +// min-llvm-version: 15.0 # this test assumes `ptr`s + +#![crate_type = "lib"] +#![feature(core_intrinsics)] +#![feature(custom_mir)] +#![feature(inline_const)] + +use std::mem::transmute; + +// Some of the cases here are statically rejected by `mem::transmute`, so +// we need to generate custom MIR for those cases to get to codegen. +use std::intrinsics::mir::*; + +enum Never {} + +#[repr(align(2))] +pub struct BigNever(Never, u16, Never); + +#[repr(align(8))] +pub struct Scalar64(i64); + +#[repr(C, align(4))] +pub struct Aggregate64(u16, u8, i8, f32); + +// CHECK-LABEL: @check_bigger_size( +#[no_mangle] +#[custom_mir(dialect = "runtime", phase = "initial")] +pub unsafe fn check_bigger_size(x: u16) -> u32 { + // CHECK: call void @llvm.trap + mir!{ + { + RET = CastTransmute(x); + Return() + } + } +} + +// CHECK-LABEL: @check_smaller_size( +#[no_mangle] +#[custom_mir(dialect = "runtime", phase = "initial")] +pub unsafe fn check_smaller_size(x: u32) -> u16 { + // CHECK: call void @llvm.trap + mir!{ + { + RET = CastTransmute(x); + Return() + } + } +} + +// CHECK-LABEL: @check_to_uninhabited( +#[no_mangle] +#[custom_mir(dialect = "runtime", phase = "initial")] +pub unsafe fn check_to_uninhabited(x: u16) -> BigNever { + // CHECK: call void @llvm.trap + mir!{ + { + RET = CastTransmute(x); + Return() + } + } +} + +// CHECK-LABEL: @check_from_uninhabited( +#[no_mangle] +#[custom_mir(dialect = "runtime", phase = "initial")] +pub unsafe fn check_from_uninhabited(x: BigNever) -> u16 { + // CHECK: call void @llvm.trap + mir!{ + { + RET = CastTransmute(x); + Return() + } + } +} + +// CHECK-LABEL: @check_to_newtype( +#[no_mangle] +pub unsafe fn check_to_newtype(x: u64) -> Scalar64 { + // CHECK: %0 = alloca i64 + // CHECK: store i64 %x, ptr %0 + // CHECK: %1 = load i64, ptr %0 + // CHECK: ret i64 %1 + transmute(x) +} + +// CHECK-LABEL: @check_from_newtype( +#[no_mangle] +pub unsafe fn check_from_newtype(x: Scalar64) -> u64 { + // CHECK: %0 = alloca i64 + // CHECK: store i64 %x, ptr %0 + // CHECK: %1 = load i64, ptr %0 + // CHECK: ret i64 %1 + transmute(x) +} + +// CHECK-LABEL: @check_to_pair( +#[no_mangle] +pub unsafe fn check_to_pair(x: u64) -> Option<i32> { + // CHECK: %0 = alloca { i32, i32 }, align 4 + // CHECK: store i64 %x, ptr %0, align 4 + transmute(x) +} + +// CHECK-LABEL: @check_from_pair( +#[no_mangle] +pub unsafe fn check_from_pair(x: Option<i32>) -> u64 { + // The two arguments are of types that are only 4-aligned, but they're + // immediates so we can write using the destination alloca's alignment. + const { assert!(std::mem::align_of::<Option<i32>>() == 4) }; + + // CHECK: %0 = alloca i64, align 8 + // CHECK: store i32 %x.0, ptr %1, align 8 + // CHECK: store i32 %x.1, ptr %2, align 4 + // CHECK: %3 = load i64, ptr %0, align 8 + // CHECK: ret i64 %3 + transmute(x) +} + +// CHECK-LABEL: @check_to_float( +#[no_mangle] +pub unsafe fn check_to_float(x: u32) -> f32 { + // CHECK: %0 = alloca float + // CHECK: store i32 %x, ptr %0 + // CHECK: %1 = load float, ptr %0 + // CHECK: ret float %1 + transmute(x) +} + +// CHECK-LABEL: @check_from_float( +#[no_mangle] +pub unsafe fn check_from_float(x: f32) -> u32 { + // CHECK: %0 = alloca i32 + // CHECK: store float %x, ptr %0 + // CHECK: %1 = load i32, ptr %0 + // CHECK: ret i32 %1 + transmute(x) +} + +// CHECK-LABEL: @check_to_bytes( +#[no_mangle] +pub unsafe fn check_to_bytes(x: u32) -> [u8; 4] { + // CHECK: %0 = alloca [4 x i8], align 1 + // CHECK: store i32 %x, ptr %0, align 1 + // CHECK: %1 = load i32, ptr %0, align 1 + // CHECK: ret i32 %1 + transmute(x) +} + +// CHECK-LABEL: @check_from_bytes( +#[no_mangle] +pub unsafe fn check_from_bytes(x: [u8; 4]) -> u32 { + // CHECK: %1 = alloca i32, align 4 + // CHECK: %x = alloca [4 x i8], align 1 + // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %1, ptr align 1 %x, i64 4, i1 false) + // CHECK: %3 = load i32, ptr %1, align 4 + // CHECK: ret i32 %3 + transmute(x) +} + +// CHECK-LABEL: @check_to_aggregate( +#[no_mangle] +pub unsafe fn check_to_aggregate(x: u64) -> Aggregate64 { + // CHECK: %0 = alloca %Aggregate64, align 4 + // CHECK: store i64 %x, ptr %0, align 4 + // CHECK: %1 = load i64, ptr %0, align 4 + // CHECK: ret i64 %1 + transmute(x) +} + +// CHECK-LABEL: @check_from_aggregate( +#[no_mangle] +pub unsafe fn check_from_aggregate(x: Aggregate64) -> u64 { + // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 8 %{{[0-9]+}}, ptr align 4 %x, i64 8, i1 false) + transmute(x) +} + +// CHECK-LABEL: @check_long_array_less_aligned( +#[no_mangle] +pub unsafe fn check_long_array_less_aligned(x: [u64; 100]) -> [u16; 400] { + // CHECK-NEXT: start + // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 2 %0, ptr align 8 %x, i64 800, i1 false) + // CHECK-NEXT: ret void + transmute(x) +} + +// CHECK-LABEL: @check_long_array_more_aligned( +#[no_mangle] +pub unsafe fn check_long_array_more_aligned(x: [u8; 100]) -> [u32; 25] { + // CHECK-NEXT: start + // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %0, ptr align 1 %x, i64 100, i1 false) + // CHECK-NEXT: ret void + transmute(x) +} diff --git a/tests/codegen/auxiliary/static_dllimport_aux.rs b/tests/codegen/issues/auxiliary/static_dllimport_aux.rs index afb0dc42f44..afb0dc42f44 100644 --- a/tests/codegen/auxiliary/static_dllimport_aux.rs +++ b/tests/codegen/issues/auxiliary/static_dllimport_aux.rs diff --git a/tests/codegen/issue-103285-ptr-addr-overflow-check.rs b/tests/codegen/issues/issue-103285-ptr-addr-overflow-check.rs index a3499babea2..a3499babea2 100644 --- a/tests/codegen/issue-103285-ptr-addr-overflow-check.rs +++ b/tests/codegen/issues/issue-103285-ptr-addr-overflow-check.rs diff --git a/tests/codegen/issue-103840.rs b/tests/codegen/issues/issue-103840.rs index f19d7031bb3..f19d7031bb3 100644 --- a/tests/codegen/issue-103840.rs +++ b/tests/codegen/issues/issue-103840.rs diff --git a/tests/codegen/issue-105386-ub-in-debuginfo.rs b/tests/codegen/issues/issue-105386-ub-in-debuginfo.rs index d54ac9e33bc..d54ac9e33bc 100644 --- a/tests/codegen/issue-105386-ub-in-debuginfo.rs +++ b/tests/codegen/issues/issue-105386-ub-in-debuginfo.rs diff --git a/tests/codegen/issue-13018.rs b/tests/codegen/issues/issue-13018.rs index b70ea1f48c8..b70ea1f48c8 100644 --- a/tests/codegen/issue-13018.rs +++ b/tests/codegen/issues/issue-13018.rs diff --git a/tests/codegen/issue-15953.rs b/tests/codegen/issues/issue-15953.rs index 28d28428904..28d28428904 100644 --- a/tests/codegen/issue-15953.rs +++ b/tests/codegen/issues/issue-15953.rs diff --git a/tests/codegen/issue-27130.rs b/tests/codegen/issues/issue-27130.rs index e5ee94e1f45..e5ee94e1f45 100644 --- a/tests/codegen/issue-27130.rs +++ b/tests/codegen/issues/issue-27130.rs diff --git a/tests/codegen/issue-32031.rs b/tests/codegen/issues/issue-32031.rs index abef92c19b6..abef92c19b6 100644 --- a/tests/codegen/issue-32031.rs +++ b/tests/codegen/issues/issue-32031.rs diff --git a/tests/codegen/issue-32364.rs b/tests/codegen/issues/issue-32364.rs index 85493a4bb73..85493a4bb73 100644 --- a/tests/codegen/issue-32364.rs +++ b/tests/codegen/issues/issue-32364.rs diff --git a/tests/codegen/issue-34634.rs b/tests/codegen/issues/issue-34634.rs index f53fa240cd1..f53fa240cd1 100644 --- a/tests/codegen/issue-34634.rs +++ b/tests/codegen/issues/issue-34634.rs diff --git a/tests/codegen/issue-34947-pow-i32.rs b/tests/codegen/issues/issue-34947-pow-i32.rs index 653da8e8b5f..653da8e8b5f 100644 --- a/tests/codegen/issue-34947-pow-i32.rs +++ b/tests/codegen/issues/issue-34947-pow-i32.rs diff --git a/tests/codegen/issue-37945.rs b/tests/codegen/issues/issue-37945.rs index fe54375bbf6..fe54375bbf6 100644 --- a/tests/codegen/issue-37945.rs +++ b/tests/codegen/issues/issue-37945.rs diff --git a/tests/codegen/issue-44056-macos-tls-align.rs b/tests/codegen/issues/issue-44056-macos-tls-align.rs index 1a3923f1bb1..1a3923f1bb1 100644 --- a/tests/codegen/issue-44056-macos-tls-align.rs +++ b/tests/codegen/issues/issue-44056-macos-tls-align.rs diff --git a/tests/codegen/issue-45222.rs b/tests/codegen/issues/issue-45222.rs index e9b05e648b4..e9b05e648b4 100644 --- a/tests/codegen/issue-45222.rs +++ b/tests/codegen/issues/issue-45222.rs diff --git a/tests/codegen/issue-45466.rs b/tests/codegen/issues/issue-45466.rs index c7954276777..c7954276777 100644 --- a/tests/codegen/issue-45466.rs +++ b/tests/codegen/issues/issue-45466.rs diff --git a/tests/codegen/issue-45964-bounds-check-slice-pos.rs b/tests/codegen/issues/issue-45964-bounds-check-slice-pos.rs index 1daa213fc82..1daa213fc82 100644 --- a/tests/codegen/issue-45964-bounds-check-slice-pos.rs +++ b/tests/codegen/issues/issue-45964-bounds-check-slice-pos.rs diff --git a/tests/codegen/issue-47278.rs b/tests/codegen/issues/issue-47278.rs index 9076274f45e..9076274f45e 100644 --- a/tests/codegen/issue-47278.rs +++ b/tests/codegen/issues/issue-47278.rs diff --git a/tests/codegen/issue-47442.rs b/tests/codegen/issues/issue-47442.rs index 6944336d335..6944336d335 100644 --- a/tests/codegen/issue-47442.rs +++ b/tests/codegen/issues/issue-47442.rs diff --git a/tests/codegen/issue-56267-2.rs b/tests/codegen/issues/issue-56267-2.rs index 4dc9ebfebbc..4dc9ebfebbc 100644 --- a/tests/codegen/issue-56267-2.rs +++ b/tests/codegen/issues/issue-56267-2.rs diff --git a/tests/codegen/issue-56267.rs b/tests/codegen/issues/issue-56267.rs index 7bdd2577998..7bdd2577998 100644 --- a/tests/codegen/issue-56267.rs +++ b/tests/codegen/issues/issue-56267.rs diff --git a/tests/codegen/issue-56927.rs b/tests/codegen/issues/issue-56927.rs index 044d721814b..044d721814b 100644 --- a/tests/codegen/issue-56927.rs +++ b/tests/codegen/issues/issue-56927.rs diff --git a/tests/codegen/issue-58881.rs b/tests/codegen/issues/issue-58881.rs index 00f8953d949..00f8953d949 100644 --- a/tests/codegen/issue-58881.rs +++ b/tests/codegen/issues/issue-58881.rs diff --git a/tests/codegen/issue-59352.rs b/tests/codegen/issues/issue-59352.rs index d271fe027e3..d271fe027e3 100644 --- a/tests/codegen/issue-59352.rs +++ b/tests/codegen/issues/issue-59352.rs diff --git a/tests/codegen/issue-69101-bounds-check.rs b/tests/codegen/issues/issue-69101-bounds-check.rs index a3aca3a2912..a3aca3a2912 100644 --- a/tests/codegen/issue-69101-bounds-check.rs +++ b/tests/codegen/issues/issue-69101-bounds-check.rs diff --git a/tests/codegen/issue-73031.rs b/tests/codegen/issues/issue-73031.rs index a09c4bcfbea..a09c4bcfbea 100644 --- a/tests/codegen/issue-73031.rs +++ b/tests/codegen/issues/issue-73031.rs diff --git a/tests/codegen/issue-73338-effecient-cmp.rs b/tests/codegen/issues/issue-73338-effecient-cmp.rs index 85c2bbfd040..85c2bbfd040 100644 --- a/tests/codegen/issue-73338-effecient-cmp.rs +++ b/tests/codegen/issues/issue-73338-effecient-cmp.rs diff --git a/tests/codegen/issue-73396-bounds-check-after-position.rs b/tests/codegen/issues/issue-73396-bounds-check-after-position.rs index 8d07a67a1b4..8d07a67a1b4 100644 --- a/tests/codegen/issue-73396-bounds-check-after-position.rs +++ b/tests/codegen/issues/issue-73396-bounds-check-after-position.rs diff --git a/tests/codegen/issue-73827-bounds-check-index-in-subexpr.rs b/tests/codegen/issues/issue-73827-bounds-check-index-in-subexpr.rs index 1ad05906e21..1ad05906e21 100644 --- a/tests/codegen/issue-73827-bounds-check-index-in-subexpr.rs +++ b/tests/codegen/issues/issue-73827-bounds-check-index-in-subexpr.rs diff --git a/tests/codegen/issue-75525-bounds-checks.rs b/tests/codegen/issues/issue-75525-bounds-checks.rs index 2d363d8f73b..2d363d8f73b 100644 --- a/tests/codegen/issue-75525-bounds-checks.rs +++ b/tests/codegen/issues/issue-75525-bounds-checks.rs diff --git a/tests/codegen/issue-75546.rs b/tests/codegen/issues/issue-75546.rs index 470a9e04096..470a9e04096 100644 --- a/tests/codegen/issue-75546.rs +++ b/tests/codegen/issues/issue-75546.rs diff --git a/tests/codegen/issue-75659.rs b/tests/codegen/issues/issue-75659.rs index 9394868c08d..9394868c08d 100644 --- a/tests/codegen/issue-75659.rs +++ b/tests/codegen/issues/issue-75659.rs diff --git a/tests/codegen/issue-77812.rs b/tests/codegen/issues/issue-77812.rs index 4cc82414546..4cc82414546 100644 --- a/tests/codegen/issue-77812.rs +++ b/tests/codegen/issues/issue-77812.rs diff --git a/tests/codegen/issue-81408-dllimport-thinlto-windows.rs b/tests/codegen/issues/issue-81408-dllimport-thinlto-windows.rs index 0b6ab4f7ecb..0b6ab4f7ecb 100644 --- a/tests/codegen/issue-81408-dllimport-thinlto-windows.rs +++ b/tests/codegen/issues/issue-81408-dllimport-thinlto-windows.rs diff --git a/tests/codegen/issue-84268.rs b/tests/codegen/issues/issue-84268.rs index 7ca19544700..7ca19544700 100644 --- a/tests/codegen/issue-84268.rs +++ b/tests/codegen/issues/issue-84268.rs diff --git a/tests/codegen/issue-85872-multiple-reverse.rs b/tests/codegen/issues/issue-85872-multiple-reverse.rs index 591a1aca747..591a1aca747 100644 --- a/tests/codegen/issue-85872-multiple-reverse.rs +++ b/tests/codegen/issues/issue-85872-multiple-reverse.rs diff --git a/tests/codegen/issue-86106.rs b/tests/codegen/issues/issue-86106.rs index 9ccbcb24f56..9ccbcb24f56 100644 --- a/tests/codegen/issue-86106.rs +++ b/tests/codegen/issues/issue-86106.rs diff --git a/tests/codegen/issue-96274.rs b/tests/codegen/issues/issue-96274.rs index 28bfcce0d7b..28bfcce0d7b 100644 --- a/tests/codegen/issue-96274.rs +++ b/tests/codegen/issues/issue-96274.rs diff --git a/tests/codegen/issue-96497-slice-size-nowrap.rs b/tests/codegen/issues/issue-96497-slice-size-nowrap.rs index 0413ed6b26f..0413ed6b26f 100644 --- a/tests/codegen/issue-96497-slice-size-nowrap.rs +++ b/tests/codegen/issues/issue-96497-slice-size-nowrap.rs diff --git a/tests/codegen/issue-98156-const-arg-temp-lifetime.rs b/tests/codegen/issues/issue-98156-const-arg-temp-lifetime.rs index 12ace5fff6b..12ace5fff6b 100644 --- a/tests/codegen/issue-98156-const-arg-temp-lifetime.rs +++ b/tests/codegen/issues/issue-98156-const-arg-temp-lifetime.rs diff --git a/tests/codegen/issue-98294-get-mut-copy-from-slice-opt.rs b/tests/codegen/issues/issue-98294-get-mut-copy-from-slice-opt.rs index 7da29cd7952..7da29cd7952 100644 --- a/tests/codegen/issue-98294-get-mut-copy-from-slice-opt.rs +++ b/tests/codegen/issues/issue-98294-get-mut-copy-from-slice-opt.rs diff --git a/tests/codegen/transmute-scalar.rs b/tests/codegen/transmute-scalar.rs index 260dcbac0fc..4d7a80bfbe5 100644 --- a/tests/codegen/transmute-scalar.rs +++ b/tests/codegen/transmute-scalar.rs @@ -1,13 +1,19 @@ // compile-flags: -O -C no-prepopulate-passes +// min-llvm-version: 15.0 # this test assumes `ptr`s and thus no `pointercast`s #![crate_type = "lib"] -// FIXME(eddyb) all of these tests show memory stores and loads, even after a -// scalar `bitcast`, more special-casing is required to remove `alloca` usage. +// With opaque ptrs in LLVM, `transmute` can load/store any `alloca` as any type, +// without needing to pointercast, and SRoA will turn that into a `bitcast`. +// As such, there's no longer special-casing in `transmute` to attempt to +// generate `bitcast` ourselves, as that just made the IR longer. + +// FIXME: That said, `bitcast`s could still be a valuable addition if they could +// be done in `rvalue_creates_operand`, and thus avoid the `alloca`s entirely. // CHECK-LABEL: define{{.*}}i32 @f32_to_bits(float noundef %x) -// CHECK: store i32 %{{.*}}, {{.*}} %0 -// CHECK-NEXT: %[[RES:.*]] = load i32, {{.*}} %0 +// CHECK: store float %{{.*}}, ptr %0 +// CHECK-NEXT: %[[RES:.*]] = load i32, ptr %0 // CHECK: ret i32 %[[RES]] #[no_mangle] pub fn f32_to_bits(x: f32) -> u32 { @@ -25,12 +31,10 @@ pub fn bool_to_byte(b: bool) -> u8 { } // CHECK-LABEL: define{{.*}}noundef zeroext i1 @byte_to_bool(i8 noundef %byte) -// CHECK: %1 = trunc i8 %byte to i1 -// CHECK-NEXT: %2 = zext i1 %1 to i8 -// CHECK-NEXT: store i8 %2, {{.*}} %0 -// CHECK-NEXT: %3 = load i8, {{.*}} %0 -// CHECK-NEXT: %4 = trunc i8 %3 to i1 -// CHECK: ret i1 %4 +// CHECK: store i8 %byte, ptr %0 +// CHECK-NEXT: %1 = load i8, {{.*}} %0 +// CHECK-NEXT: %2 = trunc i8 %1 to i1 +// CHECK: ret i1 %2 #[no_mangle] pub unsafe fn byte_to_bool(byte: u8) -> bool { std::mem::transmute(byte) @@ -45,20 +49,8 @@ pub fn ptr_to_ptr(p: *mut u16) -> *mut u8 { unsafe { std::mem::transmute(p) } } -// HACK(eddyb) scalar `transmute`s between pointers and non-pointers are -// currently not special-cased like other scalar `transmute`s, because -// LLVM requires specifically `ptrtoint`/`inttoptr` instead of `bitcast`. -// -// Tests below show the non-special-cased behavior (with the possible -// future special-cased instructions in the "NOTE(eddyb)" comments). - // CHECK: define{{.*}}[[USIZE:i[0-9]+]] @ptr_to_int({{i16\*|ptr}} noundef %p) - -// NOTE(eddyb) see above, the following two CHECK lines should ideally be this: -// %2 = ptrtoint i16* %p to [[USIZE]] -// store [[USIZE]] %2, [[USIZE]]* %0 // CHECK: store {{i16\*|ptr}} %p, {{.*}} - // CHECK-NEXT: %[[RES:.*]] = load [[USIZE]], {{.*}} %0 // CHECK: ret [[USIZE]] %[[RES]] #[no_mangle] @@ -67,12 +59,7 @@ pub fn ptr_to_int(p: *mut u16) -> usize { } // CHECK: define{{.*}}{{i16\*|ptr}} @int_to_ptr([[USIZE]] noundef %i) - -// NOTE(eddyb) see above, the following two CHECK lines should ideally be this: -// %2 = inttoptr [[USIZE]] %i to i16* -// store i16* %2, i16** %0 // CHECK: store [[USIZE]] %i, {{.*}} - // CHECK-NEXT: %[[RES:.*]] = load {{i16\*|ptr}}, {{.*}} %0 // CHECK: ret {{i16\*|ptr}} %[[RES]] #[no_mangle] diff --git a/tests/codegen/vec-shrink-panik.rs b/tests/codegen/vec-shrink-panik.rs index aa6589dc35b..b3c3483fea9 100644 --- a/tests/codegen/vec-shrink-panik.rs +++ b/tests/codegen/vec-shrink-panik.rs @@ -1,3 +1,8 @@ +// revisions: old new +// LLVM 17 realizes double panic is not possible and doesn't generate calls +// to panic_cannot_unwind. +// [old]ignore-llvm-version: 17 - 99 +// [new]min-llvm-version: 17 // compile-flags: -O // ignore-debug: the debug assertions get in the way #![crate_type = "lib"] @@ -18,11 +23,11 @@ pub fn shrink_to_fit(vec: &mut Vec<u32>) { pub fn issue71861(vec: Vec<u32>) -> Box<[u32]> { // CHECK-NOT: panic - // Call to panic_cannot_unwind in case of double-panic is expected, - // but other panics are not. + // Call to panic_cannot_unwind in case of double-panic is expected + // on LLVM 16 and older, but other panics are not. // CHECK: cleanup - // CHECK-NEXT: ; call core::panicking::panic_cannot_unwind - // CHECK-NEXT: panic_cannot_unwind + // old-NEXT: ; call core::panicking::panic_cannot_unwind + // old-NEXT: panic_cannot_unwind // CHECK-NOT: panic vec.into_boxed_slice() @@ -34,14 +39,14 @@ pub fn issue75636<'a>(iter: &[&'a str]) -> Box<[&'a str]> { // CHECK-NOT: panic // Call to panic_cannot_unwind in case of double-panic is expected, - // but other panics are not. + // on LLVM 16 and older, but other panics are not. // CHECK: cleanup - // CHECK-NEXT: ; call core::panicking::panic_cannot_unwind - // CHECK-NEXT: panic_cannot_unwind + // old-NEXT: ; call core::panicking::panic_cannot_unwind + // old-NEXT: panic_cannot_unwind // CHECK-NOT: panic iter.iter().copied().collect() } -// CHECK: ; core::panicking::panic_cannot_unwind -// CHECK: declare void @{{.*}}panic_cannot_unwind +// old: ; core::panicking::panic_cannot_unwind +// old: declare void @{{.*}}panic_cannot_unwind diff --git a/tests/mir-opt/building/custom/composite_return.rs b/tests/mir-opt/building/custom/composite_return.rs new file mode 100644 index 00000000000..701d6b1ab71 --- /dev/null +++ b/tests/mir-opt/building/custom/composite_return.rs @@ -0,0 +1,21 @@ +#![feature(custom_mir, core_intrinsics)] + +extern crate core; +use core::intrinsics::mir::*; + +// EMIT_MIR composite_return.tuple.built.after.mir +#[custom_mir(dialect = "runtime", phase = "optimized")] +fn tuple() -> (i32, bool) { + mir!( + type RET = (i32, bool); + { + RET.0 = 1; + RET.1 = true; + Return() + } + ) +} + +fn main() { + assert_eq!(tuple(), (1, true)); +} diff --git a/tests/mir-opt/building/custom/composite_return.tuple.built.after.mir b/tests/mir-opt/building/custom/composite_return.tuple.built.after.mir new file mode 100644 index 00000000000..d159c1a655e --- /dev/null +++ b/tests/mir-opt/building/custom/composite_return.tuple.built.after.mir @@ -0,0 +1,11 @@ +// MIR for `tuple` after built + +fn tuple() -> (i32, bool) { + let mut _0: (i32, bool); // return place in scope 0 at $DIR/composite_return.rs:+0:15: +0:26 + + bb0: { + (_0.0: i32) = const 1_i32; // scope 0 at $DIR/composite_return.rs:+4:13: +4:22 + (_0.1: bool) = const true; // scope 0 at $DIR/composite_return.rs:+5:13: +5:25 + return; // scope 0 at $DIR/composite_return.rs:+6:13: +6:21 + } +} diff --git a/tests/mir-opt/building/shifts.rs b/tests/mir-opt/building/shifts.rs new file mode 100644 index 00000000000..4b63a00a304 --- /dev/null +++ b/tests/mir-opt/building/shifts.rs @@ -0,0 +1,20 @@ +// compile-flags: -C debug-assertions=yes + +// EMIT_MIR shifts.shift_signed.built.after.mir +fn shift_signed(small: i8, big: u128, a: i8, b: i32, c: i128) -> ([i8; 3], [u128; 3]) { + ( + [small >> a, small >> b, small >> c], + [big << a, big << b, big << c], + ) +} + +// EMIT_MIR shifts.shift_unsigned.built.after.mir +fn shift_unsigned(small: u8, big: i128, a: u8, b: u32, c: u128) -> ([u8; 3], [i128; 3]) { + ( + [small >> a, small >> b, small >> c], + [big << a, big << b, big << c], + ) +} + +fn main() { +} diff --git a/tests/mir-opt/building/shifts.shift_signed.built.after.mir b/tests/mir-opt/building/shifts.shift_signed.built.after.mir new file mode 100644 index 00000000000..028777cefdd --- /dev/null +++ b/tests/mir-opt/building/shifts.shift_signed.built.after.mir @@ -0,0 +1,147 @@ +// MIR for `shift_signed` after built + +fn shift_signed(_1: i8, _2: u128, _3: i8, _4: i32, _5: i128) -> ([i8; 3], [u128; 3]) { + debug small => _1; // in scope 0 at $DIR/shifts.rs:+0:17: +0:22 + debug big => _2; // in scope 0 at $DIR/shifts.rs:+0:28: +0:31 + debug a => _3; // in scope 0 at $DIR/shifts.rs:+0:39: +0:40 + debug b => _4; // in scope 0 at $DIR/shifts.rs:+0:46: +0:47 + debug c => _5; // in scope 0 at $DIR/shifts.rs:+0:54: +0:55 + let mut _0: ([i8; 3], [u128; 3]); // return place in scope 0 at $DIR/shifts.rs:+0:66: +0:86 + let mut _6: [i8; 3]; // in scope 0 at $DIR/shifts.rs:+2:9: +2:45 + let mut _7: i8; // in scope 0 at $DIR/shifts.rs:+2:10: +2:20 + let mut _8: i8; // in scope 0 at $DIR/shifts.rs:+2:10: +2:15 + let mut _9: i8; // in scope 0 at $DIR/shifts.rs:+2:19: +2:20 + let mut _10: u8; // in scope 0 at $DIR/shifts.rs:+2:10: +2:20 + let mut _11: bool; // in scope 0 at $DIR/shifts.rs:+2:10: +2:20 + let mut _12: i8; // in scope 0 at $DIR/shifts.rs:+2:22: +2:32 + let mut _13: i8; // in scope 0 at $DIR/shifts.rs:+2:22: +2:27 + let mut _14: i32; // in scope 0 at $DIR/shifts.rs:+2:31: +2:32 + let mut _15: u32; // in scope 0 at $DIR/shifts.rs:+2:22: +2:32 + let mut _16: bool; // in scope 0 at $DIR/shifts.rs:+2:22: +2:32 + let mut _17: i8; // in scope 0 at $DIR/shifts.rs:+2:34: +2:44 + let mut _18: i8; // in scope 0 at $DIR/shifts.rs:+2:34: +2:39 + let mut _19: i128; // in scope 0 at $DIR/shifts.rs:+2:43: +2:44 + let mut _20: u128; // in scope 0 at $DIR/shifts.rs:+2:34: +2:44 + let mut _21: bool; // in scope 0 at $DIR/shifts.rs:+2:34: +2:44 + let mut _22: [u128; 3]; // in scope 0 at $DIR/shifts.rs:+3:9: +3:39 + let mut _23: u128; // in scope 0 at $DIR/shifts.rs:+3:10: +3:18 + let mut _24: u128; // in scope 0 at $DIR/shifts.rs:+3:10: +3:13 + let mut _25: i8; // in scope 0 at $DIR/shifts.rs:+3:17: +3:18 + let mut _26: u8; // in scope 0 at $DIR/shifts.rs:+3:10: +3:18 + let mut _27: bool; // in scope 0 at $DIR/shifts.rs:+3:10: +3:18 + let mut _28: u128; // in scope 0 at $DIR/shifts.rs:+3:20: +3:28 + let mut _29: u128; // in scope 0 at $DIR/shifts.rs:+3:20: +3:23 + let mut _30: i32; // in scope 0 at $DIR/shifts.rs:+3:27: +3:28 + let mut _31: u32; // in scope 0 at $DIR/shifts.rs:+3:20: +3:28 + let mut _32: bool; // in scope 0 at $DIR/shifts.rs:+3:20: +3:28 + let mut _33: u128; // in scope 0 at $DIR/shifts.rs:+3:30: +3:38 + let mut _34: u128; // in scope 0 at $DIR/shifts.rs:+3:30: +3:33 + let mut _35: i128; // in scope 0 at $DIR/shifts.rs:+3:37: +3:38 + let mut _36: u128; // in scope 0 at $DIR/shifts.rs:+3:30: +3:38 + let mut _37: bool; // in scope 0 at $DIR/shifts.rs:+3:30: +3:38 + + bb0: { + StorageLive(_6); // scope 0 at $DIR/shifts.rs:+2:9: +2:45 + StorageLive(_7); // scope 0 at $DIR/shifts.rs:+2:10: +2:20 + StorageLive(_8); // scope 0 at $DIR/shifts.rs:+2:10: +2:15 + _8 = _1; // scope 0 at $DIR/shifts.rs:+2:10: +2:15 + StorageLive(_9); // scope 0 at $DIR/shifts.rs:+2:19: +2:20 + _9 = _3; // scope 0 at $DIR/shifts.rs:+2:19: +2:20 + _10 = _9 as u8 (IntToInt); // scope 0 at $DIR/shifts.rs:+2:10: +2:20 + _11 = Lt(move _10, const 8_u8); // scope 0 at $DIR/shifts.rs:+2:10: +2:20 + assert(move _11, "attempt to shift right by `{}`, which would overflow", _9) -> [success: bb1, unwind: bb7]; // scope 0 at $DIR/shifts.rs:+2:10: +2:20 + } + + bb1: { + _7 = Shr(move _8, move _9); // scope 0 at $DIR/shifts.rs:+2:10: +2:20 + StorageDead(_9); // scope 0 at $DIR/shifts.rs:+2:19: +2:20 + StorageDead(_8); // scope 0 at $DIR/shifts.rs:+2:19: +2:20 + StorageLive(_12); // scope 0 at $DIR/shifts.rs:+2:22: +2:32 + StorageLive(_13); // scope 0 at $DIR/shifts.rs:+2:22: +2:27 + _13 = _1; // scope 0 at $DIR/shifts.rs:+2:22: +2:27 + StorageLive(_14); // scope 0 at $DIR/shifts.rs:+2:31: +2:32 + _14 = _4; // scope 0 at $DIR/shifts.rs:+2:31: +2:32 + _15 = _14 as u32 (IntToInt); // scope 0 at $DIR/shifts.rs:+2:22: +2:32 + _16 = Lt(move _15, const 8_u32); // scope 0 at $DIR/shifts.rs:+2:22: +2:32 + assert(move _16, "attempt to shift right by `{}`, which would overflow", _14) -> [success: bb2, unwind: bb7]; // scope 0 at $DIR/shifts.rs:+2:22: +2:32 + } + + bb2: { + _12 = Shr(move _13, move _14); // scope 0 at $DIR/shifts.rs:+2:22: +2:32 + StorageDead(_14); // scope 0 at $DIR/shifts.rs:+2:31: +2:32 + StorageDead(_13); // scope 0 at $DIR/shifts.rs:+2:31: +2:32 + StorageLive(_17); // scope 0 at $DIR/shifts.rs:+2:34: +2:44 + StorageLive(_18); // scope 0 at $DIR/shifts.rs:+2:34: +2:39 + _18 = _1; // scope 0 at $DIR/shifts.rs:+2:34: +2:39 + StorageLive(_19); // scope 0 at $DIR/shifts.rs:+2:43: +2:44 + _19 = _5; // scope 0 at $DIR/shifts.rs:+2:43: +2:44 + _20 = _19 as u128 (IntToInt); // scope 0 at $DIR/shifts.rs:+2:34: +2:44 + _21 = Lt(move _20, const 8_u128); // scope 0 at $DIR/shifts.rs:+2:34: +2:44 + assert(move _21, "attempt to shift right by `{}`, which would overflow", _19) -> [success: bb3, unwind: bb7]; // scope 0 at $DIR/shifts.rs:+2:34: +2:44 + } + + bb3: { + _17 = Shr(move _18, move _19); // scope 0 at $DIR/shifts.rs:+2:34: +2:44 + StorageDead(_19); // scope 0 at $DIR/shifts.rs:+2:43: +2:44 + StorageDead(_18); // scope 0 at $DIR/shifts.rs:+2:43: +2:44 + _6 = [move _7, move _12, move _17]; // scope 0 at $DIR/shifts.rs:+2:9: +2:45 + StorageDead(_17); // scope 0 at $DIR/shifts.rs:+2:44: +2:45 + StorageDead(_12); // scope 0 at $DIR/shifts.rs:+2:44: +2:45 + StorageDead(_7); // scope 0 at $DIR/shifts.rs:+2:44: +2:45 + StorageLive(_22); // scope 0 at $DIR/shifts.rs:+3:9: +3:39 + StorageLive(_23); // scope 0 at $DIR/shifts.rs:+3:10: +3:18 + StorageLive(_24); // scope 0 at $DIR/shifts.rs:+3:10: +3:13 + _24 = _2; // scope 0 at $DIR/shifts.rs:+3:10: +3:13 + StorageLive(_25); // scope 0 at $DIR/shifts.rs:+3:17: +3:18 + _25 = _3; // scope 0 at $DIR/shifts.rs:+3:17: +3:18 + _26 = _25 as u8 (IntToInt); // scope 0 at $DIR/shifts.rs:+3:10: +3:18 + _27 = Lt(move _26, const 128_u8); // scope 0 at $DIR/shifts.rs:+3:10: +3:18 + assert(move _27, "attempt to shift left by `{}`, which would overflow", _25) -> [success: bb4, unwind: bb7]; // scope 0 at $DIR/shifts.rs:+3:10: +3:18 + } + + bb4: { + _23 = Shl(move _24, move _25); // scope 0 at $DIR/shifts.rs:+3:10: +3:18 + StorageDead(_25); // scope 0 at $DIR/shifts.rs:+3:17: +3:18 + StorageDead(_24); // scope 0 at $DIR/shifts.rs:+3:17: +3:18 + StorageLive(_28); // scope 0 at $DIR/shifts.rs:+3:20: +3:28 + StorageLive(_29); // scope 0 at $DIR/shifts.rs:+3:20: +3:23 + _29 = _2; // scope 0 at $DIR/shifts.rs:+3:20: +3:23 + StorageLive(_30); // scope 0 at $DIR/shifts.rs:+3:27: +3:28 + _30 = _4; // scope 0 at $DIR/shifts.rs:+3:27: +3:28 + _31 = _30 as u32 (IntToInt); // scope 0 at $DIR/shifts.rs:+3:20: +3:28 + _32 = Lt(move _31, const 128_u32); // scope 0 at $DIR/shifts.rs:+3:20: +3:28 + assert(move _32, "attempt to shift left by `{}`, which would overflow", _30) -> [success: bb5, unwind: bb7]; // scope 0 at $DIR/shifts.rs:+3:20: +3:28 + } + + bb5: { + _28 = Shl(move _29, move _30); // scope 0 at $DIR/shifts.rs:+3:20: +3:28 + StorageDead(_30); // scope 0 at $DIR/shifts.rs:+3:27: +3:28 + StorageDead(_29); // scope 0 at $DIR/shifts.rs:+3:27: +3:28 + StorageLive(_33); // scope 0 at $DIR/shifts.rs:+3:30: +3:38 + StorageLive(_34); // scope 0 at $DIR/shifts.rs:+3:30: +3:33 + _34 = _2; // scope 0 at $DIR/shifts.rs:+3:30: +3:33 + StorageLive(_35); // scope 0 at $DIR/shifts.rs:+3:37: +3:38 + _35 = _5; // scope 0 at $DIR/shifts.rs:+3:37: +3:38 + _36 = _35 as u128 (IntToInt); // scope 0 at $DIR/shifts.rs:+3:30: +3:38 + _37 = Lt(move _36, const 128_u128); // scope 0 at $DIR/shifts.rs:+3:30: +3:38 + assert(move _37, "attempt to shift left by `{}`, which would overflow", _35) -> [success: bb6, unwind: bb7]; // scope 0 at $DIR/shifts.rs:+3:30: +3:38 + } + + bb6: { + _33 = Shl(move _34, move _35); // scope 0 at $DIR/shifts.rs:+3:30: +3:38 + StorageDead(_35); // scope 0 at $DIR/shifts.rs:+3:37: +3:38 + StorageDead(_34); // scope 0 at $DIR/shifts.rs:+3:37: +3:38 + _22 = [move _23, move _28, move _33]; // scope 0 at $DIR/shifts.rs:+3:9: +3:39 + StorageDead(_33); // scope 0 at $DIR/shifts.rs:+3:38: +3:39 + StorageDead(_28); // scope 0 at $DIR/shifts.rs:+3:38: +3:39 + StorageDead(_23); // scope 0 at $DIR/shifts.rs:+3:38: +3:39 + _0 = (move _6, move _22); // scope 0 at $DIR/shifts.rs:+1:5: +4:6 + StorageDead(_22); // scope 0 at $DIR/shifts.rs:+4:5: +4:6 + StorageDead(_6); // scope 0 at $DIR/shifts.rs:+4:5: +4:6 + return; // scope 0 at $DIR/shifts.rs:+5:2: +5:2 + } + + bb7 (cleanup): { + resume; // scope 0 at $DIR/shifts.rs:+0:1: +5:2 + } +} diff --git a/tests/mir-opt/building/shifts.shift_unsigned.built.after.mir b/tests/mir-opt/building/shifts.shift_unsigned.built.after.mir new file mode 100644 index 00000000000..04da2d20d24 --- /dev/null +++ b/tests/mir-opt/building/shifts.shift_unsigned.built.after.mir @@ -0,0 +1,135 @@ +// MIR for `shift_unsigned` after built + +fn shift_unsigned(_1: u8, _2: i128, _3: u8, _4: u32, _5: u128) -> ([u8; 3], [i128; 3]) { + debug small => _1; // in scope 0 at $DIR/shifts.rs:+0:19: +0:24 + debug big => _2; // in scope 0 at $DIR/shifts.rs:+0:30: +0:33 + debug a => _3; // in scope 0 at $DIR/shifts.rs:+0:41: +0:42 + debug b => _4; // in scope 0 at $DIR/shifts.rs:+0:48: +0:49 + debug c => _5; // in scope 0 at $DIR/shifts.rs:+0:56: +0:57 + let mut _0: ([u8; 3], [i128; 3]); // return place in scope 0 at $DIR/shifts.rs:+0:68: +0:88 + let mut _6: [u8; 3]; // in scope 0 at $DIR/shifts.rs:+2:9: +2:45 + let mut _7: u8; // in scope 0 at $DIR/shifts.rs:+2:10: +2:20 + let mut _8: u8; // in scope 0 at $DIR/shifts.rs:+2:10: +2:15 + let mut _9: u8; // in scope 0 at $DIR/shifts.rs:+2:19: +2:20 + let mut _10: bool; // in scope 0 at $DIR/shifts.rs:+2:10: +2:20 + let mut _11: u8; // in scope 0 at $DIR/shifts.rs:+2:22: +2:32 + let mut _12: u8; // in scope 0 at $DIR/shifts.rs:+2:22: +2:27 + let mut _13: u32; // in scope 0 at $DIR/shifts.rs:+2:31: +2:32 + let mut _14: bool; // in scope 0 at $DIR/shifts.rs:+2:22: +2:32 + let mut _15: u8; // in scope 0 at $DIR/shifts.rs:+2:34: +2:44 + let mut _16: u8; // in scope 0 at $DIR/shifts.rs:+2:34: +2:39 + let mut _17: u128; // in scope 0 at $DIR/shifts.rs:+2:43: +2:44 + let mut _18: bool; // in scope 0 at $DIR/shifts.rs:+2:34: +2:44 + let mut _19: [i128; 3]; // in scope 0 at $DIR/shifts.rs:+3:9: +3:39 + let mut _20: i128; // in scope 0 at $DIR/shifts.rs:+3:10: +3:18 + let mut _21: i128; // in scope 0 at $DIR/shifts.rs:+3:10: +3:13 + let mut _22: u8; // in scope 0 at $DIR/shifts.rs:+3:17: +3:18 + let mut _23: bool; // in scope 0 at $DIR/shifts.rs:+3:10: +3:18 + let mut _24: i128; // in scope 0 at $DIR/shifts.rs:+3:20: +3:28 + let mut _25: i128; // in scope 0 at $DIR/shifts.rs:+3:20: +3:23 + let mut _26: u32; // in scope 0 at $DIR/shifts.rs:+3:27: +3:28 + let mut _27: bool; // in scope 0 at $DIR/shifts.rs:+3:20: +3:28 + let mut _28: i128; // in scope 0 at $DIR/shifts.rs:+3:30: +3:38 + let mut _29: i128; // in scope 0 at $DIR/shifts.rs:+3:30: +3:33 + let mut _30: u128; // in scope 0 at $DIR/shifts.rs:+3:37: +3:38 + let mut _31: bool; // in scope 0 at $DIR/shifts.rs:+3:30: +3:38 + + bb0: { + StorageLive(_6); // scope 0 at $DIR/shifts.rs:+2:9: +2:45 + StorageLive(_7); // scope 0 at $DIR/shifts.rs:+2:10: +2:20 + StorageLive(_8); // scope 0 at $DIR/shifts.rs:+2:10: +2:15 + _8 = _1; // scope 0 at $DIR/shifts.rs:+2:10: +2:15 + StorageLive(_9); // scope 0 at $DIR/shifts.rs:+2:19: +2:20 + _9 = _3; // scope 0 at $DIR/shifts.rs:+2:19: +2:20 + _10 = Lt(_9, const 8_u8); // scope 0 at $DIR/shifts.rs:+2:10: +2:20 + assert(move _10, "attempt to shift right by `{}`, which would overflow", _9) -> [success: bb1, unwind: bb7]; // scope 0 at $DIR/shifts.rs:+2:10: +2:20 + } + + bb1: { + _7 = Shr(move _8, move _9); // scope 0 at $DIR/shifts.rs:+2:10: +2:20 + StorageDead(_9); // scope 0 at $DIR/shifts.rs:+2:19: +2:20 + StorageDead(_8); // scope 0 at $DIR/shifts.rs:+2:19: +2:20 + StorageLive(_11); // scope 0 at $DIR/shifts.rs:+2:22: +2:32 + StorageLive(_12); // scope 0 at $DIR/shifts.rs:+2:22: +2:27 + _12 = _1; // scope 0 at $DIR/shifts.rs:+2:22: +2:27 + StorageLive(_13); // scope 0 at $DIR/shifts.rs:+2:31: +2:32 + _13 = _4; // scope 0 at $DIR/shifts.rs:+2:31: +2:32 + _14 = Lt(_13, const 8_u32); // scope 0 at $DIR/shifts.rs:+2:22: +2:32 + assert(move _14, "attempt to shift right by `{}`, which would overflow", _13) -> [success: bb2, unwind: bb7]; // scope 0 at $DIR/shifts.rs:+2:22: +2:32 + } + + bb2: { + _11 = Shr(move _12, move _13); // scope 0 at $DIR/shifts.rs:+2:22: +2:32 + StorageDead(_13); // scope 0 at $DIR/shifts.rs:+2:31: +2:32 + StorageDead(_12); // scope 0 at $DIR/shifts.rs:+2:31: +2:32 + StorageLive(_15); // scope 0 at $DIR/shifts.rs:+2:34: +2:44 + StorageLive(_16); // scope 0 at $DIR/shifts.rs:+2:34: +2:39 + _16 = _1; // scope 0 at $DIR/shifts.rs:+2:34: +2:39 + StorageLive(_17); // scope 0 at $DIR/shifts.rs:+2:43: +2:44 + _17 = _5; // scope 0 at $DIR/shifts.rs:+2:43: +2:44 + _18 = Lt(_17, const 8_u128); // scope 0 at $DIR/shifts.rs:+2:34: +2:44 + assert(move _18, "attempt to shift right by `{}`, which would overflow", _17) -> [success: bb3, unwind: bb7]; // scope 0 at $DIR/shifts.rs:+2:34: +2:44 + } + + bb3: { + _15 = Shr(move _16, move _17); // scope 0 at $DIR/shifts.rs:+2:34: +2:44 + StorageDead(_17); // scope 0 at $DIR/shifts.rs:+2:43: +2:44 + StorageDead(_16); // scope 0 at $DIR/shifts.rs:+2:43: +2:44 + _6 = [move _7, move _11, move _15]; // scope 0 at $DIR/shifts.rs:+2:9: +2:45 + StorageDead(_15); // scope 0 at $DIR/shifts.rs:+2:44: +2:45 + StorageDead(_11); // scope 0 at $DIR/shifts.rs:+2:44: +2:45 + StorageDead(_7); // scope 0 at $DIR/shifts.rs:+2:44: +2:45 + StorageLive(_19); // scope 0 at $DIR/shifts.rs:+3:9: +3:39 + StorageLive(_20); // scope 0 at $DIR/shifts.rs:+3:10: +3:18 + StorageLive(_21); // scope 0 at $DIR/shifts.rs:+3:10: +3:13 + _21 = _2; // scope 0 at $DIR/shifts.rs:+3:10: +3:13 + StorageLive(_22); // scope 0 at $DIR/shifts.rs:+3:17: +3:18 + _22 = _3; // scope 0 at $DIR/shifts.rs:+3:17: +3:18 + _23 = Lt(_22, const 128_u8); // scope 0 at $DIR/shifts.rs:+3:10: +3:18 + assert(move _23, "attempt to shift left by `{}`, which would overflow", _22) -> [success: bb4, unwind: bb7]; // scope 0 at $DIR/shifts.rs:+3:10: +3:18 + } + + bb4: { + _20 = Shl(move _21, move _22); // scope 0 at $DIR/shifts.rs:+3:10: +3:18 + StorageDead(_22); // scope 0 at $DIR/shifts.rs:+3:17: +3:18 + StorageDead(_21); // scope 0 at $DIR/shifts.rs:+3:17: +3:18 + StorageLive(_24); // scope 0 at $DIR/shifts.rs:+3:20: +3:28 + StorageLive(_25); // scope 0 at $DIR/shifts.rs:+3:20: +3:23 + _25 = _2; // scope 0 at $DIR/shifts.rs:+3:20: +3:23 + StorageLive(_26); // scope 0 at $DIR/shifts.rs:+3:27: +3:28 + _26 = _4; // scope 0 at $DIR/shifts.rs:+3:27: +3:28 + _27 = Lt(_26, const 128_u32); // scope 0 at $DIR/shifts.rs:+3:20: +3:28 + assert(move _27, "attempt to shift left by `{}`, which would overflow", _26) -> [success: bb5, unwind: bb7]; // scope 0 at $DIR/shifts.rs:+3:20: +3:28 + } + + bb5: { + _24 = Shl(move _25, move _26); // scope 0 at $DIR/shifts.rs:+3:20: +3:28 + StorageDead(_26); // scope 0 at $DIR/shifts.rs:+3:27: +3:28 + StorageDead(_25); // scope 0 at $DIR/shifts.rs:+3:27: +3:28 + StorageLive(_28); // scope 0 at $DIR/shifts.rs:+3:30: +3:38 + StorageLive(_29); // scope 0 at $DIR/shifts.rs:+3:30: +3:33 + _29 = _2; // scope 0 at $DIR/shifts.rs:+3:30: +3:33 + StorageLive(_30); // scope 0 at $DIR/shifts.rs:+3:37: +3:38 + _30 = _5; // scope 0 at $DIR/shifts.rs:+3:37: +3:38 + _31 = Lt(_30, const 128_u128); // scope 0 at $DIR/shifts.rs:+3:30: +3:38 + assert(move _31, "attempt to shift left by `{}`, which would overflow", _30) -> [success: bb6, unwind: bb7]; // scope 0 at $DIR/shifts.rs:+3:30: +3:38 + } + + bb6: { + _28 = Shl(move _29, move _30); // scope 0 at $DIR/shifts.rs:+3:30: +3:38 + StorageDead(_30); // scope 0 at $DIR/shifts.rs:+3:37: +3:38 + StorageDead(_29); // scope 0 at $DIR/shifts.rs:+3:37: +3:38 + _19 = [move _20, move _24, move _28]; // scope 0 at $DIR/shifts.rs:+3:9: +3:39 + StorageDead(_28); // scope 0 at $DIR/shifts.rs:+3:38: +3:39 + StorageDead(_24); // scope 0 at $DIR/shifts.rs:+3:38: +3:39 + StorageDead(_20); // scope 0 at $DIR/shifts.rs:+3:38: +3:39 + _0 = (move _6, move _19); // scope 0 at $DIR/shifts.rs:+1:5: +4:6 + StorageDead(_19); // scope 0 at $DIR/shifts.rs:+4:5: +4:6 + StorageDead(_6); // scope 0 at $DIR/shifts.rs:+4:5: +4:6 + return; // scope 0 at $DIR/shifts.rs:+5:2: +5:2 + } + + bb7 (cleanup): { + resume; // scope 0 at $DIR/shifts.rs:+0:1: +5:2 + } +} diff --git a/tests/mir-opt/const_prop/transmute.from_char.ConstProp.diff b/tests/mir-opt/const_prop/transmute.from_char.ConstProp.diff new file mode 100644 index 00000000000..933dfbb5166 --- /dev/null +++ b/tests/mir-opt/const_prop/transmute.from_char.ConstProp.diff @@ -0,0 +1,15 @@ +- // MIR for `from_char` before ConstProp ++ // MIR for `from_char` after ConstProp + + fn from_char() -> i32 { + let mut _0: i32; // return place in scope 0 at $DIR/transmute.rs:+0:23: +0:26 + scope 1 { + } + + bb0: { +- _0 = const 'R' as i32 (Transmute); // scope 1 at $DIR/transmute.rs:+1:14: +1:28 ++ _0 = const 82_i32; // scope 1 at $DIR/transmute.rs:+1:14: +1:28 + return; // scope 0 at $DIR/transmute.rs:+2:2: +2:2 + } + } + diff --git a/tests/mir-opt/const_prop/transmute.invalid_bool.ConstProp.diff b/tests/mir-opt/const_prop/transmute.invalid_bool.ConstProp.diff new file mode 100644 index 00000000000..f3474855f02 --- /dev/null +++ b/tests/mir-opt/const_prop/transmute.invalid_bool.ConstProp.diff @@ -0,0 +1,14 @@ +- // MIR for `invalid_bool` before ConstProp ++ // MIR for `invalid_bool` after ConstProp + + fn invalid_bool() -> bool { + let mut _0: bool; // return place in scope 0 at $DIR/transmute.rs:+0:33: +0:37 + scope 1 { + } + + bb0: { + _0 = const -1_i8 as bool (Transmute); // scope 1 at $DIR/transmute.rs:+1:14: +1:30 + return; // scope 0 at $DIR/transmute.rs:+2:2: +2:2 + } + } + diff --git a/tests/mir-opt/const_prop/transmute.invalid_char.ConstProp.diff b/tests/mir-opt/const_prop/transmute.invalid_char.ConstProp.diff new file mode 100644 index 00000000000..ba087e226c9 --- /dev/null +++ b/tests/mir-opt/const_prop/transmute.invalid_char.ConstProp.diff @@ -0,0 +1,14 @@ +- // MIR for `invalid_char` before ConstProp ++ // MIR for `invalid_char` after ConstProp + + fn invalid_char() -> char { + let mut _0: char; // return place in scope 0 at $DIR/transmute.rs:+0:33: +0:37 + scope 1 { + } + + bb0: { + _0 = const _ as char (Transmute); // scope 1 at $DIR/transmute.rs:+1:14: +1:33 + return; // scope 0 at $DIR/transmute.rs:+2:2: +2:2 + } + } + diff --git a/tests/mir-opt/const_prop/transmute.less_as_i8.ConstProp.diff b/tests/mir-opt/const_prop/transmute.less_as_i8.ConstProp.diff new file mode 100644 index 00000000000..76d464789c1 --- /dev/null +++ b/tests/mir-opt/const_prop/transmute.less_as_i8.ConstProp.diff @@ -0,0 +1,23 @@ +- // MIR for `less_as_i8` before ConstProp ++ // MIR for `less_as_i8` after ConstProp + + fn less_as_i8() -> i8 { + let mut _0: i8; // return place in scope 0 at $DIR/transmute.rs:+0:24: +0:26 + let mut _1: std::cmp::Ordering; // in scope 0 at $DIR/transmute.rs:+1:24: +1:48 + scope 1 { + } + + bb0: { + StorageLive(_1); // scope 1 at $DIR/transmute.rs:+1:24: +1:48 +- _1 = Less; // scope 1 at $DIR/transmute.rs:+1:24: +1:48 +- _0 = move _1 as i8 (Transmute); // scope 1 at $DIR/transmute.rs:+1:14: +1:49 ++ _1 = const Less; // scope 1 at $DIR/transmute.rs:+1:24: +1:48 ++ // mir::Constant ++ // + span: no-location ++ // + literal: Const { ty: std::cmp::Ordering, val: Value(Scalar(0xff)) } ++ _0 = const -1_i8; // scope 1 at $DIR/transmute.rs:+1:14: +1:49 + StorageDead(_1); // scope 1 at $DIR/transmute.rs:+1:48: +1:49 + return; // scope 0 at $DIR/transmute.rs:+2:2: +2:2 + } + } + diff --git a/tests/mir-opt/const_prop/transmute.rs b/tests/mir-opt/const_prop/transmute.rs new file mode 100644 index 00000000000..b753cdccd60 --- /dev/null +++ b/tests/mir-opt/const_prop/transmute.rs @@ -0,0 +1,61 @@ +// unit-test: ConstProp +// compile-flags: -O --crate-type=lib + +use std::mem::transmute; + +// EMIT_MIR transmute.less_as_i8.ConstProp.diff +pub fn less_as_i8() -> i8 { + unsafe { transmute(std::cmp::Ordering::Less) } +} + +// EMIT_MIR transmute.from_char.ConstProp.diff +pub fn from_char() -> i32 { + unsafe { transmute('R') } +} + +// EMIT_MIR transmute.valid_char.ConstProp.diff +pub fn valid_char() -> char { + unsafe { transmute(0x52_u32) } +} + +// EMIT_MIR transmute.invalid_char.ConstProp.diff +pub unsafe fn invalid_char() -> char { + unsafe { transmute(i32::MAX) } +} + +// EMIT_MIR transmute.invalid_bool.ConstProp.diff +pub unsafe fn invalid_bool() -> bool { + unsafe { transmute(-1_i8) } +} + +// EMIT_MIR transmute.undef_union_as_integer.ConstProp.diff +pub unsafe fn undef_union_as_integer() -> u32 { + union Union32 { value: u32, unit: () } + unsafe { transmute(Union32 { unit: () }) } +} + +// EMIT_MIR transmute.unreachable_direct.ConstProp.diff +pub unsafe fn unreachable_direct() -> ! { + let x: Never = unsafe { transmute(()) }; + match x {} +} + +// EMIT_MIR transmute.unreachable_ref.ConstProp.diff +pub unsafe fn unreachable_ref() -> ! { + let x: &Never = unsafe { transmute(1_usize) }; + match *x {} +} + +// EMIT_MIR transmute.unreachable_mut.ConstProp.diff +pub unsafe fn unreachable_mut() -> ! { + let x: &mut Never = unsafe { transmute(1_usize) }; + match *x {} +} + +// EMIT_MIR transmute.unreachable_box.ConstProp.diff +pub unsafe fn unreachable_box() -> ! { + let x: Box<Never> = unsafe { transmute(1_usize) }; + match *x {} +} + +enum Never {} diff --git a/tests/mir-opt/const_prop/transmute.undef_union_as_integer.ConstProp.diff b/tests/mir-opt/const_prop/transmute.undef_union_as_integer.ConstProp.diff new file mode 100644 index 00000000000..538b1f26e4c --- /dev/null +++ b/tests/mir-opt/const_prop/transmute.undef_union_as_integer.ConstProp.diff @@ -0,0 +1,22 @@ +- // MIR for `undef_union_as_integer` before ConstProp ++ // MIR for `undef_union_as_integer` after ConstProp + + fn undef_union_as_integer() -> u32 { + let mut _0: u32; // return place in scope 0 at $DIR/transmute.rs:+0:43: +0:46 + let mut _1: undef_union_as_integer::Union32; // in scope 0 at $DIR/transmute.rs:+2:24: +2:44 + let mut _2: (); // in scope 0 at $DIR/transmute.rs:+2:40: +2:42 + scope 1 { + } + + bb0: { + StorageLive(_1); // scope 1 at $DIR/transmute.rs:+2:24: +2:44 + StorageLive(_2); // scope 1 at $DIR/transmute.rs:+2:40: +2:42 + _2 = (); // scope 1 at $DIR/transmute.rs:+2:40: +2:42 + _1 = Union32 { value: move _2 }; // scope 1 at $DIR/transmute.rs:+2:24: +2:44 + StorageDead(_2); // scope 1 at $DIR/transmute.rs:+2:43: +2:44 + _0 = move _1 as u32 (Transmute); // scope 1 at $DIR/transmute.rs:+2:14: +2:45 + StorageDead(_1); // scope 1 at $DIR/transmute.rs:+2:44: +2:45 + return; // scope 0 at $DIR/transmute.rs:+3:2: +3:2 + } + } + diff --git a/tests/mir-opt/const_prop/transmute.unreachable_box.ConstProp.diff b/tests/mir-opt/const_prop/transmute.unreachable_box.ConstProp.diff new file mode 100644 index 00000000000..8bf97996a67 --- /dev/null +++ b/tests/mir-opt/const_prop/transmute.unreachable_box.ConstProp.diff @@ -0,0 +1,23 @@ +- // MIR for `unreachable_box` before ConstProp ++ // MIR for `unreachable_box` after ConstProp + + fn unreachable_box() -> ! { + let mut _0: !; // return place in scope 0 at $DIR/transmute.rs:+0:36: +0:37 + let mut _1: !; // in scope 0 at $DIR/transmute.rs:+0:38: +3:2 + let _2: std::boxed::Box<Never>; // in scope 0 at $DIR/transmute.rs:+1:9: +1:10 + let mut _3: !; // in scope 0 at $DIR/transmute.rs:+2:5: +2:16 + scope 1 { + debug x => _2; // in scope 1 at $DIR/transmute.rs:+1:9: +1:10 + } + scope 2 { + } + + bb0: { + StorageLive(_1); // scope 0 at $DIR/transmute.rs:+0:38: +3:2 + StorageLive(_2); // scope 0 at $DIR/transmute.rs:+1:9: +1:10 + _2 = const 1_usize as std::boxed::Box<Never> (Transmute); // scope 2 at $DIR/transmute.rs:+1:34: +1:52 + StorageLive(_3); // scope 1 at $DIR/transmute.rs:+2:5: +2:16 + unreachable; // scope 1 at $DIR/transmute.rs:+2:11: +2:13 + } + } + diff --git a/tests/mir-opt/const_prop/transmute.unreachable_direct.ConstProp.diff b/tests/mir-opt/const_prop/transmute.unreachable_direct.ConstProp.diff new file mode 100644 index 00000000000..81b7b368993 --- /dev/null +++ b/tests/mir-opt/const_prop/transmute.unreachable_direct.ConstProp.diff @@ -0,0 +1,25 @@ +- // MIR for `unreachable_direct` before ConstProp ++ // MIR for `unreachable_direct` after ConstProp + + fn unreachable_direct() -> ! { + let mut _0: !; // return place in scope 0 at $DIR/transmute.rs:+0:39: +0:40 + let mut _1: !; // in scope 0 at $DIR/transmute.rs:+0:41: +3:2 + let _2: Never; // in scope 0 at $DIR/transmute.rs:+1:9: +1:10 + let mut _3: (); // in scope 0 at $DIR/transmute.rs:+1:39: +1:41 + let mut _4: !; // in scope 0 at $DIR/transmute.rs:+2:5: +2:15 + scope 1 { + debug x => _2; // in scope 1 at $DIR/transmute.rs:+1:9: +1:10 + } + scope 2 { + } + + bb0: { + StorageLive(_1); // scope 0 at $DIR/transmute.rs:+0:41: +3:2 + StorageLive(_2); // scope 0 at $DIR/transmute.rs:+1:9: +1:10 + StorageLive(_3); // scope 2 at $DIR/transmute.rs:+1:39: +1:41 + _3 = (); // scope 2 at $DIR/transmute.rs:+1:39: +1:41 + _2 = move _3 as Never (Transmute); // scope 2 at $DIR/transmute.rs:+1:29: +1:42 + unreachable; // scope 2 at $DIR/transmute.rs:+1:29: +1:42 + } + } + diff --git a/tests/mir-opt/const_prop/transmute.unreachable_mut.ConstProp.diff b/tests/mir-opt/const_prop/transmute.unreachable_mut.ConstProp.diff new file mode 100644 index 00000000000..34f7aea8ed2 --- /dev/null +++ b/tests/mir-opt/const_prop/transmute.unreachable_mut.ConstProp.diff @@ -0,0 +1,27 @@ +- // MIR for `unreachable_mut` before ConstProp ++ // MIR for `unreachable_mut` after ConstProp + + fn unreachable_mut() -> ! { + let mut _0: !; // return place in scope 0 at $DIR/transmute.rs:+0:36: +0:37 + let mut _1: !; // in scope 0 at $DIR/transmute.rs:+0:38: +3:2 + let _2: &mut Never; // in scope 0 at $DIR/transmute.rs:+1:9: +1:10 + let mut _3: &mut Never; // in scope 0 at $DIR/transmute.rs:+1:34: +1:52 + let mut _4: !; // in scope 0 at $DIR/transmute.rs:+2:5: +2:16 + scope 1 { + debug x => _2; // in scope 1 at $DIR/transmute.rs:+1:9: +1:10 + } + scope 2 { + } + + bb0: { + StorageLive(_1); // scope 0 at $DIR/transmute.rs:+0:38: +3:2 + StorageLive(_2); // scope 0 at $DIR/transmute.rs:+1:9: +1:10 + StorageLive(_3); // scope 0 at $DIR/transmute.rs:+1:34: +1:52 + _3 = const 1_usize as &mut Never (Transmute); // scope 2 at $DIR/transmute.rs:+1:34: +1:52 + _2 = &mut (*_3); // scope 0 at $DIR/transmute.rs:+1:34: +1:52 + StorageDead(_3); // scope 0 at $DIR/transmute.rs:+1:54: +1:55 + StorageLive(_4); // scope 1 at $DIR/transmute.rs:+2:5: +2:16 + unreachable; // scope 1 at $DIR/transmute.rs:+2:11: +2:13 + } + } + diff --git a/tests/mir-opt/const_prop/transmute.unreachable_ref.ConstProp.diff b/tests/mir-opt/const_prop/transmute.unreachable_ref.ConstProp.diff new file mode 100644 index 00000000000..ff95f2a0b94 --- /dev/null +++ b/tests/mir-opt/const_prop/transmute.unreachable_ref.ConstProp.diff @@ -0,0 +1,23 @@ +- // MIR for `unreachable_ref` before ConstProp ++ // MIR for `unreachable_ref` after ConstProp + + fn unreachable_ref() -> ! { + let mut _0: !; // return place in scope 0 at $DIR/transmute.rs:+0:36: +0:37 + let mut _1: !; // in scope 0 at $DIR/transmute.rs:+0:38: +3:2 + let _2: &Never; // in scope 0 at $DIR/transmute.rs:+1:9: +1:10 + let mut _3: !; // in scope 0 at $DIR/transmute.rs:+2:5: +2:16 + scope 1 { + debug x => _2; // in scope 1 at $DIR/transmute.rs:+1:9: +1:10 + } + scope 2 { + } + + bb0: { + StorageLive(_1); // scope 0 at $DIR/transmute.rs:+0:38: +3:2 + StorageLive(_2); // scope 0 at $DIR/transmute.rs:+1:9: +1:10 + _2 = const 1_usize as &Never (Transmute); // scope 2 at $DIR/transmute.rs:+1:30: +1:48 + StorageLive(_3); // scope 1 at $DIR/transmute.rs:+2:5: +2:16 + unreachable; // scope 1 at $DIR/transmute.rs:+2:11: +2:13 + } + } + diff --git a/tests/mir-opt/const_prop/transmute.valid_char.ConstProp.diff b/tests/mir-opt/const_prop/transmute.valid_char.ConstProp.diff new file mode 100644 index 00000000000..eac33b73003 --- /dev/null +++ b/tests/mir-opt/const_prop/transmute.valid_char.ConstProp.diff @@ -0,0 +1,15 @@ +- // MIR for `valid_char` before ConstProp ++ // MIR for `valid_char` after ConstProp + + fn valid_char() -> char { + let mut _0: char; // return place in scope 0 at $DIR/transmute.rs:+0:24: +0:28 + scope 1 { + } + + bb0: { +- _0 = const 82_u32 as char (Transmute); // scope 1 at $DIR/transmute.rs:+1:14: +1:33 ++ _0 = const 'R'; // scope 1 at $DIR/transmute.rs:+1:14: +1:33 + return; // scope 0 at $DIR/transmute.rs:+2:2: +2:2 + } + } + diff --git a/tests/mir-opt/issue_101973.inner.ConstProp.diff b/tests/mir-opt/issue_101973.inner.ConstProp.diff index fb0b3866e69..b377a65b964 100644 --- a/tests/mir-opt/issue_101973.inner.ConstProp.diff +++ b/tests/mir-opt/issue_101973.inner.ConstProp.diff @@ -12,9 +12,9 @@ let mut _7: u32; // in scope 0 at $DIR/issue_101973.rs:+1:31: +1:52 let mut _8: u32; // in scope 0 at $DIR/issue_101973.rs:+1:32: +1:45 let mut _9: u32; // in scope 0 at $DIR/issue_101973.rs:+1:33: +1:39 - let mut _10: i32; // in scope 0 at $DIR/issue_101973.rs:+1:32: +1:45 + let mut _10: u32; // in scope 0 at $DIR/issue_101973.rs:+1:32: +1:45 let mut _11: bool; // in scope 0 at $DIR/issue_101973.rs:+1:32: +1:45 - let mut _12: i32; // in scope 0 at $DIR/issue_101973.rs:+1:31: +1:57 + let mut _12: u32; // in scope 0 at $DIR/issue_101973.rs:+1:31: +1:57 let mut _13: bool; // in scope 0 at $DIR/issue_101973.rs:+1:31: +1:57 scope 1 (inlined imm8) { // at $DIR/issue_101973.rs:14:5: 14:17 debug x => _1; // in scope 1 at $DIR/issue_101973.rs:5:13: 5:14 @@ -43,24 +43,24 @@ StorageLive(_6); // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57 StorageLive(_7); // scope 0 at $DIR/issue_101973.rs:+1:31: +1:52 StorageLive(_8); // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45 -- _10 = BitAnd(const 8_i32, const -32_i32); // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45 -- _11 = Ne(move _10, const 0_i32); // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45 -- assert(!move _11, "attempt to shift right by `{}`, which would overflow", const 8_i32) -> bb1; // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45 -+ _10 = const 0_i32; // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45 -+ _11 = const false; // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45 -+ assert(!const false, "attempt to shift right by `{}`, which would overflow", const 8_i32) -> bb1; // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45 +- _10 = const 8_i32 as u32 (IntToInt); // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45 +- _11 = Lt(move _10, const 32_u32); // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45 +- assert(move _11, "attempt to shift right by `{}`, which would overflow", const 8_i32) -> bb1; // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45 ++ _10 = const 8_u32; // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45 ++ _11 = const true; // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45 ++ assert(const true, "attempt to shift right by `{}`, which would overflow", const 8_i32) -> bb1; // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45 } bb1: { _8 = Shr(_1, const 8_i32); // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45 _7 = BitAnd(move _8, const 15_u32); // scope 0 at $DIR/issue_101973.rs:+1:31: +1:52 StorageDead(_8); // scope 0 at $DIR/issue_101973.rs:+1:51: +1:52 -- _12 = BitAnd(const 1_i32, const -32_i32); // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57 -- _13 = Ne(move _12, const 0_i32); // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57 -- assert(!move _13, "attempt to shift left by `{}`, which would overflow", const 1_i32) -> bb2; // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57 -+ _12 = const 0_i32; // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57 -+ _13 = const false; // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57 -+ assert(!const false, "attempt to shift left by `{}`, which would overflow", const 1_i32) -> bb2; // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57 +- _12 = const 1_i32 as u32 (IntToInt); // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57 +- _13 = Lt(move _12, const 32_u32); // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57 +- assert(move _13, "attempt to shift left by `{}`, which would overflow", const 1_i32) -> bb2; // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57 ++ _12 = const 1_u32; // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57 ++ _13 = const true; // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57 ++ assert(const true, "attempt to shift left by `{}`, which would overflow", const 1_i32) -> bb2; // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57 } bb2: { diff --git a/tests/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff b/tests/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff index bcda1288045..8e6e6fc0ec2 100644 --- a/tests/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff +++ b/tests/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff @@ -24,61 +24,49 @@ StorageLive(_2); // scope 0 at $DIR/issue_75439.rs:+2:9: +2:15 StorageLive(_3); // scope 2 at $DIR/issue_75439.rs:+2:47: +2:52 _3 = _1; // scope 2 at $DIR/issue_75439.rs:+2:47: +2:52 - _2 = transmute::<[u8; 16], [u32; 4]>(move _3) -> bb1; // scope 2 at $DIR/issue_75439.rs:+2:37: +2:53 - // mir::Constant - // + span: $DIR/issue_75439.rs:8:37: 8:46 - // + literal: Const { ty: unsafe extern "rust-intrinsic" fn([u8; 16]) -> [u32; 4] {transmute::<[u8; 16], [u32; 4]>}, val: Value(<ZST>) } + _2 = move _3 as [u32; 4] (Transmute); // scope 2 at $DIR/issue_75439.rs:+2:37: +2:53 + StorageDead(_3); // scope 2 at $DIR/issue_75439.rs:+2:52: +2:53 + switchInt(_2[0 of 4]) -> [0: bb1, otherwise: bb6]; // scope 3 at $DIR/issue_75439.rs:+4:12: +4:30 } bb1: { - StorageDead(_3); // scope 2 at $DIR/issue_75439.rs:+2:52: +2:53 - switchInt(_2[0 of 4]) -> [0: bb2, otherwise: bb8]; // scope 3 at $DIR/issue_75439.rs:+4:12: +4:30 + switchInt(_2[1 of 4]) -> [0: bb2, otherwise: bb6]; // scope 3 at $DIR/issue_75439.rs:+4:12: +4:30 } bb2: { - switchInt(_2[1 of 4]) -> [0: bb3, otherwise: bb8]; // scope 3 at $DIR/issue_75439.rs:+4:12: +4:30 + switchInt(_2[2 of 4]) -> [0: bb4, 4294901760: bb5, otherwise: bb6]; // scope 3 at $DIR/issue_75439.rs:+4:12: +4:30 } bb3: { - switchInt(_2[2 of 4]) -> [0: bb5, 4294901760: bb6, otherwise: bb8]; // scope 3 at $DIR/issue_75439.rs:+4:12: +4:30 - } - - bb4: { StorageLive(_5); // scope 3 at $DIR/issue_75439.rs:+5:14: +5:38 StorageLive(_6); // scope 4 at $DIR/issue_75439.rs:+5:33: +5:35 _6 = _4; // scope 4 at $DIR/issue_75439.rs:+5:33: +5:35 - _5 = transmute::<u32, [u8; 4]>(move _6) -> bb7; // scope 4 at $DIR/issue_75439.rs:+5:23: +5:36 - // mir::Constant - // + span: $DIR/issue_75439.rs:11:23: 11:32 - // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(u32) -> [u8; 4] {transmute::<u32, [u8; 4]>}, val: Value(<ZST>) } + _5 = move _6 as [u8; 4] (Transmute); // scope 4 at $DIR/issue_75439.rs:+5:23: +5:36 + StorageDead(_6); // scope 4 at $DIR/issue_75439.rs:+5:35: +5:36 + _0 = Option::<[u8; 4]>::Some(move _5); // scope 3 at $DIR/issue_75439.rs:+5:9: +5:39 + StorageDead(_5); // scope 3 at $DIR/issue_75439.rs:+5:38: +5:39 + StorageDead(_4); // scope 1 at $DIR/issue_75439.rs:+6:5: +6:6 + goto -> bb7; // scope 1 at $DIR/issue_75439.rs:+4:5: +8:6 } - bb5: { + bb4: { StorageLive(_4); // scope 3 at $DIR/issue_75439.rs:+4:27: +4:29 _4 = _2[3 of 4]; // scope 3 at $DIR/issue_75439.rs:+4:27: +4:29 - goto -> bb4; // scope 3 at $DIR/issue_75439.rs:+4:12: +4:30 + goto -> bb3; // scope 3 at $DIR/issue_75439.rs:+4:12: +4:30 } - bb6: { + bb5: { StorageLive(_4); // scope 3 at $DIR/issue_75439.rs:+4:27: +4:29 _4 = _2[3 of 4]; // scope 3 at $DIR/issue_75439.rs:+4:27: +4:29 - goto -> bb4; // scope 3 at $DIR/issue_75439.rs:+4:12: +4:30 + goto -> bb3; // scope 3 at $DIR/issue_75439.rs:+4:12: +4:30 } - bb7: { - StorageDead(_6); // scope 4 at $DIR/issue_75439.rs:+5:35: +5:36 - _0 = Option::<[u8; 4]>::Some(move _5); // scope 3 at $DIR/issue_75439.rs:+5:9: +5:39 - StorageDead(_5); // scope 3 at $DIR/issue_75439.rs:+5:38: +5:39 - StorageDead(_4); // scope 1 at $DIR/issue_75439.rs:+6:5: +6:6 - goto -> bb9; // scope 1 at $DIR/issue_75439.rs:+4:5: +8:6 - } - - bb8: { + bb6: { _0 = Option::<[u8; 4]>::None; // scope 1 at $DIR/issue_75439.rs:+7:9: +7:13 - goto -> bb9; // scope 1 at $DIR/issue_75439.rs:+4:5: +8:6 + goto -> bb7; // scope 1 at $DIR/issue_75439.rs:+4:5: +8:6 } - bb9: { + bb7: { StorageDead(_2); // scope 0 at $DIR/issue_75439.rs:+9:1: +9:2 return; // scope 0 at $DIR/issue_75439.rs:+9:2: +9:2 } diff --git a/tests/mir-opt/lower_intrinsics.assume.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.assume.LowerIntrinsics.diff index d9898d8e0f0..5c5a9e90a9d 100644 --- a/tests/mir-opt/lower_intrinsics.assume.LowerIntrinsics.diff +++ b/tests/mir-opt/lower_intrinsics.assume.LowerIntrinsics.diff @@ -11,7 +11,7 @@ StorageLive(_1); // scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:38 - _1 = std::intrinsics::assume(const true) -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:38 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:72:9: 72:32 +- // + span: $DIR/lower_intrinsics.rs:105:9: 105:32 - // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(bool) {std::intrinsics::assume}, val: Value(<ZST>) } + assume(const true); // scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:38 + goto -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:38 diff --git a/tests/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff index d962ef8cb12..87960521bb4 100644 --- a/tests/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff +++ b/tests/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff @@ -31,7 +31,7 @@ _3 = &(*_4); // scope 0 at $DIR/lower_intrinsics.rs:+1:42: +1:44 - _2 = discriminant_value::<T>(move _3) -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:45 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:49:5: 49:41 +- // + span: $DIR/lower_intrinsics.rs:82:5: 82:41 - // + literal: Const { ty: for<'a> extern "rust-intrinsic" fn(&'a T) -> <T as DiscriminantKind>::Discriminant {discriminant_value::<T>}, val: Value(<ZST>) } + _2 = discriminant((*_3)); // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:45 + goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:45 @@ -46,13 +46,13 @@ StorageLive(_7); // scope 0 at $DIR/lower_intrinsics.rs:+2:42: +2:44 _19 = const _; // scope 0 at $DIR/lower_intrinsics.rs:+2:42: +2:44 // mir::Constant - // + span: $DIR/lower_intrinsics.rs:50:42: 50:44 + // + span: $DIR/lower_intrinsics.rs:83:42: 83:44 // + literal: Const { ty: &i32, val: Unevaluated(discriminant, [T], Some(promoted[2])) } _7 = &(*_19); // scope 0 at $DIR/lower_intrinsics.rs:+2:42: +2:44 _6 = &(*_7); // scope 0 at $DIR/lower_intrinsics.rs:+2:42: +2:44 - _5 = discriminant_value::<i32>(move _6) -> bb2; // scope 0 at $DIR/lower_intrinsics.rs:+2:5: +2:45 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:50:5: 50:41 +- // + span: $DIR/lower_intrinsics.rs:83:5: 83:41 - // + literal: Const { ty: for<'a> extern "rust-intrinsic" fn(&'a i32) -> <i32 as DiscriminantKind>::Discriminant {discriminant_value::<i32>}, val: Value(<ZST>) } + _5 = discriminant((*_6)); // scope 0 at $DIR/lower_intrinsics.rs:+2:5: +2:45 + goto -> bb2; // scope 0 at $DIR/lower_intrinsics.rs:+2:5: +2:45 @@ -67,13 +67,13 @@ StorageLive(_11); // scope 0 at $DIR/lower_intrinsics.rs:+3:42: +3:45 _18 = const _; // scope 0 at $DIR/lower_intrinsics.rs:+3:42: +3:45 // mir::Constant - // + span: $DIR/lower_intrinsics.rs:51:42: 51:45 + // + span: $DIR/lower_intrinsics.rs:84:42: 84:45 // + literal: Const { ty: &(), val: Unevaluated(discriminant, [T], Some(promoted[1])) } _11 = &(*_18); // scope 0 at $DIR/lower_intrinsics.rs:+3:42: +3:45 _10 = &(*_11); // scope 0 at $DIR/lower_intrinsics.rs:+3:42: +3:45 - _9 = discriminant_value::<()>(move _10) -> bb3; // scope 0 at $DIR/lower_intrinsics.rs:+3:5: +3:46 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:51:5: 51:41 +- // + span: $DIR/lower_intrinsics.rs:84:5: 84:41 - // + literal: Const { ty: for<'a> extern "rust-intrinsic" fn(&'a ()) -> <() as DiscriminantKind>::Discriminant {discriminant_value::<()>}, val: Value(<ZST>) } + _9 = discriminant((*_10)); // scope 0 at $DIR/lower_intrinsics.rs:+3:5: +3:46 + goto -> bb3; // scope 0 at $DIR/lower_intrinsics.rs:+3:5: +3:46 @@ -88,13 +88,13 @@ StorageLive(_15); // scope 0 at $DIR/lower_intrinsics.rs:+4:42: +4:47 _17 = const _; // scope 0 at $DIR/lower_intrinsics.rs:+4:42: +4:47 // mir::Constant - // + span: $DIR/lower_intrinsics.rs:52:42: 52:47 + // + span: $DIR/lower_intrinsics.rs:85:42: 85:47 // + literal: Const { ty: &E, val: Unevaluated(discriminant, [T], Some(promoted[0])) } _15 = &(*_17); // scope 0 at $DIR/lower_intrinsics.rs:+4:42: +4:47 _14 = &(*_15); // scope 0 at $DIR/lower_intrinsics.rs:+4:42: +4:47 - _13 = discriminant_value::<E>(move _14) -> bb4; // scope 0 at $DIR/lower_intrinsics.rs:+4:5: +4:48 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:52:5: 52:41 +- // + span: $DIR/lower_intrinsics.rs:85:5: 85:41 - // + literal: Const { ty: for<'a> extern "rust-intrinsic" fn(&'a E) -> <E as DiscriminantKind>::Discriminant {discriminant_value::<E>}, val: Value(<ZST>) } + _13 = discriminant((*_14)); // scope 0 at $DIR/lower_intrinsics.rs:+4:5: +4:48 + goto -> bb4; // scope 0 at $DIR/lower_intrinsics.rs:+4:5: +4:48 diff --git a/tests/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.diff index 5c972a00e46..15cce7f4a2c 100644 --- a/tests/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.diff +++ b/tests/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.diff @@ -49,7 +49,7 @@ StorageDead(_9); // scope 3 at $DIR/lower_intrinsics.rs:+4:90: +4:91 - _3 = copy_nonoverlapping::<i32>(move _4, move _8, const 0_usize) -> bb1; // scope 3 at $DIR/lower_intrinsics.rs:+4:9: +4:95 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:65:9: 65:28 +- // + span: $DIR/lower_intrinsics.rs:98:9: 98:28 - // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(*const i32, *mut i32, usize) {copy_nonoverlapping::<i32>}, val: Value(<ZST>) } + copy_nonoverlapping(dst = move _8, src = move _4, count = const 0_usize); // scope 3 at $DIR/lower_intrinsics.rs:+4:9: +4:95 + goto -> bb1; // scope 3 at $DIR/lower_intrinsics.rs:+4:9: +4:95 diff --git a/tests/mir-opt/lower_intrinsics.option_payload.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.option_payload.LowerIntrinsics.diff new file mode 100644 index 00000000000..c563703b250 --- /dev/null +++ b/tests/mir-opt/lower_intrinsics.option_payload.LowerIntrinsics.diff @@ -0,0 +1,54 @@ +- // MIR for `option_payload` before LowerIntrinsics ++ // MIR for `option_payload` after LowerIntrinsics + + fn option_payload(_1: &Option<usize>, _2: &Option<String>) -> () { + debug o => _1; // in scope 0 at $DIR/lower_intrinsics.rs:+0:23: +0:24 + debug p => _2; // in scope 0 at $DIR/lower_intrinsics.rs:+0:42: +0:43 + let mut _0: (); // return place in scope 0 at $DIR/lower_intrinsics.rs:+0:62: +0:62 + let mut _4: *const std::option::Option<usize>; // in scope 0 at $DIR/lower_intrinsics.rs:+2:55: +2:56 + let mut _6: *const std::option::Option<std::string::String>; // in scope 0 at $DIR/lower_intrinsics.rs:+3:55: +3:56 + scope 1 { + let _3: *const usize; // in scope 1 at $DIR/lower_intrinsics.rs:+2:13: +2:15 + scope 2 { + debug _x => _3; // in scope 2 at $DIR/lower_intrinsics.rs:+2:13: +2:15 + let _5: *const std::string::String; // in scope 2 at $DIR/lower_intrinsics.rs:+3:13: +3:15 + scope 3 { + debug _y => _5; // in scope 3 at $DIR/lower_intrinsics.rs:+3:13: +3:15 + } + } + } + + bb0: { + StorageLive(_3); // scope 1 at $DIR/lower_intrinsics.rs:+2:13: +2:15 + StorageLive(_4); // scope 1 at $DIR/lower_intrinsics.rs:+2:55: +2:56 + _4 = &raw const (*_1); // scope 1 at $DIR/lower_intrinsics.rs:+2:55: +2:56 +- _3 = option_payload_ptr::<usize>(move _4) -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+2:18: +2:57 +- // mir::Constant +- // + span: $DIR/lower_intrinsics.rs:132:18: 132:54 +- // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(*const Option<usize>) -> *const usize {option_payload_ptr::<usize>}, val: Value(<ZST>) } ++ _3 = &raw const (((*_4) as Some).0: usize); // scope 1 at $DIR/lower_intrinsics.rs:+2:18: +2:57 ++ goto -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+2:18: +2:57 + } + + bb1: { + StorageDead(_4); // scope 1 at $DIR/lower_intrinsics.rs:+2:56: +2:57 + StorageLive(_5); // scope 2 at $DIR/lower_intrinsics.rs:+3:13: +3:15 + StorageLive(_6); // scope 2 at $DIR/lower_intrinsics.rs:+3:55: +3:56 + _6 = &raw const (*_2); // scope 2 at $DIR/lower_intrinsics.rs:+3:55: +3:56 +- _5 = option_payload_ptr::<String>(move _6) -> bb2; // scope 2 at $DIR/lower_intrinsics.rs:+3:18: +3:57 +- // mir::Constant +- // + span: $DIR/lower_intrinsics.rs:133:18: 133:54 +- // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(*const Option<String>) -> *const String {option_payload_ptr::<String>}, val: Value(<ZST>) } ++ _5 = &raw const (((*_6) as Some).0: std::string::String); // scope 2 at $DIR/lower_intrinsics.rs:+3:18: +3:57 ++ goto -> bb2; // scope 2 at $DIR/lower_intrinsics.rs:+3:18: +3:57 + } + + bb2: { + StorageDead(_6); // scope 2 at $DIR/lower_intrinsics.rs:+3:56: +3:57 + _0 = const (); // scope 1 at $DIR/lower_intrinsics.rs:+1:5: +4:6 + StorageDead(_5); // scope 2 at $DIR/lower_intrinsics.rs:+4:5: +4:6 + StorageDead(_3); // scope 1 at $DIR/lower_intrinsics.rs:+4:5: +4:6 + return; // scope 0 at $DIR/lower_intrinsics.rs:+5:2: +5:2 + } + } + diff --git a/tests/mir-opt/lower_intrinsics.read_via_copy_primitive.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.read_via_copy_primitive.LowerIntrinsics.diff index 27fceeedf6e..f2f676843b2 100644 --- a/tests/mir-opt/lower_intrinsics.read_via_copy_primitive.LowerIntrinsics.diff +++ b/tests/mir-opt/lower_intrinsics.read_via_copy_primitive.LowerIntrinsics.diff @@ -13,7 +13,7 @@ _2 = &raw const (*_1); // scope 1 at $DIR/lower_intrinsics.rs:+1:46: +1:47 - _0 = read_via_copy::<i32>(move _2) -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:48 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:85:14: 85:45 +- // + span: $DIR/lower_intrinsics.rs:118:14: 118:45 - // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(*const i32) -> i32 {read_via_copy::<i32>}, val: Value(<ZST>) } + _0 = (*_2); // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:48 + goto -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:48 diff --git a/tests/mir-opt/lower_intrinsics.read_via_copy_uninhabited.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.read_via_copy_uninhabited.LowerIntrinsics.diff index 610c67d2fec..3ad21283fa4 100644 --- a/tests/mir-opt/lower_intrinsics.read_via_copy_uninhabited.LowerIntrinsics.diff +++ b/tests/mir-opt/lower_intrinsics.read_via_copy_uninhabited.LowerIntrinsics.diff @@ -13,7 +13,7 @@ _2 = &raw const (*_1); // scope 1 at $DIR/lower_intrinsics.rs:+1:46: +1:47 - _0 = read_via_copy::<Never>(move _2); // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:48 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:90:14: 90:45 +- // + span: $DIR/lower_intrinsics.rs:123:14: 123:45 - // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(*const Never) -> Never {read_via_copy::<Never>}, val: Value(<ZST>) } + unreachable; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:48 } diff --git a/tests/mir-opt/lower_intrinsics.rs b/tests/mir-opt/lower_intrinsics.rs index a0a1df4e5ca..ec215c9a664 100644 --- a/tests/mir-opt/lower_intrinsics.rs +++ b/tests/mir-opt/lower_intrinsics.rs @@ -38,6 +38,39 @@ pub fn non_const<T>() -> usize { size_of_t() } +// EMIT_MIR lower_intrinsics.transmute_inhabited.LowerIntrinsics.diff +pub fn transmute_inhabited(c: std::cmp::Ordering) -> i8 { + unsafe { std::mem::transmute(c) } +} + +// EMIT_MIR lower_intrinsics.transmute_uninhabited.LowerIntrinsics.diff +pub unsafe fn transmute_uninhabited(u: ()) -> Never { + unsafe { std::mem::transmute::<(), Never>(u) } +} + +// EMIT_MIR lower_intrinsics.transmute_ref_dst.LowerIntrinsics.diff +pub unsafe fn transmute_ref_dst<T: ?Sized>(u: &T) -> *const T { + unsafe { std::mem::transmute(u) } +} + +// EMIT_MIR lower_intrinsics.transmute_to_ref_uninhabited.LowerIntrinsics.diff +pub unsafe fn transmute_to_ref_uninhabited() -> ! { + let x: &Never = std::mem::transmute(1usize); + match *x {} +} + +// EMIT_MIR lower_intrinsics.transmute_to_mut_uninhabited.LowerIntrinsics.diff +pub unsafe fn transmute_to_mut_uninhabited() -> ! { + let x: &mut Never = std::mem::transmute(1usize); + match *x {} +} + +// EMIT_MIR lower_intrinsics.transmute_to_box_uninhabited.LowerIntrinsics.diff +pub unsafe fn transmute_to_box_uninhabited() -> ! { + let x: Box<Never> = std::mem::transmute(1usize); + match *x {} +} + pub enum E { A, B, @@ -91,3 +124,12 @@ pub fn read_via_copy_uninhabited(r: &Never) -> Never { } pub enum Never {} + +// EMIT_MIR lower_intrinsics.option_payload.LowerIntrinsics.diff +#[cfg(not(bootstrap))] +pub fn option_payload(o: &Option<usize>, p: &Option<String>) { + unsafe { + let _x = core::intrinsics::option_payload_ptr(o); + let _y = core::intrinsics::option_payload_ptr(p); + } +} diff --git a/tests/mir-opt/lower_intrinsics.transmute_inhabited.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.transmute_inhabited.LowerIntrinsics.diff new file mode 100644 index 00000000000..814368ec021 --- /dev/null +++ b/tests/mir-opt/lower_intrinsics.transmute_inhabited.LowerIntrinsics.diff @@ -0,0 +1,27 @@ +- // MIR for `transmute_inhabited` before LowerIntrinsics ++ // MIR for `transmute_inhabited` after LowerIntrinsics + + fn transmute_inhabited(_1: std::cmp::Ordering) -> i8 { + debug c => _1; // in scope 0 at $DIR/lower_intrinsics.rs:+0:28: +0:29 + let mut _0: i8; // return place in scope 0 at $DIR/lower_intrinsics.rs:+0:54: +0:56 + let mut _2: std::cmp::Ordering; // in scope 0 at $DIR/lower_intrinsics.rs:+1:34: +1:35 + scope 1 { + } + + bb0: { + StorageLive(_2); // scope 1 at $DIR/lower_intrinsics.rs:+1:34: +1:35 + _2 = _1; // scope 1 at $DIR/lower_intrinsics.rs:+1:34: +1:35 +- _0 = transmute::<std::cmp::Ordering, i8>(move _2) -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:36 +- // mir::Constant +- // + span: $DIR/lower_intrinsics.rs:43:14: 43:33 +- // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(std::cmp::Ordering) -> i8 {transmute::<std::cmp::Ordering, i8>}, val: Value(<ZST>) } ++ _0 = move _2 as i8 (Transmute); // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:36 ++ goto -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:36 + } + + bb1: { + StorageDead(_2); // scope 1 at $DIR/lower_intrinsics.rs:+1:35: +1:36 + return; // scope 0 at $DIR/lower_intrinsics.rs:+2:2: +2:2 + } + } + diff --git a/tests/mir-opt/lower_intrinsics.transmute_ref_dst.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.transmute_ref_dst.LowerIntrinsics.diff new file mode 100644 index 00000000000..5440c7a4c8e --- /dev/null +++ b/tests/mir-opt/lower_intrinsics.transmute_ref_dst.LowerIntrinsics.diff @@ -0,0 +1,27 @@ +- // MIR for `transmute_ref_dst` before LowerIntrinsics ++ // MIR for `transmute_ref_dst` after LowerIntrinsics + + fn transmute_ref_dst(_1: &T) -> *const T { + debug u => _1; // in scope 0 at $DIR/lower_intrinsics.rs:+0:44: +0:45 + let mut _0: *const T; // return place in scope 0 at $DIR/lower_intrinsics.rs:+0:54: +0:62 + let mut _2: &T; // in scope 0 at $DIR/lower_intrinsics.rs:+1:34: +1:35 + scope 1 { + } + + bb0: { + StorageLive(_2); // scope 1 at $DIR/lower_intrinsics.rs:+1:34: +1:35 + _2 = _1; // scope 1 at $DIR/lower_intrinsics.rs:+1:34: +1:35 +- _0 = transmute::<&T, *const T>(move _2) -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:36 +- // mir::Constant +- // + span: $DIR/lower_intrinsics.rs:53:14: 53:33 +- // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(&T) -> *const T {transmute::<&T, *const T>}, val: Value(<ZST>) } ++ _0 = move _2 as *const T (Transmute); // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:36 ++ goto -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:36 + } + + bb1: { + StorageDead(_2); // scope 1 at $DIR/lower_intrinsics.rs:+1:35: +1:36 + return; // scope 0 at $DIR/lower_intrinsics.rs:+2:2: +2:2 + } + } + diff --git a/tests/mir-opt/lower_intrinsics.transmute_to_box_uninhabited.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.transmute_to_box_uninhabited.LowerIntrinsics.diff new file mode 100644 index 00000000000..43ddccc1ef7 --- /dev/null +++ b/tests/mir-opt/lower_intrinsics.transmute_to_box_uninhabited.LowerIntrinsics.diff @@ -0,0 +1,29 @@ +- // MIR for `transmute_to_box_uninhabited` before LowerIntrinsics ++ // MIR for `transmute_to_box_uninhabited` after LowerIntrinsics + + fn transmute_to_box_uninhabited() -> ! { + let mut _0: !; // return place in scope 0 at $DIR/lower_intrinsics.rs:+0:49: +0:50 + let mut _1: !; // in scope 0 at $DIR/lower_intrinsics.rs:+0:51: +3:2 + let _2: std::boxed::Box<Never>; // in scope 0 at $DIR/lower_intrinsics.rs:+1:9: +1:10 + let mut _3: !; // in scope 0 at $DIR/lower_intrinsics.rs:+2:5: +2:16 + scope 1 { + debug x => _2; // in scope 1 at $DIR/lower_intrinsics.rs:+1:9: +1:10 + } + + bb0: { + StorageLive(_1); // scope 0 at $DIR/lower_intrinsics.rs:+0:51: +3:2 + StorageLive(_2); // scope 0 at $DIR/lower_intrinsics.rs:+1:9: +1:10 +- _2 = transmute::<usize, Box<Never>>(const 1_usize) -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:25: +1:52 +- // mir::Constant +- // + span: $DIR/lower_intrinsics.rs:70:25: 70:44 +- // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(usize) -> Box<Never> {transmute::<usize, Box<Never>>}, val: Value(<ZST>) } ++ _2 = const 1_usize as std::boxed::Box<Never> (Transmute); // scope 0 at $DIR/lower_intrinsics.rs:+1:25: +1:52 ++ goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:25: +1:52 + } + + bb1: { + StorageLive(_3); // scope 1 at $DIR/lower_intrinsics.rs:+2:5: +2:16 + unreachable; // scope 1 at $DIR/lower_intrinsics.rs:+2:11: +2:13 + } + } + diff --git a/tests/mir-opt/lower_intrinsics.transmute_to_mut_uninhabited.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.transmute_to_mut_uninhabited.LowerIntrinsics.diff new file mode 100644 index 00000000000..bf529a9ca67 --- /dev/null +++ b/tests/mir-opt/lower_intrinsics.transmute_to_mut_uninhabited.LowerIntrinsics.diff @@ -0,0 +1,29 @@ +- // MIR for `transmute_to_mut_uninhabited` before LowerIntrinsics ++ // MIR for `transmute_to_mut_uninhabited` after LowerIntrinsics + + fn transmute_to_mut_uninhabited() -> ! { + let mut _0: !; // return place in scope 0 at $DIR/lower_intrinsics.rs:+0:49: +0:50 + let mut _1: !; // in scope 0 at $DIR/lower_intrinsics.rs:+0:51: +3:2 + let _2: &mut Never; // in scope 0 at $DIR/lower_intrinsics.rs:+1:9: +1:10 + let mut _3: !; // in scope 0 at $DIR/lower_intrinsics.rs:+2:5: +2:16 + scope 1 { + debug x => _2; // in scope 1 at $DIR/lower_intrinsics.rs:+1:9: +1:10 + } + + bb0: { + StorageLive(_1); // scope 0 at $DIR/lower_intrinsics.rs:+0:51: +3:2 + StorageLive(_2); // scope 0 at $DIR/lower_intrinsics.rs:+1:9: +1:10 +- _2 = transmute::<usize, &mut Never>(const 1_usize) -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:25: +1:52 +- // mir::Constant +- // + span: $DIR/lower_intrinsics.rs:64:25: 64:44 +- // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(usize) -> &mut Never {transmute::<usize, &mut Never>}, val: Value(<ZST>) } ++ _2 = const 1_usize as &mut Never (Transmute); // scope 0 at $DIR/lower_intrinsics.rs:+1:25: +1:52 ++ goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:25: +1:52 + } + + bb1: { + StorageLive(_3); // scope 1 at $DIR/lower_intrinsics.rs:+2:5: +2:16 + unreachable; // scope 1 at $DIR/lower_intrinsics.rs:+2:11: +2:13 + } + } + diff --git a/tests/mir-opt/lower_intrinsics.transmute_to_ref_uninhabited.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.transmute_to_ref_uninhabited.LowerIntrinsics.diff new file mode 100644 index 00000000000..4940a99021f --- /dev/null +++ b/tests/mir-opt/lower_intrinsics.transmute_to_ref_uninhabited.LowerIntrinsics.diff @@ -0,0 +1,29 @@ +- // MIR for `transmute_to_ref_uninhabited` before LowerIntrinsics ++ // MIR for `transmute_to_ref_uninhabited` after LowerIntrinsics + + fn transmute_to_ref_uninhabited() -> ! { + let mut _0: !; // return place in scope 0 at $DIR/lower_intrinsics.rs:+0:49: +0:50 + let mut _1: !; // in scope 0 at $DIR/lower_intrinsics.rs:+0:51: +3:2 + let _2: &Never; // in scope 0 at $DIR/lower_intrinsics.rs:+1:9: +1:10 + let mut _3: !; // in scope 0 at $DIR/lower_intrinsics.rs:+2:5: +2:16 + scope 1 { + debug x => _2; // in scope 1 at $DIR/lower_intrinsics.rs:+1:9: +1:10 + } + + bb0: { + StorageLive(_1); // scope 0 at $DIR/lower_intrinsics.rs:+0:51: +3:2 + StorageLive(_2); // scope 0 at $DIR/lower_intrinsics.rs:+1:9: +1:10 +- _2 = transmute::<usize, &Never>(const 1_usize) -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:21: +1:48 +- // mir::Constant +- // + span: $DIR/lower_intrinsics.rs:58:21: 58:40 +- // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(usize) -> &Never {transmute::<usize, &Never>}, val: Value(<ZST>) } ++ _2 = const 1_usize as &Never (Transmute); // scope 0 at $DIR/lower_intrinsics.rs:+1:21: +1:48 ++ goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:21: +1:48 + } + + bb1: { + StorageLive(_3); // scope 1 at $DIR/lower_intrinsics.rs:+2:5: +2:16 + unreachable; // scope 1 at $DIR/lower_intrinsics.rs:+2:11: +2:13 + } + } + diff --git a/tests/mir-opt/lower_intrinsics.transmute_uninhabited.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.transmute_uninhabited.LowerIntrinsics.diff new file mode 100644 index 00000000000..f3a12b9ba5f --- /dev/null +++ b/tests/mir-opt/lower_intrinsics.transmute_uninhabited.LowerIntrinsics.diff @@ -0,0 +1,22 @@ +- // MIR for `transmute_uninhabited` before LowerIntrinsics ++ // MIR for `transmute_uninhabited` after LowerIntrinsics + + fn transmute_uninhabited(_1: ()) -> Never { + debug u => _1; // in scope 0 at $DIR/lower_intrinsics.rs:+0:37: +0:38 + let mut _0: Never; // return place in scope 0 at $DIR/lower_intrinsics.rs:+0:47: +0:52 + let mut _2: (); // in scope 0 at $DIR/lower_intrinsics.rs:+1:47: +1:48 + scope 1 { + } + + bb0: { + StorageLive(_2); // scope 1 at $DIR/lower_intrinsics.rs:+1:47: +1:48 + _2 = _1; // scope 1 at $DIR/lower_intrinsics.rs:+1:47: +1:48 +- _0 = transmute::<(), Never>(move _2); // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:49 +- // mir::Constant +- // + span: $DIR/lower_intrinsics.rs:48:14: 48:46 +- // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(()) -> Never {transmute::<(), Never>}, val: Value(<ZST>) } ++ _0 = move _2 as Never (Transmute); // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:49 ++ unreachable; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:49 + } + } + diff --git a/tests/mir-opt/lower_intrinsics.with_overflow.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.with_overflow.LowerIntrinsics.diff index 9870a70dec5..3b9a41249a4 100644 --- a/tests/mir-opt/lower_intrinsics.with_overflow.LowerIntrinsics.diff +++ b/tests/mir-opt/lower_intrinsics.with_overflow.LowerIntrinsics.diff @@ -32,7 +32,7 @@ _5 = _2; // scope 0 at $DIR/lower_intrinsics.rs:+1:53: +1:54 - _3 = add_with_overflow::<i32>(move _4, move _5) -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:14: +1:55 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:78:14: 78:49 +- // + span: $DIR/lower_intrinsics.rs:111:14: 111:49 - // + literal: Const { ty: extern "rust-intrinsic" fn(i32, i32) -> (i32, bool) {add_with_overflow::<i32>}, val: Value(<ZST>) } + _3 = CheckedAdd(move _4, move _5); // scope 0 at $DIR/lower_intrinsics.rs:+1:14: +1:55 + goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:14: +1:55 @@ -48,7 +48,7 @@ _8 = _2; // scope 1 at $DIR/lower_intrinsics.rs:+2:53: +2:54 - _6 = sub_with_overflow::<i32>(move _7, move _8) -> bb2; // scope 1 at $DIR/lower_intrinsics.rs:+2:14: +2:55 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:79:14: 79:49 +- // + span: $DIR/lower_intrinsics.rs:112:14: 112:49 - // + literal: Const { ty: extern "rust-intrinsic" fn(i32, i32) -> (i32, bool) {sub_with_overflow::<i32>}, val: Value(<ZST>) } + _6 = CheckedSub(move _7, move _8); // scope 1 at $DIR/lower_intrinsics.rs:+2:14: +2:55 + goto -> bb2; // scope 1 at $DIR/lower_intrinsics.rs:+2:14: +2:55 @@ -64,7 +64,7 @@ _11 = _2; // scope 2 at $DIR/lower_intrinsics.rs:+3:53: +3:54 - _9 = mul_with_overflow::<i32>(move _10, move _11) -> bb3; // scope 2 at $DIR/lower_intrinsics.rs:+3:14: +3:55 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:80:14: 80:49 +- // + span: $DIR/lower_intrinsics.rs:113:14: 113:49 - // + literal: Const { ty: extern "rust-intrinsic" fn(i32, i32) -> (i32, bool) {mul_with_overflow::<i32>}, val: Value(<ZST>) } + _9 = CheckedMul(move _10, move _11); // scope 2 at $DIR/lower_intrinsics.rs:+3:14: +3:55 + goto -> bb3; // scope 2 at $DIR/lower_intrinsics.rs:+3:14: +3:55 diff --git a/tests/run-make-fulldeps/issue-83045/Makefile b/tests/run-make-fulldeps/issue-83045/Makefile index 34853cb1d31..fc180ccfe28 100644 --- a/tests/run-make-fulldeps/issue-83045/Makefile +++ b/tests/run-make-fulldeps/issue-83045/Makefile @@ -29,5 +29,5 @@ all: --crate-type=rlib \ --edition=2018 \ c.rs 2>&1 | tee $(TMPDIR)/output.txt || exit 0 - $(CGREP) E0463 < $(TMPDIR)/output.txt + $(CGREP) E0519 < $(TMPDIR)/output.txt $(CGREP) -v "internal compiler error" < $(TMPDIR)/output.txt diff --git a/tests/run-make/issue-36710/Makefile b/tests/run-make/issue-36710/Makefile index d6145c07126..c6b71f5fbd4 100644 --- a/tests/run-make/issue-36710/Makefile +++ b/tests/run-make/issue-36710/Makefile @@ -4,6 +4,7 @@ # ignore-nvptx64-nvidia-cuda FIXME: can't find crate for `std` # ignore-musl FIXME: this makefile needs teaching how to use a musl toolchain # (see dist-i586-gnu-i586-i686-musl Dockerfile) +# ignore-sgx include ../../run-make-fulldeps/tools.mk diff --git a/tests/run-make/raw-dylib-cross-compilation/Makefile b/tests/run-make/raw-dylib-cross-compilation/Makefile new file mode 100644 index 00000000000..2a714f3a11f --- /dev/null +++ b/tests/run-make/raw-dylib-cross-compilation/Makefile @@ -0,0 +1,22 @@ +# Tests that raw-dylib cross compilation works correctly + +# only-gnu +# needs-i686-dlltool +# needs-x86_64-dlltool + +# i686 dlltool.exe can't product x64 binaries. +# ignore-i686-pc-windows-gnu + +include ../../run-make-fulldeps/tools.mk + +all: + # Build as x86 and make sure that we have x86 objects only. + $(RUSTC) --crate-type lib --crate-name i686_raw_dylib_test --target i686-pc-windows-gnu lib.rs + "$(LLVM_BIN_DIR)"/llvm-objdump -a $(TMPDIR)/libi686_raw_dylib_test.rlib > $(TMPDIR)/i686.objdump.txt + $(CGREP) "file format coff-i386" < $(TMPDIR)/i686.objdump.txt + $(CGREP) -v "file format coff-x86-64" < $(TMPDIR)/i686.objdump.txt + # Build as x64 and make sure that we have x64 objects only. + $(RUSTC) --crate-type lib --crate-name x64_raw_dylib_test --target x86_64-pc-windows-gnu lib.rs + "$(LLVM_BIN_DIR)"/llvm-objdump -a $(TMPDIR)/libx64_raw_dylib_test.rlib > $(TMPDIR)/x64.objdump.txt + $(CGREP) "file format coff-x86-64" < $(TMPDIR)/x64.objdump.txt + $(CGREP) -v "file format coff-i386" < $(TMPDIR)/x64.objdump.txt diff --git a/tests/run-make/raw-dylib-cross-compilation/lib.rs b/tests/run-make/raw-dylib-cross-compilation/lib.rs new file mode 100644 index 00000000000..51bf2ec6b6e --- /dev/null +++ b/tests/run-make/raw-dylib-cross-compilation/lib.rs @@ -0,0 +1,20 @@ +#![feature(raw_dylib)] +#![feature(no_core, lang_items)] +#![no_std] +#![no_core] +#![crate_type = "lib"] + +// This is needed because of #![no_core]: +#[lang = "sized"] +trait Sized {} + +#[link(name = "extern_1", kind = "raw-dylib")] +extern { + fn extern_fn(); +} + +pub fn extern_fn_caller() { + unsafe { + extern_fn(); + } +} diff --git a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_asm.checks b/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_asm.checks index e839c200bbb..af9bc8c1d62 100644 --- a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_asm.checks +++ b/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_asm.checks @@ -1,8 +1,7 @@ CHECK: cc_plus_one_asm CHECK-NEXT: movl CHECK-NEXT: lfence -CHECK-NEXT: inc -CHECK-NEXT: notq (%rsp) -CHECK-NEXT: notq (%rsp) +CHECK-NEXT: incl +CHECK-NEXT: shlq $0, (%rsp) CHECK-NEXT: lfence CHECK-NEXT: retq diff --git a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/jumpto.checks b/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/jumpto.checks index 15211e3ade7..885bf461bf3 100644 --- a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/jumpto.checks +++ b/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/jumpto.checks @@ -1,8 +1,24 @@ -CHECK: libunwind::Registers_x86_64::jumpto +CHECK: __libunwind_Registers_x86_64_jumpto CHECK: lfence CHECK: lfence CHECK: lfence CHECK: lfence -CHECK: shlq $0, (%rsp) +CHECK: lfence +CHECK: lfence +CHECK: lfence +CHECK: lfence +CHECK: lfence +CHECK: lfence +CHECK: lfence +CHECK: lfence +CHECK: lfence +CHECK: lfence +CHECK: lfence +CHECK: lfence +CHECK: lfence +CHECK: lfence +CHECK-NEXT: popq [[REGISTER:%[a-z]+]] +CHECK-NEXT: lfence +CHECK-NEXT: popq [[REGISTER:%[a-z]+]] CHECK-NEXT: lfence -CHECK-NEXT: retq +CHECK-NEXT: jmpq *[[REGISTER]] diff --git a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/print.checks b/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/print.checks index 0fe88141b24..8a5493650a7 100644 --- a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/print.checks +++ b/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/print.checks @@ -2,6 +2,5 @@ CHECK: print CHECK: lfence CHECK: lfence CHECK: lfence -CHECK: popq CHECK: callq 0x{{[[:xdigit:]]*}} <_Unwind_Resume> CHECK-NEXT: ud2 diff --git a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/script.sh b/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/script.sh index 944343df6e5..235bb603b84 100644 --- a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/script.sh +++ b/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/script.sh @@ -20,39 +20,38 @@ function build { } function check { - local func=$1 + local func_re="$1" local checks="${TEST_DIR}/$2" local asm=$(mktemp) - local objdump="${BUILD_DIR}/x86_64-unknown-linux-gnu/llvm/build/bin/llvm-objdump" - local filecheck="${BUILD_DIR}/x86_64-unknown-linux-gnu/llvm/build/bin/FileCheck" - - ${objdump} --disassemble-symbols=${func} --demangle \ - ${WORK_DIR}/enclave/target/x86_64-fortanix-unknown-sgx/debug/enclave > ${asm} + local objdump="${LLVM_BIN_DIR}/llvm-objdump" + local filecheck="${LLVM_BIN_DIR}/FileCheck" + local enclave=${WORK_DIR}/enclave/target/x86_64-fortanix-unknown-sgx/debug/enclave + + func="$(${objdump} --syms --demangle ${enclave} | \ + grep --only-matching -E "[[:blank:]]+${func_re}\$" | \ + sed -e 's/^[[:space:]]*//' )" + ${objdump} --disassemble-symbols="${func}" --demangle \ + ${enclave} > ${asm} ${filecheck} --input-file ${asm} ${checks} } build -check unw_getcontext unw_getcontext.checks -check "libunwind::Registers_x86_64::jumpto()" jumpto.checks -check "std::io::stdio::_print::h87f0c238421c45bc" print.checks -check rust_plus_one_global_asm rust_plus_one_global_asm.checks \ - || echo "warning: module level assembly currently not hardened" +check "unw_getcontext" unw_getcontext.checks +check "__libunwind_Registers_x86_64_jumpto" jumpto.checks +check 'std::io::stdio::_print::[[:alnum:]]+' print.checks +check rust_plus_one_global_asm rust_plus_one_global_asm.checks check cc_plus_one_c cc_plus_one_c.checks check cc_plus_one_c_asm cc_plus_one_c_asm.checks check cc_plus_one_cxx cc_plus_one_cxx.checks check cc_plus_one_cxx_asm cc_plus_one_cxx_asm.checks -check cc_plus_one_asm cc_plus_one_asm.checks \ - || echo "warning: the cc crate forwards assembly files to the CC compiler." \ - "Clang uses its own integrated assembler, which does not include the LVI passes." +check cc_plus_one_asm cc_plus_one_asm.checks check cmake_plus_one_c cmake_plus_one_c.checks check cmake_plus_one_c_asm cmake_plus_one_c_asm.checks -check cmake_plus_one_c_global_asm cmake_plus_one_c_global_asm.checks \ - || echo "warning: module level assembly currently not hardened" +check cmake_plus_one_c_global_asm cmake_plus_one_c_global_asm.checks check cmake_plus_one_cxx cmake_plus_one_cxx.checks check cmake_plus_one_cxx_asm cmake_plus_one_cxx_asm.checks -check cmake_plus_one_cxx_global_asm cmake_plus_one_cxx_global_asm.checks \ - || echo "warning: module level assembly currently not hardened" +check cmake_plus_one_cxx_global_asm cmake_plus_one_cxx_global_asm.checks check cmake_plus_one_asm cmake_plus_one_asm.checks diff --git a/tests/rustdoc-gui/setting-auto-hide-content-large-items.goml b/tests/rustdoc-gui/setting-auto-hide-content-large-items.goml new file mode 100644 index 00000000000..0ebb96d7870 --- /dev/null +++ b/tests/rustdoc-gui/setting-auto-hide-content-large-items.goml @@ -0,0 +1,51 @@ +// This test ensures that the "Auto-hide item contents for large items" setting is working as +// expected. + +// We need to disable this check because `implementors/test_docs/trait.Iterator.js` doesn't exist. +fail-on-request-error: false + +define-function: ( + "check-setting", + (storage_value, setting_attribute_value, toggle_attribute_value), + block { + assert-local-storage: {"rustdoc-auto-hide-large-items": |storage_value|} + click: "#settings-menu" + wait-for: "#settings" + assert-property: ("#auto-hide-large-items", {"checked": |setting_attribute_value|}) + assert-attribute: (".item-decl .type-contents-toggle", {"open": |toggle_attribute_value|}) + } +) + +goto: "file://" + |DOC_PATH| + "/lib2/scroll_traits/trait.Iterator.html" + +// We check that the setting is enabled by default and is working. +call-function: ("check-setting", { + "storage_value": null, + "setting_attribute_value": "true", + "toggle_attribute_value": null, +}) + +// Now we change its value. +click: "#auto-hide-large-items" +assert-local-storage: {"rustdoc-auto-hide-large-items": "false"} + +// We check that the changes were applied as expected. +reload: + +call-function: ("check-setting", { + "storage_value": "false", + "setting_attribute_value": "false", + "toggle_attribute_value": "", +}) + +// And now we re-enable the setting. +click: "#auto-hide-large-items" +assert-local-storage: {"rustdoc-auto-hide-large-items": "true"} + +// And we check everything is back the way it was before. +reload: +call-function: ("check-setting", { + "storage_value": "true", + "setting_attribute_value": "true", + "toggle_attribute_value": null, +}) diff --git a/tests/rustdoc-js-std/parser-errors.js b/tests/rustdoc-js-std/parser-errors.js index 98c6f27ca61..d1aa840ab08 100644 --- a/tests/rustdoc-js-std/parser-errors.js +++ b/tests/rustdoc-js-std/parser-errors.js @@ -17,6 +17,7 @@ const QUERY = [ "a b:", "a (b:", "_:", + "_:a", "a-bb", "a>bb", "ab'", @@ -48,7 +49,6 @@ const PARSED = [ foundElems: 0, original: "<P>", returned: [], - typeFilter: -1, userQuery: "<p>", error: "Found generics without a path", }, @@ -57,7 +57,6 @@ const PARSED = [ foundElems: 0, original: "-> <P>", returned: [], - typeFilter: -1, userQuery: "-> <p>", error: "Found generics without a path", }, @@ -66,7 +65,6 @@ const PARSED = [ foundElems: 0, original: "a<\"P\">", returned: [], - typeFilter: -1, userQuery: "a<\"p\">", error: "Unexpected `\"` in generics", }, @@ -75,7 +73,6 @@ const PARSED = [ foundElems: 0, original: "\"P\" \"P\"", returned: [], - typeFilter: -1, userQuery: "\"p\" \"p\"", error: "Cannot have more than one literal search element", }, @@ -84,7 +81,6 @@ const PARSED = [ foundElems: 0, original: "P \"P\"", returned: [], - typeFilter: -1, userQuery: "p \"p\"", error: "Cannot use literal search when there is more than one element", }, @@ -93,7 +89,6 @@ const PARSED = [ foundElems: 0, original: "\"p\" p", returned: [], - typeFilter: -1, userQuery: "\"p\" p", error: "You cannot have more than one element if you use quotes", }, @@ -102,7 +97,6 @@ const PARSED = [ foundElems: 0, original: "\"const\": p", returned: [], - typeFilter: -1, userQuery: "\"const\": p", error: "You cannot use quotes on type filter", }, @@ -111,16 +105,14 @@ const PARSED = [ foundElems: 0, original: "a<:a>", returned: [], - typeFilter: -1, userQuery: "a<:a>", - error: "Unexpected `:` after `<`", + error: "Expected type filter before `:`", }, { elems: [], foundElems: 0, original: "a<::a>", returned: [], - typeFilter: -1, userQuery: "a<::a>", error: "Unexpected `::`: paths cannot start with `::`", }, @@ -129,7 +121,6 @@ const PARSED = [ foundElems: 0, original: "((a))", returned: [], - typeFilter: -1, userQuery: "((a))", error: "Unexpected `(`", }, @@ -138,7 +129,6 @@ const PARSED = [ foundElems: 0, original: "(p -> p", returned: [], - typeFilter: -1, userQuery: "(p -> p", error: "Unexpected `(`", }, @@ -147,7 +137,6 @@ const PARSED = [ foundElems: 0, original: "::a::b", returned: [], - typeFilter: -1, userQuery: "::a::b", error: "Paths cannot start with `::`", }, @@ -156,7 +145,6 @@ const PARSED = [ foundElems: 0, original: "a::::b", returned: [], - typeFilter: -1, userQuery: "a::::b", error: "Unexpected `::::`", }, @@ -165,7 +153,6 @@ const PARSED = [ foundElems: 0, original: "a::b::", returned: [], - typeFilter: -1, userQuery: "a::b::", error: "Paths cannot end with `::`", }, @@ -174,7 +161,6 @@ const PARSED = [ foundElems: 0, original: ":a", returned: [], - typeFilter: -1, userQuery: ":a", error: "Expected type filter before `:`", }, @@ -183,16 +169,14 @@ const PARSED = [ foundElems: 0, original: "a b:", returned: [], - typeFilter: -1, userQuery: "a b:", - error: "Unexpected `:`", + error: "Unexpected `:` (expected path after type filter)", }, { elems: [], foundElems: 0, original: "a (b:", returned: [], - typeFilter: -1, userQuery: "a (b:", error: "Unexpected `(`", }, @@ -201,8 +185,15 @@ const PARSED = [ foundElems: 0, original: "_:", returned: [], - typeFilter: -1, userQuery: "_:", + error: "Unexpected `:` (expected path after type filter)", + }, + { + elems: [], + foundElems: 0, + original: "_:a", + returned: [], + userQuery: "_:a", error: "Unknown type filter `_`", }, { @@ -210,7 +201,6 @@ const PARSED = [ foundElems: 0, original: "a-bb", returned: [], - typeFilter: -1, userQuery: "a-bb", error: "Unexpected `-` (did you mean `->`?)", }, @@ -219,7 +209,6 @@ const PARSED = [ foundElems: 0, original: "a>bb", returned: [], - typeFilter: -1, userQuery: "a>bb", error: "Unexpected `>` (did you mean `->`?)", }, @@ -228,7 +217,6 @@ const PARSED = [ foundElems: 0, original: "ab'", returned: [], - typeFilter: -1, userQuery: "ab'", error: "Unexpected `'`", }, @@ -237,7 +225,6 @@ const PARSED = [ foundElems: 0, original: "a->", returned: [], - typeFilter: -1, userQuery: "a->", error: "Expected at least one item after `->`", }, @@ -246,7 +233,6 @@ const PARSED = [ foundElems: 0, original: '"p" <a>', returned: [], - typeFilter: -1, userQuery: '"p" <a>', error: "Found generics without a path", }, @@ -255,7 +241,6 @@ const PARSED = [ foundElems: 0, original: '"p" a<a>', returned: [], - typeFilter: -1, userQuery: '"p" a<a>', error: "You cannot have more than one element if you use quotes", }, @@ -264,7 +249,6 @@ const PARSED = [ foundElems: 0, original: 'a,<', returned: [], - typeFilter: -1, userQuery: 'a,<', error: 'Found generics without a path', }, @@ -273,7 +257,6 @@ const PARSED = [ foundElems: 0, original: 'aaaaa<>b', returned: [], - typeFilter: -1, userQuery: 'aaaaa<>b', error: 'Expected `,`, ` `, `:` or `->`, found `b`', }, @@ -282,16 +265,14 @@ const PARSED = [ foundElems: 0, original: 'fn:aaaaa<>b', returned: [], - typeFilter: -1, userQuery: 'fn:aaaaa<>b', - error: 'Expected `,`, ` ` or `->`, found `b`', + error: 'Expected `,`, ` `, `:` or `->`, found `b`', }, { elems: [], foundElems: 0, original: '->a<>b', returned: [], - typeFilter: -1, userQuery: '->a<>b', error: 'Expected `,` or ` `, found `b`', }, @@ -300,7 +281,6 @@ const PARSED = [ foundElems: 0, original: 'a<->', returned: [], - typeFilter: -1, userQuery: 'a<->', error: 'Unexpected `-` after `<`', }, @@ -309,7 +289,6 @@ const PARSED = [ foundElems: 0, original: 'a:: a', returned: [], - typeFilter: -1, userQuery: 'a:: a', error: 'Paths cannot end with `::`', }, @@ -318,7 +297,6 @@ const PARSED = [ foundElems: 0, original: 'a ::a', returned: [], - typeFilter: -1, userQuery: 'a ::a', error: 'Paths cannot start with `::`', }, @@ -327,16 +305,14 @@ const PARSED = [ foundElems: 0, original: "a<a>:", returned: [], - typeFilter: -1, userQuery: "a<a>:", - error: 'Unexpected `:`', + error: 'Unexpected `<` in type filter', }, { elems: [], foundElems: 0, original: "a<>:", returned: [], - typeFilter: -1, userQuery: "a<>:", error: 'Unexpected `<` in type filter', }, @@ -345,7 +321,6 @@ const PARSED = [ foundElems: 0, original: "a,:", returned: [], - typeFilter: -1, userQuery: "a,:", error: 'Unexpected `,` in type filter', }, @@ -354,7 +329,6 @@ const PARSED = [ foundElems: 0, original: "a<> :", returned: [], - typeFilter: -1, userQuery: "a<> :", error: 'Unexpected `<` in type filter', }, @@ -363,7 +337,6 @@ const PARSED = [ foundElems: 0, original: "mod : :", returned: [], - typeFilter: -1, userQuery: "mod : :", error: 'Unexpected `:`', }, @@ -372,7 +345,6 @@ const PARSED = [ foundElems: 0, original: "a!a", returned: [], - typeFilter: -1, userQuery: "a!a", error: 'Unexpected `!`: it can only be at the end of an ident', }, @@ -381,7 +353,6 @@ const PARSED = [ foundElems: 0, original: "a!!", returned: [], - typeFilter: -1, userQuery: "a!!", error: 'Cannot have more than one `!` in an ident', }, @@ -390,7 +361,6 @@ const PARSED = [ foundElems: 0, original: "mod:a!", returned: [], - typeFilter: -1, userQuery: "mod:a!", error: 'Invalid search type: macro `!` and `mod` both specified', }, @@ -399,7 +369,6 @@ const PARSED = [ foundElems: 0, original: "a!::a", returned: [], - typeFilter: -1, userQuery: "a!::a", error: 'Cannot have associated items in macros', }, @@ -408,7 +377,6 @@ const PARSED = [ foundElems: 0, original: "a<", returned: [], - typeFilter: -1, userQuery: "a<", error: "Unclosed `<`", }, diff --git a/tests/rustdoc-js-std/parser-filter.js b/tests/rustdoc-js-std/parser-filter.js index 01f65b478f8..e23447ab75d 100644 --- a/tests/rustdoc-js-std/parser-filter.js +++ b/tests/rustdoc-js-std/parser-filter.js @@ -1,4 +1,14 @@ -const QUERY = ['fn:foo', 'enum : foo', 'macro<f>:foo', 'macro!', 'macro:mac!', 'a::mac!']; +const QUERY = [ + 'fn:foo', + 'enum : foo', + 'macro<f>:foo', + 'macro!', + 'macro:mac!', + 'a::mac!', + '-> fn:foo', + '-> fn:foo<fn:bar>', + '-> fn:foo<fn:bar, enum : baz::fuzz>', +]; const PARSED = [ { @@ -8,11 +18,11 @@ const PARSED = [ pathWithoutLast: [], pathLast: "foo", generics: [], + typeFilter: 5, }], foundElems: 1, original: "fn:foo", returned: [], - typeFilter: 5, userQuery: "fn:foo", error: null, }, @@ -23,11 +33,11 @@ const PARSED = [ pathWithoutLast: [], pathLast: "foo", generics: [], + typeFilter: 4, }], foundElems: 1, original: "enum : foo", returned: [], - typeFilter: 4, userQuery: "enum : foo", error: null, }, @@ -36,9 +46,8 @@ const PARSED = [ foundElems: 0, original: "macro<f>:foo", returned: [], - typeFilter: -1, userQuery: "macro<f>:foo", - error: "Unexpected `:`", + error: "Unexpected `<` in type filter", }, { elems: [{ @@ -47,11 +56,11 @@ const PARSED = [ pathWithoutLast: [], pathLast: "macro", generics: [], + typeFilter: 14, }], foundElems: 1, original: "macro!", returned: [], - typeFilter: 14, userQuery: "macro!", error: null, }, @@ -62,11 +71,11 @@ const PARSED = [ pathWithoutLast: [], pathLast: "mac", generics: [], + typeFilter: 14, }], foundElems: 1, original: "macro:mac!", returned: [], - typeFilter: 14, userQuery: "macro:mac!", error: null, }, @@ -77,12 +86,83 @@ const PARSED = [ pathWithoutLast: ["a"], pathLast: "mac", generics: [], + typeFilter: 14, }], foundElems: 1, original: "a::mac!", returned: [], - typeFilter: 14, userQuery: "a::mac!", error: null, }, + { + elems: [], + foundElems: 1, + original: "-> fn:foo", + returned: [{ + name: "foo", + fullPath: ["foo"], + pathWithoutLast: [], + pathLast: "foo", + generics: [], + typeFilter: 5, + }], + userQuery: "-> fn:foo", + error: null, + }, + { + elems: [], + foundElems: 1, + original: "-> fn:foo<fn:bar>", + returned: [{ + name: "foo", + fullPath: ["foo"], + pathWithoutLast: [], + pathLast: "foo", + generics: [ + { + name: "bar", + fullPath: ["bar"], + pathWithoutLast: [], + pathLast: "bar", + generics: [], + typeFilter: 5, + } + ], + typeFilter: 5, + }], + userQuery: "-> fn:foo<fn:bar>", + error: null, + }, + { + elems: [], + foundElems: 1, + original: "-> fn:foo<fn:bar, enum : baz::fuzz>", + returned: [{ + name: "foo", + fullPath: ["foo"], + pathWithoutLast: [], + pathLast: "foo", + generics: [ + { + name: "bar", + fullPath: ["bar"], + pathWithoutLast: [], + pathLast: "bar", + generics: [], + typeFilter: 5, + }, + { + name: "baz::fuzz", + fullPath: ["baz", "fuzz"], + pathWithoutLast: ["baz"], + pathLast: "fuzz", + generics: [], + typeFilter: 4, + }, + ], + typeFilter: 5, + }], + userQuery: "-> fn:foo<fn:bar, enum : baz::fuzz>", + error: null, + }, ]; diff --git a/tests/rustdoc-js-std/parser-generics.js b/tests/rustdoc-js-std/parser-generics.js index 0cf7f5019aa..c448d845acb 100644 --- a/tests/rustdoc-js-std/parser-generics.js +++ b/tests/rustdoc-js-std/parser-generics.js @@ -6,7 +6,6 @@ const PARSED = [ foundElems: 0, original: 'A<B<C<D>, E>', returned: [], - typeFilter: -1, userQuery: 'a<b<c<d>, e>', error: 'Unexpected `<` after `<`', }, @@ -18,6 +17,7 @@ const PARSED = [ pathWithoutLast: [], pathLast: "p", generics: [], + typeFilter: -1, }, { name: "u8", @@ -25,12 +25,12 @@ const PARSED = [ pathWithoutLast: [], pathLast: "u8", generics: [], + typeFilter: -1, }, ], foundElems: 2, original: "p<> u8", returned: [], - typeFilter: -1, userQuery: "p<> u8", error: null, }, @@ -50,12 +50,12 @@ const PARSED = [ generics: [], }, ], + typeFilter: -1, }, ], foundElems: 1, original: '"p"<a>', returned: [], - typeFilter: -1, userQuery: '"p"<a>', error: null, }, diff --git a/tests/rustdoc-js-std/parser-ident.js b/tests/rustdoc-js-std/parser-ident.js index 6c17d00f16e..be42b7aa463 100644 --- a/tests/rustdoc-js-std/parser-ident.js +++ b/tests/rustdoc-js-std/parser-ident.js @@ -23,11 +23,11 @@ const PARSED = [ generics: [], }, ], + typeFilter: -1, }], foundElems: 1, original: "R<!>", returned: [], - typeFilter: -1, userQuery: "r<!>", error: null, }, @@ -38,11 +38,11 @@ const PARSED = [ pathWithoutLast: [], pathLast: "!", generics: [], + typeFilter: -1, }], foundElems: 1, original: "!", returned: [], - typeFilter: -1, userQuery: "!", error: null, }, @@ -53,11 +53,11 @@ const PARSED = [ pathWithoutLast: [], pathLast: "a", generics: [], + typeFilter: 14, }], foundElems: 1, original: "a!", returned: [], - typeFilter: 14, userQuery: "a!", error: null, }, @@ -66,7 +66,6 @@ const PARSED = [ foundElems: 0, original: "a!::b", returned: [], - typeFilter: -1, userQuery: "a!::b", error: "Cannot have associated items in macros", }, @@ -77,11 +76,11 @@ const PARSED = [ pathWithoutLast: ["!"], pathLast: "b", generics: [], + typeFilter: -1, }], foundElems: 1, original: "!::b", returned: [], - typeFilter: -1, userQuery: "!::b", error: null, }, @@ -90,7 +89,6 @@ const PARSED = [ foundElems: 0, original: "a!::b!", returned: [], - typeFilter: -1, userQuery: "a!::b!", error: "Cannot have associated items in macros", }, diff --git a/tests/rustdoc-js-std/parser-literal.js b/tests/rustdoc-js-std/parser-literal.js index 87b3baff1e2..3a31d1bddff 100644 --- a/tests/rustdoc-js-std/parser-literal.js +++ b/tests/rustdoc-js-std/parser-literal.js @@ -16,11 +16,11 @@ const PARSED = [ generics: [], }, ], + typeFilter: -1, }], foundElems: 1, original: "R<P>", returned: [], - typeFilter: -1, userQuery: "r<p>", error: null, } diff --git a/tests/rustdoc-js-std/parser-paths.js b/tests/rustdoc-js-std/parser-paths.js index 9f823f9336a..f3e421f5ffa 100644 --- a/tests/rustdoc-js-std/parser-paths.js +++ b/tests/rustdoc-js-std/parser-paths.js @@ -8,11 +8,11 @@ const PARSED = [ pathWithoutLast: ["a"], pathLast: "b", generics: [], + typeFilter: -1, }], foundElems: 1, original: "A::B", returned: [], - typeFilter: -1, userQuery: "a::b", error: null, }, @@ -24,6 +24,7 @@ const PARSED = [ pathWithoutLast: ["a"], pathLast: "b", generics: [], + typeFilter: -1, }, { name: "c", @@ -31,12 +32,12 @@ const PARSED = [ pathWithoutLast: [], pathLast: "c", generics: [], + typeFilter: -1, }, ], foundElems: 2, original: 'A::B,C', returned: [], - typeFilter: -1, userQuery: 'a::b,c', error: null, }, @@ -56,6 +57,7 @@ const PARSED = [ generics: [], }, ], + typeFilter: -1, }, { name: "c", @@ -63,12 +65,12 @@ const PARSED = [ pathWithoutLast: [], pathLast: "c", generics: [], + typeFilter: -1, }, ], foundElems: 2, original: 'A::B<f>,C', returned: [], - typeFilter: -1, userQuery: 'a::b<f>,c', error: null, }, @@ -79,11 +81,11 @@ const PARSED = [ pathWithoutLast: ["mod"], pathLast: "a", generics: [], + typeFilter: -1, }], foundElems: 1, original: "mod::a", returned: [], - typeFilter: -1, userQuery: "mod::a", error: null, }, diff --git a/tests/rustdoc-js-std/parser-quote.js b/tests/rustdoc-js-std/parser-quote.js index 1e16c90de5e..d5d67cac892 100644 --- a/tests/rustdoc-js-std/parser-quote.js +++ b/tests/rustdoc-js-std/parser-quote.js @@ -19,8 +19,8 @@ const PARSED = [ pathWithoutLast: [], pathLast: "p", generics: [], + typeFilter: -1, }], - typeFilter: -1, userQuery: '-> "p"', error: null, }, @@ -31,11 +31,11 @@ const PARSED = [ pathWithoutLast: [], pathLast: "p", generics: [], + typeFilter: -1, }], foundElems: 1, original: '"p",', returned: [], - typeFilter: -1, userQuery: '"p",', error: null, }, @@ -44,7 +44,6 @@ const PARSED = [ foundElems: 0, original: '"p" -> a', returned: [], - typeFilter: -1, userQuery: '"p" -> a', error: "You cannot have more than one element if you use quotes", }, @@ -53,7 +52,6 @@ const PARSED = [ foundElems: 0, original: '"a" -> "p"', returned: [], - typeFilter: -1, userQuery: '"a" -> "p"', error: "Cannot have more than one literal search element", }, @@ -62,7 +60,6 @@ const PARSED = [ foundElems: 0, original: '->"-"', returned: [], - typeFilter: -1, userQuery: '->"-"', error: 'Unexpected `-` in a string element', }, @@ -71,7 +68,6 @@ const PARSED = [ foundElems: 0, original: '"a', returned: [], - typeFilter: -1, userQuery: '"a', error: 'Unclosed `"`', }, @@ -80,7 +76,6 @@ const PARSED = [ foundElems: 0, original: '""', returned: [], - typeFilter: -1, userQuery: '""', error: 'Cannot have empty string element', }, diff --git a/tests/rustdoc-js-std/parser-returned.js b/tests/rustdoc-js-std/parser-returned.js index 6fce17dcabd..c2981319055 100644 --- a/tests/rustdoc-js-std/parser-returned.js +++ b/tests/rustdoc-js-std/parser-returned.js @@ -25,8 +25,8 @@ const PARSED = [ generics: [], }, ], + typeFilter: -1, }], - typeFilter: -1, userQuery: "-> f<p>", error: null, }, @@ -40,8 +40,8 @@ const PARSED = [ pathWithoutLast: [], pathLast: "p", generics: [], + typeFilter: -1, }], - typeFilter: -1, userQuery: "-> p", error: null, }, @@ -55,8 +55,8 @@ const PARSED = [ pathWithoutLast: [], pathLast: "a", generics: [], + typeFilter: -1, }], - typeFilter: -1, userQuery: "->,a", error: null, }, @@ -67,6 +67,7 @@ const PARSED = [ pathWithoutLast: [], pathLast: "aaaaa", generics: [], + typeFilter: -1, }], foundElems: 2, original: "aaaaa->a", @@ -76,8 +77,8 @@ const PARSED = [ pathWithoutLast: [], pathLast: "a", generics: [], + typeFilter: -1, }], - typeFilter: -1, userQuery: "aaaaa->a", error: null, }, @@ -91,8 +92,8 @@ const PARSED = [ pathWithoutLast: [], pathLast: "!", generics: [], + typeFilter: -1, }], - typeFilter: -1, userQuery: "-> !", error: null, }, diff --git a/tests/rustdoc-js-std/parser-separators.js b/tests/rustdoc-js-std/parser-separators.js index 5b7abdfa8d6..fc8c5114c4e 100644 --- a/tests/rustdoc-js-std/parser-separators.js +++ b/tests/rustdoc-js-std/parser-separators.js @@ -19,6 +19,7 @@ const PARSED = [ pathWithoutLast: [], pathLast: 'aaaaaa', generics: [], + typeFilter: -1, }, { name: 'b', @@ -26,12 +27,12 @@ const PARSED = [ pathWithoutLast: [], pathLast: 'b', generics: [], + typeFilter: -1, }, ], foundElems: 2, original: "aaaaaa b", returned: [], - typeFilter: -1, userQuery: "aaaaaa b", error: null, }, @@ -43,6 +44,7 @@ const PARSED = [ pathWithoutLast: [], pathLast: 'a', generics: [], + typeFilter: -1, }, { name: 'b', @@ -50,12 +52,12 @@ const PARSED = [ pathWithoutLast: [], pathLast: 'b', generics: [], + typeFilter: -1, }, ], foundElems: 2, original: "a b", returned: [], - typeFilter: -1, userQuery: "a b", error: null, }, @@ -67,6 +69,7 @@ const PARSED = [ pathWithoutLast: [], pathLast: 'a', generics: [], + typeFilter: -1, }, { name: 'b', @@ -74,12 +77,12 @@ const PARSED = [ pathWithoutLast: [], pathLast: 'b', generics: [], + typeFilter: -1, }, ], foundElems: 2, original: "a,b", returned: [], - typeFilter: -1, userQuery: "a,b", error: null, }, @@ -91,6 +94,7 @@ const PARSED = [ pathWithoutLast: [], pathLast: 'a', generics: [], + typeFilter: -1, }, { name: 'b', @@ -98,12 +102,12 @@ const PARSED = [ pathWithoutLast: [], pathLast: 'b', generics: [], + typeFilter: -1, }, ], foundElems: 2, original: "a\tb", returned: [], - typeFilter: -1, userQuery: "a\tb", error: null, }, @@ -130,12 +134,12 @@ const PARSED = [ generics: [], }, ], + typeFilter: -1, }, ], foundElems: 1, original: "a<b c>", returned: [], - typeFilter: -1, userQuery: "a<b c>", error: null, }, @@ -162,12 +166,12 @@ const PARSED = [ generics: [], }, ], + typeFilter: -1, }, ], foundElems: 1, original: "a<b,c>", returned: [], - typeFilter: -1, userQuery: "a<b,c>", error: null, }, @@ -194,12 +198,12 @@ const PARSED = [ generics: [], }, ], + typeFilter: -1, }, ], foundElems: 1, original: "a<b\tc>", returned: [], - typeFilter: -1, userQuery: "a<b\tc>", error: null, }, diff --git a/tests/rustdoc-js-std/parser-weird-queries.js b/tests/rustdoc-js-std/parser-weird-queries.js index a3d85aeca5e..dc1049a70bc 100644 --- a/tests/rustdoc-js-std/parser-weird-queries.js +++ b/tests/rustdoc-js-std/parser-weird-queries.js @@ -20,6 +20,7 @@ const PARSED = [ pathWithoutLast: [], pathLast: "a", generics: [], + typeFilter: -1, }, { name: "b", @@ -27,12 +28,12 @@ const PARSED = [ pathWithoutLast: [], pathLast: "b", generics: [], + typeFilter: -1, }, ], foundElems: 2, original: "a b", returned: [], - typeFilter: -1, userQuery: "a b", error: null, }, @@ -44,6 +45,7 @@ const PARSED = [ pathWithoutLast: [], pathLast: "a", generics: [], + typeFilter: -1, }, { name: "b", @@ -51,12 +53,12 @@ const PARSED = [ pathWithoutLast: [], pathLast: "b", generics: [], + typeFilter: -1, }, ], foundElems: 2, original: "a b", returned: [], - typeFilter: -1, userQuery: "a b", error: null, }, @@ -65,7 +67,6 @@ const PARSED = [ foundElems: 0, original: "a,b(c)", returned: [], - typeFilter: -1, userQuery: "a,b(c)", error: "Unexpected `(`", }, @@ -77,6 +78,7 @@ const PARSED = [ pathWithoutLast: [], pathLast: "aaa", generics: [], + typeFilter: -1, }, { name: "a", @@ -84,12 +86,12 @@ const PARSED = [ pathWithoutLast: [], pathLast: "a", generics: [], + typeFilter: -1, }, ], foundElems: 2, original: "aaa,a", returned: [], - typeFilter: -1, userQuery: "aaa,a", error: null, }, @@ -98,7 +100,6 @@ const PARSED = [ foundElems: 0, original: ",,,,", returned: [], - typeFilter: -1, userQuery: ",,,,", error: null, }, @@ -107,17 +108,15 @@ const PARSED = [ foundElems: 0, original: 'mod :', returned: [], - typeFilter: 0, userQuery: 'mod :', - error: null, + error: "Unexpected `:` (expected path after type filter)", }, { elems: [], foundElems: 0, original: 'mod\t:', returned: [], - typeFilter: 0, userQuery: 'mod\t:', - error: null, + error: "Unexpected `:` (expected path after type filter)", }, ]; diff --git a/tests/rustdoc-js/generics-impl.js b/tests/rustdoc-js/generics-impl.js index bb6e0041db5..5051743bda2 100644 --- a/tests/rustdoc-js/generics-impl.js +++ b/tests/rustdoc-js/generics-impl.js @@ -5,6 +5,8 @@ const QUERY = [ 'Aaaaaaa -> bool', 'Aaaaaaa -> usize', 'Read -> u64', + 'trait:Read -> u64', + 'struct:Read -> u64', 'bool -> u64', 'Ddddddd -> u64', '-> Ddddddd' @@ -37,6 +39,17 @@ const EXPECTED = [ ], }, { + // trait:Read -> u64 + 'others': [ + { 'path': 'generics_impl::Ddddddd', 'name': 'eeeeeee' }, + { 'path': 'generics_impl::Ddddddd', 'name': 'ggggggg' }, + ], + }, + { + // struct:Read -> u64 + 'others': [], + }, + { // bool -> u64 'others': [ { 'path': 'generics_impl::Ddddddd', 'name': 'fffffff' }, diff --git a/tests/rustdoc-js/generics.js b/tests/rustdoc-js/generics.js index 5e5ba7cd9ac..f79c709ad6c 100644 --- a/tests/rustdoc-js/generics.js +++ b/tests/rustdoc-js/generics.js @@ -2,6 +2,8 @@ const QUERY = [ 'R<P>', + 'R<struct:P>', + 'R<enum:P>', '"P"', 'P', 'ExtraCreditStructMulti<ExtraCreditInnerMulti, ExtraCreditInnerMulti>', @@ -21,6 +23,20 @@ const EXPECTED = [ ], }, { + // R<struct:P> + 'returned': [ + { 'path': 'generics', 'name': 'alef' }, + ], + 'in_args': [ + { 'path': 'generics', 'name': 'alpha' }, + ], + }, + { + // R<enum:P> + 'returned': [], + 'in_args': [], + }, + { // "P" 'others': [ { 'path': 'generics', 'name': 'P' }, diff --git a/tests/rustdoc-js/primitive.js b/tests/rustdoc-js/primitive.js index 918f7099918..4aec98c3403 100644 --- a/tests/rustdoc-js/primitive.js +++ b/tests/rustdoc-js/primitive.js @@ -3,6 +3,8 @@ const QUERY = [ "i32", "str", + "primitive:str", + "struct:str", "TotoIsSomewhere", ]; @@ -18,6 +20,14 @@ const EXPECTED = [ ], }, { + 'returned': [ + { 'path': 'primitive', 'name': 'foo' }, + ], + }, + { + 'returned': [], + }, + { 'others': [], 'in_args': [], 'returned': [], diff --git a/tests/rustdoc-ui/intra-doc/auxiliary/inner-crate-doc.rs b/tests/rustdoc-ui/intra-doc/auxiliary/inner-crate-doc.rs new file mode 100644 index 00000000000..15bf51e6f8e --- /dev/null +++ b/tests/rustdoc-ui/intra-doc/auxiliary/inner-crate-doc.rs @@ -0,0 +1 @@ +//! Inner doc comment diff --git a/tests/rustdoc-ui/intra-doc/import-inline-merge-module.rs b/tests/rustdoc-ui/intra-doc/import-inline-merge-module.rs new file mode 100644 index 00000000000..4d6a3256645 --- /dev/null +++ b/tests/rustdoc-ui/intra-doc/import-inline-merge-module.rs @@ -0,0 +1,10 @@ +// Test for issue #108501. +// Module parent scope doesn't hijack import's parent scope for the import's doc links. + +// check-pass +// aux-build: inner-crate-doc.rs +// compile-flags: --extern inner_crate_doc --edition 2018 + +/// Import doc comment [inner_crate_doc] +#[doc(inline)] +pub use inner_crate_doc; diff --git a/tests/rustdoc-ui/z-help.stdout b/tests/rustdoc-ui/z-help.stdout index 5ad38e4fd98..72f5f933d8d 100644 --- a/tests/rustdoc-ui/z-help.stdout +++ b/tests/rustdoc-ui/z-help.stdout @@ -183,6 +183,7 @@ -Z threads=val -- use a thread pool with N threads -Z time-llvm-passes=val -- measure time of each LLVM pass (default: no) -Z time-passes=val -- measure time of each rustc pass (default: no) + -Z time-passes-format=val -- the format to use for -Z time-passes (`text` (default) or `json`) -Z tiny-const-eval-limit=val -- sets a tiny, non-configurable limit for const eval; useful for compiler tests -Z tls-model=val -- choose the TLS model to use (`rustc --print tls-models` for details) -Z trace-macros=val -- for every macro invocation, print its name and arguments (default: no) diff --git a/tests/rustdoc/doc-notable_trait-mut_t_is_not_an_iterator.rs b/tests/rustdoc/notable-trait/doc-notable_trait-mut_t_is_not_an_iterator.rs index bfce46cf444..bfce46cf444 100644 --- a/tests/rustdoc/doc-notable_trait-mut_t_is_not_an_iterator.rs +++ b/tests/rustdoc/notable-trait/doc-notable_trait-mut_t_is_not_an_iterator.rs diff --git a/tests/rustdoc/doc-notable_trait-mut_t_is_not_ref_t.rs b/tests/rustdoc/notable-trait/doc-notable_trait-mut_t_is_not_ref_t.rs index b359dcea0ff..b359dcea0ff 100644 --- a/tests/rustdoc/doc-notable_trait-mut_t_is_not_ref_t.rs +++ b/tests/rustdoc/notable-trait/doc-notable_trait-mut_t_is_not_ref_t.rs diff --git a/tests/rustdoc/doc-notable_trait-slice.bare_fn_matches.html b/tests/rustdoc/notable-trait/doc-notable_trait-slice.bare_fn_matches.html index 46be00a0804..46be00a0804 100644 --- a/tests/rustdoc/doc-notable_trait-slice.bare_fn_matches.html +++ b/tests/rustdoc/notable-trait/doc-notable_trait-slice.bare_fn_matches.html diff --git a/tests/rustdoc/doc-notable_trait-slice.rs b/tests/rustdoc/notable-trait/doc-notable_trait-slice.rs index 2411da8cd45..ef206710b4b 100644 --- a/tests/rustdoc/doc-notable_trait-slice.rs +++ b/tests/rustdoc/notable-trait/doc-notable_trait-slice.rs @@ -18,3 +18,9 @@ pub fn bare_fn_matches() -> &'static [SomeStruct] { pub fn bare_fn_no_matches() -> &'static [OtherStruct] { &[] } + +// @has doc_notable_trait_slice/fn.bare_fn_mut_no_matches.html +// @count - '//script[@id="notable-traits-data"]' 0 +pub fn bare_fn_mut_no_matches() -> &'static mut [SomeStruct] { + &mut [] +} diff --git a/tests/rustdoc/doc-notable_trait.bare-fn.html b/tests/rustdoc/notable-trait/doc-notable_trait.bare-fn.html index f592e3b375c..f592e3b375c 100644 --- a/tests/rustdoc/doc-notable_trait.bare-fn.html +++ b/tests/rustdoc/notable-trait/doc-notable_trait.bare-fn.html diff --git a/tests/rustdoc/doc-notable_trait.rs b/tests/rustdoc/notable-trait/doc-notable_trait.rs index d8941769fa6..d8941769fa6 100644 --- a/tests/rustdoc/doc-notable_trait.rs +++ b/tests/rustdoc/notable-trait/doc-notable_trait.rs diff --git a/tests/rustdoc/doc-notable_trait.some-struct-new.html b/tests/rustdoc/notable-trait/doc-notable_trait.some-struct-new.html index e8f4f600045..e8f4f600045 100644 --- a/tests/rustdoc/doc-notable_trait.some-struct-new.html +++ b/tests/rustdoc/notable-trait/doc-notable_trait.some-struct-new.html diff --git a/tests/rustdoc/doc-notable_trait.wrap-me.html b/tests/rustdoc/notable-trait/doc-notable_trait.wrap-me.html index e7909669b15..e7909669b15 100644 --- a/tests/rustdoc/doc-notable_trait.wrap-me.html +++ b/tests/rustdoc/notable-trait/doc-notable_trait.wrap-me.html diff --git a/tests/rustdoc/doc-notable_trait_box_is_not_an_iterator.rs b/tests/rustdoc/notable-trait/doc-notable_trait_box_is_not_an_iterator.rs index 3fb00c7db84..3fb00c7db84 100644 --- a/tests/rustdoc/doc-notable_trait_box_is_not_an_iterator.rs +++ b/tests/rustdoc/notable-trait/doc-notable_trait_box_is_not_an_iterator.rs diff --git a/tests/rustdoc/notable-trait/notable-trait-generics.rs b/tests/rustdoc/notable-trait/notable-trait-generics.rs new file mode 100644 index 00000000000..611902abad6 --- /dev/null +++ b/tests/rustdoc/notable-trait/notable-trait-generics.rs @@ -0,0 +1,35 @@ +#![feature(doc_notable_trait)] + +// Notable traits SHOULD NOT be shown when the `impl` has a concrete type and +// the return type has a generic type. +pub mod generic_return { + pub struct Wrapper<T>(T); + + #[doc(notable_trait)] + pub trait NotableTrait {} + + impl NotableTrait for Wrapper<u8> {} + + // @has notable_trait_generics/generic_return/fn.returning.html + // @!has - '//a[@class="tooltip"]/@data-notable-ty' 'Wrapper<T>' + pub fn returning<T>() -> Wrapper<T> { + loop {} + } +} + +// Notable traits SHOULD be shown when the `impl` has a generic type and the +// return type has a concrete type. +pub mod generic_impl { + pub struct Wrapper<T>(T); + + #[doc(notable_trait)] + pub trait NotableTrait {} + + impl<T> NotableTrait for Wrapper<T> {} + + // @has notable_trait_generics/generic_impl/fn.returning.html + // @has - '//a[@class="tooltip"]/@data-notable-ty' 'Wrapper<u8>' + pub fn returning() -> Wrapper<u8> { + loop {} + } +} diff --git a/tests/rustdoc/spotlight-from-dependency.odd.html b/tests/rustdoc/notable-trait/spotlight-from-dependency.odd.html index 5f54b7522ae..5f54b7522ae 100644 --- a/tests/rustdoc/spotlight-from-dependency.odd.html +++ b/tests/rustdoc/notable-trait/spotlight-from-dependency.odd.html diff --git a/tests/rustdoc/spotlight-from-dependency.rs b/tests/rustdoc/notable-trait/spotlight-from-dependency.rs index 426759c7bf8..426759c7bf8 100644 --- a/tests/rustdoc/spotlight-from-dependency.rs +++ b/tests/rustdoc/notable-trait/spotlight-from-dependency.rs diff --git a/tests/ui-fulldeps/auxiliary/lint-for-crate-rpass.rs b/tests/ui-fulldeps/auxiliary/lint-for-crate-rpass.rs deleted file mode 100644 index a3b570ad8c4..00000000000 --- a/tests/ui-fulldeps/auxiliary/lint-for-crate-rpass.rs +++ /dev/null @@ -1,80 +0,0 @@ -// force-host - -#![feature(rustc_private)] - -extern crate rustc_driver; -extern crate rustc_hir; -extern crate rustc_lint; -extern crate rustc_span; -#[macro_use] -extern crate rustc_session; -extern crate rustc_ast; - -use rustc_ast::attr; -use rustc_driver::plugin::Registry; -use rustc_lint::{LateContext, LateLintPass, LintContext, LintPass}; -use rustc_span::def_id::CRATE_DEF_ID; -use rustc_span::symbol::Symbol; - -macro_rules! fake_lint_pass { - ($struct:ident, $($attr:expr),*) => { - struct $struct; - - impl LintPass for $struct { - fn name(&self) -> &'static str { - stringify!($struct) - } - } - - impl LateLintPass<'_> for $struct { - fn check_crate(&mut self, cx: &LateContext) { - let attrs = cx.tcx.hir().attrs(rustc_hir::CRATE_HIR_ID); - let span = cx.tcx.def_span(CRATE_DEF_ID); - $( - if !cx.sess().contains_name(attrs, $attr) { - cx.lint(CRATE_NOT_OKAY, |lint| { - let msg = format!("crate is not marked with #![{}]", $attr); - lint.build(&msg).set_span(span).emit(); - }); - } - )* - } - } - - } -} - -declare_lint!(CRATE_NOT_OKAY, Warn, "crate not marked with #![crate_okay]"); -declare_lint!(CRATE_NOT_RED, Warn, "crate not marked with #![crate_red]"); -declare_lint!(CRATE_NOT_BLUE, Warn, "crate not marked with #![crate_blue]"); -declare_lint!(CRATE_NOT_GREY, Warn, "crate not marked with #![crate_grey]"); -declare_lint!(CRATE_NOT_GREEN, Warn, "crate not marked with #![crate_green]"); - -fake_lint_pass! { - PassOkay, - Symbol::intern("crate_okay") -} - -fake_lint_pass! { - PassRedBlue, - Symbol::intern("crate_red"), Symbol::intern("crate_blue") -} - -fake_lint_pass! { - PassGreyGreen, - Symbol::intern("crate_grey"), Symbol::intern("crate_green") -} - -#[no_mangle] -fn __rustc_plugin_registrar(reg: &mut Registry) { - reg.lint_store.register_lints(&[ - &CRATE_NOT_OKAY, - &CRATE_NOT_RED, - &CRATE_NOT_BLUE, - &CRATE_NOT_GREY, - &CRATE_NOT_GREEN, - ]); - reg.lint_store.register_late_pass(|_| Box::new(PassOkay)); - reg.lint_store.register_late_pass(|_| Box::new(PassRedBlue)); - reg.lint_store.register_late_pass(|_| Box::new(PassGreyGreen)); -} diff --git a/tests/ui-fulldeps/auxiliary/lint-for-crate.rs b/tests/ui-fulldeps/auxiliary/lint-for-crate.rs index 073da688c7c..6304c07d2c7 100644 --- a/tests/ui-fulldeps/auxiliary/lint-for-crate.rs +++ b/tests/ui-fulldeps/auxiliary/lint-for-crate.rs @@ -4,13 +4,13 @@ extern crate rustc_driver; extern crate rustc_hir; -#[macro_use] extern crate rustc_lint; #[macro_use] extern crate rustc_session; extern crate rustc_ast; extern crate rustc_span; +use rustc_ast::attr; use rustc_driver::plugin::Registry; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_span::def_id::CRATE_DEF_ID; @@ -28,12 +28,10 @@ impl<'tcx> LateLintPass<'tcx> for Pass { fn check_crate(&mut self, cx: &LateContext) { let attrs = cx.tcx.hir().attrs(rustc_hir::CRATE_HIR_ID); let span = cx.tcx.def_span(CRATE_DEF_ID); - if !cx.sess().contains_name(attrs, Symbol::intern("crate_okay")) { - cx.lint( - CRATE_NOT_OKAY, - "crate is not marked with #![crate_okay]", - |lint| lint.set_span(span) - ); + if !attr::contains_name(attrs, Symbol::intern("crate_okay")) { + cx.lint(CRATE_NOT_OKAY, "crate is not marked with #![crate_okay]", |lint| { + lint.set_span(span) + }); } } } diff --git a/tests/ui/associated-inherent-types/issue-109299-1.rs b/tests/ui/associated-inherent-types/issue-109299-1.rs new file mode 100644 index 00000000000..6f95273116b --- /dev/null +++ b/tests/ui/associated-inherent-types/issue-109299-1.rs @@ -0,0 +1,12 @@ +#![feature(inherent_associated_types, non_lifetime_binders, type_alias_impl_trait)] +#![allow(incomplete_features)] + +struct Lexer<T>(T); + +impl Lexer<i32> { + type Cursor = (); +} + +type X = impl for<T> Fn() -> Lexer<T>::Cursor; //~ ERROR associated type `Cursor` not found for `Lexer<T>` in the current scope + +fn main() {} diff --git a/tests/ui/associated-inherent-types/issue-109299-1.stderr b/tests/ui/associated-inherent-types/issue-109299-1.stderr new file mode 100644 index 00000000000..dc59b56ee20 --- /dev/null +++ b/tests/ui/associated-inherent-types/issue-109299-1.stderr @@ -0,0 +1,15 @@ +error[E0220]: associated type `Cursor` not found for `Lexer<T>` in the current scope + --> $DIR/issue-109299-1.rs:10:40 + | +LL | struct Lexer<T>(T); + | --------------- associated item `Cursor` not found for this struct +... +LL | type X = impl for<T> Fn() -> Lexer<T>::Cursor; + | ^^^^^^ associated item not found in `Lexer<T>` + | + = note: the associated type was found for + - `Lexer<i32>` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0220`. diff --git a/tests/ui/associated-inherent-types/issue-109299.rs b/tests/ui/associated-inherent-types/issue-109299.rs new file mode 100644 index 00000000000..84e4f9e7252 --- /dev/null +++ b/tests/ui/associated-inherent-types/issue-109299.rs @@ -0,0 +1,12 @@ +#![feature(inherent_associated_types)] +#![allow(incomplete_features)] + +struct Lexer<'d>(&'d ()); + +impl Lexer<'d> { //~ ERROR use of undeclared lifetime name `'d` + type Cursor = (); +} + +fn test(_: Lexer::Cursor) {} + +fn main() {} diff --git a/tests/ui/associated-inherent-types/issue-109299.stderr b/tests/ui/associated-inherent-types/issue-109299.stderr new file mode 100644 index 00000000000..63f50732d3c --- /dev/null +++ b/tests/ui/associated-inherent-types/issue-109299.stderr @@ -0,0 +1,11 @@ +error[E0261]: use of undeclared lifetime name `'d` + --> $DIR/issue-109299.rs:6:12 + | +LL | impl Lexer<'d> { + | - ^^ undeclared lifetime + | | + | help: consider introducing lifetime `'d` here: `<'d>` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0261`. diff --git a/tests/ui/async-await/in-trait/issue-104678.rs b/tests/ui/async-await/in-trait/issue-104678.rs index e396df4e5d1..3d010f18009 100644 --- a/tests/ui/async-await/in-trait/issue-104678.rs +++ b/tests/ui/async-await/in-trait/issue-104678.rs @@ -1,5 +1,7 @@ // edition:2021 // check-pass +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// revisions: current next #![feature(async_fn_in_trait)] #![allow(incomplete_features)] diff --git a/tests/ui/cfg/auxiliary/cfg_false_lib.rs b/tests/ui/cfg/auxiliary/cfg_false_lib.rs new file mode 100644 index 00000000000..3c011d72b02 --- /dev/null +++ b/tests/ui/cfg/auxiliary/cfg_false_lib.rs @@ -0,0 +1,6 @@ +// It is unclear whether a fully unconfigured crate should link to standard library, +// or what its `no_std`/`no_core`/`compiler_builtins` status, more precisely. +// Currently the usual standard library prelude is added to such crates, +// and therefore they link to libstd. + +#![cfg(FALSE)] diff --git a/tests/ui/cfg/cfg-false-feature.rs b/tests/ui/cfg/cfg-false-feature.rs new file mode 100644 index 00000000000..21ea3ec79b4 --- /dev/null +++ b/tests/ui/cfg/cfg-false-feature.rs @@ -0,0 +1,20 @@ +// It is unclear which features should be in effect in a fully unconfigured crate (issue #104633). +// Currently none on the features are in effect, so we get the feature gates reported. + +// check-pass +// compile-flags: --crate-type lib + +#![feature(decl_macro)] +#![cfg(FALSE)] +#![feature(box_syntax)] + +macro mac() {} //~ WARN `macro` is experimental + //~| WARN unstable syntax can change at any point in the future + +trait A = Clone; //~ WARN trait aliases are experimental + //~| WARN unstable syntax can change at any point in the future + +fn main() { + let box _ = Box::new(0); //~ WARN box pattern syntax is experimental + //~| WARN unstable syntax can change at any point in the future +} diff --git a/tests/ui/cfg/cfg-false-feature.stderr b/tests/ui/cfg/cfg-false-feature.stderr new file mode 100644 index 00000000000..14673fbdb14 --- /dev/null +++ b/tests/ui/cfg/cfg-false-feature.stderr @@ -0,0 +1,35 @@ +warning: trait aliases are experimental + --> $DIR/cfg-false-feature.rs:14:1 + | +LL | trait A = Clone; + | ^^^^^^^^^^^^^^^^ + | + = note: see issue #41517 <https://github.com/rust-lang/rust/issues/41517> for more information + = help: add `#![feature(trait_alias)]` to the crate attributes to enable + = warning: unstable syntax can change at any point in the future, causing a hard error! + = note: for more information, see issue #65860 <https://github.com/rust-lang/rust/issues/65860> + +warning: `macro` is experimental + --> $DIR/cfg-false-feature.rs:11:1 + | +LL | macro mac() {} + | ^^^^^^^^^^^^^^ + | + = note: see issue #39412 <https://github.com/rust-lang/rust/issues/39412> for more information + = help: add `#![feature(decl_macro)]` to the crate attributes to enable + = warning: unstable syntax can change at any point in the future, causing a hard error! + = note: for more information, see issue #65860 <https://github.com/rust-lang/rust/issues/65860> + +warning: box pattern syntax is experimental + --> $DIR/cfg-false-feature.rs:18:9 + | +LL | let box _ = Box::new(0); + | ^^^^^ + | + = note: see issue #29641 <https://github.com/rust-lang/rust/issues/29641> for more information + = help: add `#![feature(box_patterns)]` to the crate attributes to enable + = warning: unstable syntax can change at any point in the future, causing a hard error! + = note: for more information, see issue #65860 <https://github.com/rust-lang/rust/issues/65860> + +warning: 3 warnings emitted + diff --git a/tests/ui/cfg/cfg_false_no_std.rs b/tests/ui/cfg/cfg_false_no_std.rs new file mode 100644 index 00000000000..319ea078187 --- /dev/null +++ b/tests/ui/cfg/cfg_false_no_std.rs @@ -0,0 +1,11 @@ +// Currently no error because the panic handler is supplied by libstd linked though the empty +// library, but the desirable behavior is unclear (see comments in cfg_false_lib.rs). + +// check-pass +// aux-build: cfg_false_lib.rs + +#![no_std] + +extern crate cfg_false_lib as _; + +fn main() {} diff --git a/tests/ui/closures/issue-109188.rs b/tests/ui/closures/issue-109188.rs new file mode 100644 index 00000000000..cae1ced9958 --- /dev/null +++ b/tests/ui/closures/issue-109188.rs @@ -0,0 +1,22 @@ +enum Either { + One(X), + Two(X), +} + +struct X(Y); + +struct Y; + +fn consume_fnmut(f: &dyn FnMut()) { + f(); +} + +fn move_into_fnmut() { + let x = move_into_fnmut(); + consume_fnmut(&|| { + let Either::One(_t) = x; //~ ERROR mismatched types + let Either::Two(_t) = x; //~ ERROR mismatched types + }); +} + +fn main() { } diff --git a/tests/ui/closures/issue-109188.stderr b/tests/ui/closures/issue-109188.stderr new file mode 100644 index 00000000000..d52b516294f --- /dev/null +++ b/tests/ui/closures/issue-109188.stderr @@ -0,0 +1,19 @@ +error[E0308]: mismatched types + --> $DIR/issue-109188.rs:17:13 + | +LL | let Either::One(_t) = x; + | ^^^^^^^^^^^^^^^ - this expression has type `()` + | | + | expected `()`, found `Either` + +error[E0308]: mismatched types + --> $DIR/issue-109188.rs:18:13 + | +LL | let Either::Two(_t) = x; + | ^^^^^^^^^^^^^^^ - this expression has type `()` + | | + | expected `()`, found `Either` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/const-generics/generic_const_exprs/cross_crate_predicate.stderr b/tests/ui/const-generics/generic_const_exprs/cross_crate_predicate.stderr index 7b4d46b8209..6b3396a25cf 100644 --- a/tests/ui/const-generics/generic_const_exprs/cross_crate_predicate.stderr +++ b/tests/ui/const-generics/generic_const_exprs/cross_crate_predicate.stderr @@ -1,8 +1,8 @@ error: unconstrained generic constant - --> $DIR/cross_crate_predicate.rs:7:13 + --> $DIR/cross_crate_predicate.rs:7:44 | LL | let _ = const_evaluatable_lib::test1::<T>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^ | = help: try adding a `where` bound using this expression: `where [(); std::mem::size_of::<T>() - 1]:` note: required by a bound in `test1` @@ -12,10 +12,10 @@ LL | [u8; std::mem::size_of::<T>() - 1]: Sized, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `test1` error: unconstrained generic constant - --> $DIR/cross_crate_predicate.rs:7:13 + --> $DIR/cross_crate_predicate.rs:7:44 | LL | let _ = const_evaluatable_lib::test1::<T>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^ | = help: try adding a `where` bound using this expression: `where [(); std::mem::size_of::<T>() - 1]:` note: required by a bound in `test1` diff --git a/tests/ui/const-generics/generic_const_exprs/typeid-equality-by-subtyping.rs b/tests/ui/const-generics/generic_const_exprs/typeid-equality-by-subtyping.rs new file mode 100644 index 00000000000..64317b9d39a --- /dev/null +++ b/tests/ui/const-generics/generic_const_exprs/typeid-equality-by-subtyping.rs @@ -0,0 +1,52 @@ +// check-pass +// known-bug: #97156 + +#![feature(const_type_id, generic_const_exprs)] +#![allow(incomplete_features)] + +use std::any::TypeId; +// `One` and `Two` are currently considered equal types, as both +// `One <: Two` and `One :> Two` holds. +type One = for<'a> fn(&'a (), &'a ()); +type Two = for<'a, 'b> fn(&'a (), &'b ()); +trait AssocCt { + const ASSOC: usize; +} +const fn to_usize<T: 'static>() -> usize { + const WHAT_A_TYPE: TypeId = TypeId::of::<One>(); + match TypeId::of::<T>() { + WHAT_A_TYPE => 0, + _ => 1000, + } +} +impl<T: 'static> AssocCt for T { + const ASSOC: usize = to_usize::<T>(); +} + +trait WithAssoc<U> { + type Assoc; +} +impl<T: 'static> WithAssoc<()> for T where [(); <T as AssocCt>::ASSOC]: { + type Assoc = [u8; <T as AssocCt>::ASSOC]; +} + +fn generic<T: 'static, U>(x: <T as WithAssoc<U>>::Assoc) -> <T as WithAssoc<U>>::Assoc +where + [(); <T as AssocCt>::ASSOC]:, + T: WithAssoc<U>, +{ + x +} + + +fn unsound<T>(x: <One as WithAssoc<T>>::Assoc) -> <Two as WithAssoc<T>>::Assoc +where + One: WithAssoc<T>, +{ + let x: <Two as WithAssoc<T>>::Assoc = generic::<One, T>(x); + x +} + +fn main() { + println!("{:?}", unsound::<()>([])); +} diff --git a/tests/ui/const-generics/type_mismatch.stderr b/tests/ui/const-generics/type_mismatch.stderr index 6d8955e411e..394dd44d40d 100644 --- a/tests/ui/const-generics/type_mismatch.stderr +++ b/tests/ui/const-generics/type_mismatch.stderr @@ -1,8 +1,8 @@ error: the constant `N` is not of type `u8` - --> $DIR/type_mismatch.rs:2:5 + --> $DIR/type_mismatch.rs:2:11 | LL | bar::<N>() - | ^^^^^^^^ + | ^ expected `u8`, found `usize` | note: required by a bound in `bar` --> $DIR/type_mismatch.rs:6:8 diff --git a/tests/ui/consts/const-eval/panic-assoc-never-type.rs b/tests/ui/consts/const-eval/panic-assoc-never-type.rs index 28edf514402..1abe708d19e 100644 --- a/tests/ui/consts/const-eval/panic-assoc-never-type.rs +++ b/tests/ui/consts/const-eval/panic-assoc-never-type.rs @@ -11,5 +11,5 @@ impl PrintName { } fn main() { - let _ = PrintName::VOID; //~ constant + let _ = PrintName::VOID; //~ erroneous constant used } diff --git a/tests/ui/consts/const-eval/transmute-size-mismatch.rs b/tests/ui/consts/const-eval/transmute-size-mismatch.rs new file mode 100644 index 00000000000..2410baea28c --- /dev/null +++ b/tests/ui/consts/const-eval/transmute-size-mismatch.rs @@ -0,0 +1,24 @@ +#![feature(core_intrinsics)] +#![feature(custom_mir)] + +// These cases are statically rejected by `mem::transmute`, so we need custom +// MIR to be able to get to constant evaluation. +use std::intrinsics::mir::*; + +#[custom_mir(dialect = "runtime", phase = "initial")] +const unsafe fn mir_transmute<T, U>(x: T) -> U { + mir!{ + { + RET = CastTransmute(x); + //~^ ERROR evaluation of constant value failed + //~| ERROR evaluation of constant value failed + Return() + } + } +} + +const FROM_BIGGER: u16 = unsafe { mir_transmute(123_i32) }; + +const FROM_SMALLER: u32 = unsafe { mir_transmute(123_i16) }; + +fn main() {} diff --git a/tests/ui/consts/const-eval/transmute-size-mismatch.stderr b/tests/ui/consts/const-eval/transmute-size-mismatch.stderr new file mode 100644 index 00000000000..e051491d343 --- /dev/null +++ b/tests/ui/consts/const-eval/transmute-size-mismatch.stderr @@ -0,0 +1,37 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/transmute-size-mismatch.rs:12:13 + | +LL | RET = CastTransmute(x); + | ^^^^^^^^^^^^^^^^^^^^^^ transmuting from 4-byte type to 2-byte type: `i32` -> `u16` + | +note: inside `mir_transmute::<i32, u16>` + --> $DIR/transmute-size-mismatch.rs:12:13 + | +LL | RET = CastTransmute(x); + | ^^^^^^^^^^^^^^^^^^^^^^ +note: inside `FROM_BIGGER` + --> $DIR/transmute-size-mismatch.rs:20:35 + | +LL | const FROM_BIGGER: u16 = unsafe { mir_transmute(123_i32) }; + | ^^^^^^^^^^^^^^^^^^^^^^ + +error[E0080]: evaluation of constant value failed + --> $DIR/transmute-size-mismatch.rs:12:13 + | +LL | RET = CastTransmute(x); + | ^^^^^^^^^^^^^^^^^^^^^^ transmuting from 2-byte type to 4-byte type: `i16` -> `u32` + | +note: inside `mir_transmute::<i16, u32>` + --> $DIR/transmute-size-mismatch.rs:12:13 + | +LL | RET = CastTransmute(x); + | ^^^^^^^^^^^^^^^^^^^^^^ +note: inside `FROM_SMALLER` + --> $DIR/transmute-size-mismatch.rs:22:36 + | +LL | const FROM_SMALLER: u32 = unsafe { mir_transmute(123_i16) }; + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/ub-enum.32bit.stderr b/tests/ui/consts/const-eval/ub-enum.32bit.stderr index 2d86bd88f1c..3ad1ac974c8 100644 --- a/tests/ui/consts/const-eval/ub-enum.32bit.stderr +++ b/tests/ui/consts/const-eval/ub-enum.32bit.stderr @@ -108,13 +108,13 @@ error[E0080]: evaluation of constant value failed --> $DIR/ub-enum.rs:96:77 | LL | const BAD_UNINHABITED_WITH_DATA1: Result<(i32, Never), (i32, !)> = unsafe { mem::transmute(0u64) }; - | ^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type + | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-variant(Ok)>.0.1: encountered a value of uninhabited type Never error[E0080]: evaluation of constant value failed --> $DIR/ub-enum.rs:98:77 | LL | const BAD_UNINHABITED_WITH_DATA2: Result<(i32, !), (i32, Never)> = unsafe { mem::transmute(0u64) }; - | ^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type + | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-variant(Ok)>.0.1: encountered a value of the never type `!` error: aborting due to 13 previous errors diff --git a/tests/ui/consts/const-eval/ub-enum.64bit.stderr b/tests/ui/consts/const-eval/ub-enum.64bit.stderr index a89d7ec5f6d..a66706d1af9 100644 --- a/tests/ui/consts/const-eval/ub-enum.64bit.stderr +++ b/tests/ui/consts/const-eval/ub-enum.64bit.stderr @@ -108,13 +108,13 @@ error[E0080]: evaluation of constant value failed --> $DIR/ub-enum.rs:96:77 | LL | const BAD_UNINHABITED_WITH_DATA1: Result<(i32, Never), (i32, !)> = unsafe { mem::transmute(0u64) }; - | ^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type + | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-variant(Ok)>.0.1: encountered a value of uninhabited type Never error[E0080]: evaluation of constant value failed --> $DIR/ub-enum.rs:98:77 | LL | const BAD_UNINHABITED_WITH_DATA2: Result<(i32, !), (i32, Never)> = unsafe { mem::transmute(0u64) }; - | ^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type + | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-variant(Ok)>.0.1: encountered a value of the never type `!` error: aborting due to 13 previous errors diff --git a/tests/ui/consts/const-eval/ub-uninhabit.rs b/tests/ui/consts/const-eval/ub-uninhabit.rs index 4c4ef216d86..10edae437ee 100644 --- a/tests/ui/consts/const-eval/ub-uninhabit.rs +++ b/tests/ui/consts/const-eval/ub-uninhabit.rs @@ -14,12 +14,12 @@ union MaybeUninit<T: Copy> { } const BAD_BAD_BAD: Bar = unsafe { MaybeUninit { uninit: () }.init }; -//~^ ERROR it is undefined behavior to use this value +//~^ ERROR evaluation of constant value failed const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) }; //~^ ERROR it is undefined behavior to use this value const BAD_BAD_ARRAY: [Bar; 1] = unsafe { MaybeUninit { uninit: () }.init }; -//~^ ERROR it is undefined behavior to use this value +//~^ ERROR evaluation of constant value failed fn main() {} diff --git a/tests/ui/consts/const-eval/ub-uninhabit.stderr b/tests/ui/consts/const-eval/ub-uninhabit.stderr index 0ae376d03fc..733975fc0e9 100644 --- a/tests/ui/consts/const-eval/ub-uninhabit.stderr +++ b/tests/ui/consts/const-eval/ub-uninhabit.stderr @@ -1,11 +1,8 @@ -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-uninhabit.rs:16:1 +error[E0080]: evaluation of constant value failed + --> $DIR/ub-uninhabit.rs:16:35 | LL | const BAD_BAD_BAD: Bar = unsafe { MaybeUninit { uninit: () }.init }; - | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a value of uninhabited type Bar - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a value of uninhabited type Bar error[E0080]: it is undefined behavior to use this value --> $DIR/ub-uninhabit.rs:19:1 @@ -18,14 +15,11 @@ LL | const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) }; HEX_DUMP } -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-uninhabit.rs:22:1 +error[E0080]: evaluation of constant value failed + --> $DIR/ub-uninhabit.rs:22:42 | LL | const BAD_BAD_ARRAY: [Bar; 1] = unsafe { MaybeUninit { uninit: () }.init }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at [0]: encountered a value of uninhabited type Bar - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at [0]: encountered a value of uninhabited type Bar error: aborting due to 3 previous errors diff --git a/tests/ui/consts/const-eval/validate_uninhabited_zsts.32bit.stderr b/tests/ui/consts/const-eval/validate_uninhabited_zsts.32bit.stderr index 69fb1a59d4f..74bc6317c80 100644 --- a/tests/ui/consts/const-eval/validate_uninhabited_zsts.32bit.stderr +++ b/tests/ui/consts/const-eval/validate_uninhabited_zsts.32bit.stderr @@ -11,7 +11,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/validate_uninhabited_zsts.rs:4:14 | LL | unsafe { std::mem::transmute(()) } - | ^^^^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type + | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a value of the never type `!` | note: inside `foo` --> $DIR/validate_uninhabited_zsts.rs:4:14 @@ -24,14 +24,11 @@ note: inside `FOO` LL | const FOO: [empty::Empty; 3] = [foo(); 3]; | ^^^^^ -error[E0080]: it is undefined behavior to use this value - --> $DIR/validate_uninhabited_zsts.rs:21:1 +error[E0080]: evaluation of constant value failed + --> $DIR/validate_uninhabited_zsts.rs:21:42 | LL | const BAR: [empty::Empty; 3] = [unsafe { std::mem::transmute(()) }; 3]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at [0].0: encountered a value of uninhabited type empty::Void - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - = note: the raw bytes of the constant (size: 0, align: 1) {} + | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered a value of uninhabited type empty::Void warning: the type `empty::Empty` does not permit zero-initialization --> $DIR/validate_uninhabited_zsts.rs:21:42 diff --git a/tests/ui/consts/const-eval/validate_uninhabited_zsts.64bit.stderr b/tests/ui/consts/const-eval/validate_uninhabited_zsts.64bit.stderr index 69fb1a59d4f..74bc6317c80 100644 --- a/tests/ui/consts/const-eval/validate_uninhabited_zsts.64bit.stderr +++ b/tests/ui/consts/const-eval/validate_uninhabited_zsts.64bit.stderr @@ -11,7 +11,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/validate_uninhabited_zsts.rs:4:14 | LL | unsafe { std::mem::transmute(()) } - | ^^^^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type + | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a value of the never type `!` | note: inside `foo` --> $DIR/validate_uninhabited_zsts.rs:4:14 @@ -24,14 +24,11 @@ note: inside `FOO` LL | const FOO: [empty::Empty; 3] = [foo(); 3]; | ^^^^^ -error[E0080]: it is undefined behavior to use this value - --> $DIR/validate_uninhabited_zsts.rs:21:1 +error[E0080]: evaluation of constant value failed + --> $DIR/validate_uninhabited_zsts.rs:21:42 | LL | const BAR: [empty::Empty; 3] = [unsafe { std::mem::transmute(()) }; 3]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at [0].0: encountered a value of uninhabited type empty::Void - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - = note: the raw bytes of the constant (size: 0, align: 1) {} + | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered a value of uninhabited type empty::Void warning: the type `empty::Empty` does not permit zero-initialization --> $DIR/validate_uninhabited_zsts.rs:21:42 diff --git a/tests/ui/consts/const-eval/validate_uninhabited_zsts.rs b/tests/ui/consts/const-eval/validate_uninhabited_zsts.rs index c0b32621505..b6783175dd3 100644 --- a/tests/ui/consts/const-eval/validate_uninhabited_zsts.rs +++ b/tests/ui/consts/const-eval/validate_uninhabited_zsts.rs @@ -19,7 +19,7 @@ pub mod empty { const FOO: [empty::Empty; 3] = [foo(); 3]; const BAR: [empty::Empty; 3] = [unsafe { std::mem::transmute(()) }; 3]; -//~^ ERROR it is undefined behavior to use this value +//~^ ERROR evaluation of constant value failed //~| WARN the type `empty::Empty` does not permit zero-initialization fn main() { diff --git a/tests/ui/consts/issue-64506.rs b/tests/ui/consts/issue-64506.rs index db3e85a7bdf..9275a8a072d 100644 --- a/tests/ui/consts/issue-64506.rs +++ b/tests/ui/consts/issue-64506.rs @@ -1,4 +1,4 @@ -// check-pass +// check-fail #[derive(Copy, Clone)] pub struct ChildStdin { @@ -14,6 +14,7 @@ const FOO: () = { b: (), } let x = unsafe { Foo { b: () }.a }; + //~^ ERROR: evaluation of constant value failed let x = &x.inner; }; diff --git a/tests/ui/consts/issue-64506.stderr b/tests/ui/consts/issue-64506.stderr new file mode 100644 index 00000000000..31a5b1df837 --- /dev/null +++ b/tests/ui/consts/issue-64506.stderr @@ -0,0 +1,9 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/issue-64506.rs:16:22 + | +LL | let x = unsafe { Foo { b: () }.a }; + | ^^^^^^^^^^^^^^^ constructing invalid value at .inner: encountered a value of uninhabited type AnonPipe + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/feature-gates/feature-gate-link_cfg.stderr b/tests/ui/feature-gates/feature-gate-link_cfg.stderr index 8f47d596521..97b6cbca412 100644 --- a/tests/ui/feature-gates/feature-gate-link_cfg.stderr +++ b/tests/ui/feature-gates/feature-gate-link_cfg.stderr @@ -4,7 +4,6 @@ error[E0658]: link cfg is unstable LL | #[link(name = "foo", cfg(foo))] | ^^^^^^^^ | - = note: see issue #37406 <https://github.com/rust-lang/rust/issues/37406> for more information = help: add `#![feature(link_cfg)]` to the crate attributes to enable error: aborting due to previous error diff --git a/tests/ui/impl-trait/in-trait/auxiliary/rpitit.rs b/tests/ui/impl-trait/in-trait/auxiliary/rpitit.rs index 74df300f85a..74f7bc603aa 100644 --- a/tests/ui/impl-trait/in-trait/auxiliary/rpitit.rs +++ b/tests/ui/impl-trait/in-trait/auxiliary/rpitit.rs @@ -1,3 +1,5 @@ +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty + #![feature(return_position_impl_trait_in_trait)] pub trait Foo { diff --git a/tests/ui/impl-trait/in-trait/dont-project-to-rpitit-with-no-value.stderr b/tests/ui/impl-trait/in-trait/dont-project-to-rpitit-with-no-value.current.stderr index d7f2e460fb0..b8a793e1a7b 100644 --- a/tests/ui/impl-trait/in-trait/dont-project-to-rpitit-with-no-value.stderr +++ b/tests/ui/impl-trait/in-trait/dont-project-to-rpitit-with-no-value.current.stderr @@ -1,5 +1,5 @@ warning: the feature `return_position_impl_trait_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/dont-project-to-rpitit-with-no-value.rs:1:12 + --> $DIR/dont-project-to-rpitit-with-no-value.rs:4:12 | LL | #![feature(return_position_impl_trait_in_trait)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | #![feature(return_position_impl_trait_in_trait)] = note: `#[warn(incomplete_features)]` on by default error[E0046]: not all trait items implemented, missing: `foo` - --> $DIR/dont-project-to-rpitit-with-no-value.rs:9:1 + --> $DIR/dont-project-to-rpitit-with-no-value.rs:12:1 | LL | fn foo(&self) -> impl Sized; | ---------------------------- `foo` from trait diff --git a/tests/ui/impl-trait/in-trait/dont-project-to-rpitit-with-no-value.next.stderr b/tests/ui/impl-trait/in-trait/dont-project-to-rpitit-with-no-value.next.stderr new file mode 100644 index 00000000000..b8a793e1a7b --- /dev/null +++ b/tests/ui/impl-trait/in-trait/dont-project-to-rpitit-with-no-value.next.stderr @@ -0,0 +1,21 @@ +warning: the feature `return_position_impl_trait_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/dont-project-to-rpitit-with-no-value.rs:4:12 + | +LL | #![feature(return_position_impl_trait_in_trait)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information + = note: `#[warn(incomplete_features)]` on by default + +error[E0046]: not all trait items implemented, missing: `foo` + --> $DIR/dont-project-to-rpitit-with-no-value.rs:12:1 + | +LL | fn foo(&self) -> impl Sized; + | ---------------------------- `foo` from trait +... +LL | impl MyTrait for i32 { + | ^^^^^^^^^^^^^^^^^^^^ missing `foo` in implementation + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0046`. diff --git a/tests/ui/impl-trait/in-trait/dont-project-to-rpitit-with-no-value.rs b/tests/ui/impl-trait/in-trait/dont-project-to-rpitit-with-no-value.rs index 746a4a929ae..8329ce1f835 100644 --- a/tests/ui/impl-trait/in-trait/dont-project-to-rpitit-with-no-value.rs +++ b/tests/ui/impl-trait/in-trait/dont-project-to-rpitit-with-no-value.rs @@ -1,3 +1,6 @@ +// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty +// revisions: current next + #![feature(return_position_impl_trait_in_trait)] //~^ WARN the feature `return_position_impl_trait_in_trait` is incomplete @@ -7,7 +10,7 @@ trait MyTrait { } impl MyTrait for i32 { -//~^ ERROR not all trait items implemented, missing: `foo` + //~^ ERROR not all trait items implemented, missing: `foo` fn bar(&self) -> impl Sized { self.foo() } diff --git a/tests/ui/impl-trait/nested-return-type2.rs b/tests/ui/impl-trait/nested-return-type2.rs index fe883ce6fc8..e1d5511379e 100644 --- a/tests/ui/impl-trait/nested-return-type2.rs +++ b/tests/ui/impl-trait/nested-return-type2.rs @@ -26,7 +26,6 @@ impl<R: Duh, F: FnMut() -> R> Trait for F { // Lazy TAIT would error out, but we inserted a hack to make it work again, // keeping backwards compatibility. fn foo() -> impl Trait<Assoc = impl Send> { - //~^ WARN opaque type `impl Trait<Assoc = impl Send>` does not satisfy its associated type bounds || 42 } diff --git a/tests/ui/impl-trait/nested-return-type2.stderr b/tests/ui/impl-trait/nested-return-type2.stderr deleted file mode 100644 index 09ad3bd05c1..00000000000 --- a/tests/ui/impl-trait/nested-return-type2.stderr +++ /dev/null @@ -1,17 +0,0 @@ -warning: opaque type `impl Trait<Assoc = impl Send>` does not satisfy its associated type bounds - --> $DIR/nested-return-type2.rs:28:24 - | -LL | type Assoc: Duh; - | --- this associated type bound is unsatisfied for `impl Send` -... -LL | fn foo() -> impl Trait<Assoc = impl Send> { - | ^^^^^^^^^^^^^^^^^ - | - = note: `#[warn(opaque_hidden_inferred_bound)]` on by default -help: add this bound - | -LL | fn foo() -> impl Trait<Assoc = impl Send + Duh> { - | +++++ - -warning: 1 warning emitted - diff --git a/tests/ui/impl-trait/nested-return-type3.rs b/tests/ui/impl-trait/nested-return-type3.rs index 5a764fc4c28..74b4dae22eb 100644 --- a/tests/ui/impl-trait/nested-return-type3.rs +++ b/tests/ui/impl-trait/nested-return-type3.rs @@ -13,7 +13,6 @@ impl<F: Duh> Trait for F { } fn foo() -> impl Trait<Assoc = impl Send> { - //~^ WARN opaque type `impl Trait<Assoc = impl Send>` does not satisfy its associated type bounds 42 } diff --git a/tests/ui/impl-trait/nested-return-type3.stderr b/tests/ui/impl-trait/nested-return-type3.stderr deleted file mode 100644 index 632de71aa4c..00000000000 --- a/tests/ui/impl-trait/nested-return-type3.stderr +++ /dev/null @@ -1,17 +0,0 @@ -warning: opaque type `impl Trait<Assoc = impl Send>` does not satisfy its associated type bounds - --> $DIR/nested-return-type3.rs:15:24 - | -LL | type Assoc: Duh; - | --- this associated type bound is unsatisfied for `impl Send` -... -LL | fn foo() -> impl Trait<Assoc = impl Send> { - | ^^^^^^^^^^^^^^^^^ - | - = note: `#[warn(opaque_hidden_inferred_bound)]` on by default -help: add this bound - | -LL | fn foo() -> impl Trait<Assoc = impl Send + Duh> { - | +++++ - -warning: 1 warning emitted - diff --git a/tests/ui/imports/auxiliary/glob-conflict.rs b/tests/ui/imports/auxiliary/glob-conflict.rs index c83db64c643..8a146378b43 100644 --- a/tests/ui/imports/auxiliary/glob-conflict.rs +++ b/tests/ui/imports/auxiliary/glob-conflict.rs @@ -1,3 +1,5 @@ +#![allow(ambiguous_glob_reexports)] + mod m1 { pub fn f() {} } diff --git a/tests/ui/imports/issue-99695-b.fixed b/tests/ui/imports/issue-99695-b.fixed index 0f688fa2823..0e60c73b67a 100644 --- a/tests/ui/imports/issue-99695-b.fixed +++ b/tests/ui/imports/issue-99695-b.fixed @@ -1,5 +1,5 @@ // run-rustfix -#![allow(unused, nonstandard_style, useless_anonymous_reexport)] +#![allow(unused, nonstandard_style)] mod m { mod p { diff --git a/tests/ui/imports/issue-99695-b.rs b/tests/ui/imports/issue-99695-b.rs index b433997e53f..031443a1f5d 100644 --- a/tests/ui/imports/issue-99695-b.rs +++ b/tests/ui/imports/issue-99695-b.rs @@ -1,5 +1,5 @@ // run-rustfix -#![allow(unused, nonstandard_style, useless_anonymous_reexport)] +#![allow(unused, nonstandard_style)] mod m { mod p { diff --git a/tests/ui/imports/issue-99695.fixed b/tests/ui/imports/issue-99695.fixed index 17ff409324e..6bf228b23aa 100644 --- a/tests/ui/imports/issue-99695.fixed +++ b/tests/ui/imports/issue-99695.fixed @@ -1,5 +1,5 @@ // run-rustfix -#![allow(unused, nonstandard_style, useless_anonymous_reexport)] +#![allow(unused, nonstandard_style)] mod m { #[macro_export] macro_rules! nu { diff --git a/tests/ui/imports/issue-99695.rs b/tests/ui/imports/issue-99695.rs index b8979bcb734..f7199f1497a 100644 --- a/tests/ui/imports/issue-99695.rs +++ b/tests/ui/imports/issue-99695.rs @@ -1,5 +1,5 @@ // run-rustfix -#![allow(unused, nonstandard_style, useless_anonymous_reexport)] +#![allow(unused, nonstandard_style)] mod m { #[macro_export] macro_rules! nu { diff --git a/tests/ui/imports/local-modularized-tricky-fail-1.rs b/tests/ui/imports/local-modularized-tricky-fail-1.rs index 29e9b8ec841..ce700ae0de9 100644 --- a/tests/ui/imports/local-modularized-tricky-fail-1.rs +++ b/tests/ui/imports/local-modularized-tricky-fail-1.rs @@ -1,4 +1,5 @@ #![feature(decl_macro)] +#![allow(ambiguous_glob_reexports)] macro_rules! define_exported { () => { #[macro_export] diff --git a/tests/ui/imports/local-modularized-tricky-fail-1.stderr b/tests/ui/imports/local-modularized-tricky-fail-1.stderr index 20eadaaaa56..52a01e8bcdf 100644 --- a/tests/ui/imports/local-modularized-tricky-fail-1.stderr +++ b/tests/ui/imports/local-modularized-tricky-fail-1.stderr @@ -1,12 +1,12 @@ error[E0659]: `exported` is ambiguous - --> $DIR/local-modularized-tricky-fail-1.rs:28:1 + --> $DIR/local-modularized-tricky-fail-1.rs:29:1 | LL | exported!(); | ^^^^^^^^ ambiguous name | = note: ambiguous because of a conflict between a name from a glob import and a macro-expanded name in the same module during import or macro resolution note: `exported` could refer to the macro defined here - --> $DIR/local-modularized-tricky-fail-1.rs:5:5 + --> $DIR/local-modularized-tricky-fail-1.rs:6:5 | LL | / macro_rules! exported { LL | | () => () @@ -16,7 +16,7 @@ LL | | } LL | define_exported!(); | ------------------ in this macro invocation note: `exported` could also refer to the macro imported here - --> $DIR/local-modularized-tricky-fail-1.rs:22:5 + --> $DIR/local-modularized-tricky-fail-1.rs:23:5 | LL | use inner1::*; | ^^^^^^^^^ @@ -24,7 +24,7 @@ LL | use inner1::*; = note: this error originates in the macro `define_exported` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0659]: `panic` is ambiguous - --> $DIR/local-modularized-tricky-fail-1.rs:35:5 + --> $DIR/local-modularized-tricky-fail-1.rs:36:5 | LL | panic!(); | ^^^^^ ambiguous name @@ -32,7 +32,7 @@ LL | panic!(); = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution = note: `panic` could refer to a macro from prelude note: `panic` could also refer to the macro defined here - --> $DIR/local-modularized-tricky-fail-1.rs:11:5 + --> $DIR/local-modularized-tricky-fail-1.rs:12:5 | LL | / macro_rules! panic { LL | | () => () @@ -45,7 +45,7 @@ LL | define_panic!(); = note: this error originates in the macro `define_panic` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0659]: `include` is ambiguous - --> $DIR/local-modularized-tricky-fail-1.rs:46:1 + --> $DIR/local-modularized-tricky-fail-1.rs:47:1 | LL | include!(); | ^^^^^^^ ambiguous name @@ -53,7 +53,7 @@ LL | include!(); = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution = note: `include` could refer to a macro from prelude note: `include` could also refer to the macro defined here - --> $DIR/local-modularized-tricky-fail-1.rs:17:5 + --> $DIR/local-modularized-tricky-fail-1.rs:18:5 | LL | / macro_rules! include { LL | | () => () diff --git a/tests/ui/lint/anonymous-reexport.rs b/tests/ui/lint/anonymous-reexport.rs index 5d56ae6f969..11ac5d07140 100644 --- a/tests/ui/lint/anonymous-reexport.rs +++ b/tests/ui/lint/anonymous-reexport.rs @@ -1,4 +1,4 @@ -#![deny(useless_anonymous_reexport)] +#![deny(unused_imports)] #![crate_type = "rlib"] mod my_mod { @@ -9,13 +9,11 @@ mod my_mod { } pub use self::my_mod::Foo as _; -pub use self::my_mod::TyFoo as _; -pub use self::my_mod::Bar as _; //~ ERROR -pub use self::my_mod::TyBar as _; //~ ERROR -pub use self::my_mod::{Bar as _}; //~ ERROR -pub use self::my_mod::{Bar as _, Foo as _}; //~ ERROR -pub use self::my_mod::{Bar as _, TyBar as _}; -//~^ ERROR -//~| ERROR +pub use self::my_mod::TyFoo as _; //~ ERROR unused import +pub use self::my_mod::Bar as _; //~ ERROR unused import +pub use self::my_mod::TyBar as _; //~ ERROR unused import +pub use self::my_mod::{Bar as _}; //~ ERROR unused import +pub use self::my_mod::{Bar as _, Foo as _}; //~ ERROR unused import +pub use self::my_mod::{Bar as _, TyBar as _}; //~ ERROR unused imports #[allow(unused_imports)] use self::my_mod::TyBar as _; diff --git a/tests/ui/lint/anonymous-reexport.stderr b/tests/ui/lint/anonymous-reexport.stderr index f4f8b41c417..e3854a5459e 100644 --- a/tests/ui/lint/anonymous-reexport.stderr +++ b/tests/ui/lint/anonymous-reexport.stderr @@ -1,55 +1,44 @@ -error: useless anonymous re-export - --> $DIR/anonymous-reexport.rs:13:1 +error: unused import: `self::my_mod::TyFoo as _` + --> $DIR/anonymous-reexport.rs:12:9 | -LL | pub use self::my_mod::Bar as _; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | pub use self::my_mod::TyFoo as _; + | ^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: only anonymous re-exports of traits are useful, this is a `struct` note: the lint level is defined here --> $DIR/anonymous-reexport.rs:1:9 | -LL | #![deny(useless_anonymous_reexport)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #![deny(unused_imports)] + | ^^^^^^^^^^^^^^ -error: useless anonymous re-export - --> $DIR/anonymous-reexport.rs:14:1 +error: unused import: `self::my_mod::Bar as _` + --> $DIR/anonymous-reexport.rs:13:9 | -LL | pub use self::my_mod::TyBar as _; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | pub use self::my_mod::Bar as _; + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: unused import: `self::my_mod::TyBar as _` + --> $DIR/anonymous-reexport.rs:14:9 | - = note: only anonymous re-exports of traits are useful, this is a `type alias` +LL | pub use self::my_mod::TyBar as _; + | ^^^^^^^^^^^^^^^^^^^^^^^^ -error: useless anonymous re-export +error: unused import: `Bar as _` --> $DIR/anonymous-reexport.rs:15:24 | LL | pub use self::my_mod::{Bar as _}; | ^^^^^^^^ - | - = note: only anonymous re-exports of traits are useful, this is a `struct` -error: useless anonymous re-export +error: unused import: `Bar as _` --> $DIR/anonymous-reexport.rs:16:24 | LL | pub use self::my_mod::{Bar as _, Foo as _}; | ^^^^^^^^ - | - = note: only anonymous re-exports of traits are useful, this is a `struct` -error: useless anonymous re-export +error: unused imports: `Bar as _`, `TyBar as _` --> $DIR/anonymous-reexport.rs:17:24 | LL | pub use self::my_mod::{Bar as _, TyBar as _}; - | ^^^^^^^^ - | - = note: only anonymous re-exports of traits are useful, this is a `struct` - -error: useless anonymous re-export - --> $DIR/anonymous-reexport.rs:17:34 - | -LL | pub use self::my_mod::{Bar as _, TyBar as _}; - | ^^^^^^^^^^ - | - = note: only anonymous re-exports of traits are useful, this is a `type alias` + | ^^^^^^^^ ^^^^^^^^^^ error: aborting due to 6 previous errors diff --git a/tests/ui/parser/ident-recovery.rs b/tests/ui/parser/ident-recovery.rs new file mode 100644 index 00000000000..7575372b940 --- /dev/null +++ b/tests/ui/parser/ident-recovery.rs @@ -0,0 +1,16 @@ +fn ,comma() { + //~^ ERROR expected identifier, found `,` + struct Foo { + x: i32,, + //~^ ERROR expected identifier, found `,` + y: u32, + } +} + +fn break() { +//~^ ERROR expected identifier, found keyword `break` + let continue = 5; + //~^ ERROR expected identifier, found keyword `continue` +} + +fn main() {} diff --git a/tests/ui/parser/ident-recovery.stderr b/tests/ui/parser/ident-recovery.stderr new file mode 100644 index 00000000000..e9a55026d12 --- /dev/null +++ b/tests/ui/parser/ident-recovery.stderr @@ -0,0 +1,42 @@ +error: expected identifier, found `,` + --> $DIR/ident-recovery.rs:1:4 + | +LL | fn ,comma() { + | ^ + | | + | expected identifier + | help: remove this comma + +error: expected identifier, found `,` + --> $DIR/ident-recovery.rs:4:16 + | +LL | x: i32,, + | ^ + | | + | expected identifier + | help: remove this comma + +error: expected identifier, found keyword `break` + --> $DIR/ident-recovery.rs:10:4 + | +LL | fn break() { + | ^^^^^ expected identifier, found keyword + | +help: escape `break` to use it as an identifier + | +LL | fn r#break() { + | ++ + +error: expected identifier, found keyword `continue` + --> $DIR/ident-recovery.rs:12:9 + | +LL | let continue = 5; + | ^^^^^^^^ expected identifier, found keyword + | +help: escape `continue` to use it as an identifier + | +LL | let r#continue = 5; + | ++ + +error: aborting due to 4 previous errors + diff --git a/tests/ui/parser/integer-literal-start-ident.stderr b/tests/ui/parser/integer-literal-start-ident.stderr index 51c37a0d24c..b2c66129656 100644 --- a/tests/ui/parser/integer-literal-start-ident.stderr +++ b/tests/ui/parser/integer-literal-start-ident.stderr @@ -4,7 +4,11 @@ error: expected identifier, found `1main` LL | fn 1main() {} | ^^^^^ expected identifier | - = help: identifiers cannot start with a number +help: identifiers cannot start with a number + --> $DIR/integer-literal-start-ident.rs:1:4 + | +LL | fn 1main() {} + | ^ error: aborting due to previous error diff --git a/tests/ui/parser/issues/issue-104088.rs b/tests/ui/parser/issues/issue-104088.rs index 86988c8cd21..3dc636b6a33 100644 --- a/tests/ui/parser/issues/issue-104088.rs +++ b/tests/ui/parser/issues/issue-104088.rs @@ -1,26 +1,19 @@ -fn test() { +fn 1234test() { +//~^ ERROR expected identifier, found `1234test` if let 123 = 123 { println!("yes"); } -} - -fn test_2() { - let 1x = 123; - //~^ ERROR expected identifier, found `1x` -} - -fn test_3() { - let 2x: i32 = 123; - //~^ ERROR expected identifier, found `2x` -} -fn test_4() { if let 2e1 = 123 { //~^ ERROR mismatched types } -} -fn test_5() { let 23name = 123; //~^ ERROR expected identifier, found `23name` + + let 2x: i32 = 123; + //~^ ERROR expected identifier, found `2x` + + let 1x = 123; + //~^ ERROR expected identifier, found `1x` } fn main() {} diff --git a/tests/ui/parser/issues/issue-104088.stderr b/tests/ui/parser/issues/issue-104088.stderr index 6511a313149..8b751759d69 100644 --- a/tests/ui/parser/issues/issue-104088.stderr +++ b/tests/ui/parser/issues/issue-104088.stderr @@ -1,35 +1,59 @@ -error: expected identifier, found `1x` - --> $DIR/issue-104088.rs:6:9 +error: expected identifier, found `1234test` + --> $DIR/issue-104088.rs:1:4 | -LL | let 1x = 123; - | ^^ expected identifier +LL | fn 1234test() { + | ^^^^^^^^ expected identifier + | +help: identifiers cannot start with a number + --> $DIR/issue-104088.rs:1:4 + | +LL | fn 1234test() { + | ^^^^ + +error: expected identifier, found `23name` + --> $DIR/issue-104088.rs:9:9 + | +LL | let 23name = 123; + | ^^^^^^ expected identifier + | +help: identifiers cannot start with a number + --> $DIR/issue-104088.rs:9:9 | - = help: identifiers cannot start with a number +LL | let 23name = 123; + | ^^ error: expected identifier, found `2x` - --> $DIR/issue-104088.rs:11:9 + --> $DIR/issue-104088.rs:12:9 | LL | let 2x: i32 = 123; | ^^ expected identifier | - = help: identifiers cannot start with a number +help: identifiers cannot start with a number + --> $DIR/issue-104088.rs:12:9 + | +LL | let 2x: i32 = 123; + | ^ -error: expected identifier, found `23name` - --> $DIR/issue-104088.rs:22:9 +error: expected identifier, found `1x` + --> $DIR/issue-104088.rs:15:9 | -LL | let 23name = 123; - | ^^^^^^ expected identifier +LL | let 1x = 123; + | ^^ expected identifier | - = help: identifiers cannot start with a number +help: identifiers cannot start with a number + --> $DIR/issue-104088.rs:15:9 + | +LL | let 1x = 123; + | ^ error[E0308]: mismatched types - --> $DIR/issue-104088.rs:16:12 + --> $DIR/issue-104088.rs:5:12 | LL | if let 2e1 = 123 { | ^^^ --- this expression has type `{integer}` | | | expected integer, found floating-point number -error: aborting due to 4 previous errors +error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/resolve/issue-107563-ambiguous-glob-reexports.rs b/tests/ui/resolve/issue-107563-ambiguous-glob-reexports.rs new file mode 100644 index 00000000000..431213e25e4 --- /dev/null +++ b/tests/ui/resolve/issue-107563-ambiguous-glob-reexports.rs @@ -0,0 +1,33 @@ +#![deny(ambiguous_glob_reexports)] + +pub mod foo { + pub type X = u8; +} + +pub mod bar { + pub type X = u8; + pub type Y = u8; +} + +pub use foo::*; +//~^ ERROR ambiguous glob re-exports +pub use bar::*; + +mod ambiguous { + mod m1 { pub type A = u8; } + mod m2 { pub type A = u8; } + pub use self::m1::*; + //~^ ERROR ambiguous glob re-exports + pub use self::m2::*; +} + +pub mod single { + pub use ambiguous::A; + //~^ ERROR `A` is ambiguous +} + +pub mod glob { + pub use ambiguous::*; +} + +pub fn main() {} diff --git a/tests/ui/resolve/issue-107563-ambiguous-glob-reexports.stderr b/tests/ui/resolve/issue-107563-ambiguous-glob-reexports.stderr new file mode 100644 index 00000000000..07e61dd8643 --- /dev/null +++ b/tests/ui/resolve/issue-107563-ambiguous-glob-reexports.stderr @@ -0,0 +1,47 @@ +error[E0659]: `A` is ambiguous + --> $DIR/issue-107563-ambiguous-glob-reexports.rs:25:24 + | +LL | pub use ambiguous::A; + | ^ ambiguous name + | + = note: ambiguous because of multiple glob imports of a name in the same module +note: `A` could refer to the type alias imported here + --> $DIR/issue-107563-ambiguous-glob-reexports.rs:19:13 + | +LL | pub use self::m1::*; + | ^^^^^^^^^^^ + = help: consider adding an explicit import of `A` to disambiguate +note: `A` could also refer to the type alias imported here + --> $DIR/issue-107563-ambiguous-glob-reexports.rs:21:13 + | +LL | pub use self::m2::*; + | ^^^^^^^^^^^ + = help: consider adding an explicit import of `A` to disambiguate + +error: ambiguous glob re-exports + --> $DIR/issue-107563-ambiguous-glob-reexports.rs:12:9 + | +LL | pub use foo::*; + | ^^^^^^ the name `X` in the type namespace is first re-exported here +LL | +LL | pub use bar::*; + | ------ but the name `X` in the type namespace is also re-exported here + | +note: the lint level is defined here + --> $DIR/issue-107563-ambiguous-glob-reexports.rs:1:9 + | +LL | #![deny(ambiguous_glob_reexports)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ambiguous glob re-exports + --> $DIR/issue-107563-ambiguous-glob-reexports.rs:19:13 + | +LL | pub use self::m1::*; + | ^^^^^^^^^^^ the name `A` in the type namespace is first re-exported here +LL | +LL | pub use self::m2::*; + | ----------- but the name `A` in the type namespace is also re-exported here + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0659`. diff --git a/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.stderr b/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.stderr index 6d7028c5e70..83f311efd39 100644 --- a/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.stderr +++ b/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.stderr @@ -2,7 +2,7 @@ error: the constant `N` is not of type `usize` --> $DIR/bad-const-wf-doesnt-specialize.rs:8:29 | LL | impl<const N: i32> Copy for S<N> {} - | ^^^^ + | ^^^^ expected `usize`, found `i32` | note: required by a bound in `S` --> $DIR/bad-const-wf-doesnt-specialize.rs:6:10 diff --git a/tests/ui/statics/uninhabited-static.stderr b/tests/ui/statics/uninhabited-static.stderr index 437053a4476..35fdcae6a59 100644 --- a/tests/ui/statics/uninhabited-static.stderr +++ b/tests/ui/statics/uninhabited-static.stderr @@ -47,7 +47,7 @@ error[E0080]: could not evaluate static initializer --> $DIR/uninhabited-static.rs:12:31 | LL | static VOID2: Void = unsafe { std::mem::transmute(()) }; - | ^^^^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type + | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a value of uninhabited type Void warning: the type `Void` does not permit zero-initialization --> $DIR/uninhabited-static.rs:12:31 @@ -66,7 +66,7 @@ error[E0080]: could not evaluate static initializer --> $DIR/uninhabited-static.rs:16:32 | LL | static NEVER2: Void = unsafe { std::mem::transmute(()) }; - | ^^^^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type + | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a value of uninhabited type Void warning: the type `Void` does not permit zero-initialization --> $DIR/uninhabited-static.rs:16:32 diff --git a/tests/ui/suggestions/issue-109436.rs b/tests/ui/suggestions/issue-109436.rs new file mode 100644 index 00000000000..e45ee5991db --- /dev/null +++ b/tests/ui/suggestions/issue-109436.rs @@ -0,0 +1,13 @@ +struct Foo; +struct Bar; + +impl From<&Foo> for Bar { + fn from(foo: &Foo) -> Bar { + Bar + } +} + +fn main() { + let foo = Foo; + let b: Bar = foo.into(); //~ ERROR E0277 +} diff --git a/tests/ui/suggestions/issue-109436.stderr b/tests/ui/suggestions/issue-109436.stderr new file mode 100644 index 00000000000..48518b33d12 --- /dev/null +++ b/tests/ui/suggestions/issue-109436.stderr @@ -0,0 +1,15 @@ +error[E0277]: the trait bound `Foo: Into<_>` is not satisfied + --> $DIR/issue-109436.rs:12:22 + | +LL | let b: Bar = foo.into(); + | ^^^^ the trait `~const Into<_>` is not implemented for `Foo` + | + = note: required for `Foo` to implement `Into<Bar>` +help: consider borrowing here + | +LL | let b: Bar = (&foo).into(); + | ++ + + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/new-solver/alias-eq-in-canonical-response.rs b/tests/ui/traits/new-solver/alias-eq-in-canonical-response.rs new file mode 100644 index 00000000000..4bfb6323a53 --- /dev/null +++ b/tests/ui/traits/new-solver/alias-eq-in-canonical-response.rs @@ -0,0 +1,40 @@ +// check-pass +// compile-flags: -Ztrait-solver=next + +trait Foo { + type Gat<'a> + where + Self: 'a; + fn bar(&self) -> Self::Gat<'_>; +} + +enum Option<T> { + Some(T), + None, +} + +impl<T> Option<T> { + fn as_ref(&self) -> Option<&T> { + match self { + Option::Some(t) => Option::Some(t), + Option::None => Option::None, + } + } + + fn map<U>(self, f: impl FnOnce(T) -> U) -> Option<U> { + match self { + Option::Some(t) => Option::Some(f(t)), + Option::None => Option::None, + } + } +} + +impl<T: Foo + 'static> Foo for Option<T> { + type Gat<'a> = Option<<T as Foo>::Gat<'a>> where Self: 'a; + + fn bar(&self) -> Self::Gat<'_> { + self.as_ref().map(Foo::bar) + } +} + +fn main() {} diff --git a/tests/ui/traits/new-solver/alias-sub.rs b/tests/ui/traits/new-solver/alias-sub.rs new file mode 100644 index 00000000000..30c1981a92e --- /dev/null +++ b/tests/ui/traits/new-solver/alias-sub.rs @@ -0,0 +1,34 @@ +// compile-flags: -Ztrait-solver=next +// check-pass + +trait Trait { + type Assoc: Sized; +} + +impl Trait for &'static str { + type Assoc = &'static str; +} + +// Wrapper is just here to get around stupid `Sized` obligations in mir typeck +struct Wrapper<T: ?Sized>(std::marker::PhantomData<T>); +fn mk<T: Trait>(x: T) -> Wrapper<<T as Trait>::Assoc> { todo!() } + + +trait IsStaticStr {} +impl IsStaticStr for (&'static str,) {} +fn define<T: IsStaticStr>(_: T) {} + +fn foo<'a, T: Trait>() { + let y = Default::default(); + + // `<?0 as Trait>::Assoc <: &'a str` + // In the old solver, this would *equate* the LHS and RHS. + let _: Wrapper<&'a str> = mk(y); + + // ... then later on, we constrain `?0 = &'static str` + // but that should not mean that `'a = 'static`, because + // we should use *sub* above. + define((y,)); +} + +fn main() {} diff --git a/tests/ui/traits/new-solver/coherence/issue-102048.rs b/tests/ui/traits/new-solver/coherence/issue-102048.rs new file mode 100644 index 00000000000..11636bfeb55 --- /dev/null +++ b/tests/ui/traits/new-solver/coherence/issue-102048.rs @@ -0,0 +1,44 @@ +// This must fail coherence. +// +// Getting this to pass was fairly difficult, so here's an explanation +// of what's happening: +// +// Normalizing projections currently tries to replace them with inference variables +// while emitting a nested `Projection` obligation. This cannot be done if the projection +// has bound variables which is the case here. +// +// So the projections stay until after normalization. When unifying two projections we +// currently treat them as if they are injective, so we **incorrectly** unify their +// substs. This means that coherence for the two impls ends up unifying `?T` and `?U` +// as it tries to unify `<?T as WithAssoc1<'a>>::Assoc` with `<?U as WithAssoc1<'a>>::Assoc`. +// +// `impl1` therefore has the projection `<?T as WithAssoc2<'a>>::Assoc` and we have the +// assumption `?T: for<'a> WithAssoc2<'a, Assoc = i32>` in the `param_env`, so we normalize +// that to `i32`. We then try to unify `i32` from `impl1` with `u32` from `impl2` which fails, +// causing coherence to consider these two impls distinct. + +// compile-flags: -Ztrait-solver=next +pub trait Trait<T> {} + +pub trait WithAssoc1<'a> { + type Assoc; +} +pub trait WithAssoc2<'a> { + type Assoc; +} + +// impl 1 +impl<T, U> Trait<for<'a> fn(<T as WithAssoc1<'a>>::Assoc, <U as WithAssoc2<'a>>::Assoc)> for (T, U) +where + T: for<'a> WithAssoc1<'a> + for<'a> WithAssoc2<'a, Assoc = i32>, + U: for<'a> WithAssoc2<'a>, +{ +} + +// impl 2 +impl<T, U> Trait<for<'a> fn(<U as WithAssoc1<'a>>::Assoc, u32)> for (T, U) where + U: for<'a> WithAssoc1<'a> //~^ ERROR conflicting implementations of trait +{ +} + +fn main() {} diff --git a/tests/ui/traits/new-solver/coherence/issue-102048.stderr b/tests/ui/traits/new-solver/coherence/issue-102048.stderr new file mode 100644 index 00000000000..17a43838fe2 --- /dev/null +++ b/tests/ui/traits/new-solver/coherence/issue-102048.stderr @@ -0,0 +1,12 @@ +error[E0119]: conflicting implementations of trait `Trait<for<'a> fn(<_ as WithAssoc1<'a>>::Assoc, <_ as WithAssoc2<'a>>::Assoc)>` for type `(_, _)` + --> $DIR/issue-102048.rs:39:1 + | +LL | impl<T, U> Trait<for<'a> fn(<T as WithAssoc1<'a>>::Assoc, <U as WithAssoc2<'a>>::Assoc)> for (T, U) + | --------------------------------------------------------------------------------------------------- first implementation here +... +LL | impl<T, U> Trait<for<'a> fn(<U as WithAssoc1<'a>>::Assoc, u32)> for (T, U) where + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(_, _)` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/traits/reservation-impl/coherence-conflict.next.stderr b/tests/ui/traits/reservation-impl/coherence-conflict.next.stderr new file mode 100644 index 00000000000..e5a3c3f5cc4 --- /dev/null +++ b/tests/ui/traits/reservation-impl/coherence-conflict.next.stderr @@ -0,0 +1,11 @@ +error[E0119]: conflicting implementations of trait `OtherTrait` for type `()` + --> $DIR/coherence-conflict.rs:12:1 + | +LL | impl OtherTrait for () {} + | ---------------------- first implementation here +LL | impl<T: MyTrait> OtherTrait for T {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `()` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/traits/reservation-impl/coherence-conflict.stderr b/tests/ui/traits/reservation-impl/coherence-conflict.old.stderr index a811d7e3201..393350ea3f1 100644 --- a/tests/ui/traits/reservation-impl/coherence-conflict.stderr +++ b/tests/ui/traits/reservation-impl/coherence-conflict.old.stderr @@ -1,5 +1,5 @@ error[E0119]: conflicting implementations of trait `OtherTrait` for type `()` - --> $DIR/coherence-conflict.rs:11:1 + --> $DIR/coherence-conflict.rs:12:1 | LL | impl OtherTrait for () {} | ---------------------- first implementation here diff --git a/tests/ui/traits/reservation-impl/coherence-conflict.rs b/tests/ui/traits/reservation-impl/coherence-conflict.rs index fa4a309315b..6bbd90f94dc 100644 --- a/tests/ui/traits/reservation-impl/coherence-conflict.rs +++ b/tests/ui/traits/reservation-impl/coherence-conflict.rs @@ -1,5 +1,6 @@ // check that reservation impls are accounted for in negative reasoning. - +// revisions: old next +//[next] compile-flags: -Ztrait-solver=next #![feature(rustc_attrs)] trait MyTrait {} diff --git a/tests/ui/traits/reservation-impl/no-use.stderr b/tests/ui/traits/reservation-impl/no-use.next.stderr index cefb2a8792f..542e3a28adf 100644 --- a/tests/ui/traits/reservation-impl/no-use.stderr +++ b/tests/ui/traits/reservation-impl/no-use.next.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `(): MyTrait` is not satisfied - --> $DIR/no-use.rs:10:26 + --> $DIR/no-use.rs:11:26 | LL | <() as MyTrait>::foo(&()); | -------------------- ^^^ the trait `MyTrait` is not implemented for `()` diff --git a/tests/ui/traits/reservation-impl/no-use.old.stderr b/tests/ui/traits/reservation-impl/no-use.old.stderr new file mode 100644 index 00000000000..542e3a28adf --- /dev/null +++ b/tests/ui/traits/reservation-impl/no-use.old.stderr @@ -0,0 +1,13 @@ +error[E0277]: the trait bound `(): MyTrait` is not satisfied + --> $DIR/no-use.rs:11:26 + | +LL | <() as MyTrait>::foo(&()); + | -------------------- ^^^ the trait `MyTrait` is not implemented for `()` + | | + | required by a bound introduced by this call + | + = help: the trait `MyTrait` is implemented for `()` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/reservation-impl/no-use.rs b/tests/ui/traits/reservation-impl/no-use.rs index 65a55d9e209..864f1791fd0 100644 --- a/tests/ui/traits/reservation-impl/no-use.rs +++ b/tests/ui/traits/reservation-impl/no-use.rs @@ -1,5 +1,6 @@ // check that reservation impls can't be used as normal impls in positive reasoning. - +// revisions: old next +//[next] compile-flags: -Ztrait-solver=next #![feature(rustc_attrs)] trait MyTrait { fn foo(&self); } diff --git a/tests/ui/traits/reservation-impl/non-lattice-ok.rs b/tests/ui/traits/reservation-impl/non-lattice-ok.rs index a71051243c8..7787904d9b2 100644 --- a/tests/ui/traits/reservation-impl/non-lattice-ok.rs +++ b/tests/ui/traits/reservation-impl/non-lattice-ok.rs @@ -30,6 +30,12 @@ // // [ii]: https://smallcultfollowing.com/babysteps/blog/2016/09/24/intersection-impls/ + +// check that reservation impls can't be used as normal impls in positive reasoning. + +// revisions: old next +//[next] compile-flags: -Ztrait-solver=next + #![feature(rustc_attrs, never_type)] trait MyTrait {} diff --git a/tests/ui/traits/reservation-impl/ok.rs b/tests/ui/traits/reservation-impl/ok.rs index 611c8d88413..8ff6645a2b3 100644 --- a/tests/ui/traits/reservation-impl/ok.rs +++ b/tests/ui/traits/reservation-impl/ok.rs @@ -3,6 +3,9 @@ // rpass test for reservation impls. Not 100% required because `From` uses them, // but still. +// revisions: old next +//[next] compile-flags: -Ztrait-solver=next + #![feature(rustc_attrs)] use std::mem; diff --git a/tests/ui/transmutability/issue-101739-1.stderr b/tests/ui/transmutability/issue-101739-1.stderr index f0fa93722b8..bf947d0ea4a 100644 --- a/tests/ui/transmutability/issue-101739-1.stderr +++ b/tests/ui/transmutability/issue-101739-1.stderr @@ -8,7 +8,7 @@ error: the constant `ASSUME_ALIGNMENT` is not of type `Assume` --> $DIR/issue-101739-1.rs:8:14 | LL | Dst: BikeshedIntrinsicFrom<Src, Context, ASSUME_ALIGNMENT>, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Assume`, found `bool` | note: required by a bound in `BikeshedIntrinsicFrom` --> $SRC_DIR/core/src/mem/transmutability.rs:LL:COL |
