diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index 715b174491bcb..a39ef22ec0834 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -307,53 +307,57 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.write_pointer(offset_ptr, dest)?; } sym::ptr_offset_from => { - let a = self.read_immediate(&args[0])?.to_scalar()?; - let b = self.read_immediate(&args[1])?.to_scalar()?; + let a = self.read_pointer(&args[0])?; + let b = self.read_pointer(&args[1])?; // Special case: if both scalars are *equal integers* // and not null, we pretend there is an allocation of size 0 right there, // and their offset is 0. (There's never a valid object at null, making it an // exception from the exception.) // This is the dual to the special exception for offset-by-0 - // in the inbounds pointer offset operation (see the Miri code, `src/operator.rs`). - // - // Control flow is weird because we cannot early-return (to reach the - // `go_to_block` at the end). - let done = if let (Ok(a), Ok(b)) = (a.try_to_int(), b.try_to_int()) { - let a = a.try_to_machine_usize(*self.tcx).unwrap(); - let b = b.try_to_machine_usize(*self.tcx).unwrap(); - if a == b && a != 0 { + // in the inbounds pointer offset operation (see `ptr_offset_inbounds` below). + match (self.memory.ptr_try_get_alloc(a), self.memory.ptr_try_get_alloc(b)) { + (Err(a), Err(b)) if a == b && a != 0 => { + // Both are the same non-null integer. self.write_scalar(Scalar::from_machine_isize(0, self), dest)?; - true - } else { - false } - } else { - false - }; - - if !done { - // General case: we need two pointers. - let a = self.scalar_to_ptr(a); - let b = self.scalar_to_ptr(b); - let (a_alloc_id, a_offset, _) = self.memory.ptr_get_alloc(a)?; - let (b_alloc_id, b_offset, _) = self.memory.ptr_get_alloc(b)?; - if a_alloc_id != b_alloc_id { - throw_ub_format!( - "ptr_offset_from cannot compute offset of pointers into different \ - allocations.", - ); + (Err(offset), _) | (_, Err(offset)) => { + throw_ub!(DanglingIntPointer(offset, CheckInAllocMsg::OffsetFromTest)); + } + (Ok((a_alloc_id, a_offset, _)), Ok((b_alloc_id, b_offset, _))) => { + // Both are pointers. They must be into the same allocation. + if a_alloc_id != b_alloc_id { + throw_ub_format!( + "ptr_offset_from cannot compute offset of pointers into different \ + allocations.", + ); + } + // And they must both be valid for zero-sized accesses ("in-bounds or one past the end"). + self.memory.check_ptr_access_align( + a, + Size::ZERO, + Align::ONE, + CheckInAllocMsg::OffsetFromTest, + )?; + self.memory.check_ptr_access_align( + b, + Size::ZERO, + Align::ONE, + CheckInAllocMsg::OffsetFromTest, + )?; + + // Compute offset. + let usize_layout = self.layout_of(self.tcx.types.usize)?; + let isize_layout = self.layout_of(self.tcx.types.isize)?; + let a_offset = ImmTy::from_uint(a_offset.bytes(), usize_layout); + let b_offset = ImmTy::from_uint(b_offset.bytes(), usize_layout); + let (val, _overflowed, _ty) = + self.overflowing_binary_op(BinOp::Sub, &a_offset, &b_offset)?; + let pointee_layout = self.layout_of(substs.type_at(0))?; + let val = ImmTy::from_scalar(val, isize_layout); + let size = ImmTy::from_int(pointee_layout.size.bytes(), isize_layout); + self.exact_div(&val, &size, dest)?; } - let usize_layout = self.layout_of(self.tcx.types.usize)?; - let isize_layout = self.layout_of(self.tcx.types.isize)?; - let a_offset = ImmTy::from_uint(a_offset.bytes(), usize_layout); - let b_offset = ImmTy::from_uint(b_offset.bytes(), usize_layout); - let (val, _overflowed, _ty) = - self.overflowing_binary_op(BinOp::Sub, &a_offset, &b_offset)?; - let pointee_layout = self.layout_of(substs.type_at(0))?; - let val = ImmTy::from_scalar(val, isize_layout); - let size = ImmTy::from_int(pointee_layout.size.bytes(), isize_layout); - self.exact_div(&val, &size, dest)?; } } diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index 5fe4672f17e5b..6397fcaaf8d10 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -388,9 +388,9 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { CheckInAllocMsg::DerefTest | CheckInAllocMsg::MemoryAccessTest => { AllocCheck::Dereferenceable } - CheckInAllocMsg::PointerArithmeticTest | CheckInAllocMsg::InboundsTest => { - AllocCheck::Live - } + CheckInAllocMsg::PointerArithmeticTest + | CheckInAllocMsg::OffsetFromTest + | CheckInAllocMsg::InboundsTest => AllocCheck::Live, }; let (size, align) = self.get_size_and_align(alloc_id, check)?; Ok((size, align, ())) diff --git a/compiler/rustc_expand/src/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs index 04137086088dd..dedfd779bb416 100644 --- a/compiler/rustc_expand/src/mbe/macro_parser.rs +++ b/compiler/rustc_expand/src/mbe/macro_parser.rs @@ -122,7 +122,7 @@ impl<'tt> TokenTreeOrTokenTreeSlice<'tt> { /// An unzipping of `TokenTree`s... see the `stack` field of `MatcherPos`. /// -/// This is used by `inner_parse_loop` to keep track of delimited submatchers that we have +/// This is used by `parse_tt_inner` to keep track of delimited submatchers that we have /// descended into. #[derive(Clone)] struct MatcherTtFrame<'tt> { @@ -439,9 +439,8 @@ fn nameize>( } Occupied(..) => return Err((sp, format!("duplicated bind name: {}", bind_name))), }, - // FIXME(c410-f3r) MetaVar and MetaVarExpr should be handled instead of being ignored - // https://github.com/rust-lang/rust/issues/9390 - TokenTree::MetaVar(..) | TokenTree::MetaVarExpr(..) | TokenTree::Token(..) => {} + TokenTree::Token(..) => (), + TokenTree::MetaVar(..) | TokenTree::MetaVarExpr(..) => unreachable!(), } Ok(()) @@ -481,21 +480,24 @@ fn token_name_eq(t1: &Token, t2: &Token) -> bool { /// successful execution of this function. /// - `next_items`: the set of newly generated items. These are used to replenish `cur_items` in /// the function `parse`. -/// - `eof_items`: the set of items that would be valid if this was the EOF. /// - `bb_items`: the set of items that are waiting for the black-box parser. /// - `token`: the current token of the parser. /// /// # Returns /// -/// A `ParseResult`. Note that matches are kept track of through the items generated. -fn inner_parse_loop<'root, 'tt>( +/// `Some(result)` if everything is finished, `None` otherwise. Note that matches are kept track of +/// through the items generated. +fn parse_tt_inner<'root, 'tt>( sess: &ParseSess, + ms: &[TokenTree], cur_items: &mut SmallVec<[MatcherPosHandle<'root, 'tt>; 1]>, - next_items: &mut Vec>, + next_items: &mut SmallVec<[MatcherPosHandle<'root, 'tt>; 1]>, bb_items: &mut SmallVec<[MatcherPosHandle<'root, 'tt>; 1]>, - eof_items: &mut EofItems<'root, 'tt>, token: &Token, -) -> Result<(), (rustc_span::Span, String)> { +) -> Option { + // Matcher positions that would be valid if the macro invocation was over now + let mut eof_items = EofItems::None; + // Pop items from `cur_items` until it is empty. while let Some(mut item) = cur_items.pop() { // When unzipped trees end, remove them. This corresponds to backtracking out of a @@ -522,6 +524,8 @@ fn inner_parse_loop<'root, 'tt>( // then we could be at the end of a sequence or at the beginning of the next // repetition. if let Some(repetition) = &item.repetition { + debug_assert!(matches!(item.top_elts, Tt(TokenTree::Sequence(..)))); + // At this point, regardless of whether there is a separator, we should add all // matches from the complete repetition of the sequence to the shared, top-level // `matches` list (actually, `up.matches`, which could itself not be the top-level, @@ -565,7 +569,7 @@ fn inner_parse_loop<'root, 'tt>( } else { // If we are not in a repetition, then being at the end of a matcher means that we // have reached the potential end of the input. - *eof_items = match eof_items { + eof_items = match eof_items { EofItems::None => EofItems::One(item), EofItems::One(_) | EofItems::Multiple => EofItems::Multiple, } @@ -613,7 +617,7 @@ fn inner_parse_loop<'root, 'tt>( // We need to match a metavar (but the identifier is invalid)... this is an error TokenTree::MetaVarDecl(span, _, None) => { if sess.missing_fragment_specifiers.borrow_mut().remove(&span).is_some() { - return Err((span, "missing fragment specifier".to_string())); + return Some(Error(span, "missing fragment specifier".to_string())); } } @@ -655,13 +659,36 @@ fn inner_parse_loop<'root, 'tt>( // rules. NOTE that this is not necessarily an error unless _all_ items in // `cur_items` end up doing this. There may still be some other matchers that do // end up working out. - TokenTree::Token(..) | TokenTree::MetaVar(..) | TokenTree::MetaVarExpr(..) => {} + TokenTree::Token(..) => {} + + TokenTree::MetaVar(..) | TokenTree::MetaVarExpr(..) => unreachable!(), } } } - // Yay a successful parse (so far)! - Ok(()) + // If we reached the EOF, check that there is EXACTLY ONE possible matcher. Otherwise, + // either the parse is ambiguous (which should never happen) or there is a syntax error. + if *token == token::Eof { + Some(match eof_items { + EofItems::One(mut eof_item) => { + let matches = + eof_item.matches.iter_mut().map(|dv| Lrc::make_mut(dv).pop().unwrap()); + nameize(sess, ms, matches) + } + EofItems::Multiple => { + Error(token.span, "ambiguity: multiple successful parses".to_string()) + } + EofItems::None => Failure( + Token::new( + token::Eof, + if token.span.is_dummy() { token.span } else { token.span.shrink_to_hi() }, + ), + "missing tokens in macro arguments", + ), + }) + } else { + None + } } /// Use the given sequence of token trees (`ms`) as a matcher. Match the token @@ -672,7 +699,7 @@ pub(super) fn parse_tt( macro_name: Ident, ) -> NamedParseResult { // A queue of possible matcher positions. We initialize it with the matcher position in which - // the "dot" is before the first token of the first token tree in `ms`. `inner_parse_loop` then + // the "dot" is before the first token of the first token tree in `ms`. `parse_tt_inner` then // processes all of these possible matcher positions and produces possible next positions into // `next_items`. After some post-processing, the contents of `next_items` replenish `cur_items` // and we start over again. @@ -681,135 +708,118 @@ pub(super) fn parse_tt( // there are frequently *no* others! -- are allocated on the heap. let mut initial = MatcherPos::new(ms); let mut cur_items = smallvec![MatcherPosHandle::Ref(&mut initial)]; - let mut next_items = Vec::new(); loop { - assert!(next_items.is_empty()); + let mut next_items = SmallVec::new(); // Matcher positions black-box parsed by parser.rs (`parser`) let mut bb_items = SmallVec::new(); - // Matcher positions that would be valid if the macro invocation was over now - let mut eof_items = EofItems::None; - // Process `cur_items` until either we have finished the input or we need to get some // parsing from the black-box parser done. The result is that `next_items` will contain a // bunch of possible next matcher positions in `next_items`. - match inner_parse_loop( + if let Some(result) = parse_tt_inner( parser.sess, + ms, &mut cur_items, &mut next_items, &mut bb_items, - &mut eof_items, &parser.token, ) { - Ok(()) => {} - Err((sp, msg)) => return Error(sp, msg), + return result; } - // inner parse loop handled all cur_items, so it's empty + // `parse_tt_inner` handled all cur_items, so it's empty. assert!(cur_items.is_empty()); - // We need to do some post processing after the `inner_parse_loop`. + // We need to do some post processing after the `parse_tt_inner`. // // Error messages here could be improved with links to original rules. - // If we reached the EOF, check that there is EXACTLY ONE possible matcher. Otherwise, - // either the parse is ambiguous (which should never happen) or there is a syntax error. - if parser.token == token::Eof { - return match eof_items { - EofItems::One(mut eof_item) => { - let matches = - eof_item.matches.iter_mut().map(|dv| Lrc::make_mut(dv).pop().unwrap()); - nameize(parser.sess, ms, matches) - } - EofItems::Multiple => { - Error(parser.token.span, "ambiguity: multiple successful parses".to_string()) - } - EofItems::None => Failure( - Token::new( - token::Eof, - if parser.token.span.is_dummy() { - parser.token.span - } else { - parser.token.span.shrink_to_hi() - }, - ), - "missing tokens in macro arguments", - ), - }; - } - // Performance hack: `eof_items` may share matchers via `Rc` with other things that we want - // to modify. Dropping `eof_items` now may drop these refcounts to 1, preventing an - // unnecessary implicit clone later in `Rc::make_mut`. - drop(eof_items); - - // If there are no possible next positions AND we aren't waiting for the black-box parser, - // then there is a syntax error. - if bb_items.is_empty() && next_items.is_empty() { - return Failure(parser.token.clone(), "no rules expected this token in macro call"); - } + match (next_items.len(), bb_items.len()) { + (0, 0) => { + // There are no possible next positions AND we aren't waiting for the black-box + // parser: syntax error. + return Failure(parser.token.clone(), "no rules expected this token in macro call"); + } - if (!bb_items.is_empty() && !next_items.is_empty()) || bb_items.len() > 1 { - // We need to call out to parse some rust nonterminal (black-box) parser. But something - // is wrong, because there is not EXACTLY ONE of these. - let nts = bb_items - .iter() - .map(|item| match item.top_elts.get_tt(item.idx) { - TokenTree::MetaVarDecl(_, bind, Some(kind)) => format!("{} ('{}')", kind, bind), - _ => panic!(), - }) - .collect::>() - .join(" or "); - - return Error( - parser.token.span, - format!( - "local ambiguity when calling macro `{macro_name}`: multiple parsing options: {}", - match next_items.len() { - 0 => format!("built-in NTs {}.", nts), - 1 => format!("built-in NTs {} or 1 other option.", nts), - n => format!("built-in NTs {} or {} other options.", nts, n), - } - ), - ); - } + (_, 0) => { + // Dump all possible `next_items` into `cur_items` for the next iteration. Then + // process the next token. + cur_items.extend(next_items.drain(..)); + parser.to_mut().bump(); + } - if !next_items.is_empty() { - // Dump all possible `next_items` into `cur_items` for the next iteration. Then process - // the next token. - cur_items.extend(next_items.drain(..)); - parser.to_mut().bump(); - } else { - // Finally, we have the case where we need to call the black-box parser to get some - // nonterminal. - assert_eq!(bb_items.len(), 1); - - let mut item = bb_items.pop().unwrap(); - if let TokenTree::MetaVarDecl(span, _, Some(kind)) = item.top_elts.get_tt(item.idx) { - let match_cur = item.match_cur; - // We use the span of the metavariable declaration to determine any - // edition-specific matching behavior for non-terminals. - let nt = match parser.to_mut().parse_nonterminal(kind) { - Err(mut err) => { - err.span_label( - span, - format!("while parsing argument for this `{}` macro fragment", kind), - ) - .emit(); - return ErrorReported; - } - Ok(nt) => nt, - }; - item.push_match(match_cur, MatchedNonterminal(Lrc::new(nt))); - item.idx += 1; - item.match_cur += 1; - } else { - unreachable!() + (0, 1) => { + // We need to call the black-box parser to get some nonterminal. + let mut item = bb_items.pop().unwrap(); + if let TokenTree::MetaVarDecl(span, _, Some(kind)) = item.top_elts.get_tt(item.idx) + { + let match_cur = item.match_cur; + // We use the span of the metavariable declaration to determine any + // edition-specific matching behavior for non-terminals. + let nt = match parser.to_mut().parse_nonterminal(kind) { + Err(mut err) => { + err.span_label( + span, + format!("while parsing argument for this `{kind}` macro fragment"), + ) + .emit(); + return ErrorReported; + } + Ok(nt) => nt, + }; + item.push_match(match_cur, MatchedNonterminal(Lrc::new(nt))); + item.idx += 1; + item.match_cur += 1; + } else { + unreachable!() + } + cur_items.push(item); + } + + (_, _) => { + // We need to call the black-box parser to get some nonterminal, but something is + // wrong. + return bb_items_ambiguity_error( + macro_name, + next_items, + bb_items, + parser.token.span, + ); } - cur_items.push(item); } assert!(!cur_items.is_empty()); } } + +fn bb_items_ambiguity_error<'root, 'tt>( + macro_name: Ident, + next_items: SmallVec<[MatcherPosHandle<'root, 'tt>; 1]>, + bb_items: SmallVec<[MatcherPosHandle<'root, 'tt>; 1]>, + token_span: rustc_span::Span, +) -> NamedParseResult { + let nts = bb_items + .iter() + .map(|item| match item.top_elts.get_tt(item.idx) { + TokenTree::MetaVarDecl(_, bind, Some(kind)) => { + format!("{} ('{}')", kind, bind) + } + _ => panic!(), + }) + .collect::>() + .join(" or "); + + Error( + token_span, + format!( + "local ambiguity when calling macro `{macro_name}`: multiple parsing options: {}", + match next_items.len() { + 0 => format!("built-in NTs {}.", nts), + 1 => format!("built-in NTs {} or 1 other option.", nts), + n => format!("built-in NTs {} or {} other options.", nts, n), + } + ), + ) +} diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index e524625f96646..c978659047698 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -184,6 +184,8 @@ pub enum CheckInAllocMsg { MemoryAccessTest, /// We are doing pointer arithmetic. PointerArithmeticTest, + /// We are doing pointer offset_from. + OffsetFromTest, /// None of the above -- generic/unspecific inbounds test. InboundsTest, } @@ -199,6 +201,7 @@ impl fmt::Display for CheckInAllocMsg { CheckInAllocMsg::DerefTest => "dereferencing pointer failed: ", CheckInAllocMsg::MemoryAccessTest => "memory access failed: ", CheckInAllocMsg::PointerArithmeticTest => "pointer arithmetic failed: ", + CheckInAllocMsg::OffsetFromTest => "out-of-bounds offset_from: ", CheckInAllocMsg::InboundsTest => "", } ) @@ -358,6 +361,9 @@ impl fmt::Display for UndefinedBehaviorInfo<'_> { DanglingIntPointer(0, CheckInAllocMsg::InboundsTest) => { write!(f, "null pointer is not a valid pointer for this operation") } + DanglingIntPointer(0, msg) => { + write!(f, "{}null pointer is not a valid pointer", msg) + } DanglingIntPointer(i, msg) => { write!(f, "{}0x{:x} is not a valid pointer", msg, i) } diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 06460c7b1b31d..122fe10e80f8f 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1534,6 +1534,16 @@ impl<'a> Parser<'a> { let name = self.parse_field_ident(adt_ty, lo)?; self.expect_field_ty_separator()?; let ty = self.parse_ty()?; + if self.token.kind == token::Colon && self.look_ahead(1, |tok| tok.kind != token::Colon) { + self.struct_span_err(self.token.span, "found single colon in a struct field type path") + .span_suggestion_verbose( + self.token.span, + "write a path separator here", + "::".to_string(), + Applicability::MaybeIncorrect, + ) + .emit(); + } if self.token.kind == token::Eq { self.bump(); let const_expr = self.parse_anon_const_expr()?; diff --git a/library/core/src/char/convert.rs b/library/core/src/char/convert.rs index 139841368d6a1..4ee0310b361fb 100644 --- a/library/core/src/char/convert.rs +++ b/library/core/src/char/convert.rs @@ -218,6 +218,8 @@ impl const From for char { } /// An error which can be returned when parsing a char. +/// +/// This `struct` is created when using the [`char::from_str`] method. #[stable(feature = "char_from_str", since = "1.20.0")] #[derive(Clone, Debug, PartialEq, Eq)] pub struct ParseCharError { @@ -300,7 +302,10 @@ impl TryFrom for char { } } -/// The error type returned when a conversion from u32 to char fails. +/// The error type returned when a conversion from [`prim@u32`] to [`prim@char`] fails. +/// +/// This `struct` is created by the [`char::try_from`](char#impl-TryFrom) method. +/// See its documentation for more. #[stable(feature = "try_from", since = "1.34.0")] #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct CharTryFromError(()); diff --git a/library/core/src/future/into_future.rs b/library/core/src/future/into_future.rs index 0912f8675fa84..8014dacdd98da 100644 --- a/library/core/src/future/into_future.rs +++ b/library/core/src/future/into_future.rs @@ -9,20 +9,20 @@ pub trait IntoFuture { /// Which kind of future are we turning this into? #[unstable(feature = "into_future", issue = "67644")] - type Future: Future; + type IntoFuture: Future; /// Creates a future from a value. #[unstable(feature = "into_future", issue = "67644")] #[lang = "into_future"] - fn into_future(self) -> Self::Future; + fn into_future(self) -> Self::IntoFuture; } #[unstable(feature = "into_future", issue = "67644")] impl IntoFuture for F { type Output = F::Output; - type Future = F; + type IntoFuture = F; - fn into_future(self) -> Self::Future { + fn into_future(self) -> Self::IntoFuture { self } } diff --git a/library/core/src/num/dec2flt/mod.rs b/library/core/src/num/dec2flt/mod.rs index d45ba595f1bae..541adb69b8e2b 100644 --- a/library/core/src/num/dec2flt/mod.rs +++ b/library/core/src/num/dec2flt/mod.rs @@ -112,21 +112,24 @@ macro_rules! from_str_float_impl { /// * '2.5E-10' /// * '5.' /// * '.5', or, equivalently, '0.5' - /// * 'inf', '-inf', 'NaN' + /// * 'inf', '-inf', '+infinity', 'NaN' + /// + /// Note that alphabetical characters are not case-sensitive. /// /// Leading and trailing whitespace represent an error. /// /// # Grammar /// - /// All strings that adhere to the following [EBNF] grammar - /// will result in an [`Ok`] being returned: + /// All strings that adhere to the following [EBNF] grammar when + /// lowercased will result in an [`Ok`] being returned: /// /// ```txt - /// Float ::= Sign? ( 'inf' | 'NaN' | Number ) + /// Float ::= Sign? ( 'inf' | 'infinity' | 'nan' | Number ) /// Number ::= ( Digit+ | + /// '.' Digit* | /// Digit+ '.' Digit* | /// Digit* '.' Digit+ ) Exp? - /// Exp ::= [eE] Sign? Digit+ + /// Exp ::= 'e' Sign? Digit+ /// Sign ::= [+-] /// Digit ::= [0-9] /// ``` diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 26f29a3524b00..34d1268a7df61 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -699,7 +699,13 @@ fn short_item_info( // Render the list of items inside one of the sections "Trait Implementations", // "Auto Trait Implementations," "Blanket Trait Implementations" (on struct/enum pages). -fn render_impls(cx: &Context<'_>, w: &mut Buffer, impls: &[&&Impl], containing_item: &clean::Item) { +fn render_impls( + cx: &Context<'_>, + w: &mut Buffer, + impls: &[&&Impl], + containing_item: &clean::Item, + toggle_open_by_default: bool, +) { let tcx = cx.tcx(); let mut rendered_impls = impls .iter() @@ -722,7 +728,7 @@ fn render_impls(cx: &Context<'_>, w: &mut Buffer, impls: &[&&Impl], containing_i is_on_foreign_type: false, show_default_items: true, show_non_assoc_items: true, - toggle_open_by_default: true, + toggle_open_by_default, }, ); buffer.into_inner() @@ -1143,7 +1149,7 @@ fn render_assoc_items_inner( concrete.into_iter().partition(|t| t.inner_impl().kind.is_blanket()); let mut impls = Buffer::empty_from(w); - render_impls(cx, &mut impls, &concrete, containing_item); + render_impls(cx, &mut impls, &concrete, containing_item, true); let impls = impls.into_inner(); if !impls.is_empty() { write!( @@ -1165,7 +1171,7 @@ fn render_assoc_items_inner( \
", ); - render_impls(cx, w, &synthetic, containing_item); + render_impls(cx, w, &synthetic, containing_item, false); w.write_str("
"); } @@ -1177,7 +1183,7 @@ fn render_assoc_items_inner( \
", ); - render_impls(cx, w, &blanket_impl, containing_item); + render_impls(cx, w, &blanket_impl, containing_item, false); w.write_str("
"); } } diff --git a/src/test/rustdoc-gui/toggle-docs.goml b/src/test/rustdoc-gui/toggle-docs.goml index f98111484f315..bbc85ecd4ad49 100644 --- a/src/test/rustdoc-gui/toggle-docs.goml +++ b/src/test/rustdoc-gui/toggle-docs.goml @@ -17,7 +17,14 @@ assert-text: ("#toggle-all-docs", "[−]") goto: file://|DOC_PATH|/test_docs/struct.Foo.html // We first check that everything is visible. assert-text: ("#toggle-all-docs", "[−]") -assert-attribute: ("details.rustdoc-toggle", {"open": ""}, ALL) +assert-attribute: ("#implementations-list details.rustdoc-toggle", {"open": ""}, ALL) +assert-attribute: ("#trait-implementations-list details.rustdoc-toggle", {"open": ""}, ALL) +assert-attribute-false: ( + "#blanket-implementations-list > details.rustdoc-toggle", + {"open": ""}, + ALL, +) + // We collapse them all. click: "#toggle-all-docs" wait-for: 50 diff --git a/src/test/ui/async-await/await-into-future.rs b/src/test/ui/async-await/await-into-future.rs index b74b168444085..6e1b155e181ee 100644 --- a/src/test/ui/async-await/await-into-future.rs +++ b/src/test/ui/async-await/await-into-future.rs @@ -10,9 +10,9 @@ struct AwaitMe; impl IntoFuture for AwaitMe { type Output = i32; - type Future = Pin>>; + type IntoFuture = Pin>>; - fn into_future(self) -> Self::Future { + fn into_future(self) -> Self::IntoFuture { Box::pin(me()) } } diff --git a/src/test/ui/consts/offset_from_ub.rs b/src/test/ui/consts/offset_from_ub.rs index cbc88bc4d9c38..fee61907eb3ca 100644 --- a/src/test/ui/consts/offset_from_ub.rs +++ b/src/test/ui/consts/offset_from_ub.rs @@ -1,4 +1,4 @@ -#![feature(const_ptr_offset_from)] +#![feature(const_ptr_offset_from, const_ptr_offset)] #![feature(core_intrinsics)] use std::intrinsics::ptr_offset_from; @@ -44,4 +44,30 @@ pub const DIFFERENT_INT: isize = { // offset_from with two different integers: l //~| 0x10 is not a valid pointer }; +const OUT_OF_BOUNDS_1: isize = { + let start_ptr = &4 as *const _ as *const u8; + let length = 10; + let end_ptr = (start_ptr).wrapping_add(length); + // First ptr is out of bounds + unsafe { ptr_offset_from(end_ptr, start_ptr) } //~ERROR evaluation of constant value failed + //~| pointer at offset 10 is out-of-bounds +}; + +const OUT_OF_BOUNDS_2: isize = { + let start_ptr = &4 as *const _ as *const u8; + let length = 10; + let end_ptr = (start_ptr).wrapping_add(length); + // Second ptr is out of bounds + unsafe { ptr_offset_from(start_ptr, end_ptr) } //~ERROR evaluation of constant value failed + //~| pointer at offset 10 is out-of-bounds +}; + +const OUT_OF_BOUNDS_SAME: isize = { + let start_ptr = &4 as *const _ as *const u8; + let length = 10; + let end_ptr = (start_ptr).wrapping_add(length); + unsafe { ptr_offset_from(end_ptr, end_ptr) } //~ERROR evaluation of constant value failed + //~| pointer at offset 10 is out-of-bounds +}; + fn main() {} diff --git a/src/test/ui/consts/offset_from_ub.stderr b/src/test/ui/consts/offset_from_ub.stderr index ffd6ad58c301d..4d60d4df203b3 100644 --- a/src/test/ui/consts/offset_from_ub.stderr +++ b/src/test/ui/consts/offset_from_ub.stderr @@ -10,7 +10,7 @@ error[E0080]: evaluation of constant value failed LL | unsafe { intrinsics::ptr_offset_from(self, origin) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | - | 0x2a is not a valid pointer + | out-of-bounds offset_from: 0x2a is not a valid pointer | inside `ptr::const_ptr::::offset_from` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | ::: $DIR/offset_from_ub.rs:23:14 @@ -28,14 +28,32 @@ error[E0080]: evaluation of constant value failed --> $DIR/offset_from_ub.rs:36:14 | LL | unsafe { ptr_offset_from(ptr, ptr) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^ null pointer is not a valid pointer for this operation + | ^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: null pointer is not a valid pointer error[E0080]: evaluation of constant value failed --> $DIR/offset_from_ub.rs:43:14 | LL | unsafe { ptr_offset_from(ptr2, ptr1) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ 0x10 is not a valid pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: 0x10 is not a valid pointer -error: aborting due to 5 previous errors +error[E0080]: evaluation of constant value failed + --> $DIR/offset_from_ub.rs:52:14 + | +LL | unsafe { ptr_offset_from(end_ptr, start_ptr) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: alloc18 has size 4, so pointer at offset 10 is out-of-bounds + +error[E0080]: evaluation of constant value failed + --> $DIR/offset_from_ub.rs:61:14 + | +LL | unsafe { ptr_offset_from(start_ptr, end_ptr) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: alloc21 has size 4, so pointer at offset 10 is out-of-bounds + +error[E0080]: evaluation of constant value failed + --> $DIR/offset_from_ub.rs:69:14 + | +LL | unsafe { ptr_offset_from(end_ptr, end_ptr) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: alloc24 has size 4, so pointer at offset 10 is out-of-bounds + +error: aborting due to 8 previous errors For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/offset_ub.stderr b/src/test/ui/consts/offset_ub.stderr index 4c3f373e0801c..237950a30e841 100644 --- a/src/test/ui/consts/offset_ub.stderr +++ b/src/test/ui/consts/offset_ub.stderr @@ -144,7 +144,7 @@ error[E0080]: evaluation of constant value failed LL | unsafe { intrinsics::offset(self, count) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | - | pointer arithmetic failed: 0x0 is not a valid pointer + | pointer arithmetic failed: null pointer is not a valid pointer | inside `ptr::const_ptr::::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | ::: $DIR/offset_ub.rs:22:50 diff --git a/src/test/ui/suggestions/struct-field-type-including-single-colon.rs b/src/test/ui/suggestions/struct-field-type-including-single-colon.rs new file mode 100644 index 0000000000000..b7ad6d996f1ab --- /dev/null +++ b/src/test/ui/suggestions/struct-field-type-including-single-colon.rs @@ -0,0 +1,20 @@ +mod foo { + struct A; + mod bar { + struct B; + } +} + +struct Foo { + a: foo:A, + //~^ ERROR found single colon in a struct field type path + //~| expected `,`, or `}`, found `:` +} + +struct Bar { + b: foo::bar:B, + //~^ ERROR found single colon in a struct field type path + //~| expected `,`, or `}`, found `:` +} + +fn main() {} diff --git a/src/test/ui/suggestions/struct-field-type-including-single-colon.stderr b/src/test/ui/suggestions/struct-field-type-including-single-colon.stderr new file mode 100644 index 0000000000000..189759d64fc4e --- /dev/null +++ b/src/test/ui/suggestions/struct-field-type-including-single-colon.stderr @@ -0,0 +1,36 @@ +error: found single colon in a struct field type path + --> $DIR/struct-field-type-including-single-colon.rs:9:11 + | +LL | a: foo:A, + | ^ + | +help: write a path separator here + | +LL | a: foo::A, + | ~~ + +error: expected `,`, or `}`, found `:` + --> $DIR/struct-field-type-including-single-colon.rs:9:11 + | +LL | a: foo:A, + | ^ + +error: found single colon in a struct field type path + --> $DIR/struct-field-type-including-single-colon.rs:15:16 + | +LL | b: foo::bar:B, + | ^ + | +help: write a path separator here + | +LL | b: foo::bar::B, + | ~~ + +error: expected `,`, or `}`, found `:` + --> $DIR/struct-field-type-including-single-colon.rs:15:16 + | +LL | b: foo::bar:B, + | ^ + +error: aborting due to 4 previous errors +