diff --git a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs index c1d95d07f4c65..b9b6ca261193f 100644 --- a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs +++ b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs @@ -10,7 +10,7 @@ use crate::session_diagnostics; pub(crate) struct AllowInternalUnstableParser; impl CombineAttributeParser for AllowInternalUnstableParser { - const PATH: &'static [rustc_span::Symbol] = &[sym::allow_internal_unstable]; + const PATH: &'static [Symbol] = &[sym::allow_internal_unstable]; type Item = (Symbol, Span); const CONVERT: ConvertFn = AttributeKind::AllowInternalUnstable; @@ -24,7 +24,7 @@ impl CombineAttributeParser for AllowInternalUnstableParser { pub(crate) struct AllowConstFnUnstableParser; impl CombineAttributeParser for AllowConstFnUnstableParser { - const PATH: &'static [rustc_span::Symbol] = &[sym::rustc_allow_const_fn_unstable]; + const PATH: &'static [Symbol] = &[sym::rustc_allow_const_fn_unstable]; type Item = Symbol; const CONVERT: ConvertFn = AttributeKind::AllowConstFnUnstable; diff --git a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs index fb3d5f57d4fac..1775770ec680e 100644 --- a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs +++ b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs @@ -42,9 +42,9 @@ fn get( } impl SingleAttributeParser for DeprecationParser { - const PATH: &'static [rustc_span::Symbol] = &[sym::deprecated]; + const PATH: &'static [Symbol] = &[sym::deprecated]; - fn on_duplicate(cx: &AcceptContext<'_>, first_span: rustc_span::Span) { + fn on_duplicate(cx: &AcceptContext<'_>, first_span: Span) { // FIXME(jdonszelmann): merge with errors from check_attrs.rs cx.emit_err(session_diagnostics::UnusedMultiple { this: cx.attr_span, diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index 6ecd6b4d7dbb7..f45cf984f7191 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -17,7 +17,7 @@ use std::marker::PhantomData; use rustc_attr_data_structures::AttributeKind; -use rustc_span::Span; +use rustc_span::{Span, Symbol}; use thin_vec::ThinVec; use crate::context::{AcceptContext, FinalizeContext}; @@ -33,7 +33,7 @@ pub(crate) mod transparency; pub(crate) mod util; type AcceptFn = fn(&mut T, &AcceptContext<'_>, &ArgParser<'_>); -type AcceptMapping = &'static [(&'static [rustc_span::Symbol], AcceptFn)]; +type AcceptMapping = &'static [(&'static [Symbol], AcceptFn)]; /// An [`AttributeParser`] is a type which searches for syntactic attributes. /// @@ -72,7 +72,7 @@ pub(crate) trait AttributeParser: Default + 'static { /// [`SingleAttributeParser`] can only convert attributes one-to-one, and cannot combine multiple /// attributes together like is necessary for `#[stable()]` and `#[unstable()]` for example. pub(crate) trait SingleAttributeParser: 'static { - const PATH: &'static [rustc_span::Symbol]; + const PATH: &'static [Symbol]; /// Caled when a duplicate attribute is found. /// @@ -119,7 +119,7 @@ type ConvertFn = fn(ThinVec) -> AttributeKind; /// [`CombineAttributeParser`] can only convert a single kind of attribute, and cannot combine multiple /// attributes together like is necessary for `#[stable()]` and `#[unstable()]` for example. pub(crate) trait CombineAttributeParser: 'static { - const PATH: &'static [rustc_span::Symbol]; + const PATH: &'static [Symbol]; type Item; const CONVERT: ConvertFn; diff --git a/compiler/rustc_attr_parsing/src/attributes/repr.rs b/compiler/rustc_attr_parsing/src/attributes/repr.rs index 43dfb85a7c411..ab523ce0038da 100644 --- a/compiler/rustc_attr_parsing/src/attributes/repr.rs +++ b/compiler/rustc_attr_parsing/src/attributes/repr.rs @@ -1,7 +1,7 @@ use rustc_abi::Align; use rustc_ast::{IntTy, LitIntType, LitKind, UintTy}; use rustc_attr_data_structures::{AttributeKind, IntType, ReprAttr}; -use rustc_span::{Span, Symbol, sym}; +use rustc_span::{DUMMY_SP, Span, Symbol, sym}; use super::{CombineAttributeParser, ConvertFn}; use crate::context::AcceptContext; @@ -21,7 +21,7 @@ pub(crate) struct ReprParser; impl CombineAttributeParser for ReprParser { type Item = (ReprAttr, Span); - const PATH: &'static [rustc_span::Symbol] = &[sym::repr]; + const PATH: &'static [Symbol] = &[sym::repr]; const CONVERT: ConvertFn = AttributeKind::Repr; fn extend<'a>( @@ -99,7 +99,7 @@ fn parse_repr(cx: &AcceptContext<'_>, param: &MetaItemParser<'_>) -> Option, _first_span: Span) {} diff --git a/compiler/rustc_attr_parsing/src/attributes/transparency.rs b/compiler/rustc_attr_parsing/src/attributes/transparency.rs index ce42b0507ed57..d229fc0974010 100644 --- a/compiler/rustc_attr_parsing/src/attributes/transparency.rs +++ b/compiler/rustc_attr_parsing/src/attributes/transparency.rs @@ -1,6 +1,6 @@ use rustc_attr_data_structures::AttributeKind; use rustc_span::hygiene::Transparency; -use rustc_span::sym; +use rustc_span::{Span, Symbol, sym}; use super::{AcceptContext, SingleAttributeParser}; use crate::parser::ArgParser; @@ -11,9 +11,9 @@ pub(crate) struct TransparencyParser; #[allow(rustc::untranslatable_diagnostic)] #[allow(rustc::diagnostic_outside_of_impl)] impl SingleAttributeParser for TransparencyParser { - const PATH: &'static [rustc_span::Symbol] = &[sym::rustc_macro_transparency]; + const PATH: &'static [Symbol] = &[sym::rustc_macro_transparency]; - fn on_duplicate(cx: &crate::context::AcceptContext<'_>, first_span: rustc_span::Span) { + fn on_duplicate(cx: &crate::context::AcceptContext<'_>, first_span: Span) { cx.dcx().span_err(vec![first_span, cx.attr_span], "multiple macro transparency attributes"); } diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 55c3df003fe16..1360fc6871422 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -26,12 +26,16 @@ macro_rules! attribute_groups { ( pub(crate) static $name: ident = [$($names: ty),* $(,)?]; ) => { - pub(crate) static $name: LazyLock<( - BTreeMap<&'static [Symbol], Vec, &ArgParser<'_>) + Send + Sync>>>, - Vec) -> Option>> - )> = LazyLock::new(|| { - let mut accepts = BTreeMap::<_, Vec, &ArgParser<'_>) + Send + Sync>>>::new(); - let mut finalizes = Vec::) -> Option>>::new(); + type Accepts = BTreeMap< + &'static [Symbol], + Box, &ArgParser<'_>)> + >; + type Finalizes = Vec< + Box) -> Option> + >; + pub(crate) static $name: LazyLock<(Accepts, Finalizes)> = LazyLock::new(|| { + let mut accepts = Accepts::new(); + let mut finalizes = Finalizes::new(); $( { thread_local! { @@ -39,11 +43,12 @@ macro_rules! attribute_groups { }; for (k, v) in <$names>::ATTRIBUTES { - accepts.entry(*k).or_default().push(Box::new(|cx, args| { + let old = accepts.insert(*k, Box::new(|cx, args| { STATE_OBJECT.with_borrow_mut(|s| { v(s, cx, args) }) })); + assert!(old.is_none()); } finalizes.push(Box::new(|cx| { @@ -110,7 +115,8 @@ impl<'a> Deref for AcceptContext<'a> { /// Context given to every attribute parser during finalization. /// -/// Gives [`AttributeParser`](crate::attributes::AttributeParser)s enough information to create errors, for example. +/// Gives [`AttributeParser`](crate::attributes::AttributeParser)s enough information to create +/// errors, for example. pub(crate) struct FinalizeContext<'a> { /// The parse context, gives access to the session and the /// diagnostics context. @@ -141,10 +147,9 @@ pub struct AttributeParser<'sess> { sess: &'sess Session, features: Option<&'sess Features>, - /// *only* parse attributes with this symbol. + /// *Only* parse attributes with this symbol. /// - /// Used in cases where we want the lowering infrastructure for - /// parse just a single attribute. + /// Used in cases where we want the lowering infrastructure for parse just a single attribute. parse_only: Option, /// Can be used to instruct parsers to reduce the number of diagnostics it emits. @@ -157,9 +162,9 @@ impl<'sess> AttributeParser<'sess> { /// One example where this is necessary, is to parse `feature` attributes themselves for /// example. /// - /// Try to use this as little as possible. Attributes *should* be lowered during `rustc_ast_lowering`. - /// Some attributes require access to features to parse, which would crash if you tried to do so - /// through [`parse_limited`](Self::parse_limited). + /// Try to use this as little as possible. Attributes *should* be lowered during + /// `rustc_ast_lowering`. Some attributes require access to features to parse, which would + /// crash if you tried to do so through [`parse_limited`](Self::parse_limited). /// /// To make sure use is limited, supply a `Symbol` you'd like to parse. Only attributes with /// that symbol are picked out of the list of instructions and parsed. Those are returned. @@ -217,19 +222,18 @@ impl<'sess> AttributeParser<'sess> { let group_cx = FinalizeContext { cx: self, target_span }; for attr in attrs { - // if we're only looking for a single attribute, - // skip all the ones we don't care about + // If we're only looking for a single attribute, skip all the ones we don't care about. if let Some(expected) = self.parse_only { if !attr.has_name(expected) { continue; } } - // sometimes, for example for `#![doc = include_str!("readme.md")]`, + // Sometimes, for example for `#![doc = include_str!("readme.md")]`, // doc still contains a non-literal. You might say, when we're lowering attributes // that's expanded right? But no, sometimes, when parsing attributes on macros, // we already use the lowering logic and these are still there. So, when `omit_doc` - // is set we *also* want to ignore these + // is set we *also* want to ignore these. if omit_doc == OmitDoc::Skip && attr.has_name(sym::doc) { continue; } @@ -263,21 +267,17 @@ impl<'sess> AttributeParser<'sess> { let (path, args) = parser.deconstruct(); let parts = path.segments().map(|i| i.name).collect::>(); - if let Some(accepts) = ATTRIBUTE_MAPPING.0.get(parts.as_slice()) { - for f in accepts { - let cx = AcceptContext { - group_cx: &group_cx, - attr_span: lower_span(attr.span), - }; + if let Some(accept) = ATTRIBUTE_MAPPING.0.get(parts.as_slice()) { + let cx = + AcceptContext { group_cx: &group_cx, attr_span: lower_span(attr.span) }; - f(&cx, &args) - } + accept(&cx, &args) } else { - // if we're here, we must be compiling a tool attribute... Or someone forgot to - // parse their fancy new attribute. Let's warn them in any case. If you are that - // person, and you really your attribute should remain unparsed, carefully read the - // documentation in this module and if you still think so you can add an exception - // to this assertion. + // If we're here, we must be compiling a tool attribute... Or someone + // forgot to parse their fancy new attribute. Let's warn them in any case. + // If you are that person, and you really think your attribute should + // remain unparsed, carefully read the documentation in this module and if + // you still think so you can add an exception to this assertion. // FIXME(jdonszelmann): convert other attributes, and check with this that // we caught em all diff --git a/compiler/rustc_attr_parsing/src/parser.rs b/compiler/rustc_attr_parsing/src/parser.rs index 077d953cfa318..f433d3574e186 100644 --- a/compiler/rustc_attr_parsing/src/parser.rs +++ b/compiler/rustc_attr_parsing/src/parser.rs @@ -12,8 +12,7 @@ use rustc_ast::{AttrArgs, DelimArgs, Expr, ExprKind, LitKind, MetaItemLit, Norma use rustc_ast_pretty::pprust; use rustc_errors::DiagCtxtHandle; use rustc_hir::{self as hir, AttrPath}; -use rustc_span::symbol::{Ident, kw, sym}; -use rustc_span::{ErrorGuaranteed, Span, Symbol}; +use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol, kw, sym}; pub struct SegmentIterator<'a> { offset: usize, diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl index f4defd2aa1343..7d4afc9d3d952 100644 --- a/compiler/rustc_const_eval/messages.ftl +++ b/compiler/rustc_const_eval/messages.ftl @@ -424,8 +424,7 @@ const_eval_unstable_in_stable_exposed = .unstable_sugg = if the {$is_function_call2 -> [true] caller *[false] function - } is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) - .bypass_sugg = otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) + } is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` const_eval_unstable_intrinsic = `{$name}` is not yet stable as a const intrinsic const_eval_unstable_intrinsic_suggestion = add `#![feature({$feature})]` to the crate attributes to enable diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs index 826ea0e58ecca..7c35e47bbf805 100644 --- a/compiler/rustc_const_eval/src/errors.rs +++ b/compiler/rustc_const_eval/src/errors.rs @@ -58,11 +58,6 @@ pub(crate) struct UnstableInStableExposed { code = "#[rustc_const_unstable(feature = \"...\", issue = \"...\")]\n", applicability = "has-placeholders" )] - #[suggestion( - const_eval_bypass_sugg, - code = "#[rustc_allow_const_fn_unstable({gate})]\n", - applicability = "has-placeholders" - )] pub attr_span: Span, } diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index e505e2280953e..06161cb6c7ce5 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -1173,6 +1173,7 @@ impl str { /// The iterator returned will return string slices that are sub-slices of /// the original string slice, separated by any amount of ASCII whitespace. /// + /// This uses the same definition as [`char::is_ascii_whitespace`]. /// To split by Unicode `Whitespace` instead, use [`split_whitespace`]. /// /// [`split_whitespace`]: str::split_whitespace @@ -1191,7 +1192,8 @@ impl str { /// assert_eq!(None, iter.next()); /// ``` /// - /// All kinds of ASCII whitespace are considered: + /// Various kinds of ASCII whitespace are considered + /// (see [`char::is_ascii_whitespace`]): /// /// ``` /// let mut iter = " Mary had\ta little \n\t lamb".split_ascii_whitespace(); diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index ead4877512727..b0580b467be68 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -594,9 +594,9 @@ impl OsString { /// The slice must be valid for the platform encoding (as described in /// [`OsStr::from_encoded_bytes_unchecked`]). /// - /// This bypasses the encoding-dependent surrogate joining, so `self` must - /// not end with a leading surrogate half and `other` must not start with - /// with a trailing surrogate half. + /// This bypasses the encoding-dependent surrogate joining, so either + /// `self` must not end with a leading surrogate half, or `other` must not + /// start with a trailing surrogate half. #[inline] pub(crate) unsafe fn extend_from_slice_unchecked(&mut self, other: &[u8]) { // SAFETY: Guaranteed by caller. diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index 509e673bdb8b9..8047c0c03ad4f 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -2803,8 +2803,8 @@ pub fn create_dir>(path: P) -> io::Result<()> { /// Recursively create a directory and all of its parent components if they /// are missing. /// -/// If this function returns an error, some of the parent components might have -/// been created already. +/// This function is not atomic. If it returns an error, any parent components it was able to create +/// will remain. /// /// If the empty path is passed to this function, it always succeeds without /// creating any directories. diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 7959c63385816..2cdded1dfcf99 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -2154,6 +2154,13 @@ pub struct Path { #[stable(since = "1.7.0", feature = "strip_prefix")] pub struct StripPrefixError(()); +/// An error returned from [`Path::normalize_lexically`] if a `..` parent reference +/// would escape the path. +#[unstable(feature = "normalize_lexically", issue = "134694")] +#[derive(Debug, PartialEq)] +#[non_exhaustive] +pub struct NormalizeError; + impl Path { // The following (private!) function allows construction of a path from a u8 // slice, which is only safe when it is known to follow the OsStr encoding. @@ -2961,6 +2968,67 @@ impl Path { fs::canonicalize(self) } + /// Normalize a path, including `..` without traversing the filesystem. + /// + /// Returns an error if normalization would leave leading `..` components. + /// + ///
+ /// + /// This function always resolves `..` to the "lexical" parent. + /// That is "a/b/../c" will always resolve to `a/c` which can change the meaning of the path. + /// In particular, `a/c` and `a/b/../c` are distinct on many systems because `b` may be a symbolic link, so its parent isn’t `a`. + /// + ///
+ /// + /// [`path::absolute`](absolute) is an alternative that preserves `..`. + /// Or [`Path::canonicalize`] can be used to resolve any `..` by querying the filesystem. + #[unstable(feature = "normalize_lexically", issue = "134694")] + pub fn normalize_lexically(&self) -> Result { + let mut lexical = PathBuf::new(); + let mut iter = self.components().peekable(); + + // Find the root, if any, and add it to the lexical path. + // Here we treat the Windows path "C:\" as a single "root" even though + // `components` splits it into two: (Prefix, RootDir). + let root = match iter.peek() { + Some(Component::ParentDir) => return Err(NormalizeError), + Some(p @ Component::RootDir) | Some(p @ Component::CurDir) => { + lexical.push(p); + iter.next(); + lexical.as_os_str().len() + } + Some(Component::Prefix(prefix)) => { + lexical.push(prefix.as_os_str()); + iter.next(); + if let Some(p @ Component::RootDir) = iter.peek() { + lexical.push(p); + iter.next(); + } + lexical.as_os_str().len() + } + None => return Ok(PathBuf::new()), + Some(Component::Normal(_)) => 0, + }; + + for component in iter { + match component { + Component::RootDir => unreachable!(), + Component::Prefix(_) => return Err(NormalizeError), + Component::CurDir => continue, + Component::ParentDir => { + // It's an error if ParentDir causes us to go above the "root". + if lexical.as_os_str().len() == root { + return Err(NormalizeError); + } else { + lexical.pop(); + } + } + Component::Normal(path) => lexical.push(path), + } + } + Ok(lexical) + } + /// Reads a symbolic link, returning the file that the link points to. /// /// This is an alias to [`fs::read_link`]. @@ -3502,6 +3570,15 @@ impl Error for StripPrefixError { } } +#[unstable(feature = "normalize_lexically", issue = "134694")] +impl fmt::Display for NormalizeError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("parent reference `..` points outside of base directory") + } +} +#[unstable(feature = "normalize_lexically", issue = "134694")] +impl Error for NormalizeError {} + /// Makes the path absolute without accessing the filesystem. /// /// If the path is relative, the current directory is used as the base directory. diff --git a/library/std/src/sys/os_str/wtf8.rs b/library/std/src/sys/os_str/wtf8.rs index 5174ea65d0cd9..892bd2e3de659 100644 --- a/library/std/src/sys/os_str/wtf8.rs +++ b/library/std/src/sys/os_str/wtf8.rs @@ -215,9 +215,9 @@ impl Buf { /// The slice must be valid for the platform encoding (as described in /// [`Slice::from_encoded_bytes_unchecked`]). /// - /// This bypasses the WTF-8 surrogate joining, so `self` must not end with a - /// leading surrogate half and `other` must not start with with a trailing - /// surrogate half. + /// This bypasses the WTF-8 surrogate joining, so either `self` must not + /// end with a leading surrogate half, or `other` must not start with a + /// trailing surrogate half. #[inline] pub unsafe fn extend_from_slice_unchecked(&mut self, other: &[u8]) { self.inner.extend_from_slice(other); diff --git a/library/std/tests/path.rs b/library/std/tests/path.rs index 87e0d226cbd31..781855a2d14aa 100644 --- a/library/std/tests/path.rs +++ b/library/std/tests/path.rs @@ -3,7 +3,8 @@ path_add_extension, path_file_prefix, maybe_uninit_slice, - os_string_pathbuf_leak + os_string_pathbuf_leak, + normalize_lexically )] use std::clone::CloneToUninit; @@ -2007,3 +2008,56 @@ fn test_embedded_newline() { assert_eq!(path.file_name(), Some(OsStr::new("foo\nbar"))); assert_eq!(path.to_str(), Some("foo\nbar")); } + +#[test] +fn normalize_lexically() { + #[track_caller] + fn check_ok(a: &str, b: &str) { + assert_eq!(Path::new(a).normalize_lexically().unwrap(), PathBuf::from(b)); + } + + #[track_caller] + fn check_err(a: &str) { + assert!(Path::new(a).normalize_lexically().is_err()); + } + + // Relative paths + check_ok("a", "a"); + check_ok("./a", "./a"); + check_ok("a/b/c", "a/b/c"); + check_ok("a/././b/./c/.", "a/b/c"); + check_ok("a/../c", "c"); + check_ok("./a/b", "./a/b"); + check_ok("a/../b/c/..", "b"); + + check_err(".."); + check_err("../.."); + check_err("a/../.."); + check_err("a/../../b"); + check_err("a/../../b/c"); + check_err("a/../b/../.."); + + // Check we don't escape the root or prefix + #[cfg(unix)] + { + check_err("/.."); + check_err("/a/../.."); + } + #[cfg(windows)] + { + check_err(r"C:\.."); + check_err(r"C:\a\..\.."); + + check_err(r"C:.."); + check_err(r"C:a\..\.."); + + check_err(r"\\server\share\.."); + check_err(r"\\server\share\a\..\.."); + + check_err(r"\.."); + check_err(r"\a\..\.."); + + check_err(r"\\?\UNC\server\share\.."); + check_err(r"\\?\UNC\server\share\a\..\.."); + } +} diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index 2daa862460534..1d175bd97e6a1 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -123,7 +123,7 @@ pr: DOCKER_SCRIPT: x86_64-gnu-llvm.sh <<: *job-linux-16c - name: x86_64-gnu-tools - <<: *job-linux-16c + <<: *job-linux-36c-codebuild # Jobs that run when you perform a try build (@bors try) # These jobs automatically inherit envs.try, to avoid repeating diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 07ecd98f77596..bb3469867d51e 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -610,6 +610,9 @@ impl Item { UnionItem(ref union_) => Some(union_.has_stripped_entries()), EnumItem(ref enum_) => Some(enum_.has_stripped_entries()), VariantItem(ref v) => v.has_stripped_entries(), + TypeAliasItem(ref type_alias) => { + type_alias.inner_type.as_ref().and_then(|t| t.has_stripped_entries()) + } _ => None, } } @@ -761,14 +764,11 @@ impl Item { Some(tcx.visibility(def_id)) } - pub(crate) fn attributes(&self, tcx: TyCtxt<'_>, cache: &Cache, is_json: bool) -> Vec { + pub(crate) fn attributes_without_repr(&self, tcx: TyCtxt<'_>, is_json: bool) -> Vec { const ALLOWED_ATTRIBUTES: &[Symbol] = &[sym::export_name, sym::link_section, sym::no_mangle, sym::non_exhaustive]; - use rustc_abi::IntegerType; - - let mut attrs: Vec = self - .attrs + self.attrs .other_attrs .iter() .filter_map(|attr| { @@ -796,74 +796,28 @@ impl Item { None } }) - .collect(); + .collect() + } - // Add #[repr(...)] - if let Some(def_id) = self.def_id() - && let ItemType::Struct | ItemType::Enum | ItemType::Union = self.type_() - { - let adt = tcx.adt_def(def_id); - let repr = adt.repr(); - let mut out = Vec::new(); - if repr.c() { - out.push("C"); - } - if repr.transparent() { - // Render `repr(transparent)` iff the non-1-ZST field is public or at least one - // field is public in case all fields are 1-ZST fields. - let render_transparent = is_json - || cache.document_private - || adt - .all_fields() - .find(|field| { - let ty = - field.ty(tcx, ty::GenericArgs::identity_for_item(tcx, field.did)); - tcx.layout_of( - ty::TypingEnv::post_analysis(tcx, field.did).as_query_input(ty), - ) - .is_ok_and(|layout| !layout.is_1zst()) - }) - .map_or_else( - || adt.all_fields().any(|field| field.vis.is_public()), - |field| field.vis.is_public(), - ); + pub(crate) fn attributes_and_repr( + &self, + tcx: TyCtxt<'_>, + cache: &Cache, + is_json: bool, + ) -> Vec { + let mut attrs = self.attributes_without_repr(tcx, is_json); - if render_transparent { - out.push("transparent"); - } - } - if repr.simd() { - out.push("simd"); - } - let pack_s; - if let Some(pack) = repr.pack { - pack_s = format!("packed({})", pack.bytes()); - out.push(&pack_s); - } - let align_s; - if let Some(align) = repr.align { - align_s = format!("align({})", align.bytes()); - out.push(&align_s); - } - let int_s; - if let Some(int) = repr.int { - int_s = match int { - IntegerType::Pointer(is_signed) => { - format!("{}size", if is_signed { 'i' } else { 'u' }) - } - IntegerType::Fixed(size, is_signed) => { - format!("{}{}", if is_signed { 'i' } else { 'u' }, size.size().bytes() * 8) - } - }; - out.push(&int_s); - } - if !out.is_empty() { - attrs.push(format!("#[repr({})]", out.join(", "))); - } + if let Some(repr_attr) = self.repr(tcx, cache, is_json) { + attrs.push(repr_attr); } attrs } + /// Returns a stringified `#[repr(...)]` attribute. + pub(crate) fn repr(&self, tcx: TyCtxt<'_>, cache: &Cache, is_json: bool) -> Option { + repr_attributes(tcx, cache, self.def_id()?, self.type_(), is_json) + } + pub fn is_doc_hidden(&self) -> bool { self.attrs.is_doc_hidden() } @@ -873,6 +827,73 @@ impl Item { } } +pub(crate) fn repr_attributes( + tcx: TyCtxt<'_>, + cache: &Cache, + def_id: DefId, + item_type: ItemType, + is_json: bool, +) -> Option { + use rustc_abi::IntegerType; + + if !matches!(item_type, ItemType::Struct | ItemType::Enum | ItemType::Union) { + return None; + } + let adt = tcx.adt_def(def_id); + let repr = adt.repr(); + let mut out = Vec::new(); + if repr.c() { + out.push("C"); + } + if repr.transparent() { + // Render `repr(transparent)` iff the non-1-ZST field is public or at least one + // field is public in case all fields are 1-ZST fields. + let render_transparent = cache.document_private + || is_json + || adt + .all_fields() + .find(|field| { + let ty = field.ty(tcx, ty::GenericArgs::identity_for_item(tcx, field.did)); + tcx.layout_of(ty::TypingEnv::post_analysis(tcx, field.did).as_query_input(ty)) + .is_ok_and(|layout| !layout.is_1zst()) + }) + .map_or_else( + || adt.all_fields().any(|field| field.vis.is_public()), + |field| field.vis.is_public(), + ); + + if render_transparent { + out.push("transparent"); + } + } + if repr.simd() { + out.push("simd"); + } + let pack_s; + if let Some(pack) = repr.pack { + pack_s = format!("packed({})", pack.bytes()); + out.push(&pack_s); + } + let align_s; + if let Some(align) = repr.align { + align_s = format!("align({})", align.bytes()); + out.push(&align_s); + } + let int_s; + if let Some(int) = repr.int { + int_s = match int { + IntegerType::Pointer(is_signed) => { + format!("{}size", if is_signed { 'i' } else { 'u' }) + } + IntegerType::Fixed(size, is_signed) => { + format!("{}{}", if is_signed { 'i' } else { 'u' }, size.size().bytes() * 8) + } + }; + out.push(&int_s); + } + if !out.is_empty() { Some(format!("#[repr({})]", out.join(", "))) } else { None } +} + #[derive(Clone, Debug)] pub(crate) enum ItemKind { ExternCrateItem { @@ -2107,7 +2128,7 @@ impl Enum { self.variants.iter().any(|f| f.is_stripped()) } - pub(crate) fn variants(&self) -> impl Iterator { + pub(crate) fn non_stripped_variants(&self) -> impl Iterator { self.variants.iter().filter(|v| !v.is_stripped()) } } @@ -2345,6 +2366,17 @@ pub(crate) enum TypeAliasInnerType { Struct { ctor_kind: Option, fields: Vec }, } +impl TypeAliasInnerType { + fn has_stripped_entries(&self) -> Option { + Some(match self { + Self::Enum { variants, .. } => variants.iter().any(|v| v.is_stripped()), + Self::Union { fields } | Self::Struct { fields, .. } => { + fields.iter().any(|f| f.is_stripped()) + } + }) + } +} + #[derive(Clone, Debug)] pub(crate) struct TypeAlias { pub(crate) type_: Type, diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 06cb9269cc87f..5677b13033db5 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -1194,18 +1194,36 @@ fn render_assoc_item( // a whitespace prefix and newline. fn render_attributes_in_pre(it: &clean::Item, prefix: &str, cx: &Context<'_>) -> impl fmt::Display { fmt::from_fn(move |f| { - for a in it.attributes(cx.tcx(), cx.cache(), false) { + for a in it.attributes_and_repr(cx.tcx(), cx.cache(), false) { writeln!(f, "{prefix}{a}")?; } Ok(()) }) } +struct CodeAttribute(String); + +fn render_code_attribute(code_attr: CodeAttribute, w: &mut impl fmt::Write) { + write!(w, "
{}
", code_attr.0).unwrap(); +} + // When an attribute is rendered inside a tag, it is formatted using // a div to produce a newline after it. fn render_attributes_in_code(w: &mut impl fmt::Write, it: &clean::Item, cx: &Context<'_>) { - for attr in it.attributes(cx.tcx(), cx.cache(), false) { - write!(w, "
{attr}
").unwrap(); + for attr in it.attributes_and_repr(cx.tcx(), cx.cache(), false) { + render_code_attribute(CodeAttribute(attr), w); + } +} + +/// used for type aliases to only render their `repr` attribute. +fn render_repr_attributes_in_code( + w: &mut impl fmt::Write, + cx: &Context<'_>, + def_id: DefId, + item_type: ItemType, +) { + if let Some(repr) = clean::repr_attributes(cx.tcx(), cx.cache(), def_id, item_type, false) { + render_code_attribute(CodeAttribute(repr), w); } } diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 39a631b637bd4..b4663961c1b71 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -20,7 +20,7 @@ use super::{ collect_paths_for_type, document, ensure_trailing_slash, get_filtered_impls_for_reference, item_ty_to_section, notable_traits_button, notable_traits_json, render_all_impls, render_assoc_item, render_assoc_items, render_attributes_in_code, render_attributes_in_pre, - render_impl, render_rightside, render_stability_since_raw, + render_impl, render_repr_attributes_in_code, render_rightside, render_stability_since_raw, render_stability_since_raw_with_extra, write_section_heading, }; use crate::clean; @@ -1278,94 +1278,58 @@ fn item_type_alias(cx: &Context<'_>, it: &clean::Item, t: &clean::TypeAlias) -> match inner_type { clean::TypeAliasInnerType::Enum { variants, is_non_exhaustive } => { - let variants_iter = || variants.iter().filter(|i| !i.is_stripped()); let ty = cx.tcx().type_of(it.def_id().unwrap()).instantiate_identity(); let enum_def_id = ty.ty_adt_def().unwrap().did(); - wrap_item(w, |w| { - let variants_len = variants.len(); - let variants_count = variants_iter().count(); - let has_stripped_entries = variants_len != variants_count; - - write!( - w, - "enum {}{}{}", - it.name.unwrap(), - t.generics.print(cx), - render_enum_fields( - cx, - Some(&t.generics), - variants, - variants_count, - has_stripped_entries, - *is_non_exhaustive, - enum_def_id, - ) - ) - })?; - write!(w, "{}", item_variants(cx, it, variants, enum_def_id))?; + DisplayEnum { + variants, + generics: &t.generics, + is_non_exhaustive: *is_non_exhaustive, + def_id: enum_def_id, + } + .render_into(cx, it, true, w)?; } clean::TypeAliasInnerType::Union { fields } => { - wrap_item(w, |w| { - let fields_count = fields.iter().filter(|i| !i.is_stripped()).count(); - let has_stripped_fields = fields.len() != fields_count; + let ty = cx.tcx().type_of(it.def_id().unwrap()).instantiate_identity(); + let union_def_id = ty.ty_adt_def().unwrap().did(); - write!( - w, - "union {}{}{}", - it.name.unwrap(), - t.generics.print(cx), - render_struct_fields( - Some(&t.generics), - None, - fields, - "", - true, - has_stripped_fields, - cx, - ), - ) - })?; - write!(w, "{}", item_fields(cx, it, fields, None))?; + ItemUnion { + cx, + it, + fields, + generics: &t.generics, + is_type_alias: true, + def_id: union_def_id, + } + .render_into(w)?; } clean::TypeAliasInnerType::Struct { ctor_kind, fields } => { - wrap_item(w, |w| { - let fields_count = fields.iter().filter(|i| !i.is_stripped()).count(); - let has_stripped_fields = fields.len() != fields_count; + let ty = cx.tcx().type_of(it.def_id().unwrap()).instantiate_identity(); + let struct_def_id = ty.ty_adt_def().unwrap().did(); - write!( - w, - "struct {}{}{}", - it.name.unwrap(), - t.generics.print(cx), - render_struct_fields( - Some(&t.generics), - *ctor_kind, - fields, - "", - true, - has_stripped_fields, - cx, - ), - ) - })?; - write!(w, "{}", item_fields(cx, it, fields, None))?; + DisplayStruct { + ctor_kind: *ctor_kind, + generics: &t.generics, + fields, + def_id: struct_def_id, + } + .render_into(cx, it, true, w)?; } } + } else { + let def_id = it.item_id.expect_def_id(); + // Render any items associated directly to this alias, as otherwise they + // won't be visible anywhere in the docs. It would be nice to also show + // associated items from the aliased type (see discussion in #32077), but + // we need #14072 to make sense of the generics. + write!( + w, + "{}{}", + render_assoc_items(cx, it, def_id, AssocItemRender::All), + document_type_layout(cx, def_id) + )?; } - let def_id = it.item_id.expect_def_id(); - // Render any items associated directly to this alias, as otherwise they - // won't be visible anywhere in the docs. It would be nice to also show - // associated items from the aliased type (see discussion in #32077), but - // we need #14072 to make sense of the generics. - write!( - w, - "{}{}", - render_assoc_items(cx, it, def_id, AssocItemRender::All), - document_type_layout(cx, def_id) - )?; - // [RUSTDOCIMPL] type.impl // // Include type definitions from the alias target type. @@ -1463,50 +1427,83 @@ fn item_type_alias(cx: &Context<'_>, it: &clean::Item, t: &clean::TypeAlias) -> }) } -fn item_union(cx: &Context<'_>, it: &clean::Item, s: &clean::Union) -> impl fmt::Display { - item_template!( - #[template(path = "item_union.html")] - struct ItemUnion<'a, 'cx> { - cx: &'a Context<'cx>, - it: &'a clean::Item, - s: &'a clean::Union, - }, - methods = [document, document_type_layout, render_attributes_in_pre, render_assoc_items] - ); +item_template!( + #[template(path = "item_union.html")] + struct ItemUnion<'a, 'cx> { + cx: &'a Context<'cx>, + it: &'a clean::Item, + fields: &'a [clean::Item], + generics: &'a clean::Generics, + is_type_alias: bool, + def_id: DefId, + }, + methods = [document, document_type_layout, render_assoc_items] +); + +impl<'a, 'cx: 'a> ItemUnion<'a, 'cx> { + fn render_union(&self) -> impl Display { + render_union(self.it, Some(&self.generics), &self.fields, self.cx) + } - impl<'a, 'cx: 'a> ItemUnion<'a, 'cx> { - fn render_union(&self) -> impl Display { - render_union(self.it, Some(&self.s.generics), &self.s.fields, self.cx) - } + fn document_field(&self, field: &'a clean::Item) -> impl Display { + document(self.cx, field, Some(self.it), HeadingOffset::H3) + } - fn document_field(&self, field: &'a clean::Item) -> impl Display { - document(self.cx, field, Some(self.it), HeadingOffset::H3) - } + fn stability_field(&self, field: &clean::Item) -> Option { + field.stability_class(self.cx.tcx()) + } - fn stability_field(&self, field: &clean::Item) -> Option { - field.stability_class(self.cx.tcx()) - } + fn print_ty(&self, ty: &'a clean::Type) -> impl Display { + ty.print(self.cx) + } - fn print_ty(&self, ty: &'a clean::Type) -> impl Display { - ty.print(self.cx) - } + // FIXME (GuillaumeGomez): When is implemented, + // we can replace the returned value with: + // + // `iter::Peekable>` + // + // And update `item_union.html`. + fn fields_iter(&self) -> impl Iterator { + self.fields.iter().filter_map(|f| match f.kind { + clean::StructFieldItem(ref ty) => Some((f, ty)), + _ => None, + }) + } - fn fields_iter( - &self, - ) -> iter::Peekable> { - self.s - .fields - .iter() - .filter_map(|f| match f.kind { - clean::StructFieldItem(ref ty) => Some((f, ty)), - _ => None, - }) - .peekable() - } + fn render_attributes_in_pre(&self) -> impl fmt::Display { + fmt::from_fn(move |f| { + if self.is_type_alias { + // For now the only attributes we render for type aliases are `repr` attributes. + if let Some(repr) = clean::repr_attributes( + self.cx.tcx(), + self.cx.cache(), + self.def_id, + ItemType::Union, + false, + ) { + writeln!(f, "{repr}")?; + }; + } else { + for a in self.it.attributes_and_repr(self.cx.tcx(), self.cx.cache(), false) { + writeln!(f, "{a}")?; + } + } + Ok(()) + }) } +} +fn item_union(cx: &Context<'_>, it: &clean::Item, s: &clean::Union) -> impl fmt::Display { fmt::from_fn(|w| { - ItemUnion { cx, it, s }.render_into(w).unwrap(); + ItemUnion { + cx, + it, + fields: &s.fields, + generics: &s.generics, + is_type_alias: false, + def_id: it.def_id().unwrap(), + } + .render_into(w)?; Ok(()) }) } @@ -1533,41 +1530,81 @@ fn print_tuple_struct_fields(cx: &Context<'_>, s: &[clean::Item]) -> impl Displa }) } -fn item_enum(cx: &Context<'_>, it: &clean::Item, e: &clean::Enum) -> impl fmt::Display { - fmt::from_fn(|w| { - let count_variants = e.variants().count(); +struct DisplayEnum<'clean> { + variants: &'clean IndexVec, + generics: &'clean clean::Generics, + is_non_exhaustive: bool, + def_id: DefId, +} + +impl<'clean> DisplayEnum<'clean> { + fn render_into( + self, + cx: &Context<'_>, + it: &clean::Item, + is_type_alias: bool, + w: &mut W, + ) -> fmt::Result { + let non_stripped_variant_count = self.variants.iter().filter(|i| !i.is_stripped()).count(); + let variants_len = self.variants.len(); + let has_stripped_entries = variants_len != non_stripped_variant_count; + wrap_item(w, |w| { - render_attributes_in_code(w, it, cx); + if is_type_alias { + // For now the only attributes we render for type aliases are `repr` attributes. + render_repr_attributes_in_code(w, cx, self.def_id, ItemType::Enum); + } else { + render_attributes_in_code(w, it, cx); + } write!( w, "{}enum {}{}{}", visibility_print_with_space(it, cx), it.name.unwrap(), - e.generics.print(cx), + self.generics.print(cx), render_enum_fields( cx, - Some(&e.generics), - &e.variants, - count_variants, - e.has_stripped_entries(), - it.is_non_exhaustive(), - it.def_id().unwrap(), + Some(self.generics), + self.variants, + non_stripped_variant_count, + has_stripped_entries, + self.is_non_exhaustive, + self.def_id, ), ) })?; - write!(w, "{}", document(cx, it, None, HeadingOffset::H2))?; + let def_id = it.item_id.expect_def_id(); + let layout_def_id = if is_type_alias { + self.def_id + } else { + write!(w, "{}", document(cx, it, None, HeadingOffset::H2))?; + // We don't return the same `DefId` since the layout size of the type alias might be + // different since we might have more information on the generics. + def_id + }; - if count_variants != 0 { - write!(w, "{}", item_variants(cx, it, &e.variants, it.def_id().unwrap()))?; + if non_stripped_variant_count != 0 { + write!(w, "{}", item_variants(cx, it, self.variants, self.def_id))?; } - let def_id = it.item_id.expect_def_id(); write!( w, "{}{}", render_assoc_items(cx, it, def_id, AssocItemRender::All), - document_type_layout(cx, def_id) + document_type_layout(cx, layout_def_id) ) + } +} + +fn item_enum(cx: &Context<'_>, it: &clean::Item, e: &clean::Enum) -> impl fmt::Display { + fmt::from_fn(|w| { + DisplayEnum { + variants: &e.variants, + generics: &e.generics, + is_non_exhaustive: it.is_non_exhaustive(), + def_id: it.def_id().unwrap(), + } + .render_into(cx, it, false, w) }) } @@ -1955,27 +1992,59 @@ fn item_constant( }) } -fn item_struct(cx: &Context<'_>, it: &clean::Item, s: &clean::Struct) -> impl fmt::Display { - fmt::from_fn(|w| { +struct DisplayStruct<'a> { + ctor_kind: Option, + generics: &'a clean::Generics, + fields: &'a [clean::Item], + def_id: DefId, +} + +impl<'a> DisplayStruct<'a> { + fn render_into( + self, + cx: &Context<'_>, + it: &clean::Item, + is_type_alias: bool, + w: &mut W, + ) -> fmt::Result { wrap_item(w, |w| { - render_attributes_in_code(w, it, cx); + if is_type_alias { + // For now the only attributes we render for type aliases are `repr` attributes. + render_repr_attributes_in_code(w, cx, self.def_id, ItemType::Struct); + } else { + render_attributes_in_code(w, it, cx); + } write!( w, "{}", - render_struct(it, Some(&s.generics), s.ctor_kind, &s.fields, "", true, cx) + render_struct(it, Some(self.generics), self.ctor_kind, self.fields, "", true, cx) ) })?; - let def_id = it.item_id.expect_def_id(); + if !is_type_alias { + write!(w, "{}", document(cx, it, None, HeadingOffset::H2))?; + } + let def_id = it.item_id.expect_def_id(); write!( w, - "{}{}{}{}", - document(cx, it, None, HeadingOffset::H2), - item_fields(cx, it, &s.fields, s.ctor_kind), + "{}{}{}", + item_fields(cx, it, self.fields, self.ctor_kind), render_assoc_items(cx, it, def_id, AssocItemRender::All), document_type_layout(cx, def_id), ) + } +} + +fn item_struct(cx: &Context<'_>, it: &clean::Item, s: &clean::Struct) -> impl fmt::Display { + fmt::from_fn(|w| { + DisplayStruct { + ctor_kind: s.ctor_kind, + generics: &s.generics, + fields: s.fields.as_slice(), + def_id: it.def_id().unwrap(), + } + .render_into(cx, it, false, w) }) } diff --git a/src/librustdoc/html/render/sidebar.rs b/src/librustdoc/html/render/sidebar.rs index 361966325fb3c..91540e06e3398 100644 --- a/src/librustdoc/html/render/sidebar.rs +++ b/src/librustdoc/html/render/sidebar.rs @@ -599,7 +599,7 @@ fn sidebar_enum<'a>( deref_id_map: &'a DefIdMap, ) { let mut variants = e - .variants() + .non_stripped_variants() .filter_map(|v| v.name) .map(|name| Link::new(format!("variant.{name}"), name.to_string())) .collect::>(); diff --git a/src/librustdoc/html/templates/item_union.html b/src/librustdoc/html/templates/item_union.html index b1c1d5a63a03c..b5d3367a6a10b 100644 --- a/src/librustdoc/html/templates/item_union.html +++ b/src/librustdoc/html/templates/item_union.html @@ -2,15 +2,16 @@ {{ self.render_attributes_in_pre()|safe }} {{ self.render_union()|safe }}
-{{ self.document()|safe }} -{% if self.fields_iter().peek().is_some() %} +{% if !self.is_type_alias %} + {{ self.document()|safe }} +{% endif %} +{% if self.fields_iter().next().is_some() %}

{# #} Fields§ {# #}

{% for (field, ty) in self.fields_iter() %} {% let name = field.name.expect("union field name") %} - {# #} + {# #} § {# #} {{ name }}: {{+ self.print_ty(ty)|safe }} {# #} diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index 705f9b2202c60..bfcb794b89a27 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -40,7 +40,7 @@ impl JsonRenderer<'_> { }) .collect(); let docs = item.opt_doc_value(); - let attrs = item.attributes(self.tcx, self.cache(), true); + let attrs = item.attributes_and_repr(self.tcx, self.cache(), true); let span = item.span(self.tcx); let visibility = item.visibility(self.tcx); let clean::ItemInner { name, item_id, .. } = *item.inner; diff --git a/tests/rustdoc/type-alias/repr.rs b/tests/rustdoc/type-alias/repr.rs new file mode 100644 index 0000000000000..cf90798036099 --- /dev/null +++ b/tests/rustdoc/type-alias/repr.rs @@ -0,0 +1,42 @@ +// This test ensures that the `repr` attribute is displayed in type aliases. +// +// Regression test for . + +#![crate_name = "foo"] + +/// bla +#[repr(C)] +pub struct Foo1; + +//@ has 'foo/type.Bar1.html' +//@ has - '//*[@class="rust item-decl"]/code' '#[repr(C)]pub struct Bar1;' +// Ensures that we see the doc comment of the type alias and not of the aliased type. +//@ has - '//*[@class="toggle top-doc"]/*[@class="docblock"]' 'bar' +/// bar +pub type Bar1 = Foo1; + +/// bla +#[repr(C)] +pub union Foo2 { + pub a: u8, +} + +//@ has 'foo/type.Bar2.html' +//@ matches - '//*[@class="rust item-decl"]' '#\[repr\(C\)\]\npub union Bar2 \{*' +// Ensures that we see the doc comment of the type alias and not of the aliased type. +//@ has - '//*[@class="toggle top-doc"]/*[@class="docblock"]' 'bar' +/// bar +pub type Bar2 = Foo2; + +/// bla +#[repr(C)] +pub enum Foo3 { + A, +} + +//@ has 'foo/type.Bar3.html' +//@ matches - '//*[@class="rust item-decl"]' '#\[repr\(C\)\]pub enum Bar3 \{*' +// Ensures that we see the doc comment of the type alias and not of the aliased type. +//@ has - '//*[@class="toggle top-doc"]/*[@class="docblock"]' 'bar' +/// bar +pub type Bar3 = Foo3; diff --git a/tests/rustdoc/type-layout.rs b/tests/rustdoc/type-layout.rs index 6de435dbcc143..482b8b597dd30 100644 --- a/tests/rustdoc/type-layout.rs +++ b/tests/rustdoc/type-layout.rs @@ -61,7 +61,7 @@ pub type TypeAlias = X; pub type GenericTypeAlias = (Generic<(u32, ())>, Generic); // Regression test for the rustdoc equivalent of #85103. -//@ hasraw type_layout/type.Edges.html 'Encountered an error during type layout; the type failed to be normalized.' +//@ hasraw type_layout/type.Edges.html 'Unable to compute type layout, possibly due to this type having generic parameters. Layout can only be computed for concrete, fully-instantiated types.' pub type Edges<'a, E> = std::borrow::Cow<'a, [E]>; //@ !hasraw type_layout/trait.MyTrait.html 'Size: ' diff --git a/tests/ui/consts/const-eval/dont_promote_unstable_const_fn.stderr b/tests/ui/consts/const-eval/dont_promote_unstable_const_fn.stderr index a506f2a282bbb..b505b76a6abfa 100644 --- a/tests/ui/consts/const-eval/dont_promote_unstable_const_fn.stderr +++ b/tests/ui/consts/const-eval/dont_promote_unstable_const_fn.stderr @@ -5,14 +5,9 @@ LL | const fn bar() -> u32 { foo() } | ^^^^^ | = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unstable features -help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) +help: if the caller is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` | LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | const fn bar() -> u32 { foo() } - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(foo)] LL | const fn bar() -> u32 { foo() } | diff --git a/tests/ui/consts/const-unstable-intrinsic.stderr b/tests/ui/consts/const-unstable-intrinsic.stderr index 308b02386f5c9..7e7ba966cee17 100644 --- a/tests/ui/consts/const-unstable-intrinsic.stderr +++ b/tests/ui/consts/const-unstable-intrinsic.stderr @@ -46,14 +46,9 @@ error: const function that might be (indirectly) exposed to stable cannot use `# LL | size_of_val(&x); | ^^^^^^^^^^^^^^^ | -help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) +help: if the function is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` | LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | const fn const_main() { - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(local)] LL | const fn const_main() { | @@ -63,14 +58,9 @@ error: const function that might be (indirectly) exposed to stable cannot use `# LL | min_align_of_val(&x); | ^^^^^^^^^^^^^^^^^^^^ | -help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) +help: if the function is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` | LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | const fn const_main() { - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(local)] LL | const fn const_main() { | @@ -88,14 +78,9 @@ error: const function that might be (indirectly) exposed to stable cannot use `# LL | super::size_of_val(src); | ^^^^^^^^^^^^^^^^^^^^^^^ | -help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) +help: if the function is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` | LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | const unsafe fn copy(src: *const T, _dst: *mut T, _count: usize) { - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(local)] LL | const unsafe fn copy(src: *const T, _dst: *mut T, _count: usize) { | diff --git a/tests/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr b/tests/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr index 26dedc49a3928..9efc252ce6b09 100644 --- a/tests/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr +++ b/tests/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr @@ -5,14 +5,9 @@ LL | const fn bar() -> u32 { foo() } | ^^^^^ | = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unstable features -help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) +help: if the caller is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` | LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | const fn bar() -> u32 { foo() } - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(foo)] LL | const fn bar() -> u32 { foo() } | @@ -23,14 +18,9 @@ LL | const fn bar2() -> u32 { foo2() } | ^^^^^^ | = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unstable features -help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) +help: if the caller is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` | LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | const fn bar2() -> u32 { foo2() } - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(foo2)] LL | const fn bar2() -> u32 { foo2() } | @@ -40,14 +30,9 @@ error: const function that might be (indirectly) exposed to stable cannot use `# LL | let x = async { 13 }; | ^^^^^^^^^^^^ | -help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) +help: if the function is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` | LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | const fn bar3() -> u32 { - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(const_async_blocks)] LL | const fn bar3() -> u32 { | @@ -58,14 +43,9 @@ LL | foo() | ^^^^^ | = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unstable features -help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) +help: if the caller is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` | LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | const fn bar3() -> u32 { - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(foo)] LL | const fn bar3() -> u32 { | @@ -76,14 +56,9 @@ LL | const fn bar2_gated() -> u32 { foo2_gated() } | ^^^^^^^^^^^^ | = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unstable features -help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) +help: if the caller is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` | LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | const fn bar2_gated() -> u32 { foo2_gated() } - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(foo2)] LL | const fn bar2_gated() -> u32 { foo2_gated() } | @@ -94,14 +69,9 @@ LL | pub(crate) const fn bar2_gated_stable_indirect() -> u32 { super::foo2_g | ^^^^^^^^^^^^^^^^^^^ | = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unstable features -help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) +help: if the caller is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` | LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | pub(crate) const fn bar2_gated_stable_indirect() -> u32 { super::foo2_gated() } - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(foo2)] LL | pub(crate) const fn bar2_gated_stable_indirect() -> u32 { super::foo2_gated() } | @@ -112,14 +82,9 @@ LL | const fn stable_indirect() -> u32 { foo2_gated() } | ^^^^^^^^^^^^ | = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unstable features -help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) +help: if the caller is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` | LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | const fn stable_indirect() -> u32 { foo2_gated() } - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(foo2)] LL | const fn stable_indirect() -> u32 { foo2_gated() } | diff --git a/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr b/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr index b61f7db6f43b7..0712a790955a8 100644 --- a/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr +++ b/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr @@ -5,14 +5,9 @@ LL | const unsafe fn bar() -> u32 { unsafe { foo() } } | ^^^^^ | = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unstable features -help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) +help: if the caller is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` | LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | const unsafe fn bar() -> u32 { unsafe { foo() } } - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(foo)] LL | const unsafe fn bar() -> u32 { unsafe { foo() } } | @@ -23,14 +18,9 @@ LL | const unsafe fn bar2() -> u32 { unsafe { foo2() } } | ^^^^^^ | = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unstable features -help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) +help: if the caller is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` | LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | const unsafe fn bar2() -> u32 { unsafe { foo2() } } - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(foo2)] LL | const unsafe fn bar2() -> u32 { unsafe { foo2() } } | @@ -41,14 +31,9 @@ LL | const unsafe fn bar2_gated() -> u32 { unsafe { foo2_gated() } } | ^^^^^^^^^^^^ | = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unstable features -help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) +help: if the caller is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` | LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | const unsafe fn bar2_gated() -> u32 { unsafe { foo2_gated() } } - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(foo2)] LL | const unsafe fn bar2_gated() -> u32 { unsafe { foo2_gated() } } | diff --git a/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr b/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr index fad8e396e9ab5..618b9a16dd468 100644 --- a/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr +++ b/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr @@ -5,14 +5,9 @@ LL | const unsafe fn bar() -> u32 { foo() } | ^^^^^ | = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unstable features -help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) +help: if the caller is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` | LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | const unsafe fn bar() -> u32 { foo() } - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(foo)] LL | const unsafe fn bar() -> u32 { foo() } | @@ -23,14 +18,9 @@ LL | const unsafe fn bar2() -> u32 { foo2() } | ^^^^^^ | = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unstable features -help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) +help: if the caller is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` | LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | const unsafe fn bar2() -> u32 { foo2() } - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(foo2)] LL | const unsafe fn bar2() -> u32 { foo2() } | @@ -41,14 +31,9 @@ LL | const unsafe fn bar2_gated() -> u32 { foo2_gated() } | ^^^^^^^^^^^^ | = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unstable features -help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) +help: if the caller is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` | LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | const unsafe fn bar2_gated() -> u32 { foo2_gated() } - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(foo2)] LL | const unsafe fn bar2_gated() -> u32 { foo2_gated() } | diff --git a/tests/ui/consts/min_const_fn/recursive_const_stab_unmarked_crate_imports.stderr b/tests/ui/consts/min_const_fn/recursive_const_stab_unmarked_crate_imports.stderr index bbe749f595893..04804cb6d339b 100644 --- a/tests/ui/consts/min_const_fn/recursive_const_stab_unmarked_crate_imports.stderr +++ b/tests/ui/consts/min_const_fn/recursive_const_stab_unmarked_crate_imports.stderr @@ -5,14 +5,9 @@ LL | unstable_if_unmarked_const_fn_crate::not_stably_const(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unstable features -help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) +help: if the caller is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` | LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | const fn stable_fn() { - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(rustc_private)] LL | const fn stable_fn() { | diff --git a/tests/ui/consts/min_const_fn/recursive_const_stab_unstable_if_unmarked.stderr b/tests/ui/consts/min_const_fn/recursive_const_stab_unstable_if_unmarked.stderr index 9d7b81c822bd1..14940ae93f894 100644 --- a/tests/ui/consts/min_const_fn/recursive_const_stab_unstable_if_unmarked.stderr +++ b/tests/ui/consts/min_const_fn/recursive_const_stab_unstable_if_unmarked.stderr @@ -5,14 +5,9 @@ LL | not_stably_const(); | ^^^^^^^^^^^^^^^^^^ | = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unstable features -help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) +help: if the caller is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` | LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | pub const fn expose_on_stable() { - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(rustc_private)] LL | pub const fn expose_on_stable() { | @@ -22,14 +17,9 @@ error: const function that might be (indirectly) exposed to stable cannot use `# LL | let _x = async { 15 }; | ^^^^^^^^^^^^ | -help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) +help: if the function is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` | LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | pub const fn expose_on_stable() { - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(const_async_blocks)] LL | pub const fn expose_on_stable() { | diff --git a/tests/ui/intrinsics/const-eval-select-stability.stderr b/tests/ui/intrinsics/const-eval-select-stability.stderr index 5f443b1d4ff7b..513c19cbb5b71 100644 --- a/tests/ui/intrinsics/const-eval-select-stability.stderr +++ b/tests/ui/intrinsics/const-eval-select-stability.stderr @@ -4,14 +4,9 @@ error: const function that might be (indirectly) exposed to stable cannot use `# LL | const_eval_select((), nothing, log); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) +help: if the function is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` | LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | pub const fn hey() { - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(const_eval_select)] LL | pub const fn hey() { | diff --git a/tests/ui/traits/const-traits/staged-api.stderr b/tests/ui/traits/const-traits/staged-api.stderr index cdf577287eec5..4756c490cb10a 100644 --- a/tests/ui/traits/const-traits/staged-api.stderr +++ b/tests/ui/traits/const-traits/staged-api.stderr @@ -71,14 +71,9 @@ error: const function that might be (indirectly) exposed to stable cannot use `# LL | Unstable::func(); | ^^^^^^^^^^^^^^^^ | -help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) +help: if the function is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` | LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | const fn const_context() { - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(const_trait_impl)] LL | const fn const_context() { | @@ -88,14 +83,9 @@ error: const function that might be (indirectly) exposed to stable cannot use `# LL | Unstable::func(); | ^^^^^^^^^^^^^^^^ | -help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) +help: if the function is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` | LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | const fn const_context() { - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(unstable)] LL | const fn const_context() { | @@ -105,14 +95,9 @@ error: const function that might be (indirectly) exposed to stable cannot use `# LL | Foo::func(); | ^^^^^^^^^^^ | -help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) +help: if the function is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` | LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | const fn const_context() { - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(const_trait_impl)] LL | const fn const_context() { | @@ -122,14 +107,9 @@ error: const function that might be (indirectly) exposed to stable cannot use `# LL | Foo::func(); | ^^^^^^^^^^^ | -help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) +help: if the function is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` | LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | const fn const_context() { - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(unstable)] LL | const fn const_context() { | @@ -139,14 +119,9 @@ error: const function that might be (indirectly) exposed to stable cannot use `# LL | Unstable2::func(); | ^^^^^^^^^^^^^^^^^ | -help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) +help: if the function is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` | LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | const fn const_context() { - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(const_trait_impl)] LL | const fn const_context() { | @@ -156,14 +131,9 @@ error: const function that might be (indirectly) exposed to stable cannot use `# LL | Unstable2::func(); | ^^^^^^^^^^^^^^^^^ | -help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) +help: if the function is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` | LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | const fn const_context() { - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(unstable)] LL | const fn const_context() { | @@ -173,14 +143,9 @@ error: const function that might be (indirectly) exposed to stable cannot use `# LL | conditionally_const::(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) +help: if the function is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` | LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | const fn const_context() { - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(const_trait_impl)] LL | const fn const_context() { | @@ -190,14 +155,9 @@ error: const function that might be (indirectly) exposed to stable cannot use `# LL | Unstable::func(); | ^^^^^^^^^^^^^^^^ | -help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) +help: if the function is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` | LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | const fn stable_const_context() { - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(const_trait_impl)] LL | const fn stable_const_context() { | @@ -207,14 +167,9 @@ error: const function that might be (indirectly) exposed to stable cannot use `# LL | Unstable::func(); | ^^^^^^^^^^^^^^^^ | -help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) +help: if the function is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` | LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | const fn stable_const_context() { - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(unstable)] LL | const fn stable_const_context() { | @@ -224,14 +179,9 @@ error: const function that might be (indirectly) exposed to stable cannot use `# LL | Foo::func(); | ^^^^^^^^^^^ | -help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) +help: if the function is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` | LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | const fn stable_const_context() { - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(const_trait_impl)] LL | const fn stable_const_context() { | @@ -241,14 +191,9 @@ error: const function that might be (indirectly) exposed to stable cannot use `# LL | Foo::func(); | ^^^^^^^^^^^ | -help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) +help: if the function is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` | LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | const fn stable_const_context() { - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(unstable)] LL | const fn stable_const_context() { | @@ -259,14 +204,9 @@ LL | const_context_not_const_stable(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unstable features -help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) +help: if the caller is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` | LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | const fn stable_const_context() { - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(local_feature)] LL | const fn stable_const_context() { | @@ -276,14 +216,9 @@ error: const function that might be (indirectly) exposed to stable cannot use `# LL | conditionally_const::(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) +help: if the function is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` | LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | const fn stable_const_context() { - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(const_trait_impl)] LL | const fn stable_const_context() { | @@ -293,14 +228,9 @@ error: const function that might be (indirectly) exposed to stable cannot use `# LL | Unstable::func(); | ^^^^^^^^^^^^^^^^ | -help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) +help: if the function is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` | LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | const fn implicitly_stable_const_context() { - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(const_trait_impl)] LL | const fn implicitly_stable_const_context() { | @@ -310,14 +240,9 @@ error: const function that might be (indirectly) exposed to stable cannot use `# LL | Unstable::func(); | ^^^^^^^^^^^^^^^^ | -help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) +help: if the function is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` | LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | const fn implicitly_stable_const_context() { - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(unstable)] LL | const fn implicitly_stable_const_context() { | @@ -327,14 +252,9 @@ error: const function that might be (indirectly) exposed to stable cannot use `# LL | Foo::func(); | ^^^^^^^^^^^ | -help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) +help: if the function is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` | LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | const fn implicitly_stable_const_context() { - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(const_trait_impl)] LL | const fn implicitly_stable_const_context() { | @@ -344,14 +264,9 @@ error: const function that might be (indirectly) exposed to stable cannot use `# LL | Foo::func(); | ^^^^^^^^^^^ | -help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) +help: if the function is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` | LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | const fn implicitly_stable_const_context() { - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(unstable)] LL | const fn implicitly_stable_const_context() { | @@ -362,14 +277,9 @@ LL | const_context_not_const_stable(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unstable features -help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) +help: if the caller is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` | LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | const fn implicitly_stable_const_context() { - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(local_feature)] LL | const fn implicitly_stable_const_context() { | @@ -379,14 +289,9 @@ error: const function that might be (indirectly) exposed to stable cannot use `# LL | conditionally_const::(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) +help: if the function is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` | LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | const fn implicitly_stable_const_context() { - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(const_trait_impl)] LL | const fn implicitly_stable_const_context() { |