diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index 72dd44a4b4d98..35eca23a11625 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -50,11 +50,12 @@ pub enum Delimiter { Brace, /// `[ ... ]` Bracket, - /// `Ø ... Ø` + /// `/*«*/ ... /*»*/` /// An invisible delimiter, that may, for example, appear around tokens coming from a /// "macro variable" `$var`. It is important to preserve operator priorities in cases like /// `$var * 3` where `$var` is `1 + 2`. - /// Invisible delimiters might not survive roundtrip of a token stream through a string. + /// Invisible delimiters are not directly writable in normal Rust code except as comments. + /// Therefore, they might not survive a roundtrip of a token stream through a string. Invisible, } diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index e79f4f0a0950d..c02cdc295610f 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -590,15 +590,29 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere self.nbsp(); } self.word("{"); - if !tts.is_empty() { + let empty = tts.is_empty(); + if !empty { self.space(); } self.ibox(0); self.print_tts(tts, convert_dollar_crate); self.end(); - let empty = tts.is_empty(); self.bclose(span, empty); } + Some(Delimiter::Invisible) => { + self.word("/*«*/"); + let empty = tts.is_empty(); + if !empty { + self.space(); + } + self.ibox(0); + self.print_tts(tts, convert_dollar_crate); + self.end(); + if !empty { + self.space(); + } + self.word("/*»*/"); + } Some(delim) => { let token_str = self.token_kind_to_string(&token::OpenDelim(delim)); self.word(token_str); @@ -772,9 +786,8 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere token::CloseDelim(Delimiter::Bracket) => "]".into(), token::OpenDelim(Delimiter::Brace) => "{".into(), token::CloseDelim(Delimiter::Brace) => "}".into(), - token::OpenDelim(Delimiter::Invisible) | token::CloseDelim(Delimiter::Invisible) => { - "".into() - } + token::OpenDelim(Delimiter::Invisible) => "/*«*/".into(), + token::CloseDelim(Delimiter::Invisible) => "/*»*/".into(), token::Pound => "#".into(), token::Dollar => "$".into(), token::Question => "?".into(), diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index f2d833b320249..a8a5ac2f9d95d 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -84,14 +84,18 @@ impl<'tcx, Tag: Provenance> Immediate { } #[inline] - pub fn to_scalar_pair(self) -> InterpResult<'tcx, (Scalar, Scalar)> { + pub fn to_scalar_or_uninit_pair(self) -> (ScalarMaybeUninit, ScalarMaybeUninit) { match self { - Immediate::ScalarPair(val1, val2) => Ok((val1.check_init()?, val2.check_init()?)), - Immediate::Scalar(..) => { - bug!("Got a scalar where a scalar pair was expected") - } + Immediate::ScalarPair(val1, val2) => (val1, val2), + Immediate::Scalar(..) => bug!("Got a scalar where a scalar pair was expected"), } } + + #[inline] + pub fn to_scalar_pair(self) -> InterpResult<'tcx, (Scalar, Scalar)> { + let (val1, val2) = self.to_scalar_or_uninit_pair(); + Ok((val1.check_init()?, val2.check_init()?)) + } } // ScalarPair needs a type to interpret, so we often have an immediate and a type together @@ -248,9 +252,12 @@ impl<'tcx, Tag: Provenance> ImmTy<'tcx, Tag> { impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// Try reading an immediate in memory; this is interesting particularly for `ScalarPair`. /// Returns `None` if the layout does not permit loading this as a value. - fn try_read_immediate_from_mplace( + /// + /// This is an internal function; call `read_immediate` instead. + fn read_immediate_from_mplace_raw( &self, mplace: &MPlaceTy<'tcx, M::PointerTag>, + force: bool, ) -> InterpResult<'tcx, Option>> { if mplace.layout.is_unsized() { // Don't touch unsized @@ -271,42 +278,61 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // case where some of the bytes are initialized and others are not. So, we need an extra // check that walks over the type of `mplace` to make sure it is truly correct to treat this // like a `Scalar` (or `ScalarPair`). - match mplace.layout.abi { - Abi::Scalar(abi::Scalar::Initialized { .. }) => { - let scalar = alloc.read_scalar(alloc_range(Size::ZERO, mplace.layout.size))?; - Ok(Some(ImmTy { imm: scalar.into(), layout: mplace.layout })) - } + let scalar_layout = match mplace.layout.abi { + // `if` does not work nested inside patterns, making this a bit awkward to express. + Abi::Scalar(abi::Scalar::Initialized { value: s, .. }) => Some(s), + Abi::Scalar(s) if force => Some(s.primitive()), + _ => None, + }; + if let Some(_) = scalar_layout { + let scalar = alloc.read_scalar(alloc_range(Size::ZERO, mplace.layout.size))?; + return Ok(Some(ImmTy { imm: scalar.into(), layout: mplace.layout })); + } + let scalar_pair_layout = match mplace.layout.abi { Abi::ScalarPair( abi::Scalar::Initialized { value: a, .. }, abi::Scalar::Initialized { value: b, .. }, - ) => { - // We checked `ptr_align` above, so all fields will have the alignment they need. - // We would anyway check against `ptr_align.restrict_for_offset(b_offset)`, - // which `ptr.offset(b_offset)` cannot possibly fail to satisfy. - let (a_size, b_size) = (a.size(self), b.size(self)); - let b_offset = a_size.align_to(b.align(self).abi); - assert!(b_offset.bytes() > 0); // we later use the offset to tell apart the fields - let a_val = alloc.read_scalar(alloc_range(Size::ZERO, a_size))?; - let b_val = alloc.read_scalar(alloc_range(b_offset, b_size))?; - Ok(Some(ImmTy { imm: Immediate::ScalarPair(a_val, b_val), layout: mplace.layout })) - } - _ => Ok(None), + ) => Some((a, b)), + Abi::ScalarPair(a, b) if force => Some((a.primitive(), b.primitive())), + _ => None, + }; + if let Some((a, b)) = scalar_pair_layout { + // We checked `ptr_align` above, so all fields will have the alignment they need. + // We would anyway check against `ptr_align.restrict_for_offset(b_offset)`, + // which `ptr.offset(b_offset)` cannot possibly fail to satisfy. + let (a_size, b_size) = (a.size(self), b.size(self)); + let b_offset = a_size.align_to(b.align(self).abi); + assert!(b_offset.bytes() > 0); // we later use the offset to tell apart the fields + let a_val = alloc.read_scalar(alloc_range(Size::ZERO, a_size))?; + let b_val = alloc.read_scalar(alloc_range(b_offset, b_size))?; + return Ok(Some(ImmTy { + imm: Immediate::ScalarPair(a_val, b_val), + layout: mplace.layout, + })); } + // Neither a scalar nor scalar pair. + return Ok(None); } - /// Try returning an immediate for the operand. - /// If the layout does not permit loading this as an immediate, return where in memory - /// we can find the data. + /// Try returning an immediate for the operand. If the layout does not permit loading this as an + /// immediate, return where in memory we can find the data. /// Note that for a given layout, this operation will either always fail or always /// succeed! Whether it succeeds depends on whether the layout can be represented /// in an `Immediate`, not on which data is stored there currently. - pub fn try_read_immediate( + /// + /// If `force` is `true`, then even scalars with fields that can be ununit will be + /// read. This means the load is lossy and should not be written back! + /// This flag exists only for validity checking. + /// + /// This is an internal function that should not usually be used; call `read_immediate` instead. + pub fn read_immediate_raw( &self, src: &OpTy<'tcx, M::PointerTag>, + force: bool, ) -> InterpResult<'tcx, Result, MPlaceTy<'tcx, M::PointerTag>>> { Ok(match src.try_as_mplace() { Ok(ref mplace) => { - if let Some(val) = self.try_read_immediate_from_mplace(mplace)? { + if let Some(val) = self.read_immediate_from_mplace_raw(mplace, force)? { Ok(val) } else { Err(*mplace) @@ -322,7 +348,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { &self, op: &OpTy<'tcx, M::PointerTag>, ) -> InterpResult<'tcx, ImmTy<'tcx, M::PointerTag>> { - if let Ok(imm) = self.try_read_immediate(op)? { + if let Ok(imm) = self.read_immediate_raw(op, /*force*/ false)? { Ok(imm) } else { span_bug!(self.cur_span(), "primitive read failed for type: {:?}", op.layout.ty); diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index 380eb5263618b..df6e05bb13cde 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -720,7 +720,7 @@ where } trace!("write_immediate: {:?} <- {:?}: {}", *dest, src, dest.layout.ty); - // See if we can avoid an allocation. This is the counterpart to `try_read_immediate`, + // See if we can avoid an allocation. This is the counterpart to `read_immediate_raw`, // but not factored as a separate function. let mplace = match dest.place { Place::Local { frame, local } => { @@ -879,7 +879,7 @@ where } // Let us see if the layout is simple so we take a shortcut, avoid force_allocation. - let src = match self.try_read_immediate(src)? { + let src = match self.read_immediate_raw(src, /*force*/ false)? { Ok(src_val) => { assert!(!src.layout.is_unsized(), "cannot have unsized immediates"); // Yay, we got a value that we can write directly. diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index 71d29be97d5ec..92e3ac04dc418 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -20,8 +20,8 @@ use rustc_target::abi::{Abi, Scalar as ScalarAbi, Size, VariantIdx, Variants, Wr use std::hash::Hash; use super::{ - alloc_range, CheckInAllocMsg, GlobalAlloc, InterpCx, InterpResult, MPlaceTy, Machine, - MemPlaceMeta, OpTy, Scalar, ScalarMaybeUninit, ValueVisitor, + alloc_range, CheckInAllocMsg, GlobalAlloc, Immediate, InterpCx, InterpResult, MPlaceTy, + Machine, MemPlaceMeta, OpTy, Scalar, ScalarMaybeUninit, ValueVisitor, }; macro_rules! throw_validation_failure { @@ -487,6 +487,17 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' )) } + fn read_immediate_forced( + &self, + op: &OpTy<'tcx, M::PointerTag>, + ) -> InterpResult<'tcx, Immediate> { + Ok(*try_validation!( + self.ecx.read_immediate_raw(op, /*force*/ true), + self.path, + err_unsup!(ReadPointerAsBytes) => { "(potentially part of) a pointer" } expected { "plain (non-pointer) bytes" }, + ).unwrap()) + } + /// Check if this is a value of primitive type, and if yes check the validity of the value /// at that type. Return `true` if the type is indeed primitive. fn try_visit_primitive( @@ -626,18 +637,19 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' fn visit_scalar( &mut self, - op: &OpTy<'tcx, M::PointerTag>, + scalar: ScalarMaybeUninit, scalar_layout: ScalarAbi, ) -> InterpResult<'tcx> { // We check `is_full_range` in a slightly complicated way because *if* we are checking // number validity, then we want to ensure that `Scalar::Initialized` is indeed initialized, // i.e. that we go over the `check_init` below. + let size = scalar_layout.size(self.ecx); let is_full_range = match scalar_layout { ScalarAbi::Initialized { valid_range, .. } => { if M::enforce_number_validity(self.ecx) { false // not "full" since uninit is not accepted } else { - valid_range.is_full_for(op.layout.size) + valid_range.is_full_for(size) } } ScalarAbi::Union { .. } => true, @@ -646,21 +658,19 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' // Nothing to check return Ok(()); } - // We have something to check. + // We have something to check: it must at least be initialized. let valid_range = scalar_layout.valid_range(self.ecx); let WrappingRange { start, end } = valid_range; - let max_value = op.layout.size.unsigned_int_max(); + let max_value = size.unsigned_int_max(); assert!(end <= max_value); - // Determine the allowed range - let value = self.read_scalar(op)?; let value = try_validation!( - value.check_init(), + scalar.check_init(), self.path, - err_ub!(InvalidUninitBytes(None)) => { "{:x}", value } + err_ub!(InvalidUninitBytes(None)) => { "{:x}", scalar } expected { "something {}", wrapping_range_format(valid_range, max_value) }, ); let bits = match value.try_to_int() { - Ok(int) => int.assert_bits(op.layout.size), + Ok(int) => int.assert_bits(size), Err(_) => { // So this is a pointer then, and casting to an int failed. // Can only happen during CTFE. @@ -678,7 +688,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' } else { return Ok(()); } - } else if scalar_layout.valid_range(self.ecx).is_full_for(op.layout.size) { + } else if scalar_layout.valid_range(self.ecx).is_full_for(size) { // Easy. (This is reachable if `enforce_number_validity` is set.) return Ok(()); } else { @@ -817,13 +827,23 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> ); } Abi::Scalar(scalar_layout) => { - self.visit_scalar(op, scalar_layout)?; + let scalar = self.read_immediate_forced(op)?.to_scalar_or_uninit(); + self.visit_scalar(scalar, scalar_layout)?; + } + Abi::ScalarPair(a_layout, b_layout) => { + // We would validate these things as we descend into the fields, + // but that can miss bugs in layout computation. Layout computation + // is subtle due to enums having ScalarPair layout, where one field + // is the discriminant. + if cfg!(debug_assertions) { + let (a, b) = self.read_immediate_forced(op)?.to_scalar_or_uninit_pair(); + self.visit_scalar(a, a_layout)?; + self.visit_scalar(b, b_layout)?; + } } - Abi::ScalarPair { .. } | Abi::Vector { .. } => { - // These have fields that we already visited above, so we already checked - // all their scalar-level restrictions. - // There is also no equivalent to `rustc_layout_scalar_valid_range_start` - // that would make skipping them here an issue. + Abi::Vector { .. } => { + // No checks here, we assume layout computation gets this right. + // (This is harder to check since Miri does not represent these as `Immediate`.) } Abi::Aggregate { .. } => { // Nothing to do. diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs index 691f4fb0e5425..f7535d338da40 100644 --- a/compiler/rustc_mir_transform/src/const_prop.rs +++ b/compiler/rustc_mir_transform/src/const_prop.rs @@ -415,7 +415,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { // Try to read the local as an immediate so that if it is representable as a scalar, we can // handle it as such, but otherwise, just return the value as is. - Some(match self.ecx.try_read_immediate(&op) { + Some(match self.ecx.read_immediate_raw(&op, /*force*/ false) { Ok(Ok(imm)) => imm.into(), _ => op, }) @@ -709,8 +709,8 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { return; } - // FIXME> figure out what to do when try_read_immediate fails - let imm = self.use_ecx(|this| this.ecx.try_read_immediate(value)); + // FIXME> figure out what to do when read_immediate_raw fails + let imm = self.use_ecx(|this| this.ecx.read_immediate_raw(value, /*force*/ false)); if let Some(Ok(imm)) = imm { match *imm { diff --git a/compiler/rustc_mir_transform/src/const_prop_lint.rs b/compiler/rustc_mir_transform/src/const_prop_lint.rs index 4945c10c9aaa9..aa898cfd3ba5e 100644 --- a/compiler/rustc_mir_transform/src/const_prop_lint.rs +++ b/compiler/rustc_mir_transform/src/const_prop_lint.rs @@ -412,7 +412,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { // Try to read the local as an immediate so that if it is representable as a scalar, we can // handle it as such, but otherwise, just return the value as is. - Some(match self.ecx.try_read_immediate(&op) { + Some(match self.ecx.read_immediate_raw(&op, /*force*/ false) { Ok(Ok(imm)) => imm.into(), _ => op, }) diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 1bdf53cf84fed..df6733ac45f9b 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -486,6 +486,9 @@ struct DiagnosticMetadata<'ast> { current_where_predicate: Option<&'ast WherePredicate>, current_type_path: Option<&'ast Ty>, + + /// The current impl items (used to suggest). + current_impl_items: Option<&'ast [P]>, } struct LateResolutionVisitor<'a, 'b, 'ast> { @@ -1637,7 +1640,9 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { items: ref impl_items, .. }) => { + self.diagnostic_metadata.current_impl_items = Some(impl_items); self.resolve_implementation(generics, of_trait, &self_ty, item.id, impl_items); + self.diagnostic_metadata.current_impl_items = None; } ItemKind::Trait(box Trait { ref generics, ref bounds, ref items, .. }) => { diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 3076cc1131700..4f07d0076f140 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -6,7 +6,7 @@ use crate::path_names_to_string; use crate::{Module, ModuleKind, ModuleOrUniformRoot}; use crate::{PathResult, PathSource, Segment}; -use rustc_ast::visit::FnKind; +use rustc_ast::visit::{FnCtxt, FnKind}; use rustc_ast::{ self as ast, AssocItemKind, Expr, ExprKind, GenericParam, GenericParamKind, Item, ItemKind, NodeId, Path, Ty, TyKind, @@ -144,15 +144,22 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { let is_enum_variant = &|res| matches!(res, Res::Def(DefKind::Variant, _)); // Make the base error. + struct BaseError<'a> { + msg: String, + fallback_label: String, + span: Span, + could_be_expr: bool, + suggestion: Option<(Span, &'a str, String)>, + } let mut expected = source.descr_expected(); let path_str = Segment::names_to_string(path); let item_str = path.last().unwrap().ident; - let (base_msg, fallback_label, base_span, could_be_expr) = if let Some(res) = res { - ( - format!("expected {}, found {} `{}`", expected, res.descr(), path_str), - format!("not a {}", expected), + let base_error = if let Some(res) = res { + BaseError { + msg: format!("expected {}, found {} `{}`", expected, res.descr(), path_str), + fallback_label: format!("not a {expected}"), span, - match res { + could_be_expr: match res { Res::Def(DefKind::Fn, _) => { // Verify whether this is a fn call or an Fn used as a type. self.r @@ -171,22 +178,49 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { | Res::Local(_) => true, _ => false, }, - ) + suggestion: None, + } } else { let item_span = path.last().unwrap().ident.span; - let (mod_prefix, mod_str) = if path.len() == 1 { - (String::new(), "this scope".to_string()) + let (mod_prefix, mod_str, suggestion) = if path.len() == 1 { + debug!(?self.diagnostic_metadata.current_impl_items); + debug!(?self.diagnostic_metadata.current_function); + let suggestion = if let Some(items) = self.diagnostic_metadata.current_impl_items + && let Some((fn_kind, _)) = self.diagnostic_metadata.current_function + && self.current_trait_ref.is_none() + && let Some(FnCtxt::Assoc(_)) = fn_kind.ctxt() + && let Some(item) = items.iter().find(|i| { + if let AssocItemKind::Fn(fn_) = &i.kind + && !fn_.sig.decl.has_self() + && i.ident.name == item_str.name + { + debug!(?item_str.name); + debug!(?fn_.sig.decl.inputs); + return true + } + false + }) + { + Some(( + item_span, + "consider using the associated function", + format!("Self::{}", item.ident) + )) + } else { + None + }; + (String::new(), "this scope".to_string(), suggestion) } else if path.len() == 2 && path[0].ident.name == kw::PathRoot { if self.r.session.edition() > Edition::Edition2015 { // In edition 2018 onwards, the `::foo` syntax may only pull from the extern prelude // which overrides all other expectations of item type expected = "crate"; - (String::new(), "the list of imported crates".to_string()) + (String::new(), "the list of imported crates".to_string(), None) } else { - (String::new(), "the crate root".to_string()) + (String::new(), "the crate root".to_string(), None) } } else if path.len() == 2 && path[0].ident.name == kw::Crate { - (String::new(), "the crate root".to_string()) + (String::new(), "the crate root".to_string(), None) } else { let mod_path = &path[..path.len() - 1]; let mod_prefix = match self.resolve_path(mod_path, Some(TypeNS), None) { @@ -194,22 +228,28 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { _ => None, } .map_or_else(String::new, |res| format!("{} ", res.descr())); - (mod_prefix, format!("`{}`", Segment::names_to_string(mod_path))) + (mod_prefix, format!("`{}`", Segment::names_to_string(mod_path)), None) }; - ( - format!("cannot find {} `{}` in {}{}", expected, item_str, mod_prefix, mod_str), - if path_str == "async" && expected.starts_with("struct") { + BaseError { + msg: format!("cannot find {expected} `{item_str}` in {mod_prefix}{mod_str}"), + fallback_label: if path_str == "async" && expected.starts_with("struct") { "`async` blocks are only allowed in Rust 2018 or later".to_string() } else { - format!("not found in {}", mod_str) + format!("not found in {mod_str}") }, - item_span, - false, - ) + span: item_span, + could_be_expr: false, + suggestion, + } }; let code = source.error_code(res.is_some()); - let mut err = self.r.session.struct_span_err_with_code(base_span, &base_msg, code); + let mut err = + self.r.session.struct_span_err_with_code(base_error.span, &base_error.msg, code); + + if let Some(sugg) = base_error.suggestion { + err.span_suggestion_verbose(sugg.0, sugg.1, sugg.2, Applicability::MaybeIncorrect); + } if let Some(span) = self.diagnostic_metadata.current_block_could_be_bare_struct_literal { err.multipart_suggestion( @@ -269,7 +309,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { } } - self.detect_assoct_type_constraint_meant_as_path(base_span, &mut err); + self.detect_assoct_type_constraint_meant_as_path(base_error.span, &mut err); // Emit special messages for unresolved `Self` and `self`. if is_self_type(path, ns) { @@ -471,7 +511,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { source, res, &path_str, - &fallback_label, + &base_error.fallback_label, ) { // We do this to avoid losing a secondary span when we override the main error span. self.r.add_typo_suggestion(&mut err, typo_sugg, ident_span); @@ -479,8 +519,9 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { } } - let is_macro = base_span.from_expansion() && base_span.desugaring_kind().is_none(); - if !self.type_ascription_suggestion(&mut err, base_span) { + let is_macro = + base_error.span.from_expansion() && base_error.span.desugaring_kind().is_none(); + if !self.type_ascription_suggestion(&mut err, base_error.span) { let mut fallback = false; if let ( PathSource::Trait(AliasPossibility::Maybe), @@ -493,7 +534,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { let spans: Vec = bounds .iter() .map(|bound| bound.span()) - .filter(|&sp| sp != base_span) + .filter(|&sp| sp != base_error.span) .collect(); let start_span = bounds.iter().map(|bound| bound.span()).next().unwrap(); @@ -515,7 +556,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { multi_span.push_span_label(sp, msg); } multi_span.push_span_label( - base_span, + base_error.span, "expected this type to be a trait...".to_string(), ); err.span_help( @@ -525,14 +566,14 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { ); if bounds.iter().all(|bound| match bound { ast::GenericBound::Outlives(_) => true, - ast::GenericBound::Trait(tr, _) => tr.span == base_span, + ast::GenericBound::Trait(tr, _) => tr.span == base_error.span, }) { let mut sugg = vec![]; - if base_span != start_span { - sugg.push((start_span.until(base_span), String::new())); + if base_error.span != start_span { + sugg.push((start_span.until(base_error.span), String::new())); } - if base_span != end_span { - sugg.push((base_span.shrink_to_hi().to(end_span), String::new())); + if base_error.span != end_span { + sugg.push((base_error.span.shrink_to_hi().to(end_span), String::new())); } err.multipart_suggestion( @@ -550,7 +591,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { fallback = true; match self.diagnostic_metadata.current_let_binding { Some((pat_sp, Some(ty_sp), None)) - if ty_sp.contains(base_span) && could_be_expr => + if ty_sp.contains(base_error.span) && base_error.could_be_expr => { err.span_suggestion_short( pat_sp.between(ty_sp), @@ -568,7 +609,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { } if fallback { // Fallback label. - err.span_label(base_span, fallback_label); + err.span_label(base_error.span, base_error.fallback_label); } } if let Some(err_code) = &err.code { diff --git a/compiler/rustc_typeck/src/coherence/orphan.rs b/compiler/rustc_typeck/src/coherence/orphan.rs index 19e68f0b14f4f..f57986a985cde 100644 --- a/compiler/rustc_typeck/src/coherence/orphan.rs +++ b/compiler/rustc_typeck/src/coherence/orphan.rs @@ -44,6 +44,59 @@ fn orphan_check_impl(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), ErrorGua }; let sp = tcx.sess.source_map().guess_head_span(item.span); let tr = impl_.of_trait.as_ref().unwrap(); + + // Ensure no opaque types are present in this impl header. See issues #76202 and #86411 for examples, + // and #84660 where it would otherwise allow unsoundness. + if trait_ref.has_opaque_types() { + trace!("{:#?}", item); + // First we find the opaque type in question. + for ty in trait_ref.substs { + for ty in ty.walk() { + let ty::subst::GenericArgKind::Type(ty) = ty.unpack() else { continue }; + let ty::Opaque(def_id, _) = *ty.kind() else { continue }; + trace!(?def_id); + + // Then we search for mentions of the opaque type's type alias in the HIR + struct SpanFinder<'tcx> { + sp: Span, + def_id: DefId, + tcx: TyCtxt<'tcx>, + } + impl<'v, 'tcx> hir::intravisit::Visitor<'v> for SpanFinder<'tcx> { + #[instrument(level = "trace", skip(self, _id))] + fn visit_path(&mut self, path: &'v hir::Path<'v>, _id: hir::HirId) { + // You can't mention an opaque type directly, so we look for type aliases + if let hir::def::Res::Def(hir::def::DefKind::TyAlias, def_id) = path.res { + // And check if that type alias's type contains the opaque type we're looking for + for arg in self.tcx.type_of(def_id).walk() { + if let GenericArgKind::Type(ty) = arg.unpack() { + if let ty::Opaque(def_id, _) = *ty.kind() { + if def_id == self.def_id { + // Finally we update the span to the mention of the type alias + self.sp = path.span; + return; + } + } + } + } + } + hir::intravisit::walk_path(self, path) + } + } + + let mut visitor = SpanFinder { sp, def_id, tcx }; + hir::intravisit::walk_item(&mut visitor, item); + let reported = tcx + .sess + .struct_span_err(visitor.sp, "cannot implement trait on type alias impl trait") + .span_note(tcx.def_span(def_id), "type alias impl trait defined here") + .emit(); + return Err(reported); + } + } + span_bug!(sp, "opaque type not found, but `has_opaque_types` is set") + } + match traits::orphan_check(tcx, item.def_id.to_def_id()) { Ok(()) => {} Err(err) => emit_orphan_check_error( @@ -143,58 +196,6 @@ fn orphan_check_impl(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), ErrorGua } } - // Ensure no opaque types are present in this impl header. See issues #76202 and #86411 for examples, - // and #84660 where it would otherwise allow unsoundness. - if trait_ref.has_opaque_types() { - trace!("{:#?}", item); - // First we find the opaque type in question. - for ty in trait_ref.substs { - for ty in ty.walk() { - let ty::subst::GenericArgKind::Type(ty) = ty.unpack() else { continue }; - let ty::Opaque(def_id, _) = *ty.kind() else { continue }; - trace!(?def_id); - - // Then we search for mentions of the opaque type's type alias in the HIR - struct SpanFinder<'tcx> { - sp: Span, - def_id: DefId, - tcx: TyCtxt<'tcx>, - } - impl<'v, 'tcx> hir::intravisit::Visitor<'v> for SpanFinder<'tcx> { - #[instrument(level = "trace", skip(self, _id))] - fn visit_path(&mut self, path: &'v hir::Path<'v>, _id: hir::HirId) { - // You can't mention an opaque type directly, so we look for type aliases - if let hir::def::Res::Def(hir::def::DefKind::TyAlias, def_id) = path.res { - // And check if that type alias's type contains the opaque type we're looking for - for arg in self.tcx.type_of(def_id).walk() { - if let GenericArgKind::Type(ty) = arg.unpack() { - if let ty::Opaque(def_id, _) = *ty.kind() { - if def_id == self.def_id { - // Finally we update the span to the mention of the type alias - self.sp = path.span; - return; - } - } - } - } - } - hir::intravisit::walk_path(self, path) - } - } - - let mut visitor = SpanFinder { sp, def_id, tcx }; - hir::intravisit::walk_item(&mut visitor, item); - let reported = tcx - .sess - .struct_span_err(visitor.sp, "cannot implement trait on type alias impl trait") - .span_note(tcx.def_span(def_id), "type alias impl trait defined here") - .emit(); - return Err(reported); - } - } - span_bug!(sp, "opaque type not found, but `has_opaque_types` is set") - } - Ok(()) } diff --git a/compiler/rustc_typeck/src/constrained_generic_params.rs b/compiler/rustc_typeck/src/constrained_generic_params.rs index 909c99adab5d2..6f764a952c022 100644 --- a/compiler/rustc_typeck/src/constrained_generic_params.rs +++ b/compiler/rustc_typeck/src/constrained_generic_params.rs @@ -59,7 +59,7 @@ struct ParameterCollector { impl<'tcx> TypeVisitor<'tcx> for ParameterCollector { fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { match *t.kind() { - ty::Projection(..) | ty::Opaque(..) if !self.include_nonconstraining => { + ty::Projection(..) if !self.include_nonconstraining => { // projections are not injective return ControlFlow::CONTINUE; } diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 4bcc78ae0f4b2..5295745647365 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -374,19 +374,26 @@ impl Rc { } } - /// Constructs a new `Rc` using a closure `data_fn` that has access to a - /// weak reference to the constructing `Rc`. + /// Constructs a new `Rc` while giving you a `Weak` to the allocation, + /// to allow you to construct a `T` which holds a weak pointer to itself. /// /// Generally, a structure circularly referencing itself, either directly or - /// indirectly, should not hold a strong reference to prevent a memory leak. - /// In `data_fn`, initialization of `T` can make use of the weak reference - /// by cloning and storing it inside `T` for use at a later time. + /// indirectly, should not hold a strong reference to itself to prevent a memory leak. + /// Using this function, you get access to the weak pointer during the + /// initialization of `T`, before the `Rc` is created, such that you can + /// clone and store it inside the `T`. + /// + /// `new_cyclic` first allocates the managed allocation for the `Rc`, + /// then calls your closure, giving it a `Weak` to this allocation, + /// and only afterwards completes the construction of the `Rc` by placing + /// the `T` returned from your closure into the allocation. /// /// Since the new `Rc` is not fully-constructed until `Rc::new_cyclic` - /// returns, calling [`upgrade`] on the weak reference inside `data_fn` will + /// returns, calling [`upgrade`] on the weak reference inside your closure will /// fail and result in a `None` value. /// /// # Panics + /// /// If `data_fn` panics, the panic is propagated to the caller, and the /// temporary [`Weak`] is dropped normally. /// @@ -403,7 +410,12 @@ impl Rc { /// impl Gadget { /// /// Construct a reference counted Gadget. /// fn new() -> Rc { - /// Rc::new_cyclic(|me| Gadget { me: me.clone() }) + /// // `me` is a `Weak` pointing at the new allocation of the + /// // `Rc` we're constructing. + /// Rc::new_cyclic(|me| { + /// // Create the actual struct here. + /// Gadget { me: me.clone() } + /// }) /// } /// /// /// Return a reference counted pointer to Self. diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 1e2caddcacb19..2bd8f418ee90c 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -351,23 +351,31 @@ impl Arc { unsafe { Self::from_inner(Box::leak(x).into()) } } - /// Constructs a new `Arc` using a closure `data_fn` that has access to - /// a weak reference to the constructing `Arc`. + /// Constructs a new `Arc` while giving you a `Weak` to the allocation, + /// to allow you to construct a `T` which holds a weak pointer to itself. /// /// Generally, a structure circularly referencing itself, either directly or - /// indirectly, should not hold a strong reference to prevent a memory leak. - /// In `data_fn`, initialization of `T` can make use of the weak reference - /// by cloning and storing it inside `T` for use at a later time. + /// indirectly, should not hold a strong reference to itself to prevent a memory leak. + /// Using this function, you get access to the weak pointer during the + /// initialization of `T`, before the `Arc` is created, such that you can + /// clone and store it inside the `T`. /// - /// Since the new `Arc` is not fully-constructed until - /// `Arc::new_cyclic` returns, calling [`upgrade`] on the weak - /// reference inside `data_fn` will fail and result in a `None` value. + /// `new_cyclic` first allocates the managed allocation for the `Arc`, + /// then calls your closure, giving it a `Weak` to this allocation, + /// and only afterwards completes the construction of the `Arc` by placing + /// the `T` returned from your closure into the allocation. + /// + /// Since the new `Arc` is not fully-constructed until `Arc::new_cyclic` + /// returns, calling [`upgrade`] on the weak reference inside your closure will + /// fail and result in a `None` value. /// /// # Panics + /// /// If `data_fn` panics, the panic is propagated to the caller, and the /// temporary [`Weak`] is dropped normally. /// /// # Example + /// /// ``` /// # #![allow(dead_code)] /// use std::sync::{Arc, Weak}; @@ -379,7 +387,12 @@ impl Arc { /// impl Gadget { /// /// Construct a reference counted Gadget. /// fn new() -> Arc { - /// Arc::new_cyclic(|me| Gadget { me: me.clone() }) + /// // `me` is a `Weak` pointing at the new allocation of the + /// // `Arc` we're constructing. + /// Arc::new_cyclic(|me| { + /// // Create the actual struct here. + /// Gadget { me: me.clone() } + /// }) /// } /// /// /// Return a reference counted pointer to Self. diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index 1bf447347408d..b5c7982a5a871 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -2015,7 +2015,12 @@ macro_rules! int_impl { /// /// # Panics /// - /// This function will panic if `rhs` is 0 or the division results in overflow. + /// This function will panic if `rhs` is zero. + /// + /// ## Overflow behavior + /// + /// On overflow, this function will panic if overflow checks are enabled (default in debug + /// mode) and wrap if overflow checks are disabled (default in release mode). /// /// # Examples /// @@ -2050,7 +2055,12 @@ macro_rules! int_impl { /// /// # Panics /// - /// This function will panic if `rhs` is 0 or the division results in overflow. + /// This function will panic if `rhs` is zero. + /// + /// ## Overflow behavior + /// + /// On overflow, this function will panic if overflow checks are enabled (default in debug + /// mode) and wrap if overflow checks are disabled (default in release mode). /// /// # Examples /// @@ -2088,7 +2098,12 @@ macro_rules! int_impl { /// /// # Panics /// - /// This function will panic if `rhs` is 0 or the operation results in overflow. + /// This function will panic if `rhs` is zero. + /// + /// ## Overflow behavior + /// + /// On overflow, this function will panic if overflow checks are enabled (default in debug + /// mode) and wrap if overflow checks are disabled (default in release mode). /// /// # Examples /// @@ -2157,7 +2172,6 @@ macro_rules! int_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - #[rustc_inherit_overflow_checks] pub const fn checked_next_multiple_of(self, rhs: Self) -> Option { // This would otherwise fail when calculating `r` when self == T::MIN. if rhs == -1 { diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index ce52e4773ce1f..048d6bafcdecd 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -2020,7 +2020,7 @@ macro_rules! uint_impl { /// /// # Panics /// - /// This function will panic if `rhs` is 0. + /// This function will panic if `rhs` is zero. /// /// # Examples /// @@ -2034,7 +2034,6 @@ macro_rules! uint_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline(always)] - #[rustc_inherit_overflow_checks] pub const fn div_floor(self, rhs: Self) -> Self { self / rhs } @@ -2043,7 +2042,12 @@ macro_rules! uint_impl { /// /// # Panics /// - /// This function will panic if `rhs` is 0. + /// This function will panic if `rhs` is zero. + /// + /// ## Overflow behavior + /// + /// On overflow, this function will panic if overflow checks are enabled (default in debug + /// mode) and wrap if overflow checks are disabled (default in release mode). /// /// # Examples /// @@ -2073,7 +2077,12 @@ macro_rules! uint_impl { /// /// # Panics /// - /// This function will panic if `rhs` is 0 or the operation results in overflow. + /// This function will panic if `rhs` is zero. + /// + /// ## Overflow behavior + /// + /// On overflow, this function will panic if overflow checks are enabled (default in debug + /// mode) and wrap if overflow checks are disabled (default in release mode). /// /// # Examples /// @@ -2097,7 +2106,7 @@ macro_rules! uint_impl { } /// Calculates the smallest value greater than or equal to `self` that - /// is a multiple of `rhs`. Returns `None` is `rhs` is zero or the + /// is a multiple of `rhs`. Returns `None` if `rhs` is zero or the /// operation would result in overflow. /// /// # Examples @@ -2115,7 +2124,6 @@ macro_rules! uint_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - #[rustc_inherit_overflow_checks] pub const fn checked_next_multiple_of(self, rhs: Self) -> Option { match try_opt!(self.checked_rem(rhs)) { 0 => Some(self), diff --git a/library/core/tests/num/i128.rs b/library/core/tests/num/i128.rs index 72c0b225991f6..1ddd20f33d0b1 100644 --- a/library/core/tests/num/i128.rs +++ b/library/core/tests/num/i128.rs @@ -1 +1 @@ -int_module!(i128, i128); +int_module!(i128); diff --git a/library/core/tests/num/i16.rs b/library/core/tests/num/i16.rs index f5544b914b73d..c7aa9fff964ed 100644 --- a/library/core/tests/num/i16.rs +++ b/library/core/tests/num/i16.rs @@ -1 +1 @@ -int_module!(i16, i16); +int_module!(i16); diff --git a/library/core/tests/num/i32.rs b/library/core/tests/num/i32.rs index 4acc760ffac99..efd5b1596a80d 100644 --- a/library/core/tests/num/i32.rs +++ b/library/core/tests/num/i32.rs @@ -1,4 +1,4 @@ -int_module!(i32, i32); +int_module!(i32); #[test] fn test_arith_operation() { diff --git a/library/core/tests/num/i64.rs b/library/core/tests/num/i64.rs index fa4d2ab6638d7..93d23c10adf7e 100644 --- a/library/core/tests/num/i64.rs +++ b/library/core/tests/num/i64.rs @@ -1 +1 @@ -int_module!(i64, i64); +int_module!(i64); diff --git a/library/core/tests/num/i8.rs b/library/core/tests/num/i8.rs index ccec6915fe090..887d4f17d25ff 100644 --- a/library/core/tests/num/i8.rs +++ b/library/core/tests/num/i8.rs @@ -1 +1 @@ -int_module!(i8, i8); +int_module!(i8); diff --git a/library/core/tests/num/int_macros.rs b/library/core/tests/num/int_macros.rs index d2d655ea2c750..8b84a78e6be08 100644 --- a/library/core/tests/num/int_macros.rs +++ b/library/core/tests/num/int_macros.rs @@ -1,9 +1,9 @@ macro_rules! int_module { - ($T:ident, $T_i:ident) => { + ($T:ident) => { #[cfg(test)] mod tests { use core::ops::{BitAnd, BitOr, BitXor, Not, Shl, Shr}; - use core::$T_i::*; + use core::$T::*; use crate::num; diff --git a/library/core/tests/num/u128.rs b/library/core/tests/num/u128.rs index 716d1836f2c0e..a7b0f9effefb9 100644 --- a/library/core/tests/num/u128.rs +++ b/library/core/tests/num/u128.rs @@ -1 +1 @@ -uint_module!(u128, u128); +uint_module!(u128); diff --git a/library/core/tests/num/u16.rs b/library/core/tests/num/u16.rs index 435b914224c5a..010596a34a56c 100644 --- a/library/core/tests/num/u16.rs +++ b/library/core/tests/num/u16.rs @@ -1 +1 @@ -uint_module!(u16, u16); +uint_module!(u16); diff --git a/library/core/tests/num/u32.rs b/library/core/tests/num/u32.rs index 71dc005dea370..687d3bbaa907f 100644 --- a/library/core/tests/num/u32.rs +++ b/library/core/tests/num/u32.rs @@ -1 +1 @@ -uint_module!(u32, u32); +uint_module!(u32); diff --git a/library/core/tests/num/u64.rs b/library/core/tests/num/u64.rs index b498ebc52042e..ee55071e94996 100644 --- a/library/core/tests/num/u64.rs +++ b/library/core/tests/num/u64.rs @@ -1 +1 @@ -uint_module!(u64, u64); +uint_module!(u64); diff --git a/library/core/tests/num/u8.rs b/library/core/tests/num/u8.rs index 68e938be704ac..12b038ce0f75c 100644 --- a/library/core/tests/num/u8.rs +++ b/library/core/tests/num/u8.rs @@ -1 +1 @@ -uint_module!(u8, u8); +uint_module!(u8); diff --git a/library/core/tests/num/uint_macros.rs b/library/core/tests/num/uint_macros.rs index 49f8f1f13fad4..93ae620c23302 100644 --- a/library/core/tests/num/uint_macros.rs +++ b/library/core/tests/num/uint_macros.rs @@ -1,9 +1,9 @@ macro_rules! uint_module { - ($T:ident, $T_i:ident) => { + ($T:ident) => { #[cfg(test)] mod tests { use core::ops::{BitAnd, BitOr, BitXor, Not, Shl, Shr}; - use core::$T_i::*; + use core::$T::*; use std::str::FromStr; use crate::num; diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs index f1c5eaad868e9..6f7c6305afc14 100644 --- a/library/proc_macro/src/lib.rs +++ b/library/proc_macro/src/lib.rs @@ -703,11 +703,12 @@ pub enum Delimiter { /// `[ ... ]` #[stable(feature = "proc_macro_lib2", since = "1.29.0")] Bracket, - /// `Ø ... Ø` + /// `/*«*/ ... /*»*/` /// An invisible delimiter, that may, for example, appear around tokens coming from a /// "macro variable" `$var`. It is important to preserve operator priorities in cases like /// `$var * 3` where `$var` is `1 + 2`. - /// Invisible delimiters might not survive roundtrip of a token stream through a string. + /// Invisible delimiters are not directly writable in normal Rust code except as comments. + /// Therefore, they might not survive a roundtrip of a token stream through a string. #[stable(feature = "proc_macro_lib2", since = "1.29.0")] None, } diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index 1dfd9c762c46e..667f89c07e212 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -7,6 +7,8 @@ /* global onEach, onEachLazy, removeClass */ /* global switchTheme, useSystemTheme */ +"use strict"; + if (!String.prototype.startsWith) { String.prototype.startsWith = function(searchString, position) { position = position || 0; @@ -292,15 +294,12 @@ function loadCss(cssFileName) { } (function() { - "use strict"; - function loadScript(url) { const script = document.createElement('script'); script.src = url; document.head.append(script); } - getSettingsButton().onclick = event => { event.preventDefault(); loadScript(window.settingsJS); diff --git a/src/librustdoc/html/static/js/scrape-examples.js b/src/librustdoc/html/static/js/scrape-examples.js index 491b3950ae6eb..70fcef522129e 100644 --- a/src/librustdoc/html/static/js/scrape-examples.js +++ b/src/librustdoc/html/static/js/scrape-examples.js @@ -4,6 +4,8 @@ /* eslint prefer-arrow-callback: "error" */ /* global addClass, hasClass, removeClass, onEachLazy */ +"use strict"; + (function () { // Number of lines shown when code viewer is not expanded const MAX_LINES = 10; diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index 60ad431ba7a99..54ce2508c468d 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -5,7 +5,9 @@ /* global addClass, getNakedUrl, getSettingValue, hasOwnPropertyRustdoc, initSearch, onEach */ /* global onEachLazy, removeClass, searchState, browserSupportsHistoryApi */ -(function () { +"use strict"; + +(function() { // This mapping table should match the discriminants of // `rustdoc::formats::item_type::ItemType` type in Rust. const itemTypes = [ diff --git a/src/librustdoc/html/static/js/settings.js b/src/librustdoc/html/static/js/settings.js index 43b24245ab2e8..119d4b07665a4 100644 --- a/src/librustdoc/html/static/js/settings.js +++ b/src/librustdoc/html/static/js/settings.js @@ -7,6 +7,8 @@ /* global addClass, removeClass, onEach, onEachLazy, NOT_DISPLAYED_ID */ /* global MAIN_ID, getVar, getSettingsButton, switchDisplayedElement, getNotDisplayedElem */ +"use strict"; + (function () { const isSettingsPage = window.location.pathname.endsWith("/settings.html"); diff --git a/src/librustdoc/html/static/js/source-script.js b/src/librustdoc/html/static/js/source-script.js index 290bf40a8f577..f788d41d2ded4 100644 --- a/src/librustdoc/html/static/js/source-script.js +++ b/src/librustdoc/html/static/js/source-script.js @@ -9,7 +9,10 @@ // Local js definitions: /* global addClass, getCurrentValue, hasClass, onEachLazy, removeClass, browserSupportsHistoryApi */ /* global updateLocalStorage */ -(function () { + +"use strict"; + +(function() { function getCurrentFilePath() { const parts = window.location.pathname.split("/"); diff --git a/src/librustdoc/html/static/js/storage.js b/src/librustdoc/html/static/js/storage.js index 913fc278eb387..052731e99aed2 100644 --- a/src/librustdoc/html/static/js/storage.js +++ b/src/librustdoc/html/static/js/storage.js @@ -3,6 +3,8 @@ /* eslint prefer-const: "error" */ /* eslint prefer-arrow-callback: "error" */ +"use strict"; + const darkThemes = ["dark", "ayu"]; window.currentTheme = document.getElementById("themeStyle"); window.mainTheme = document.getElementById("mainThemeStyle"); diff --git a/src/test/ui/proc-macro/auxiliary/expand-expr.rs b/src/test/ui/proc-macro/auxiliary/expand-expr.rs index 2bc34f3c6bfc0..a2e30e2e93b5a 100644 --- a/src/test/ui/proc-macro/auxiliary/expand-expr.rs +++ b/src/test/ui/proc-macro/auxiliary/expand-expr.rs @@ -12,6 +12,15 @@ use std::str::FromStr; #[proc_macro] pub fn expand_expr_is(input: TokenStream) -> TokenStream { + expand_expr_is_inner(input, false) +} + +#[proc_macro] +pub fn expand_expr_is_trim(input: TokenStream) -> TokenStream { + expand_expr_is_inner(input, true) +} + +fn expand_expr_is_inner(input: TokenStream, trim_invisible: bool) -> TokenStream { let mut iter = input.into_iter(); let mut expected_tts = Vec::new(); loop { @@ -22,14 +31,18 @@ pub fn expand_expr_is(input: TokenStream) -> TokenStream { } } - let expected = expected_tts.into_iter().collect::(); - let expanded = iter.collect::().expand_expr().expect("expand_expr failed"); - assert!( - expected.to_string() == expanded.to_string(), - "assert failed\nexpected: `{}`\nexpanded: `{}`", - expected.to_string(), - expanded.to_string() - ); + // If requested, trim the "invisible" delimiters at the start and end. + let expected = expected_tts.into_iter().collect::().to_string(); + let expected = if trim_invisible { + let len1 = "/*«*/ ".len(); + let len2 = " /*»*/".len(); + &expected[len1..expected.len() - len2] + } else { + &expected[..] + }; + let expanded = iter.collect::().expand_expr().unwrap().to_string(); + + assert_eq!(expected, expanded); TokenStream::new() } diff --git a/src/test/ui/proc-macro/capture-macro-rules-invoke.stdout b/src/test/ui/proc-macro/capture-macro-rules-invoke.stdout index 4de8746a1b460..3d0e7eaff00d8 100644 --- a/src/test/ui/proc-macro/capture-macro-rules-invoke.stdout +++ b/src/test/ui/proc-macro/capture-macro-rules-invoke.stdout @@ -1,4 +1,5 @@ PRINT-BANG INPUT (DISPLAY): self +PRINT-BANG RE-COLLECTED (DISPLAY): /*«*/ self /*»*/ PRINT-BANG INPUT (DEBUG): TokenStream [ Group { delimiter: None, @@ -13,8 +14,10 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ ] PRINT-BANG INPUT (DISPLAY): 1 + 1, { "a" }, let a = 1;, String, my_name, 'a, my_val = 30, std::option::Option, pub(in some::path) , [a b c], -30 -PRINT-BANG RE-COLLECTED (DISPLAY): 1 + 1, { "a" }, let a = 1, String, my_name, 'a, my_val = 30, -std :: option :: Option, pub(in some :: path), [a b c], - 30 +PRINT-BANG RE-COLLECTED (DISPLAY): /*«*/ 1 + 1 /*»*/, /*«*/ { "a" } /*»*/, /*«*/ let a = 1 /*»*/, /*«*/ +String /*»*/, my_name, /*«*/ 'a /*»*/, /*«*/ my_val = 30 /*»*/, /*«*/ +std :: option :: Option /*»*/, /*«*/ pub(in some :: path) /*»*/, [a b c], +/*«*/ - 30 /*»*/ PRINT-BANG INPUT (DEBUG): TokenStream [ Group { delimiter: None, @@ -295,6 +298,7 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ }, ] PRINT-BANG INPUT (DISPLAY): (a, b) +PRINT-BANG RE-COLLECTED (DISPLAY): /*«*/ (a, b) /*»*/ PRINT-BANG INPUT (DEBUG): TokenStream [ Group { delimiter: None, diff --git a/src/test/ui/proc-macro/capture-unglued-token.stdout b/src/test/ui/proc-macro/capture-unglued-token.stdout index 7e6b540332c79..5fe6ff72b4544 100644 --- a/src/test/ui/proc-macro/capture-unglued-token.stdout +++ b/src/test/ui/proc-macro/capture-unglued-token.stdout @@ -1,5 +1,5 @@ PRINT-BANG INPUT (DISPLAY): Vec -PRINT-BANG RE-COLLECTED (DISPLAY): Vec < u8 > +PRINT-BANG RE-COLLECTED (DISPLAY): /*«*/ Vec < u8 > /*»*/ PRINT-BANG INPUT (DEBUG): TokenStream [ Group { delimiter: None, diff --git a/src/test/ui/proc-macro/expand-expr.rs b/src/test/ui/proc-macro/expand-expr.rs index d1146d9703062..edcb30f892cdf 100644 --- a/src/test/ui/proc-macro/expand-expr.rs +++ b/src/test/ui/proc-macro/expand-expr.rs @@ -2,9 +2,9 @@ extern crate expand_expr; -use expand_expr::{ - check_expand_expr_file, echo_pm, expand_expr_fail, expand_expr_is, recursive_expand, -}; +use expand_expr::{check_expand_expr_file, echo_pm, expand_expr_fail, expand_expr_is}; +use expand_expr::{expand_expr_is_trim, recursive_expand}; + // Check builtin macros can be expanded. @@ -47,21 +47,21 @@ macro_rules! echo_expr { macro_rules! simple_lit { ($l:literal) => { - expand_expr_is!($l, $l); - expand_expr_is!($l, echo_lit!($l)); - expand_expr_is!($l, echo_expr!($l)); - expand_expr_is!($l, echo_tts!($l)); - expand_expr_is!($l, echo_pm!($l)); + expand_expr_is_trim!($l, $l); + expand_expr_is_trim!($l, echo_lit!($l)); + expand_expr_is_trim!($l, echo_expr!($l)); + expand_expr_is_trim!($l, echo_tts!($l)); + expand_expr_is_trim!($l, echo_pm!($l)); const _: () = { macro_rules! mac { () => { $l }; } - expand_expr_is!($l, mac!()); - expand_expr_is!($l, echo_expr!(mac!())); - expand_expr_is!($l, echo_tts!(mac!())); - expand_expr_is!($l, echo_pm!(mac!())); + expand_expr_is_trim!($l, mac!()); + expand_expr_is_trim!($l, echo_expr!(mac!())); + expand_expr_is_trim!($l, echo_tts!(mac!())); + expand_expr_is_trim!($l, echo_pm!(mac!())); }; }; } diff --git a/src/test/ui/proc-macro/expr-stmt-nonterminal-tokens.stdout b/src/test/ui/proc-macro/expr-stmt-nonterminal-tokens.stdout index 686d53e887660..04b516fd25424 100644 --- a/src/test/ui/proc-macro/expr-stmt-nonterminal-tokens.stdout +++ b/src/test/ui/proc-macro/expr-stmt-nonterminal-tokens.stdout @@ -1,5 +1,6 @@ PRINT-DERIVE INPUT (DISPLAY): enum E { V = { let _ = #[allow(warnings)] 0 ; 0 }, } -PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): enum E { V = { let _ = #[allow(warnings)] #[allow(warnings)] 0 ; 0 }, } +PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): enum E +{ V = { let _ = /*«*/ #[allow(warnings)] #[allow(warnings)] 0 /*»*/ ; 0 }, } PRINT-DERIVE INPUT (DEBUG): TokenStream [ Ident { ident: "enum", @@ -123,7 +124,7 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [ }, ] PRINT-DERIVE INPUT (DISPLAY): enum E { V = { let _ = { 0; } ; 0 }, } -PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): enum E { V = { let _ = { 0 } ; 0 }, } +PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): enum E { V = { let _ = { /*«*/ 0 /*»*/ } ; 0 }, } PRINT-DERIVE INPUT (DEBUG): TokenStream [ Ident { ident: "enum", @@ -203,6 +204,7 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [ }, ] PRINT-DERIVE INPUT (DISPLAY): enum E { V = { let _ = { {} } ; 0 }, } +PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): enum E { V = { let _ = { /*«*/ {} /*»*/ } ; 0 }, } PRINT-DERIVE INPUT (DEBUG): TokenStream [ Ident { ident: "enum", @@ -281,7 +283,7 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [ }, ] PRINT-DERIVE INPUT (DISPLAY): enum E { V = { let _ = { PATH; } ; 0 }, } -PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): enum E { V = { let _ = { PATH } ; 0 }, } +PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): enum E { V = { let _ = { /*«*/ PATH /*»*/ } ; 0 }, } PRINT-DERIVE INPUT (DEBUG): TokenStream [ Ident { ident: "enum", @@ -359,7 +361,7 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [ }, ] PRINT-DERIVE INPUT (DISPLAY): enum E { V = { let _ = { 0 + 1; } ; 0 }, } -PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): enum E { V = { let _ = { 0 + 1 } ; 0 }, } +PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): enum E { V = { let _ = { /*«*/ 0 + 1 /*»*/ } ; 0 }, } PRINT-DERIVE INPUT (DEBUG): TokenStream [ Ident { ident: "enum", @@ -450,7 +452,7 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [ }, ] PRINT-DERIVE INPUT (DISPLAY): enum E { V = { let _ = { PATH + 1; } ; 0 }, } -PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): enum E { V = { let _ = { PATH + 1 } ; 0 }, } +PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): enum E { V = { let _ = { /*«*/ PATH + 1 /*»*/ } ; 0 }, } PRINT-DERIVE INPUT (DEBUG): TokenStream [ Ident { ident: "enum", diff --git a/src/test/ui/proc-macro/issue-75734-pp-paren.stdout b/src/test/ui/proc-macro/issue-75734-pp-paren.stdout index 0fda6654ff370..55818969c7178 100644 --- a/src/test/ui/proc-macro/issue-75734-pp-paren.stdout +++ b/src/test/ui/proc-macro/issue-75734-pp-paren.stdout @@ -96,6 +96,7 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ }, ] PRINT-BANG INPUT (DISPLAY): 1 + 1 * 2 +PRINT-BANG RE-COLLECTED (DISPLAY): /*«*/ 1 + 1 /*»*/ * 2 PRINT-BANG INPUT (DEBUG): TokenStream [ Group { delimiter: None, diff --git a/src/test/ui/proc-macro/issue-78675-captured-inner-attrs.stdout b/src/test/ui/proc-macro/issue-78675-captured-inner-attrs.stdout index 60a400a5deabf..6cf8043c34f81 100644 --- a/src/test/ui/proc-macro/issue-78675-captured-inner-attrs.stdout +++ b/src/test/ui/proc-macro/issue-78675-captured-inner-attrs.stdout @@ -1,7 +1,7 @@ PRINT-BANG INPUT (DISPLAY): foo! { #[fake_attr] mod bar { #![doc = r" Foo"] } } -PRINT-BANG DEEP-RE-COLLECTED (DISPLAY): foo! { #[fake_attr] mod bar { #! [doc = r" Foo"] } } +PRINT-BANG DEEP-RE-COLLECTED (DISPLAY): foo! { #[fake_attr] /*«*/ mod bar { #! [doc = r" Foo"] } /*»*/ } PRINT-BANG INPUT (DEBUG): TokenStream [ Ident { ident: "foo", diff --git a/src/test/ui/proc-macro/issue-80760-empty-stmt.stdout b/src/test/ui/proc-macro/issue-80760-empty-stmt.stdout index 4b7ed874307d8..adbd653ead4b7 100644 --- a/src/test/ui/proc-macro/issue-80760-empty-stmt.stdout +++ b/src/test/ui/proc-macro/issue-80760-empty-stmt.stdout @@ -1,4 +1,5 @@ PRINT-BANG INPUT (DISPLAY): ; +PRINT-BANG RE-COLLECTED (DISPLAY): /*«*/ ; /*»*/ PRINT-BANG INPUT (DEBUG): TokenStream [ Group { delimiter: None, diff --git a/src/test/ui/proc-macro/nested-nonterminal-tokens.stdout b/src/test/ui/proc-macro/nested-nonterminal-tokens.stdout index a3d24dd26fe97..b912e426d5d99 100644 --- a/src/test/ui/proc-macro/nested-nonterminal-tokens.stdout +++ b/src/test/ui/proc-macro/nested-nonterminal-tokens.stdout @@ -1,4 +1,6 @@ PRINT-BANG INPUT (DISPLAY): 0 + 1 + 2 + 3 +PRINT-BANG RE-COLLECTED (DISPLAY): /*«*/ 0 + 1 + 2 /*»*/ + 3 +PRINT-BANG DEEP-RE-COLLECTED (DISPLAY): /*«*/ /*«*/ /*«*/ 0 /*»*/ + 1 /*»*/ + 2 /*»*/ + 3 PRINT-BANG INPUT (DEBUG): TokenStream [ Group { delimiter: None, diff --git a/src/test/ui/proc-macro/nodelim-groups.stdout b/src/test/ui/proc-macro/nodelim-groups.stdout index 6b410f0bfb7e3..0d2f33b41750d 100644 --- a/src/test/ui/proc-macro/nodelim-groups.stdout +++ b/src/test/ui/proc-macro/nodelim-groups.stdout @@ -1,4 +1,5 @@ PRINT-BANG INPUT (DISPLAY): "hi" 1 + (25) + 1 (1 + 1) +PRINT-BANG RE-COLLECTED (DISPLAY): "hi" /*«*/ 1 + (25) + 1 /*»*/ (1 + 1) PRINT-BANG INPUT (DEBUG): TokenStream [ Literal { kind: Str, @@ -71,6 +72,9 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ }, ] PRINT-BANG INPUT (DISPLAY): "hi" "hello".len() + "world".len() (1 + 1) +PRINT-BANG RE-COLLECTED (DISPLAY): "hi" /*«*/ "hello".len() + "world".len() /*»*/ (1 + 1) +PRINT-BANG DEEP-RE-COLLECTED (DISPLAY): "hi" /*«*/ /*«*/ "hello".len() /*»*/ + /*«*/ "world".len() /*»*/ /*»*/ +(1 + 1) PRINT-BANG INPUT (DEBUG): TokenStream [ Literal { kind: Str, diff --git a/src/test/ui/proc-macro/nonterminal-expansion.stdout b/src/test/ui/proc-macro/nonterminal-expansion.stdout index 4d884348f2ca4..32981e7011d97 100644 --- a/src/test/ui/proc-macro/nonterminal-expansion.stdout +++ b/src/test/ui/proc-macro/nonterminal-expansion.stdout @@ -1,5 +1,5 @@ PRINT-ATTR_ARGS INPUT (DISPLAY): a, line!(), b -PRINT-ATTR_ARGS RE-COLLECTED (DISPLAY): a, line! (), b +PRINT-ATTR_ARGS RE-COLLECTED (DISPLAY): a, /*«*/ line! () /*»*/, b PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [ Ident { ident: "a", diff --git a/src/test/ui/proc-macro/nonterminal-token-hygiene.stdout b/src/test/ui/proc-macro/nonterminal-token-hygiene.stdout index c08e5308138c9..ba18ca75d7fe4 100644 --- a/src/test/ui/proc-macro/nonterminal-token-hygiene.stdout +++ b/src/test/ui/proc-macro/nonterminal-token-hygiene.stdout @@ -1,5 +1,5 @@ PRINT-BANG INPUT (DISPLAY): struct S; -PRINT-BANG RE-COLLECTED (DISPLAY): struct S ; +PRINT-BANG RE-COLLECTED (DISPLAY): /*«*/ struct S ; /*»*/ PRINT-BANG INPUT (DEBUG): TokenStream [ Group { delimiter: None, diff --git a/src/test/ui/proc-macro/parent-source-spans.rs b/src/test/ui/proc-macro/parent-source-spans.rs index 354657db4db38..71e5065a87a88 100644 --- a/src/test/ui/proc-macro/parent-source-spans.rs +++ b/src/test/ui/proc-macro/parent-source-spans.rs @@ -8,16 +8,16 @@ use parent_source_spans::parent_source_spans; macro one($a:expr, $b:expr) { two!($a, $b); - //~^ ERROR first parent: "hello" - //~| ERROR second parent: "world" + //~^ ERROR first parent: /*«*/ "hello" /*»*/ + //~| ERROR second parent: /*«*/ "world" /*»*/ } macro two($a:expr, $b:expr) { three!($a, $b); - //~^ ERROR first final: "hello" - //~| ERROR second final: "world" - //~| ERROR first final: "yay" - //~| ERROR second final: "rust" + //~^ ERROR first final: /*«*/ "hello" /*»*/ + //~| ERROR second final: /*«*/ "world" /*»*/ + //~| ERROR first final: /*«*/ "yay" /*»*/ + //~| ERROR second final: /*«*/ "rust" /*»*/ } // forwarding tokens directly doesn't create a new source chain @@ -34,16 +34,16 @@ macro four($($tokens:tt)*) { fn main() { one!("hello", "world"); - //~^ ERROR first grandparent: "hello" - //~| ERROR second grandparent: "world" - //~| ERROR first source: "hello" - //~| ERROR second source: "world" + //~^ ERROR first grandparent: /*«*/ "hello" /*»*/ + //~| ERROR second grandparent: /*«*/ "world" /*»*/ + //~| ERROR first source: /*«*/ "hello" /*»*/ + //~| ERROR second source: /*«*/ "world" /*»*/ two!("yay", "rust"); - //~^ ERROR first parent: "yay" - //~| ERROR second parent: "rust" - //~| ERROR first source: "yay" - //~| ERROR second source: "rust" + //~^ ERROR first parent: /*«*/ "yay" /*»*/ + //~| ERROR second parent: /*«*/ "rust" /*»*/ + //~| ERROR first source: /*«*/ "yay" /*»*/ + //~| ERROR second source: /*«*/ "rust" /*»*/ three!("hip", "hop"); //~^ ERROR first final: "hip" diff --git a/src/test/ui/proc-macro/parent-source-spans.stderr b/src/test/ui/proc-macro/parent-source-spans.stderr index 4548269b50793..e42218ea70117 100644 --- a/src/test/ui/proc-macro/parent-source-spans.stderr +++ b/src/test/ui/proc-macro/parent-source-spans.stderr @@ -1,4 +1,4 @@ -error: first final: "hello" +error: first final: /*«*/ "hello" /*»*/ --> $DIR/parent-source-spans.rs:16:12 | LL | three!($a, $b); @@ -9,7 +9,7 @@ LL | one!("hello", "world"); | = note: this error originates in the macro `two` (in Nightly builds, run with -Z macro-backtrace for more info) -error: second final: "world" +error: second final: /*«*/ "world" /*»*/ --> $DIR/parent-source-spans.rs:16:16 | LL | three!($a, $b); @@ -20,7 +20,7 @@ LL | one!("hello", "world"); | = note: this error originates in the macro `two` (in Nightly builds, run with -Z macro-backtrace for more info) -error: first parent: "hello" +error: first parent: /*«*/ "hello" /*»*/ --> $DIR/parent-source-spans.rs:10:5 | LL | two!($a, $b); @@ -31,7 +31,7 @@ LL | one!("hello", "world"); | = note: this error originates in the macro `one` (in Nightly builds, run with -Z macro-backtrace for more info) -error: second parent: "world" +error: second parent: /*«*/ "world" /*»*/ --> $DIR/parent-source-spans.rs:10:5 | LL | two!($a, $b); @@ -42,31 +42,31 @@ LL | one!("hello", "world"); | = note: this error originates in the macro `one` (in Nightly builds, run with -Z macro-backtrace for more info) -error: first grandparent: "hello" +error: first grandparent: /*«*/ "hello" /*»*/ --> $DIR/parent-source-spans.rs:36:5 | LL | one!("hello", "world"); | ^^^^^^^^^^^^^^^^^^^^^^ -error: second grandparent: "world" +error: second grandparent: /*«*/ "world" /*»*/ --> $DIR/parent-source-spans.rs:36:5 | LL | one!("hello", "world"); | ^^^^^^^^^^^^^^^^^^^^^^ -error: first source: "hello" +error: first source: /*«*/ "hello" /*»*/ --> $DIR/parent-source-spans.rs:36:5 | LL | one!("hello", "world"); | ^^^^^^^^^^^^^^^^^^^^^^ -error: second source: "world" +error: second source: /*«*/ "world" /*»*/ --> $DIR/parent-source-spans.rs:36:5 | LL | one!("hello", "world"); | ^^^^^^^^^^^^^^^^^^^^^^ -error: first final: "yay" +error: first final: /*«*/ "yay" /*»*/ --> $DIR/parent-source-spans.rs:16:12 | LL | three!($a, $b); @@ -77,7 +77,7 @@ LL | two!("yay", "rust"); | = note: this error originates in the macro `two` (in Nightly builds, run with -Z macro-backtrace for more info) -error: second final: "rust" +error: second final: /*«*/ "rust" /*»*/ --> $DIR/parent-source-spans.rs:16:16 | LL | three!($a, $b); @@ -88,25 +88,25 @@ LL | two!("yay", "rust"); | = note: this error originates in the macro `two` (in Nightly builds, run with -Z macro-backtrace for more info) -error: first parent: "yay" +error: first parent: /*«*/ "yay" /*»*/ --> $DIR/parent-source-spans.rs:42:5 | LL | two!("yay", "rust"); | ^^^^^^^^^^^^^^^^^^^ -error: second parent: "rust" +error: second parent: /*«*/ "rust" /*»*/ --> $DIR/parent-source-spans.rs:42:5 | LL | two!("yay", "rust"); | ^^^^^^^^^^^^^^^^^^^ -error: first source: "yay" +error: first source: /*«*/ "yay" /*»*/ --> $DIR/parent-source-spans.rs:42:5 | LL | two!("yay", "rust"); | ^^^^^^^^^^^^^^^^^^^ -error: second source: "rust" +error: second source: /*«*/ "rust" /*»*/ --> $DIR/parent-source-spans.rs:42:5 | LL | two!("yay", "rust"); diff --git a/src/test/ui/resolve/issue-2356.stderr b/src/test/ui/resolve/issue-2356.stderr index d187267388577..b8d528efc1590 100644 --- a/src/test/ui/resolve/issue-2356.stderr +++ b/src/test/ui/resolve/issue-2356.stderr @@ -48,6 +48,11 @@ error[E0425]: cannot find function `static_method` in this scope | LL | static_method(); | ^^^^^^^^^^^^^ not found in this scope + | +help: consider using the associated function + | +LL | Self::static_method(); + | ~~~~~~~~~~~~~~~~~~~ error[E0425]: cannot find function `purr` in this scope --> $DIR/issue-2356.rs:54:9 @@ -85,6 +90,11 @@ error[E0425]: cannot find function `grow_older` in this scope | LL | grow_older(); | ^^^^^^^^^^ not found in this scope + | +help: consider using the associated function + | +LL | Self::grow_older(); + | ~~~~~~~~~~~~~~~~ error[E0425]: cannot find function `shave` in this scope --> $DIR/issue-2356.rs:74:5 diff --git a/src/test/ui/suggestions/assoc_fn_without_self.rs b/src/test/ui/suggestions/assoc_fn_without_self.rs new file mode 100644 index 0000000000000..778d9847773f3 --- /dev/null +++ b/src/test/ui/suggestions/assoc_fn_without_self.rs @@ -0,0 +1,20 @@ +fn main() {} + +struct S; + +impl S { + fn foo() {} + + fn bar(&self) {} + + fn baz(a: u8, b: u8) {} + + fn b() { + fn c() { + foo(); //~ ERROR cannot find function `foo` in this scope + } + foo(); //~ ERROR cannot find function `foo` in this scope + bar(); //~ ERROR cannot find function `bar` in this scope + baz(2, 3); //~ ERROR cannot find function `baz` in this scope + } +} diff --git a/src/test/ui/suggestions/assoc_fn_without_self.stderr b/src/test/ui/suggestions/assoc_fn_without_self.stderr new file mode 100644 index 0000000000000..4a0e62e73093b --- /dev/null +++ b/src/test/ui/suggestions/assoc_fn_without_self.stderr @@ -0,0 +1,37 @@ +error[E0425]: cannot find function `foo` in this scope + --> $DIR/assoc_fn_without_self.rs:14:13 + | +LL | foo(); + | ^^^ not found in this scope + +error[E0425]: cannot find function `foo` in this scope + --> $DIR/assoc_fn_without_self.rs:16:9 + | +LL | foo(); + | ^^^ not found in this scope + | +help: consider using the associated function + | +LL | Self::foo(); + | ~~~~~~~~~ + +error[E0425]: cannot find function `bar` in this scope + --> $DIR/assoc_fn_without_self.rs:17:9 + | +LL | bar(); + | ^^^ not found in this scope + +error[E0425]: cannot find function `baz` in this scope + --> $DIR/assoc_fn_without_self.rs:18:9 + | +LL | baz(2, 3); + | ^^^ not found in this scope + | +help: consider using the associated function + | +LL | Self::baz(2, 3); + | ~~~~~~~~~ + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0425`. diff --git a/src/test/ui/type-alias-impl-trait/coherence.rs b/src/test/ui/type-alias-impl-trait/coherence.rs index 1c0f83d6c12da..98ac215ad6cc5 100644 --- a/src/test/ui/type-alias-impl-trait/coherence.rs +++ b/src/test/ui/type-alias-impl-trait/coherence.rs @@ -12,6 +12,6 @@ fn use_alias(val: T) -> AliasOfForeignType { } impl foreign_crate::ForeignTrait for AliasOfForeignType {} -//~^ ERROR the type parameter `T` is not constrained by the impl trait, self type, or predicates +//~^ ERROR cannot implement trait on type alias impl trait fn main() {} diff --git a/src/test/ui/type-alias-impl-trait/coherence.stderr b/src/test/ui/type-alias-impl-trait/coherence.stderr index 6ede0fa14ba70..3ce25d94f6e12 100644 --- a/src/test/ui/type-alias-impl-trait/coherence.stderr +++ b/src/test/ui/type-alias-impl-trait/coherence.stderr @@ -1,9 +1,14 @@ -error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates - --> $DIR/coherence.rs:14:6 +error: cannot implement trait on type alias impl trait + --> $DIR/coherence.rs:14:41 | LL | impl foreign_crate::ForeignTrait for AliasOfForeignType {} - | ^ unconstrained type parameter + | ^^^^^^^^^^^^^^^^^^^^^ + | +note: type alias impl trait defined here + --> $DIR/coherence.rs:9:30 + | +LL | type AliasOfForeignType = impl LocalTrait; + | ^^^^^^^^^^^^^^^ error: aborting due to previous error -For more information about this error, try `rustc --explain E0207`.