diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index 977b55a089058..9c032c55fe544 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -441,6 +441,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { msg, }) } + // Ensure we never consider the null pointer dereferencable. + if M::PointerTag::OFFSET_IS_ADDR { + assert_ne!(ptr.addr(), Size::ZERO); + } // Test align. Check this last; if both bounds and alignment are violated // we want the error to be about the bounds. if let Some(align) = align { diff --git a/compiler/rustc_data_structures/src/sso/set.rs b/compiler/rustc_data_structures/src/sso/set.rs index f71522d37148a..4fda3adb7b878 100644 --- a/compiler/rustc_data_structures/src/sso/set.rs +++ b/compiler/rustc_data_structures/src/sso/set.rs @@ -126,9 +126,10 @@ impl SsoHashSet { /// Adds a value to the set. /// - /// If the set did not have this value present, `true` is returned. + /// Returns whether the value was newly inserted. That is: /// - /// If the set did have this value present, `false` is returned. + /// - If the set did not previously contain this value, `true` is returned. + /// - If the set already contained this value, `false` is returned. #[inline] pub fn insert(&mut self, elem: T) -> bool { self.map.insert(elem, ()).is_none() diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index a71621a4d52c0..641b915f37362 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -145,15 +145,28 @@ impl<'tcx> ProjectionCandidateSet<'tcx> { } } -/// Takes the place of a +/// States returned from `poly_project_and_unify_type`. Takes the place +/// of the old return type, which was: +/// ```ignore (not-rust) /// Result< /// Result>>, InProgress>, /// MismatchedProjectionTypes<'tcx>, /// > +/// ``` pub(super) enum ProjectAndUnifyResult<'tcx> { + /// The projection bound holds subject to the given obligations. If the + /// projection cannot be normalized because the required trait bound does + /// not hold, this is returned, with `obligations` being a predicate that + /// cannot be proven. Holds(Vec>), + /// The projection cannot be normalized due to ambiguity. Resolving some + /// inference variables in the projection may fix this. FailedNormalization, + /// The project cannot be normalized because `poly_project_and_unify_type` + /// is called recursively while normalizing the same projection. Recursive, + // the projection can be normalized, but is not equal to the expected type. + // Returns the type error that arose from the mismatch. MismatchedProjectionTypes(MismatchedProjectionTypes<'tcx>), } @@ -163,19 +176,6 @@ pub(super) enum ProjectAndUnifyResult<'tcx> { /// ``` /// If successful, this may result in additional obligations. Also returns /// the projection cache key used to track these additional obligations. -/// -/// ## Returns -/// -/// - `Err(_)`: the projection can be normalized, but is not equal to the -/// expected type. -/// - `Ok(Err(InProgress))`: this is called recursively while normalizing -/// the same projection. -/// - `Ok(Ok(None))`: The projection cannot be normalized due to ambiguity -/// (resolving some inference variables in the projection may fix this). -/// - `Ok(Ok(Some(obligations)))`: The projection bound holds subject to -/// the given obligations. If the projection cannot be normalized because -/// the required trait bound doesn't hold this returned with `obligations` -/// being a predicate that cannot be proven. #[instrument(level = "debug", skip(selcx))] pub(super) fn poly_project_and_unify_type<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 0379b16334cdc..2ce2a44d3db76 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -81,10 +81,17 @@ pub fn trait_obligations<'a, 'tcx>( body_id: hir::HirId, trait_ref: &ty::TraitRef<'tcx>, span: Span, - item: Option<&'tcx hir::Item<'tcx>>, + item: &'tcx hir::Item<'tcx>, ) -> Vec> { - let mut wf = - WfPredicates { infcx, param_env, body_id, span, out: vec![], recursion_depth: 0, item }; + let mut wf = WfPredicates { + infcx, + param_env, + body_id, + span, + out: vec![], + recursion_depth: 0, + item: Some(item), + }; wf.compute_trait_ref(trait_ref, Elaborate::All); debug!(obligations = ?wf.out); wf.normalize() diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs index a6c7573b787c6..20ef97c085f18 100644 --- a/compiler/rustc_typeck/src/check/wfcheck.rs +++ b/compiler/rustc_typeck/src/check/wfcheck.rs @@ -1228,7 +1228,7 @@ fn check_impl<'tcx>( fcx.body_id, &trait_ref, ast_trait_ref.path.span, - Some(item), + item, ); debug!(?obligations); for obligation in obligations { diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs index 4b6f80ce57a83..7e3fefe4502d2 100644 --- a/compiler/rustc_typeck/src/collect/type_of.rs +++ b/compiler/rustc_typeck/src/collect/type_of.rs @@ -161,38 +161,23 @@ pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option< // We've encountered an `AnonConst` in some path, so we need to // figure out which generic parameter it corresponds to and return // the relevant type. - let filtered = path.segments.iter().find_map(|seg| { - seg.args? - .args + let Some((arg_index, segment)) = path.segments.iter().find_map(|seg| { + let args = seg.args?; + args.args + .iter() + .filter(|arg| arg.is_ty_or_const()) + .position(|arg| arg.id() == hir_id) + .map(|index| (index, seg)).or_else(|| args.bindings .iter() - .filter(|arg| arg.is_ty_or_const()) - .position(|arg| arg.id() == hir_id) - .map(|index| (index, seg)) - }); - - // FIXME(associated_const_generics): can we blend this with iteration above? - let (arg_index, segment) = match filtered { - None => { - let binding_filtered = path.segments.iter().find_map(|seg| { - seg.args? - .bindings - .iter() - .filter_map(TypeBinding::opt_const) - .position(|ct| ct.hir_id == hir_id) - .map(|idx| (idx, seg)) - }); - match binding_filtered { - Some(inner) => inner, - None => { - tcx.sess.delay_span_bug( - tcx.def_span(def_id), - "no arg matching AnonConst in path", - ); - return None; - } - } - } - Some(inner) => inner, + .filter_map(TypeBinding::opt_const) + .position(|ct| ct.hir_id == hir_id) + .map(|idx| (idx, seg))) + }) else { + tcx.sess.delay_span_bug( + tcx.def_span(def_id), + "no arg matching AnonConst in path", + ); + return None; }; // Try to use the segment resolution if it is valid, otherwise we diff --git a/library/alloc/src/collections/btree/set.rs b/library/alloc/src/collections/btree/set.rs index 20ef834eaeef3..caa629cf4e65e 100644 --- a/library/alloc/src/collections/btree/set.rs +++ b/library/alloc/src/collections/btree/set.rs @@ -770,10 +770,14 @@ impl BTreeSet { /// Adds a value to the set. /// - /// If the set did not have an equal element present, `true` is returned. + /// Returns whether the value was newly inserted. That is: /// - /// If the set did have an equal element present, `false` is returned, and - /// the entry is not updated. See the [module-level documentation] for more. + /// - If the set did not previously contain an equal value, `true` is + /// returned. + /// - If the set already contained an equal value, `false` is returned, and + /// the entry is not updated. + /// + /// See the [module-level documentation] for more. /// /// [module-level documentation]: index.html#insert-and-complex-keys /// diff --git a/library/core/src/num/dec2flt/mod.rs b/library/core/src/num/dec2flt/mod.rs index df0e7431f1f5f..a888ced49b376 100644 --- a/library/core/src/num/dec2flt/mod.rs +++ b/library/core/src/num/dec2flt/mod.rs @@ -126,7 +126,6 @@ macro_rules! from_str_float_impl { /// ```txt /// Float ::= Sign? ( 'inf' | 'infinity' | 'nan' | Number ) /// Number ::= ( Digit+ | - /// '.' Digit* | /// Digit+ '.' Digit* | /// Digit* '.' Digit+ ) Exp? /// Exp ::= 'e' Sign? Digit+ diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index 4ec423eb27f31..11ccdd9ea1cc5 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -896,6 +896,119 @@ where self.base.get_key_value(k) } + /// Attempts to get mutable references to `N` values in the map at once. + /// + /// Returns an array of length `N` with the results of each query. For soundness, at most one + /// mutable reference will be returned to any value. `None` will be returned if any of the + /// keys are duplicates or missing. + /// + /// # Examples + /// + /// ``` + /// #![feature(map_many_mut)] + /// use std::collections::HashMap; + /// + /// let mut libraries = HashMap::new(); + /// libraries.insert("Bodleian Library".to_string(), 1602); + /// libraries.insert("Athenæum".to_string(), 1807); + /// libraries.insert("Herzogin-Anna-Amalia-Bibliothek".to_string(), 1691); + /// libraries.insert("Library of Congress".to_string(), 1800); + /// + /// let got = libraries.get_many_mut([ + /// "Athenæum", + /// "Library of Congress", + /// ]); + /// assert_eq!( + /// got, + /// Some([ + /// &mut 1807, + /// &mut 1800, + /// ]), + /// ); + /// + /// // Missing keys result in None + /// let got = libraries.get_many_mut([ + /// "Athenæum", + /// "New York Public Library", + /// ]); + /// assert_eq!(got, None); + /// + /// // Duplicate keys result in None + /// let got = libraries.get_many_mut([ + /// "Athenæum", + /// "Athenæum", + /// ]); + /// assert_eq!(got, None); + /// ``` + #[inline] + #[unstable(feature = "map_many_mut", issue = "97601")] + pub fn get_many_mut(&mut self, ks: [&Q; N]) -> Option<[&'_ mut V; N]> + where + K: Borrow, + Q: Hash + Eq, + { + self.base.get_many_mut(ks) + } + + /// Attempts to get mutable references to `N` values in the map at once, without validating that + /// the values are unique. + /// + /// Returns an array of length `N` with the results of each query. `None` will be returned if + /// any of the keys are missing. + /// + /// For a safe alternative see [`get_many_mut`](Self::get_many_mut). + /// + /// # Safety + /// + /// Calling this method with overlapping keys is *[undefined behavior]* even if the resulting + /// references are not used. + /// + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + /// + /// # Examples + /// + /// ``` + /// #![feature(map_many_mut)] + /// use std::collections::HashMap; + /// + /// let mut libraries = HashMap::new(); + /// libraries.insert("Bodleian Library".to_string(), 1602); + /// libraries.insert("Athenæum".to_string(), 1807); + /// libraries.insert("Herzogin-Anna-Amalia-Bibliothek".to_string(), 1691); + /// libraries.insert("Library of Congress".to_string(), 1800); + /// + /// let got = libraries.get_many_mut([ + /// "Athenæum", + /// "Library of Congress", + /// ]); + /// assert_eq!( + /// got, + /// Some([ + /// &mut 1807, + /// &mut 1800, + /// ]), + /// ); + /// + /// // Missing keys result in None + /// let got = libraries.get_many_mut([ + /// "Athenæum", + /// "New York Public Library", + /// ]); + /// assert_eq!(got, None); + /// ``` + #[inline] + #[unstable(feature = "map_many_mut", issue = "97601")] + pub unsafe fn get_many_unchecked_mut( + &mut self, + ks: [&Q; N], + ) -> Option<[&'_ mut V; N]> + where + K: Borrow, + Q: Hash + Eq, + { + self.base.get_many_unchecked_mut(ks) + } + /// 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, but diff --git a/library/std/src/collections/hash/set.rs b/library/std/src/collections/hash/set.rs index da0572047eca8..19428fe9a2339 100644 --- a/library/std/src/collections/hash/set.rs +++ b/library/std/src/collections/hash/set.rs @@ -858,9 +858,10 @@ where /// Adds a value to the set. /// - /// If the set did not have this value present, `true` is returned. + /// Returns whether the value was newly inserted. That is: /// - /// If the set did have this value present, `false` is returned. + /// - If the set did not previously contain this value, `true` is returned. + /// - If the set already contained this value, `false` is returned. /// /// # Examples /// diff --git a/src/test/rustdoc/inline_cross/auxiliary/implementors_inline.rs b/src/test/rustdoc/inline_cross/auxiliary/implementors_inline.rs new file mode 100644 index 0000000000000..b003fb357d0f9 --- /dev/null +++ b/src/test/rustdoc/inline_cross/auxiliary/implementors_inline.rs @@ -0,0 +1,18 @@ +pub mod my_trait { + pub trait MyTrait { + fn my_fn(&self) -> Self; + } +} + +pub mod prelude { + #[doc(inline)] + pub use crate::my_trait::MyTrait; +} + +pub struct SomeStruct; + +impl my_trait::MyTrait for SomeStruct { + fn my_fn(&self) -> SomeStruct { + SomeStruct + } +} diff --git a/src/test/rustdoc/inline_cross/implementors-js.rs b/src/test/rustdoc/inline_cross/implementors-js.rs new file mode 100644 index 0000000000000..c79f05d8d3c9b --- /dev/null +++ b/src/test/rustdoc/inline_cross/implementors-js.rs @@ -0,0 +1,25 @@ +// aux-build:implementors_inline.rs +// build-aux-docs +// ignore-cross-compile + +extern crate implementors_inline; + +// @!has implementors/implementors_js/trait.MyTrait.js +// @has implementors/implementors_inline/my_trait/trait.MyTrait.js +// @!has implementors/implementors_inline/prelude/trait.MyTrait.js +// @has implementors_inline/my_trait/trait.MyTrait.html +// @has - '//script/@src' '../../implementors/implementors_inline/my_trait/trait.MyTrait.js' +// @has implementors_js/trait.MyTrait.html +// @has - '//script/@src' '../implementors/implementors_inline/my_trait/trait.MyTrait.js' +/// When re-exporting this trait, the HTML will be inlined, +/// but, vitally, the JavaScript will be located only at the +/// one canonical path. +pub use implementors_inline::prelude::MyTrait; + +pub struct OtherStruct; + +impl MyTrait for OtherStruct { + fn my_fn(&self) -> OtherStruct { + OtherStruct + } +} diff --git a/src/test/rustdoc/intra-doc/email-address.rs b/src/test/rustdoc/intra-doc/email-address.rs index ae74fbbc892bb..24161c3bb4858 100644 --- a/src/test/rustdoc/intra-doc/email-address.rs +++ b/src/test/rustdoc/intra-doc/email-address.rs @@ -1,8 +1,10 @@ -#![allow(rustdoc::broken_intra_doc_links)] +#![forbid(rustdoc::broken_intra_doc_links)] //! Email me at . //! Email me at . -//! Email me at (this warns but will still become a link). +//! Email me at . +//! Email me at . // @has email_address/index.html '//a[@href="mailto:hello@example.com"]' 'hello@example.com' // @has email_address/index.html '//a[@href="mailto:hello-world@example.com"]' 'hello-world@example.com' // @has email_address/index.html '//a[@href="mailto:hello@localhost"]' 'hello@localhost' +// @has email_address/index.html '//a[@href="mailto:prim@i32"]' 'prim@i32' diff --git a/src/test/ui/borrowck/issue-71546.rs b/src/test/ui/borrowck/issue-71546.rs new file mode 100644 index 0000000000000..943f7f86e5524 --- /dev/null +++ b/src/test/ui/borrowck/issue-71546.rs @@ -0,0 +1,19 @@ +// Regression test for #71546. + +// ignore-compare-mode-nll +// NLL stderr is different from the original one. + +pub fn serialize_as_csv(value: &V) -> Result +where + V: 'static, + for<'a> &'a V: IntoIterator, + for<'a> <&'a V as IntoIterator>::Item: ToString + 'static, +{ + let csv_str: String = value //~ ERROR: the associated type `<&'a V as IntoIterator>::Item` may not live long enough + .into_iter() + .map(|elem| elem.to_string()) + .collect::(); + Ok(csv_str) +} + +fn main() {} diff --git a/src/test/ui/borrowck/issue-71546.stderr b/src/test/ui/borrowck/issue-71546.stderr new file mode 100644 index 0000000000000..d479ca8f1d8b9 --- /dev/null +++ b/src/test/ui/borrowck/issue-71546.stderr @@ -0,0 +1,20 @@ +error[E0310]: the associated type `<&'a V as IntoIterator>::Item` may not live long enough + --> $DIR/issue-71546.rs:12:27 + | +LL | let csv_str: String = value + | ___________________________^ +LL | | .into_iter() +LL | | .map(|elem| elem.to_string()) + | |_____________________________________^ + | + = help: consider adding an explicit lifetime bound `<&'a V as IntoIterator>::Item: 'static`... + = note: ...so that the type `<&'a V as IntoIterator>::Item` will meet its required lifetime bounds... +note: ...that is required by this bound + --> $DIR/issue-71546.rs:10:55 + | +LL | for<'a> <&'a V as IntoIterator>::Item: ToString + 'static, + | ^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0310`.