diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 7f4775bf41a52..01e234c9be972 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -1311,6 +1311,9 @@ impl<'a> State<'a> { true, item.span, ); + if macro_def.body.need_semicolon() { + self.word(";"); + } } } self.ann.post(self, AnnNode::Item(item)) diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs index 13cf1e1083f7f..87684c2715f4e 100644 --- a/compiler/rustc_infer/src/traits/util.rs +++ b/compiler/rustc_infer/src/traits/util.rs @@ -1,9 +1,10 @@ use smallvec::smallvec; use crate::traits::{Obligation, ObligationCause, PredicateObligation}; -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; use rustc_middle::ty::outlives::Component; use rustc_middle::ty::{self, ToPredicate, TyCtxt, WithConstness}; +use rustc_span::symbol::Ident; pub fn anonymize_predicate<'tcx>( tcx: TyCtxt<'tcx>, @@ -282,6 +283,44 @@ pub fn transitive_bounds<'tcx>( elaborate_trait_refs(tcx, bounds).filter_to_traits() } +/// A specialized variant of `elaborate_trait_refs` that only elaborates trait references that may +/// define the given associated type `assoc_name`. It uses the +/// `super_predicates_that_define_assoc_type` query to avoid enumerating super-predicates that +/// aren't related to `assoc_item`. This is used when resolving types like `Self::Item` or +/// `T::Item` and helps to avoid cycle errors (see e.g. #35237). +pub fn transitive_bounds_that_define_assoc_type<'tcx>( + tcx: TyCtxt<'tcx>, + bounds: impl Iterator>, + assoc_name: Ident, +) -> impl Iterator> { + let mut stack: Vec<_> = bounds.collect(); + let mut visited = FxIndexSet::default(); + + std::iter::from_fn(move || { + while let Some(trait_ref) = stack.pop() { + let anon_trait_ref = tcx.anonymize_late_bound_regions(trait_ref); + if visited.insert(anon_trait_ref) { + let super_predicates = tcx.super_predicates_that_define_assoc_type(( + trait_ref.def_id(), + Some(assoc_name), + )); + for (super_predicate, _) in super_predicates.predicates { + let bound_predicate = super_predicate.kind(); + let subst_predicate = super_predicate + .subst_supertrait(tcx, &bound_predicate.rebind(trait_ref.skip_binder())); + if let Some(binder) = subst_predicate.to_opt_poly_trait_ref() { + stack.push(binder.value); + } + } + + return Some(trait_ref); + } + } + + return None; + }) +} + /////////////////////////////////////////////////////////////////////////// // Other /////////////////////////////////////////////////////////////////////////// diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 2cedef62519dc..20f581625dc31 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -328,6 +328,18 @@ impl UnsafeCode { cx.struct_span_lint(UNSAFE_CODE, span, decorate); } + + fn report_overriden_symbol_name(&self, cx: &EarlyContext<'_>, span: Span, msg: &str) { + self.report_unsafe(cx, span, |lint| { + lint.build(msg) + .note( + "the linker's behavior with multiple libraries exporting duplicate symbol \ + names is undefined and Rust cannot provide guarantees when you manually \ + override them", + ) + .emit(); + }) + } } impl EarlyLintPass for UnsafeCode { @@ -367,6 +379,40 @@ impl EarlyLintPass for UnsafeCode { lint.build("implementation of an `unsafe` trait").emit() }), + ast::ItemKind::Fn(..) => { + if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::no_mangle) { + self.report_overriden_symbol_name( + cx, + attr.span, + "declaration of a `no_mangle` function", + ); + } + if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::export_name) { + self.report_overriden_symbol_name( + cx, + attr.span, + "declaration of a function with `export_name`", + ); + } + } + + ast::ItemKind::Static(..) => { + if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::no_mangle) { + self.report_overriden_symbol_name( + cx, + attr.span, + "declaration of a `no_mangle` static", + ); + } + if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::export_name) { + self.report_overriden_symbol_name( + cx, + attr.span, + "declaration of a static with `export_name`", + ); + } + } + _ => {} } } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index f3f3368b090f3..f0166ec21672b 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -442,12 +442,23 @@ rustc_queries! { /// full predicates are available (note that supertraits have /// additional acyclicity requirements). query super_predicates_of(key: DefId) -> ty::GenericPredicates<'tcx> { - desc { |tcx| "computing the supertraits of `{}`", tcx.def_path_str(key) } + desc { |tcx| "computing the super predicates of `{}`", tcx.def_path_str(key) } + } + + /// The `Option` is the name of an associated type. If it is `None`, then this query + /// returns the full set of predicates. If `Some`, then the query returns only the + /// subset of super-predicates that reference traits that define the given associated type. + /// This is used to avoid cycles in resolving types like `T::Item`. + query super_predicates_that_define_assoc_type(key: (DefId, Option)) -> ty::GenericPredicates<'tcx> { + desc { |tcx| "computing the super traits of `{}`{}", + tcx.def_path_str(key.0), + if let Some(assoc_name) = key.1 { format!(" with associated type name `{}`", assoc_name) } else { "".to_string() }, + } } /// To avoid cycles within the predicates of a single item we compute /// per-type-parameter predicates for resolving `T::AssocTy`. - query type_param_predicates(key: (DefId, LocalDefId)) -> ty::GenericPredicates<'tcx> { + query type_param_predicates(key: (DefId, LocalDefId, rustc_span::symbol::Ident)) -> ty::GenericPredicates<'tcx> { desc { |tcx| "computing the bounds for type parameter `{}`", { let id = tcx.hir().local_def_id_to_hir_id(key.1); tcx.hir().ty_param_name(id) diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 1255302f74384..f83056ebe2a45 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -52,7 +52,7 @@ use rustc_session::config::{BorrowckMode, CrateType, OutputFilenames}; use rustc_session::lint::{Level, Lint}; use rustc_session::Session; use rustc_span::source_map::MultiSpan; -use rustc_span::symbol::{kw, sym, Symbol}; +use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::{Layout, TargetDataLayout, VariantIdx}; use rustc_target::spec::abi; @@ -2053,6 +2053,42 @@ impl<'tcx> TyCtxt<'tcx> { self.mk_fn_ptr(sig.map_bound(|sig| ty::FnSig { unsafety: hir::Unsafety::Unsafe, ..sig })) } + /// Given the def_id of a Trait `trait_def_id` and the name of an associated item `assoc_name` + /// returns true if the `trait_def_id` defines an associated item of name `assoc_name`. + pub fn trait_may_define_assoc_type(self, trait_def_id: DefId, assoc_name: Ident) -> bool { + self.super_traits_of(trait_def_id).any(|trait_did| { + self.associated_items(trait_did) + .find_by_name_and_kind(self, assoc_name, ty::AssocKind::Type, trait_did) + .is_some() + }) + } + + /// Computes the def-ids of the transitive super-traits of `trait_def_id`. This (intentionally) + /// does not compute the full elaborated super-predicates but just the set of def-ids. It is used + /// to identify which traits may define a given associated type to help avoid cycle errors. + /// Returns a `DefId` iterator. + fn super_traits_of(self, trait_def_id: DefId) -> impl Iterator + 'tcx { + let mut set = FxHashSet::default(); + let mut stack = vec![trait_def_id]; + + set.insert(trait_def_id); + + iter::from_fn(move || -> Option { + let trait_did = stack.pop()?; + let generic_predicates = self.super_predicates_of(trait_did); + + for (predicate, _) in generic_predicates.predicates { + if let ty::PredicateKind::Trait(data, _) = predicate.kind().skip_binder() { + if set.insert(data.def_id()) { + stack.push(data.def_id()); + } + } + } + + Some(trait_did) + }) + } + /// Given a closure signature, returns an equivalent fn signature. Detuples /// and so forth -- so e.g., if we have a sig with `Fn<(u32, i32)>` then /// you would get a `fn(u32, i32)`. diff --git a/compiler/rustc_middle/src/ty/query/keys.rs b/compiler/rustc_middle/src/ty/query/keys.rs index bfa1581aaae29..6b4714b1bb8c8 100644 --- a/compiler/rustc_middle/src/ty/query/keys.rs +++ b/compiler/rustc_middle/src/ty/query/keys.rs @@ -7,7 +7,7 @@ use crate::ty::subst::{GenericArg, SubstsRef}; use crate::ty::{self, Ty, TyCtxt}; use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE}; use rustc_query_system::query::DefaultCacheSelector; -use rustc_span::symbol::Symbol; +use rustc_span::symbol::{Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; /// The `Key` trait controls what types can legally be used as the key @@ -160,6 +160,28 @@ impl Key for (LocalDefId, DefId) { } } +impl Key for (DefId, Option) { + type CacheSelector = DefaultCacheSelector; + + fn query_crate(&self) -> CrateNum { + self.0.krate + } + fn default_span(&self, tcx: TyCtxt<'_>) -> Span { + tcx.def_span(self.0) + } +} + +impl Key for (DefId, LocalDefId, Ident) { + type CacheSelector = DefaultCacheSelector; + + fn query_crate(&self) -> CrateNum { + self.0.krate + } + fn default_span(&self, tcx: TyCtxt<'_>) -> Span { + self.1.default_span(tcx) + } +} + impl Key for (CrateNum, DefId) { type CacheSelector = DefaultCacheSelector; diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index c44ccfadda52d..ee24286241468 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1010,9 +1010,18 @@ impl<'a> Parser<'a> { ) -> PResult<'a, ItemInfo> { let impl_span = self.token.span; let mut err = self.expected_ident_found(); - let mut impl_info = self.parse_item_impl(attrs, defaultness)?; + + // Only try to recover if this is implementing a trait for a type + let mut impl_info = match self.parse_item_impl(attrs, defaultness) { + Ok(impl_info) => impl_info, + Err(mut recovery_error) => { + // Recovery failed, raise the "expected identifier" error + recovery_error.cancel(); + return Err(err); + } + }; + match impl_info.1 { - // only try to recover if this is implementing a trait for a type ItemKind::Impl(box ImplKind { of_trait: Some(ref trai), ref mut constness, .. }) => { @@ -1030,6 +1039,7 @@ impl<'a> Parser<'a> { ItemKind::Impl { .. } => return Err(err), _ => unreachable!(), } + Ok(impl_info) } diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index f7c0bafff05b4..0a81b6e105dff 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -65,7 +65,8 @@ pub use self::util::{ get_vtable_index_of_object_method, impl_item_is_final, predicate_for_trait_def, upcast_choices, }; pub use self::util::{ - supertrait_def_ids, supertraits, transitive_bounds, SupertraitDefIds, Supertraits, + supertrait_def_ids, supertraits, transitive_bounds, transitive_bounds_that_define_assoc_type, + SupertraitDefIds, Supertraits, }; pub use self::chalk_fulfill::FulfillmentContext as ChalkFulfillmentContext; diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index 5659345f0ff9c..244eba8ad5e02 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -49,9 +49,10 @@ pub trait AstConv<'tcx> { fn default_constness_for_trait_bounds(&self) -> Constness; - /// Returns predicates in scope of the form `X: Foo`, where `X` is - /// a type parameter `X` with the given id `def_id`. This is a - /// subset of the full set of predicates. + /// Returns predicates in scope of the form `X: Foo`, where `X` + /// is a type parameter `X` with the given id `def_id` and T + /// matches `assoc_name`. This is a subset of the full set of + /// predicates. /// /// This is used for one specific purpose: resolving "short-hand" /// associated type references like `T::Item`. In principle, we @@ -60,7 +61,12 @@ pub trait AstConv<'tcx> { /// but this can lead to cycle errors. The problem is that we have /// to do this resolution *in order to create the predicates in /// the first place*. Hence, we have this "special pass". - fn get_type_parameter_bounds(&self, span: Span, def_id: DefId) -> ty::GenericPredicates<'tcx>; + fn get_type_parameter_bounds( + &self, + span: Span, + def_id: DefId, + assoc_name: Ident, + ) -> ty::GenericPredicates<'tcx>; /// Returns the lifetime to use when a lifetime is omitted (and not elided). fn re_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) @@ -792,7 +798,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } // Returns `true` if a bounds list includes `?Sized`. - pub fn is_unsized(&self, ast_bounds: &[hir::GenericBound<'_>], span: Span) -> bool { + pub fn is_unsized(&self, ast_bounds: &[&hir::GenericBound<'_>], span: Span) -> bool { let tcx = self.tcx(); // Try to find an unbound in bounds. @@ -850,7 +856,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { fn add_bounds( &self, param_ty: Ty<'tcx>, - ast_bounds: &[hir::GenericBound<'_>], + ast_bounds: &[&hir::GenericBound<'_>], bounds: &mut Bounds<'tcx>, ) { let constness = self.default_constness_for_trait_bounds(); @@ -865,7 +871,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { hir::GenericBound::Trait(_, hir::TraitBoundModifier::Maybe) => {} hir::GenericBound::LangItemTrait(lang_item, span, hir_id, args) => self .instantiate_lang_item_trait_ref( - lang_item, span, hir_id, args, param_ty, bounds, + *lang_item, *span, *hir_id, args, param_ty, bounds, ), hir::GenericBound::Outlives(ref l) => bounds .region_bounds @@ -896,6 +902,42 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ast_bounds: &[hir::GenericBound<'_>], sized_by_default: SizedByDefault, span: Span, + ) -> Bounds<'tcx> { + let ast_bounds: Vec<_> = ast_bounds.iter().collect(); + self.compute_bounds_inner(param_ty, &ast_bounds, sized_by_default, span) + } + + /// Convert the bounds in `ast_bounds` that refer to traits which define an associated type + /// named `assoc_name` into ty::Bounds. Ignore the rest. + pub fn compute_bounds_that_match_assoc_type( + &self, + param_ty: Ty<'tcx>, + ast_bounds: &[hir::GenericBound<'_>], + sized_by_default: SizedByDefault, + span: Span, + assoc_name: Ident, + ) -> Bounds<'tcx> { + let mut result = Vec::new(); + + for ast_bound in ast_bounds { + if let Some(trait_ref) = ast_bound.trait_ref() { + if let Some(trait_did) = trait_ref.trait_def_id() { + if self.tcx().trait_may_define_assoc_type(trait_did, assoc_name) { + result.push(ast_bound); + } + } + } + } + + self.compute_bounds_inner(param_ty, &result, sized_by_default, span) + } + + fn compute_bounds_inner( + &self, + param_ty: Ty<'tcx>, + ast_bounds: &[&hir::GenericBound<'_>], + sized_by_default: SizedByDefault, + span: Span, ) -> Bounds<'tcx> { let mut bounds = Bounds::default(); @@ -1098,7 +1140,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // parameter to have a skipped binder. let param_ty = tcx.mk_projection(assoc_ty.def_id, projection_ty.skip_binder().substs); - self.add_bounds(param_ty, ast_bounds, bounds); + let ast_bounds: Vec<_> = ast_bounds.iter().collect(); + self.add_bounds(param_ty, &ast_bounds, bounds); } } Ok(()) @@ -1413,8 +1456,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ty_param_def_id, assoc_name, span, ); - let predicates = - &self.get_type_parameter_bounds(span, ty_param_def_id.to_def_id()).predicates; + let predicates = &self + .get_type_parameter_bounds(span, ty_param_def_id.to_def_id(), assoc_name) + .predicates; debug!("find_bound_for_assoc_item: predicates={:#?}", predicates); @@ -1422,12 +1466,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let param_name = tcx.hir().ty_param_name(param_hir_id); self.one_bound_for_assoc_type( || { - traits::transitive_bounds( + traits::transitive_bounds_that_define_assoc_type( tcx, predicates.iter().filter_map(|(p, _)| { p.to_opt_poly_trait_ref().map(|trait_ref| trait_ref.value) }), + assoc_name, ) + .into_iter() }, || param_name.to_string(), assoc_name, diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs b/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs index e9223f700dcc7..4da4835f7cfbb 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs @@ -20,6 +20,7 @@ use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::{self, Const, Ty, TyCtxt}; use rustc_session::Session; +use rustc_span::symbol::Ident; use rustc_span::{self, Span}; use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode}; @@ -183,7 +184,12 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { } } - fn get_type_parameter_bounds(&self, _: Span, def_id: DefId) -> ty::GenericPredicates<'tcx> { + fn get_type_parameter_bounds( + &self, + _: Span, + def_id: DefId, + _: Ident, + ) -> ty::GenericPredicates<'tcx> { let tcx = self.tcx; let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); let item_id = tcx.hir().ty_param_owner(hir_id); diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index b1d98d75196d5..e5045f906df59 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -1,3 +1,4 @@ +// ignore-tidy-filelength //! "Collection" is the process of determining the type and other external //! details of each item in Rust. Collection is specifically concerned //! with *inter-procedural* things -- for example, for a function @@ -77,6 +78,7 @@ pub fn provide(providers: &mut Providers) { projection_ty_from_predicates, explicit_predicates_of, super_predicates_of, + super_predicates_that_define_assoc_type, trait_explicit_predicates_and_bounds, type_param_predicates, trait_def, @@ -308,8 +310,17 @@ impl AstConv<'tcx> for ItemCtxt<'tcx> { } } - fn get_type_parameter_bounds(&self, span: Span, def_id: DefId) -> ty::GenericPredicates<'tcx> { - self.tcx.at(span).type_param_predicates((self.item_def_id, def_id.expect_local())) + fn get_type_parameter_bounds( + &self, + span: Span, + def_id: DefId, + assoc_name: Ident, + ) -> ty::GenericPredicates<'tcx> { + self.tcx.at(span).type_param_predicates(( + self.item_def_id, + def_id.expect_local(), + assoc_name, + )) } fn re_infer(&self, _: Option<&ty::GenericParamDef>, _: Span) -> Option> { @@ -490,7 +501,7 @@ fn get_new_lifetime_name<'tcx>( /// `X: Foo` where `X` is the type parameter `def_id`. fn type_param_predicates( tcx: TyCtxt<'_>, - (item_def_id, def_id): (DefId, LocalDefId), + (item_def_id, def_id, assoc_name): (DefId, LocalDefId, Ident), ) -> ty::GenericPredicates<'_> { use rustc_hir::*; @@ -515,7 +526,7 @@ fn type_param_predicates( let mut result = parent .map(|parent| { let icx = ItemCtxt::new(tcx, parent); - icx.get_type_parameter_bounds(DUMMY_SP, def_id.to_def_id()) + icx.get_type_parameter_bounds(DUMMY_SP, def_id.to_def_id(), assoc_name) }) .unwrap_or_default(); let mut extend = None; @@ -558,12 +569,18 @@ fn type_param_predicates( let icx = ItemCtxt::new(tcx, item_def_id); let extra_predicates = extend.into_iter().chain( - icx.type_parameter_bounds_in_generics(ast_generics, param_id, ty, OnlySelfBounds(true)) - .into_iter() - .filter(|(predicate, _)| match predicate.kind().skip_binder() { - ty::PredicateKind::Trait(data, _) => data.self_ty().is_param(index), - _ => false, - }), + icx.type_parameter_bounds_in_generics( + ast_generics, + param_id, + ty, + OnlySelfBounds(true), + Some(assoc_name), + ) + .into_iter() + .filter(|(predicate, _)| match predicate.kind().skip_binder() { + ty::PredicateKind::Trait(data, _) => data.self_ty().is_param(index), + _ => false, + }), ); result.predicates = tcx.arena.alloc_from_iter(result.predicates.iter().copied().chain(extra_predicates)); @@ -581,6 +598,7 @@ impl ItemCtxt<'tcx> { param_id: hir::HirId, ty: Ty<'tcx>, only_self_bounds: OnlySelfBounds, + assoc_name: Option, ) -> Vec<(ty::Predicate<'tcx>, Span)> { let constness = self.default_constness_for_trait_bounds(); let from_ty_params = ast_generics @@ -591,6 +609,10 @@ impl ItemCtxt<'tcx> { _ => None, }) .flat_map(|bounds| bounds.iter()) + .filter(|b| match assoc_name { + Some(assoc_name) => self.bound_defines_assoc_item(b, assoc_name), + None => true, + }) .flat_map(|b| predicates_from_bound(self, ty, b, constness)); let from_where_clauses = ast_generics @@ -609,12 +631,34 @@ impl ItemCtxt<'tcx> { } else { None }; - bp.bounds.iter().filter_map(move |b| bt.map(|bt| (bt, b))) + bp.bounds + .iter() + .filter(|b| match assoc_name { + Some(assoc_name) => self.bound_defines_assoc_item(b, assoc_name), + None => true, + }) + .filter_map(move |b| bt.map(|bt| (bt, b))) }) .flat_map(|(bt, b)| predicates_from_bound(self, bt, b, constness)); from_ty_params.chain(from_where_clauses).collect() } + + fn bound_defines_assoc_item(&self, b: &hir::GenericBound<'_>, assoc_name: Ident) -> bool { + debug!("bound_defines_assoc_item(b={:?}, assoc_name={:?})", b, assoc_name); + + match b { + hir::GenericBound::Trait(poly_trait_ref, _) => { + let trait_ref = &poly_trait_ref.trait_ref; + if let Some(trait_did) = trait_ref.trait_def_id() { + self.tcx.trait_may_define_assoc_type(trait_did, assoc_name) + } else { + false + } + } + _ => false, + } + } } /// Tests whether this is the AST for a reference to the type @@ -983,54 +1027,91 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::AdtDef { /// the transitive super-predicates are converted. fn super_predicates_of(tcx: TyCtxt<'_>, trait_def_id: DefId) -> ty::GenericPredicates<'_> { debug!("super_predicates(trait_def_id={:?})", trait_def_id); - let trait_hir_id = tcx.hir().local_def_id_to_hir_id(trait_def_id.expect_local()); + tcx.super_predicates_that_define_assoc_type((trait_def_id, None)) +} - let item = match tcx.hir().get(trait_hir_id) { - Node::Item(item) => item, - _ => bug!("trait_node_id {} is not an item", trait_hir_id), - }; +/// Ensures that the super-predicates of the trait with a `DefId` +/// of `trait_def_id` are converted and stored. This also ensures that +/// the transitive super-predicates are converted. +fn super_predicates_that_define_assoc_type( + tcx: TyCtxt<'_>, + (trait_def_id, assoc_name): (DefId, Option), +) -> ty::GenericPredicates<'_> { + debug!( + "super_predicates_that_define_assoc_type(trait_def_id={:?}, assoc_name={:?})", + trait_def_id, assoc_name + ); + if trait_def_id.is_local() { + debug!("super_predicates_that_define_assoc_type: local trait_def_id={:?}", trait_def_id); + let trait_hir_id = tcx.hir().local_def_id_to_hir_id(trait_def_id.expect_local()); - let (generics, bounds) = match item.kind { - hir::ItemKind::Trait(.., ref generics, ref supertraits, _) => (generics, supertraits), - hir::ItemKind::TraitAlias(ref generics, ref supertraits) => (generics, supertraits), - _ => span_bug!(item.span, "super_predicates invoked on non-trait"), - }; + let item = match tcx.hir().get(trait_hir_id) { + Node::Item(item) => item, + _ => bug!("trait_node_id {} is not an item", trait_hir_id), + }; - let icx = ItemCtxt::new(tcx, trait_def_id); - - // Convert the bounds that follow the colon, e.g., `Bar + Zed` in `trait Foo: Bar + Zed`. - let self_param_ty = tcx.types.self_param; - let superbounds1 = - AstConv::compute_bounds(&icx, self_param_ty, bounds, SizedByDefault::No, item.span); - - let superbounds1 = superbounds1.predicates(tcx, self_param_ty); - - // Convert any explicit superbounds in the where-clause, - // e.g., `trait Foo where Self: Bar`. - // In the case of trait aliases, however, we include all bounds in the where-clause, - // so e.g., `trait Foo = where u32: PartialEq` would include `u32: PartialEq` - // as one of its "superpredicates". - let is_trait_alias = tcx.is_trait_alias(trait_def_id); - let superbounds2 = icx.type_parameter_bounds_in_generics( - generics, - item.hir_id, - self_param_ty, - OnlySelfBounds(!is_trait_alias), - ); + let (generics, bounds) = match item.kind { + hir::ItemKind::Trait(.., ref generics, ref supertraits, _) => (generics, supertraits), + hir::ItemKind::TraitAlias(ref generics, ref supertraits) => (generics, supertraits), + _ => span_bug!(item.span, "super_predicates invoked on non-trait"), + }; + + let icx = ItemCtxt::new(tcx, trait_def_id); + + // Convert the bounds that follow the colon, e.g., `Bar + Zed` in `trait Foo: Bar + Zed`. + let self_param_ty = tcx.types.self_param; + let superbounds1 = if let Some(assoc_name) = assoc_name { + AstConv::compute_bounds_that_match_assoc_type( + &icx, + self_param_ty, + &bounds, + SizedByDefault::No, + item.span, + assoc_name, + ) + } else { + AstConv::compute_bounds(&icx, self_param_ty, &bounds, SizedByDefault::No, item.span) + }; - // Combine the two lists to form the complete set of superbounds: - let superbounds = &*tcx.arena.alloc_from_iter(superbounds1.into_iter().chain(superbounds2)); + let superbounds1 = superbounds1.predicates(tcx, self_param_ty); + + // Convert any explicit superbounds in the where-clause, + // e.g., `trait Foo where Self: Bar`. + // In the case of trait aliases, however, we include all bounds in the where-clause, + // so e.g., `trait Foo = where u32: PartialEq` would include `u32: PartialEq` + // as one of its "superpredicates". + let is_trait_alias = tcx.is_trait_alias(trait_def_id); + let superbounds2 = icx.type_parameter_bounds_in_generics( + generics, + item.hir_id, + self_param_ty, + OnlySelfBounds(!is_trait_alias), + assoc_name, + ); - // Now require that immediate supertraits are converted, - // which will, in turn, reach indirect supertraits. - for &(pred, span) in superbounds { - debug!("superbound: {:?}", pred); - if let ty::PredicateKind::Trait(bound, _) = pred.kind().skip_binder() { - tcx.at(span).super_predicates_of(bound.def_id()); + // Combine the two lists to form the complete set of superbounds: + let superbounds = &*tcx.arena.alloc_from_iter(superbounds1.into_iter().chain(superbounds2)); + + // Now require that immediate supertraits are converted, + // which will, in turn, reach indirect supertraits. + if assoc_name.is_none() { + // Now require that immediate supertraits are converted, + // which will, in turn, reach indirect supertraits. + for &(pred, span) in superbounds { + debug!("superbound: {:?}", pred); + if let ty::PredicateKind::Trait(bound, _) = pred.kind().skip_binder() { + tcx.at(span).super_predicates_of(bound.def_id()); + } + } } - } - ty::GenericPredicates { parent: None, predicates: superbounds } + ty::GenericPredicates { parent: None, predicates: superbounds } + } else { + // if `assoc_name` is None, then the query should've been redirected to an + // external provider + assert!(assoc_name.is_some()); + tcx.super_predicates_of(trait_def_id) + } } fn trait_def(tcx: TyCtxt<'_>, def_id: DefId) -> ty::TraitDef { diff --git a/compiler/rustc_typeck/src/collect/item_bounds.rs b/compiler/rustc_typeck/src/collect/item_bounds.rs index 537a58328942b..fe18dc5ed0c69 100644 --- a/compiler/rustc_typeck/src/collect/item_bounds.rs +++ b/compiler/rustc_typeck/src/collect/item_bounds.rs @@ -28,7 +28,7 @@ fn associated_type_bounds<'tcx>( let bounds = AstConv::compute_bounds( &ItemCtxt::new(tcx, assoc_item_def_id), item_ty, - bounds, + &bounds, SizedByDefault::Yes, span, ); @@ -69,7 +69,7 @@ fn opaque_type_bounds<'tcx>( let bounds = AstConv::compute_bounds( &ItemCtxt::new(tcx, opaque_def_id), item_ty, - bounds, + &bounds, SizedByDefault::Yes, span, ) diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index 949079e5b699c..e87303749b423 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -390,7 +390,12 @@ impl Box { // #[unstable(feature = "new_uninit", issue = "63291")] pub fn new_uninit_in(alloc: A) -> Box, A> { let layout = Layout::new::>(); - Box::try_new_uninit_in(alloc).unwrap_or_else(|_| handle_alloc_error(layout)) + // NOTE: Prefer match over unwrap_or_else since closure sometimes not inlineable. + // That would make code size bigger. + match Box::try_new_uninit_in(alloc) { + Ok(m) => m, + Err(_) => handle_alloc_error(layout), + } } /// Constructs a new box with uninitialized contents in the provided allocator, @@ -447,7 +452,12 @@ impl Box { // #[unstable(feature = "new_uninit", issue = "63291")] pub fn new_zeroed_in(alloc: A) -> Box, A> { let layout = Layout::new::>(); - Box::try_new_zeroed_in(alloc).unwrap_or_else(|_| handle_alloc_error(layout)) + // NOTE: Prefer match over unwrap_or_else since closure sometimes not inlineable. + // That would make code size bigger. + match Box::try_new_zeroed_in(alloc) { + Ok(m) => m, + Err(_) => handle_alloc_error(layout), + } } /// Constructs a new `Box` with uninitialized contents, with the memory diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 6b42d456205cd..5faa4b825605f 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -2205,6 +2205,7 @@ pub trait Iterator { /// // we can still use `iter`, as there are more elements. /// assert_eq!(iter.next(), Some(&3)); /// ``` + #[doc(alias = "every")] #[inline] #[stable(feature = "rust1", since = "1.0.0")] fn all(&mut self, f: F) -> bool diff --git a/library/core/src/ops/control_flow.rs b/library/core/src/ops/control_flow.rs index 4834ca74b8270..2f78ba8f28e29 100644 --- a/library/core/src/ops/control_flow.rs +++ b/library/core/src/ops/control_flow.rs @@ -1,13 +1,63 @@ use crate::ops::Try; -/// Used to make try_fold closures more like normal loops +/// Used to tell an operation whether it should exit early or go on as usual. +/// +/// This is used when exposing things (like graph traversals or visitors) where +/// you want the user to be able to choose whether to exit early. +/// Having the enum makes it clearer -- no more wondering "wait, what did `false` +/// mean again?" -- and allows including a value. +/// +/// # Examples +/// +/// Early-exiting from [`Iterator::try_for_each`]: +/// ``` +/// #![feature(control_flow_enum)] +/// use std::ops::ControlFlow; +/// +/// let r = (2..100).try_for_each(|x| { +/// if 403 % x == 0 { +/// return ControlFlow::Break(x) +/// } +/// +/// ControlFlow::Continue(()) +/// }); +/// assert_eq!(r, ControlFlow::Break(13)); +/// ``` +/// +/// A basic tree traversal: +/// ```no_run +/// #![feature(control_flow_enum)] +/// use std::ops::ControlFlow; +/// +/// pub struct TreeNode { +/// value: T, +/// left: Option>>, +/// right: Option>>, +/// } +/// +/// impl TreeNode { +/// pub fn traverse_inorder(&self, mut f: impl FnMut(&T) -> ControlFlow) -> ControlFlow { +/// if let Some(left) = &self.left { +/// left.traverse_inorder(&mut f)?; +/// } +/// f(&self.value)?; +/// if let Some(right) = &self.right { +/// right.traverse_inorder(&mut f)?; +/// } +/// ControlFlow::Continue(()) +/// } +/// } +/// ``` #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")] #[derive(Debug, Clone, Copy, PartialEq)] pub enum ControlFlow { - /// Continue in the loop, using the given value for the next iteration + /// Move on to the next phase of the operation as normal. Continue(C), - /// Exit the loop, yielding the given value + /// Exit the operation without running subsequent phases. Break(B), + // Yes, the order of the variants doesn't match the type parameters. + // They're in this order so that `ControlFlow` <-> `Result` + // is a no-op conversion in the `Try` implementation. } #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")] @@ -33,6 +83,16 @@ impl Try for ControlFlow { impl ControlFlow { /// Returns `true` if this is a `Break` variant. + /// + /// # Examples + /// + /// ``` + /// #![feature(control_flow_enum)] + /// use std::ops::ControlFlow; + /// + /// assert!(ControlFlow::::Break(3).is_break()); + /// assert!(!ControlFlow::::Continue(3).is_break()); + /// ``` #[inline] #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")] pub fn is_break(&self) -> bool { @@ -40,6 +100,16 @@ impl ControlFlow { } /// Returns `true` if this is a `Continue` variant. + /// + /// # Examples + /// + /// ``` + /// #![feature(control_flow_enum)] + /// use std::ops::ControlFlow; + /// + /// assert!(!ControlFlow::::Break(3).is_continue()); + /// assert!(ControlFlow::::Continue(3).is_continue()); + /// ``` #[inline] #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")] pub fn is_continue(&self) -> bool { @@ -48,6 +118,16 @@ impl ControlFlow { /// Converts the `ControlFlow` into an `Option` which is `Some` if the /// `ControlFlow` was `Break` and `None` otherwise. + /// + /// # Examples + /// + /// ``` + /// #![feature(control_flow_enum)] + /// use std::ops::ControlFlow; + /// + /// assert_eq!(ControlFlow::::Break(3).break_value(), Some(3)); + /// assert_eq!(ControlFlow::::Continue(3).break_value(), None); + /// ``` #[inline] #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")] pub fn break_value(self) -> Option { diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 4dc86e0f5f40f..339691b117694 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -15,6 +15,7 @@ #![feature(const_maybe_uninit_assume_init)] #![feature(const_ptr_read)] #![feature(const_ptr_offset)] +#![feature(control_flow_enum)] #![feature(core_intrinsics)] #![feature(core_private_bignum)] #![feature(core_private_diy_float)] diff --git a/library/core/tests/ops.rs b/library/core/tests/ops.rs index 53e5539fad91c..aa79dbac8f39d 100644 --- a/library/core/tests/ops.rs +++ b/library/core/tests/ops.rs @@ -1,3 +1,5 @@ +mod control_flow; + use core::ops::{Bound, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive}; use core::ops::{Deref, DerefMut}; diff --git a/library/core/tests/ops/control_flow.rs b/library/core/tests/ops/control_flow.rs new file mode 100644 index 0000000000000..eacfd63a6c48f --- /dev/null +++ b/library/core/tests/ops/control_flow.rs @@ -0,0 +1,18 @@ +use core::intrinsics::discriminant_value; +use core::ops::ControlFlow; + +#[test] +fn control_flow_discriminants_match_result() { + // This isn't stable surface area, but helps keep `?` cheap between them, + // even if LLVM can't always take advantage of it right now. + // (Sadly Result and Option are inconsistent, so ControlFlow can't match both.) + + assert_eq!( + discriminant_value(&ControlFlow::::Break(3)), + discriminant_value(&Result::::Err(3)), + ); + assert_eq!( + discriminant_value(&ControlFlow::::Continue(3)), + discriminant_value(&Result::::Ok(3)), + ); +} diff --git a/library/std/src/sys/windows/mutex.rs b/library/std/src/sys/windows/mutex.rs index 72a0993d94ddf..12c5ea741f9ef 100644 --- a/library/std/src/sys/windows/mutex.rs +++ b/library/std/src/sys/windows/mutex.rs @@ -23,8 +23,6 @@ pub struct Mutex { } // Windows SRW Locks are movable (while not borrowed). -// ReentrantMutexes (in Inner) are not, but those are stored indirectly through -// a Box, so do not move when the Mutex it self is moved. pub type MovableMutex = Mutex; unsafe impl Send for Mutex {} diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index c4b3e4cf95dae..30d690c970507 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -626,6 +626,7 @@ impl Step for Rustdoc { // Only include compiler crates, no dependencies of those, such as `libc`. cargo.arg("--no-deps"); cargo.arg("-p").arg("rustdoc"); + cargo.arg("-p").arg("rustdoc-json-types"); cargo.rustdocflag("--document-private-items"); cargo.rustdocflag("--enable-index-page"); diff --git a/src/etc/lldb_providers.py b/src/etc/lldb_providers.py index 9c7b07efbaa77..ca2685ca31ffd 100644 --- a/src/etc/lldb_providers.py +++ b/src/etc/lldb_providers.py @@ -531,7 +531,9 @@ def update(self): ctrl = table.GetChildMemberWithName("ctrl").GetChildAtIndex(0) self.size = table.GetChildMemberWithName("items").GetValueAsUnsigned() - self.pair_type = table.type.template_args[0].GetTypedefedType() + self.pair_type = table.type.template_args[0] + if self.pair_type.IsTypedefType(): + self.pair_type = self.pair_type.GetTypedefedType() self.pair_type_size = self.pair_type.GetByteSize() self.new_layout = not table.GetChildMemberWithName("data").IsValid() diff --git a/src/test/incremental/cyclic-trait-hierarchy.rs b/src/test/incremental/cyclic-trait-hierarchy.rs index 03bb5eea765cc..b502e7207d561 100644 --- a/src/test/incremental/cyclic-trait-hierarchy.rs +++ b/src/test/incremental/cyclic-trait-hierarchy.rs @@ -3,11 +3,11 @@ // revisions: rpass1 cfail2 #[cfg(rpass1)] -pub trait T2 { } +pub trait T2 {} #[cfg(cfail2)] -pub trait T2: T1 { } -//[cfail2]~^ ERROR cycle detected when computing the supertraits of `T2` +pub trait T2: T1 {} +//[cfail2]~^ ERROR cycle detected when computing the super predicates of `T2` -pub trait T1: T2 { } +pub trait T1: T2 {} -fn main() { } +fn main() {} diff --git a/src/test/pretty/macro_rules.rs b/src/test/pretty/macro_rules.rs new file mode 100644 index 0000000000000..da223d164f9b0 --- /dev/null +++ b/src/test/pretty/macro_rules.rs @@ -0,0 +1,19 @@ +// pp-exact + +macro_rules! brace { () => { } ; } + +macro_rules! bracket[() => { } ;]; + +macro_rules! paren(() => { } ;); + +macro_rules! matcher_brackets { + (paren) => { } ; (bracket) => { } ; (brace) => { } ; +} + +macro_rules! all_fragments { + ($ b : block, $ e : expr, $ i : ident, $ it : item, $ l : lifetime, $ lit + : literal, $ m : meta, $ p : pat, $ pth : path, $ s : stmt, $ tt : tt, $ + ty : ty, $ vis : vis) => { } ; +} + +fn main() { } diff --git a/src/test/ui/associated-type-bounds/ambiguous-associated-type2.rs b/src/test/ui/associated-type-bounds/ambiguous-associated-type2.rs new file mode 100644 index 0000000000000..1b6d6d0ff599f --- /dev/null +++ b/src/test/ui/associated-type-bounds/ambiguous-associated-type2.rs @@ -0,0 +1,12 @@ +// ignore-tidy-linelength + +trait Foo { + type Item; +} +trait Bar { + type Item; +} +trait Baz: Foo + Bar {} +//~^ ERROR cycle detected when computing the super traits of `Baz` with associated type name `Item` [E0391] + +fn main() {} diff --git a/src/test/ui/associated-type-bounds/ambiguous-associated-type2.stderr b/src/test/ui/associated-type-bounds/ambiguous-associated-type2.stderr new file mode 100644 index 0000000000000..bda1debeac0d6 --- /dev/null +++ b/src/test/ui/associated-type-bounds/ambiguous-associated-type2.stderr @@ -0,0 +1,16 @@ +error[E0391]: cycle detected when computing the super traits of `Baz` with associated type name `Item` + --> $DIR/ambiguous-associated-type2.rs:9:1 + | +LL | trait Baz: Foo + Bar {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: ...which again requires computing the super traits of `Baz` with associated type name `Item`, completing the cycle +note: cycle used when computing the super traits of `Baz` + --> $DIR/ambiguous-associated-type2.rs:9:1 + | +LL | trait Baz: Foo + Bar {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0391`. diff --git a/src/test/ui/associated-type-bounds/associated-item-through-where-clause.rs b/src/test/ui/associated-type-bounds/associated-item-through-where-clause.rs new file mode 100644 index 0000000000000..3eb50ab554735 --- /dev/null +++ b/src/test/ui/associated-type-bounds/associated-item-through-where-clause.rs @@ -0,0 +1,21 @@ +// check-pass + +trait Foo { + type Item; +} + +trait Bar +where + Self: Foo, +{ +} + +#[allow(dead_code)] +fn foo(_m: M) +where + M: Bar, + M::Item: Send, +{ +} + +fn main() {} diff --git a/src/test/ui/associated-type-bounds/handle-predicates-that-can-define-assoc-type.rs b/src/test/ui/associated-type-bounds/handle-predicates-that-can-define-assoc-type.rs new file mode 100644 index 0000000000000..b1e54ec04493b --- /dev/null +++ b/src/test/ui/associated-type-bounds/handle-predicates-that-can-define-assoc-type.rs @@ -0,0 +1,10 @@ +// check-pass + +trait Foo {} +trait Bar { + type A; + type B; +} +trait Baz: Bar + Foo {} + +fn main() {} diff --git a/src/test/ui/associated-type-bounds/missing-trait-bound-for-assoc-fails.rs b/src/test/ui/associated-type-bounds/missing-trait-bound-for-assoc-fails.rs new file mode 100644 index 0000000000000..07d0f8f8769e5 --- /dev/null +++ b/src/test/ui/associated-type-bounds/missing-trait-bound-for-assoc-fails.rs @@ -0,0 +1,10 @@ +#[allow(dead_code)] +fn foo(_m: M) +where + M::Item: Temp, + //~^ ERROR cannot find trait `Temp` in this scope [E0405] + //~| ERROR associated type `Item` not found for `M` [E0220] +{ +} + +fn main() {} diff --git a/src/test/ui/associated-type-bounds/missing-trait-bound-for-assoc-fails.stderr b/src/test/ui/associated-type-bounds/missing-trait-bound-for-assoc-fails.stderr new file mode 100644 index 0000000000000..bc2807b03961c --- /dev/null +++ b/src/test/ui/associated-type-bounds/missing-trait-bound-for-assoc-fails.stderr @@ -0,0 +1,16 @@ +error[E0405]: cannot find trait `Temp` in this scope + --> $DIR/missing-trait-bound-for-assoc-fails.rs:4:14 + | +LL | M::Item: Temp, + | ^^^^ not found in this scope + +error[E0220]: associated type `Item` not found for `M` + --> $DIR/missing-trait-bound-for-assoc-fails.rs:4:8 + | +LL | M::Item: Temp, + | ^^^^ associated type `Item` not found + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0220, E0405. +For more information about an error, try `rustc --explain E0220`. diff --git a/src/test/ui/associated-type-bounds/super-trait-referencing-self.rs b/src/test/ui/associated-type-bounds/super-trait-referencing-self.rs new file mode 100644 index 0000000000000..c82ec01f4d61d --- /dev/null +++ b/src/test/ui/associated-type-bounds/super-trait-referencing-self.rs @@ -0,0 +1,12 @@ +// check-pass +trait Foo { + type Bar; +} +trait Qux: Foo + AsRef {} +trait Foo2 {} + +trait Qux2: Foo2 + AsRef { + type Bar; +} + +fn main() {} diff --git a/src/test/ui/associated-type-bounds/super-trait-referencing.rs b/src/test/ui/associated-type-bounds/super-trait-referencing.rs new file mode 100644 index 0000000000000..2e97535157fd2 --- /dev/null +++ b/src/test/ui/associated-type-bounds/super-trait-referencing.rs @@ -0,0 +1,19 @@ +// check-pass + +// The goal of this test is to ensure that T: Bar +// in the where clause does not cycle + +trait Foo { + type Item; +} + +trait Bar {} + +fn baz() +where + T: Foo, + T: Bar, +{ +} + +fn main() {} diff --git a/src/test/ui/associated-type-bounds/super-trait-where-referencing-self.rs b/src/test/ui/associated-type-bounds/super-trait-where-referencing-self.rs new file mode 100644 index 0000000000000..72a6be9ffc388 --- /dev/null +++ b/src/test/ui/associated-type-bounds/super-trait-where-referencing-self.rs @@ -0,0 +1,27 @@ +// check-pass + +// Test that we do not get a cycle due to +// resolving `Self::Bar` in the where clauses +// on a trait definition (in particular, in +// a where clause that is defining a superpredicate). + +trait Foo { + type Bar; +} +trait Qux +where + Self: Foo, + Self: AsRef, +{ +} +trait Foo2 {} + +trait Qux2 +where + Self: Foo2, + Self: AsRef, +{ + type Bar; +} + +fn main() {} diff --git a/src/test/ui/associated-type-bounds/traits-assoc-anonymized.rs b/src/test/ui/associated-type-bounds/traits-assoc-anonymized.rs new file mode 100644 index 0000000000000..a9d6eed810a6b --- /dev/null +++ b/src/test/ui/associated-type-bounds/traits-assoc-anonymized.rs @@ -0,0 +1,33 @@ +// check-pass + +pub struct LookupInternedStorage; + +impl QueryStorageOps for LookupInternedStorage +where + Q: Query, + for<'d> Q: QueryDb<'d>, +{ + fn fmt_index(&self, db: &>::DynDb) { + <>::DynDb as HasQueryGroup>::group_storage(db); + } +} + +pub trait HasQueryGroup { + fn group_storage(&self); +} + +pub trait QueryStorageOps +where + Q: Query, +{ + fn fmt_index(&self, db: &>::DynDb); +} + +pub trait QueryDb<'d> { + type DynDb: HasQueryGroup + 'd; + type Group; +} + +pub trait Query: for<'d> QueryDb<'d> {} + +fn main() {} diff --git a/src/test/ui/associated-type-bounds/traits-assoc-type-macros.rs b/src/test/ui/associated-type-bounds/traits-assoc-type-macros.rs new file mode 100644 index 0000000000000..ad5c6aed97c2c --- /dev/null +++ b/src/test/ui/associated-type-bounds/traits-assoc-type-macros.rs @@ -0,0 +1,43 @@ +// check-pass +// compile-flags:-Cincremental=tmp/traits-assoc-type-macros + +// This test case makes sure that we can compile with incremental compilation +// enabled when there are macros, traits, inheritance and associated types involved. + +trait Deserializer { + type Error; +} + +trait Deserialize { + fn deserialize(_: D) -> D::Error + where + D: Deserializer; +} + +macro_rules! impl_deserialize { + ($name:ident) => { + impl Deserialize for $name { + fn deserialize(_: D) -> D::Error + where + D: Deserializer, + { + loop {} + } + } + }; +} + +macro_rules! formats { + { + $($name:ident,)* + } => { + $( + pub struct $name; + + impl_deserialize!($name); + )* + } +} +formats! { Foo, Bar, } + +fn main() {} diff --git a/src/test/ui/cycle-projection-based-on-where-clause.rs b/src/test/ui/cycle-projection-based-on-where-clause.rs deleted file mode 100644 index d3609acfdff63..0000000000000 --- a/src/test/ui/cycle-projection-based-on-where-clause.rs +++ /dev/null @@ -1,24 +0,0 @@ -// Example cycle where a bound on `T` uses a shorthand for `T`. This -// creates a cycle because we have to know the bounds on `T` to figure -// out what trait defines `Item`, but we can't know the bounds on `T` -// without knowing how to handle `T::Item`. -// -// Note that in the future cases like this could perhaps become legal, -// if we got more fine-grained about our cycle detection or changed -// how we handle `T::Item` resolution. - -use std::ops::Add; - -// Preamble. -trait Trait { type Item; } - -struct A - where T : Trait, - T : Add - //~^ ERROR cycle detected -{ - data: T -} - -fn main() { -} diff --git a/src/test/ui/cycle-projection-based-on-where-clause.stderr b/src/test/ui/cycle-projection-based-on-where-clause.stderr deleted file mode 100644 index 2c337cc6bf903..0000000000000 --- a/src/test/ui/cycle-projection-based-on-where-clause.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error[E0391]: cycle detected when computing the bounds for type parameter `T` - --> $DIR/cycle-projection-based-on-where-clause.rs:17:19 - | -LL | T : Add - | ^^^^^^^ - | - = note: ...which again requires computing the bounds for type parameter `T`, completing the cycle -note: cycle used when computing explicit predicates of `A` - --> $DIR/cycle-projection-based-on-where-clause.rs:17:19 - | -LL | T : Add - | ^^^^^^^ - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0391`. diff --git a/src/test/ui/cycle-trait/cycle-trait-supertrait-direct.stderr b/src/test/ui/cycle-trait/cycle-trait-supertrait-direct.stderr index 8aa3ac8abf52c..ee54b2fd151d7 100644 --- a/src/test/ui/cycle-trait/cycle-trait-supertrait-direct.stderr +++ b/src/test/ui/cycle-trait/cycle-trait-supertrait-direct.stderr @@ -1,10 +1,15 @@ -error[E0391]: cycle detected when computing the supertraits of `Chromosome` +error[E0391]: cycle detected when computing the super predicates of `Chromosome` + --> $DIR/cycle-trait-supertrait-direct.rs:3:1 + | +LL | trait Chromosome: Chromosome { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: ...which requires computing the super traits of `Chromosome`... --> $DIR/cycle-trait-supertrait-direct.rs:3:19 | LL | trait Chromosome: Chromosome { | ^^^^^^^^^^ - | - = note: ...which again requires computing the supertraits of `Chromosome`, completing the cycle + = note: ...which again requires computing the super predicates of `Chromosome`, completing the cycle note: cycle used when collecting item types in top-level module --> $DIR/cycle-trait-supertrait-direct.rs:3:1 | diff --git a/src/test/ui/cycle-trait/cycle-trait-supertrait-indirect.stderr b/src/test/ui/cycle-trait/cycle-trait-supertrait-indirect.stderr index 9740f43a4ba97..0a2284e0efbca 100644 --- a/src/test/ui/cycle-trait/cycle-trait-supertrait-indirect.stderr +++ b/src/test/ui/cycle-trait/cycle-trait-supertrait-indirect.stderr @@ -1,16 +1,26 @@ -error[E0391]: cycle detected when computing the supertraits of `B` +error[E0391]: cycle detected when computing the super predicates of `B` + --> $DIR/cycle-trait-supertrait-indirect.rs:7:1 + | +LL | trait B: C { + | ^^^^^^^^^^ + | +note: ...which requires computing the super traits of `B`... --> $DIR/cycle-trait-supertrait-indirect.rs:7:10 | LL | trait B: C { | ^ +note: ...which requires computing the super predicates of `C`... + --> $DIR/cycle-trait-supertrait-indirect.rs:11:1 | -note: ...which requires computing the supertraits of `C`... +LL | trait C: B { } + | ^^^^^^^^^^ +note: ...which requires computing the super traits of `C`... --> $DIR/cycle-trait-supertrait-indirect.rs:11:10 | LL | trait C: B { } | ^ - = note: ...which again requires computing the supertraits of `B`, completing the cycle -note: cycle used when computing the supertraits of `A` + = note: ...which again requires computing the super predicates of `B`, completing the cycle +note: cycle used when computing the super traits of `A` --> $DIR/cycle-trait-supertrait-indirect.rs:4:10 | LL | trait A: B { diff --git a/src/test/ui/issues/issue-12511.stderr b/src/test/ui/issues/issue-12511.stderr index 37e38ff60ae4b..5f2b98c5237db 100644 --- a/src/test/ui/issues/issue-12511.stderr +++ b/src/test/ui/issues/issue-12511.stderr @@ -1,15 +1,25 @@ -error[E0391]: cycle detected when computing the supertraits of `T1` +error[E0391]: cycle detected when computing the super predicates of `T1` + --> $DIR/issue-12511.rs:1:1 + | +LL | trait T1 : T2 { + | ^^^^^^^^^^^^^ + | +note: ...which requires computing the super traits of `T1`... --> $DIR/issue-12511.rs:1:12 | LL | trait T1 : T2 { | ^^ +note: ...which requires computing the super predicates of `T2`... + --> $DIR/issue-12511.rs:5:1 | -note: ...which requires computing the supertraits of `T2`... +LL | trait T2 : T1 { + | ^^^^^^^^^^^^^ +note: ...which requires computing the super traits of `T2`... --> $DIR/issue-12511.rs:5:12 | LL | trait T2 : T1 { | ^^ - = note: ...which again requires computing the supertraits of `T1`, completing the cycle + = note: ...which again requires computing the super predicates of `T1`, completing the cycle note: cycle used when collecting item types in top-level module --> $DIR/issue-12511.rs:1:1 | diff --git a/src/test/ui/issues/issue-20772.stderr b/src/test/ui/issues/issue-20772.stderr index d64636310a368..4aecc7eab4628 100644 --- a/src/test/ui/issues/issue-20772.stderr +++ b/src/test/ui/issues/issue-20772.stderr @@ -1,4 +1,4 @@ -error[E0391]: cycle detected when computing the supertraits of `T` +error[E0391]: cycle detected when computing the super traits of `T` with associated type name `Item` --> $DIR/issue-20772.rs:1:1 | LL | / trait T : Iterator @@ -6,8 +6,8 @@ LL | | LL | | {} | |__^ | - = note: ...which again requires computing the supertraits of `T`, completing the cycle -note: cycle used when collecting item types in top-level module + = note: ...which again requires computing the super traits of `T` with associated type name `Item`, completing the cycle +note: cycle used when computing the super traits of `T` --> $DIR/issue-20772.rs:1:1 | LL | / trait T : Iterator diff --git a/src/test/ui/issues/issue-20825.stderr b/src/test/ui/issues/issue-20825.stderr index 5f9709d1c649b..ccbe06d9c0d56 100644 --- a/src/test/ui/issues/issue-20825.stderr +++ b/src/test/ui/issues/issue-20825.stderr @@ -1,11 +1,11 @@ -error[E0391]: cycle detected when computing the supertraits of `Processor` +error[E0391]: cycle detected when computing the super traits of `Processor` with associated type name `Input` --> $DIR/issue-20825.rs:5:1 | LL | pub trait Processor: Subscriber { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: ...which again requires computing the supertraits of `Processor`, completing the cycle -note: cycle used when collecting item types in top-level module + = note: ...which again requires computing the super traits of `Processor` with associated type name `Input`, completing the cycle +note: cycle used when computing the super traits of `Processor` --> $DIR/issue-20825.rs:5:1 | LL | pub trait Processor: Subscriber { diff --git a/src/test/ui/issues/issue-22673.rs b/src/test/ui/issues/issue-22673.rs index ba8057b684de8..4b9b4d6b23da4 100644 --- a/src/test/ui/issues/issue-22673.rs +++ b/src/test/ui/issues/issue-22673.rs @@ -1,5 +1,6 @@ -trait Expr : PartialEq { - //~^ ERROR: cycle detected +// check-pass + +trait Expr: PartialEq { type Item; } diff --git a/src/test/ui/issues/issue-22673.stderr b/src/test/ui/issues/issue-22673.stderr deleted file mode 100644 index 9e7e4b218b1c6..0000000000000 --- a/src/test/ui/issues/issue-22673.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error[E0391]: cycle detected when computing the supertraits of `Expr` - --> $DIR/issue-22673.rs:1:1 - | -LL | trait Expr : PartialEq { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: ...which again requires computing the supertraits of `Expr`, completing the cycle -note: cycle used when collecting item types in top-level module - --> $DIR/issue-22673.rs:1:1 - | -LL | trait Expr : PartialEq { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0391`. diff --git a/src/test/ui/lint/lint-unsafe-code.rs b/src/test/ui/lint/lint-unsafe-code.rs index 735f33f601f9d..4ac02b51f62fe 100644 --- a/src/test/ui/lint/lint-unsafe-code.rs +++ b/src/test/ui/lint/lint-unsafe-code.rs @@ -12,14 +12,28 @@ mod allowed_unsafe { unsafe fn also_allowed() {} unsafe trait AllowedUnsafe { } unsafe impl AllowedUnsafe for super::Bar {} + #[no_mangle] fn allowed2() {} + #[export_name = "foo"] fn allowed3() {} } macro_rules! unsafe_in_macro { - () => { + () => {{ + #[no_mangle] fn foo() {} //~ ERROR: declaration of a `no_mangle` function + #[no_mangle] static FOO: u32 = 5; //~ ERROR: declaration of a `no_mangle` static + #[export_name = "bar"] fn bar() {} + //~^ ERROR: declaration of a function with `export_name` + #[export_name = "BAR"] static BAR: u32 = 5; + //~^ ERROR: declaration of a static with `export_name` unsafe {} //~ ERROR: usage of an `unsafe` block - } + }} } +#[no_mangle] fn foo() {} //~ ERROR: declaration of a `no_mangle` function +#[no_mangle] static FOO: u32 = 5; //~ ERROR: declaration of a `no_mangle` static + +#[export_name = "bar"] fn bar() {} //~ ERROR: declaration of a function with `export_name` +#[export_name = "BAR"] static BAR: u32 = 5; //~ ERROR: declaration of a static with `export_name` + unsafe fn baz() {} //~ ERROR: declaration of an `unsafe` function unsafe trait Foo {} //~ ERROR: declaration of an `unsafe` trait unsafe impl Foo for Bar {} //~ ERROR: implementation of an `unsafe` trait diff --git a/src/test/ui/lint/lint-unsafe-code.stderr b/src/test/ui/lint/lint-unsafe-code.stderr index 0b2b9fab3925e..a8ef047e517b4 100644 --- a/src/test/ui/lint/lint-unsafe-code.stderr +++ b/src/test/ui/lint/lint-unsafe-code.stderr @@ -1,89 +1,168 @@ -error: declaration of an `unsafe` function - --> $DIR/lint-unsafe-code.rs:23:1 +error: declaration of a `no_mangle` function + --> $DIR/lint-unsafe-code.rs:31:1 | -LL | unsafe fn baz() {} - | ^^^^^^^^^^^^^^^^^^ +LL | #[no_mangle] fn foo() {} + | ^^^^^^^^^^^^ | note: the lint level is defined here --> $DIR/lint-unsafe-code.rs:3:9 | LL | #![deny(unsafe_code)] | ^^^^^^^^^^^ + = note: the linker's behavior with multiple libraries exporting duplicate symbol names is undefined and Rust cannot provide guarantees when you manually override them + +error: declaration of a `no_mangle` static + --> $DIR/lint-unsafe-code.rs:32:1 + | +LL | #[no_mangle] static FOO: u32 = 5; + | ^^^^^^^^^^^^ + | + = note: the linker's behavior with multiple libraries exporting duplicate symbol names is undefined and Rust cannot provide guarantees when you manually override them + +error: declaration of a function with `export_name` + --> $DIR/lint-unsafe-code.rs:34:1 + | +LL | #[export_name = "bar"] fn bar() {} + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the linker's behavior with multiple libraries exporting duplicate symbol names is undefined and Rust cannot provide guarantees when you manually override them + +error: declaration of a static with `export_name` + --> $DIR/lint-unsafe-code.rs:35:1 + | +LL | #[export_name = "BAR"] static BAR: u32 = 5; + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the linker's behavior with multiple libraries exporting duplicate symbol names is undefined and Rust cannot provide guarantees when you manually override them + +error: declaration of an `unsafe` function + --> $DIR/lint-unsafe-code.rs:37:1 + | +LL | unsafe fn baz() {} + | ^^^^^^^^^^^^^^^^^^ error: declaration of an `unsafe` trait - --> $DIR/lint-unsafe-code.rs:24:1 + --> $DIR/lint-unsafe-code.rs:38:1 | LL | unsafe trait Foo {} | ^^^^^^^^^^^^^^^^^^^ error: implementation of an `unsafe` trait - --> $DIR/lint-unsafe-code.rs:25:1 + --> $DIR/lint-unsafe-code.rs:39:1 | LL | unsafe impl Foo for Bar {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: declaration of an `unsafe` method - --> $DIR/lint-unsafe-code.rs:28:5 + --> $DIR/lint-unsafe-code.rs:42:5 | LL | unsafe fn baz(&self); | ^^^^^^^^^^^^^^^^^^^^^ error: implementation of an `unsafe` method - --> $DIR/lint-unsafe-code.rs:29:5 + --> $DIR/lint-unsafe-code.rs:43:5 | LL | unsafe fn provided(&self) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: implementation of an `unsafe` method - --> $DIR/lint-unsafe-code.rs:30:5 + --> $DIR/lint-unsafe-code.rs:44:5 | LL | unsafe fn provided_override(&self) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: implementation of an `unsafe` method - --> $DIR/lint-unsafe-code.rs:34:5 + --> $DIR/lint-unsafe-code.rs:48:5 | LL | unsafe fn baz(&self) {} | ^^^^^^^^^^^^^^^^^^^^^^^ error: implementation of an `unsafe` method - --> $DIR/lint-unsafe-code.rs:35:5 + --> $DIR/lint-unsafe-code.rs:49:5 | LL | unsafe fn provided_override(&self) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: implementation of an `unsafe` method - --> $DIR/lint-unsafe-code.rs:54:5 + --> $DIR/lint-unsafe-code.rs:68:5 | LL | unsafe fn provided_override(&self) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: implementation of an `unsafe` method - --> $DIR/lint-unsafe-code.rs:65:5 + --> $DIR/lint-unsafe-code.rs:79:5 | LL | unsafe fn provided(&self) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: implementation of an `unsafe` method - --> $DIR/lint-unsafe-code.rs:71:5 + --> $DIR/lint-unsafe-code.rs:85:5 | LL | unsafe fn provided(&self) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: implementation of an `unsafe` method - --> $DIR/lint-unsafe-code.rs:75:5 + --> $DIR/lint-unsafe-code.rs:89:5 | LL | unsafe fn baz(&self) {} | ^^^^^^^^^^^^^^^^^^^^^^^ error: usage of an `unsafe` block - --> $DIR/lint-unsafe-code.rs:86:5 + --> $DIR/lint-unsafe-code.rs:100:5 | LL | unsafe {} | ^^^^^^^^^ +error: declaration of a `no_mangle` function + --> $DIR/lint-unsafe-code.rs:21:9 + | +LL | #[no_mangle] fn foo() {} + | ^^^^^^^^^^^^ +... +LL | unsafe_in_macro!() + | ------------------ in this macro invocation + | + = note: the linker's behavior with multiple libraries exporting duplicate symbol names is undefined and Rust cannot provide guarantees when you manually override them + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: declaration of a `no_mangle` static + --> $DIR/lint-unsafe-code.rs:22:9 + | +LL | #[no_mangle] static FOO: u32 = 5; + | ^^^^^^^^^^^^ +... +LL | unsafe_in_macro!() + | ------------------ in this macro invocation + | + = note: the linker's behavior with multiple libraries exporting duplicate symbol names is undefined and Rust cannot provide guarantees when you manually override them + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: declaration of a function with `export_name` + --> $DIR/lint-unsafe-code.rs:23:9 + | +LL | #[export_name = "bar"] fn bar() {} + | ^^^^^^^^^^^^^^^^^^^^^^ +... +LL | unsafe_in_macro!() + | ------------------ in this macro invocation + | + = note: the linker's behavior with multiple libraries exporting duplicate symbol names is undefined and Rust cannot provide guarantees when you manually override them + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: declaration of a static with `export_name` + --> $DIR/lint-unsafe-code.rs:25:9 + | +LL | #[export_name = "BAR"] static BAR: u32 = 5; + | ^^^^^^^^^^^^^^^^^^^^^^ +... +LL | unsafe_in_macro!() + | ------------------ in this macro invocation + | + = note: the linker's behavior with multiple libraries exporting duplicate symbol names is undefined and Rust cannot provide guarantees when you manually override them + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + error: usage of an `unsafe` block - --> $DIR/lint-unsafe-code.rs:19:9 + --> $DIR/lint-unsafe-code.rs:27:9 | LL | unsafe {} | ^^^^^^^^^ @@ -93,5 +172,5 @@ LL | unsafe_in_macro!() | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 14 previous errors +error: aborting due to 22 previous errors diff --git a/src/test/ui/parser/issue-81806.rs b/src/test/ui/parser/issue-81806.rs new file mode 100644 index 0000000000000..ca86788dff79c --- /dev/null +++ b/src/test/ui/parser/issue-81806.rs @@ -0,0 +1,5 @@ +trait T { const +impl //~ ERROR: expected identifier, found keyword `impl` +} + +fn main() {} diff --git a/src/test/ui/parser/issue-81806.stderr b/src/test/ui/parser/issue-81806.stderr new file mode 100644 index 0000000000000..b8ada11d922b2 --- /dev/null +++ b/src/test/ui/parser/issue-81806.stderr @@ -0,0 +1,17 @@ +error: expected identifier, found keyword `impl` + --> $DIR/issue-81806.rs:2:1 + | +LL | trait T { const + | - while parsing this item list starting here +LL | impl + | ^^^^ expected identifier, found keyword +LL | } + | - the item list ends here + | +help: you can escape reserved keywords to use them as identifiers + | +LL | r#impl + | ^^^^^^ + +error: aborting due to previous error + diff --git a/src/tools/rust-analyzer b/src/tools/rust-analyzer index 1a59f75cdaa73..336909b63a14b 160000 --- a/src/tools/rust-analyzer +++ b/src/tools/rust-analyzer @@ -1 +1 @@ -Subproject commit 1a59f75cdaa730c16a694a4294eccf6dfe6fe0ad +Subproject commit 336909b63a14b801520c6627d90d750babcfe280