diff options
| author | The Miri Cronjob Bot <miri@cron.bot> | 2025-07-18 05:07:47 +0000 |
|---|---|---|
| committer | The Miri Cronjob Bot <miri@cron.bot> | 2025-07-18 05:07:47 +0000 |
| commit | 3e3166f9b5821b35f19b125147ed8b4cbf71cfc5 (patch) | |
| tree | c837c657b894da8195d5386499a34c1a6b7c3da5 | |
| parent | 60f6ad81a12600ec7a584bd004a81611928875f3 (diff) | |
| parent | c004a96603bf8cfdd9ac462526a8e06ad6df5b66 (diff) | |
| download | rust-3e3166f9b5821b35f19b125147ed8b4cbf71cfc5.tar.gz rust-3e3166f9b5821b35f19b125147ed8b4cbf71cfc5.zip | |
Merge from rustc
377 files changed, 4070 insertions, 2187 deletions
diff --git a/Cargo.lock b/Cargo.lock index b8a8d7b7d23..7d2fca8bb3f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3136,9 +3136,9 @@ checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" [[package]] name = "rustc-literal-escaper" -version = "0.0.4" +version = "0.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab03008eb631b703dd16978282ae36c73282e7922fe101a4bd072a40ecea7b8b" +checksum = "e4ee29da77c5a54f42697493cd4c9b9f31b74df666a6c04dfc4fde77abe0438b" [[package]] name = "rustc-main" diff --git a/compiler/rustc_ast/Cargo.toml b/compiler/rustc_ast/Cargo.toml index 5de2e69072f..155e14a3796 100644 --- a/compiler/rustc_ast/Cargo.toml +++ b/compiler/rustc_ast/Cargo.toml @@ -7,7 +7,7 @@ edition = "2024" # tidy-alphabetical-start bitflags = "2.4.1" memchr = "2.7.4" -rustc-literal-escaper = "0.0.4" +rustc-literal-escaper = "0.0.5" rustc_ast_ir = { path = "../rustc_ast_ir" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_index = { path = "../rustc_index" } diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 3c576316f62..8c2b521c560 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -18,7 +18,7 @@ //! - [`Attribute`]: Metadata associated with item. //! - [`UnOp`], [`BinOp`], and [`BinOpKind`]: Unary and binary operators. -use std::borrow::Cow; +use std::borrow::{Borrow, Cow}; use std::{cmp, fmt}; pub use GenericArgs::*; @@ -155,6 +155,59 @@ impl Path { } } +/// Joins multiple symbols with "::" into a path, e.g. "a::b::c". If the first +/// segment is `kw::PathRoot` it will be printed as empty, e.g. "::b::c". +/// +/// The generics on the `path` argument mean it can accept many forms, such as: +/// - `&[Symbol]` +/// - `Vec<Symbol>` +/// - `Vec<&Symbol>` +/// - `impl Iterator<Item = Symbol>` +/// - `impl Iterator<Item = &Symbol>` +/// +/// Panics if `path` is empty or a segment after the first is `kw::PathRoot`. +pub fn join_path_syms(path: impl IntoIterator<Item = impl Borrow<Symbol>>) -> String { + // This is a guess at the needed capacity that works well in practice. It is slightly faster + // than (a) starting with an empty string, or (b) computing the exact capacity required. + // `8` works well because it's about the right size and jemalloc's size classes are all + // multiples of 8. + let mut iter = path.into_iter(); + let len_hint = iter.size_hint().1.unwrap_or(1); + let mut s = String::with_capacity(len_hint * 8); + + let first_sym = *iter.next().unwrap().borrow(); + if first_sym != kw::PathRoot { + s.push_str(first_sym.as_str()); + } + for sym in iter { + let sym = *sym.borrow(); + debug_assert_ne!(sym, kw::PathRoot); + s.push_str("::"); + s.push_str(sym.as_str()); + } + s +} + +/// Like `join_path_syms`, but for `Ident`s. This function is necessary because +/// `Ident::to_string` does more than just print the symbol in the `name` field. +pub fn join_path_idents(path: impl IntoIterator<Item = impl Borrow<Ident>>) -> String { + let mut iter = path.into_iter(); + let len_hint = iter.size_hint().1.unwrap_or(1); + let mut s = String::with_capacity(len_hint * 8); + + let first_ident = *iter.next().unwrap().borrow(); + if first_ident.name != kw::PathRoot { + s.push_str(&first_ident.to_string()); + } + for ident in iter { + let ident = *ident.borrow(); + debug_assert_ne!(ident.name, kw::PathRoot); + s.push_str("::"); + s.push_str(&ident.to_string()); + } + s +} + /// A segment of a path: an identifier, an optional lifetime, and a set of types. /// /// E.g., `std`, `String` or `Box<T>`. @@ -3637,6 +3690,7 @@ impl Default for FnHeader { #[derive(Clone, Encodable, Decodable, Debug)] pub struct Trait { + pub constness: Const, pub safety: Safety, pub is_auto: IsAuto, pub ident: Ident, diff --git a/compiler/rustc_ast/src/util/literal.rs b/compiler/rustc_ast/src/util/literal.rs index fa7878873e5..2dfd695d880 100644 --- a/compiler/rustc_ast/src/util/literal.rs +++ b/compiler/rustc_ast/src/util/literal.rs @@ -126,11 +126,11 @@ impl LitKind { token::CStr => { let s = symbol.as_str(); let mut buf = Vec::with_capacity(s.len()); - unescape_c_str(s, |_span, c| match c { + unescape_c_str(s, |_span, res| match res { Ok(MixedUnit::Char(c)) => { - buf.extend_from_slice(c.encode_utf8(&mut [0; 4]).as_bytes()) + buf.extend_from_slice(c.get().encode_utf8(&mut [0; 4]).as_bytes()) } - Ok(MixedUnit::HighByte(b)) => buf.push(b), + Ok(MixedUnit::HighByte(b)) => buf.push(b.get()), Err(err) => { assert!(!err.is_fatal(), "failed to unescape C string literal") } diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 37fcc0d2167..a344f23c345 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -738,7 +738,8 @@ macro_rules! common_visitor_and_walkers { try_visit!(vis.visit_ty(self_ty)); visit_assoc_items(vis, items, AssocCtxt::Impl { of_trait: of_trait.is_some() }) } - ItemKind::Trait(box Trait { safety, is_auto: _, ident, generics, bounds, items }) => { + ItemKind::Trait(box Trait { constness, safety, is_auto: _, ident, generics, bounds, items }) => { + try_visit!(visit_constness(vis, constness)); try_visit!(visit_safety(vis, safety)); try_visit!(vis.visit_ident(ident)); try_visit!(vis.visit_generics(generics)); diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 9d40a7386f6..abd70c7517c 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -417,7 +417,16 @@ impl<'hir> LoweringContext<'_, 'hir> { items: new_impl_items, })) } - ItemKind::Trait(box Trait { is_auto, safety, ident, generics, bounds, items }) => { + ItemKind::Trait(box Trait { + constness, + is_auto, + safety, + ident, + generics, + bounds, + items, + }) => { + let constness = self.lower_constness(*constness); let ident = self.lower_ident(*ident); let (generics, (safety, items, bounds)) = self.lower_generics( generics, @@ -435,7 +444,7 @@ impl<'hir> LoweringContext<'_, 'hir> { (safety, items, bounds) }, ); - hir::ItemKind::Trait(*is_auto, safety, ident, generics, bounds, items) + hir::ItemKind::Trait(constness, *is_auto, safety, ident, generics, bounds, items) } ItemKind::TraitAlias(ident, generics, bounds) => { let ident = self.lower_ident(*ident); diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl index c5780c957c9..e419154d65d 100644 --- a/compiler/rustc_ast_passes/messages.ftl +++ b/compiler/rustc_ast_passes/messages.ftl @@ -240,10 +240,10 @@ ast_passes_static_without_body = ast_passes_tilde_const_disallowed = `[const]` is not allowed here .closure = closures cannot have `[const]` trait bounds .function = this function is not `const`, so it cannot have `[const]` trait bounds - .trait = this trait is not a `#[const_trait]`, so it cannot have `[const]` trait bounds + .trait = this trait is not `const`, so it cannot have `[const]` trait bounds .trait_impl = this impl is not `const`, so it cannot have `[const]` trait bounds .impl = inherent impls cannot have `[const]` trait bounds - .trait_assoc_ty = associated types in non-`#[const_trait]` traits cannot have `[const]` trait bounds + .trait_assoc_ty = associated types in non-`const` traits cannot have `[const]` trait bounds .trait_impl_assoc_ty = associated types in non-const impls cannot have `[const]` trait bounds .inherent_assoc_ty = inherent associated types cannot have `[const]` trait bounds .object = trait objects cannot have `[const]` trait bounds diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 38889d28151..c69250c0305 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -49,14 +49,14 @@ enum SelfSemantic { } enum TraitOrTraitImpl { - Trait { span: Span, constness_span: Option<Span> }, + Trait { span: Span, constness: Const }, TraitImpl { constness: Const, polarity: ImplPolarity, trait_ref_span: Span }, } impl TraitOrTraitImpl { fn constness(&self) -> Option<Span> { match self { - Self::Trait { constness_span: Some(span), .. } + Self::Trait { constness: Const::Yes(span), .. } | Self::TraitImpl { constness: Const::Yes(span), .. } => Some(*span), _ => None, } @@ -110,15 +110,10 @@ impl<'a> AstValidator<'a> { self.outer_trait_or_trait_impl = old; } - fn with_in_trait( - &mut self, - span: Span, - constness_span: Option<Span>, - f: impl FnOnce(&mut Self), - ) { + fn with_in_trait(&mut self, span: Span, constness: Const, f: impl FnOnce(&mut Self)) { let old = mem::replace( &mut self.outer_trait_or_trait_impl, - Some(TraitOrTraitImpl::Trait { span, constness_span }), + Some(TraitOrTraitImpl::Trait { span, constness }), ); f(self); self.outer_trait_or_trait_impl = old; @@ -273,7 +268,7 @@ impl<'a> AstValidator<'a> { }; let make_trait_const_sugg = if const_trait_impl - && let TraitOrTraitImpl::Trait { span, constness_span: None } = parent + && let TraitOrTraitImpl::Trait { span, constness: ast::Const::No } = parent { Some(span.shrink_to_lo()) } else { @@ -1131,10 +1126,23 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } visit::walk_item(self, item) } - ItemKind::Trait(box Trait { is_auto, generics, ident, bounds, items, .. }) => { + ItemKind::Trait(box Trait { + constness, + is_auto, + generics, + ident, + bounds, + items, + .. + }) => { self.visit_attrs_vis_ident(&item.attrs, &item.vis, ident); - let is_const_trait = + // FIXME(const_trait_impl) remove this + let alt_const_trait_span = attr::find_by_name(&item.attrs, sym::const_trait).map(|attr| attr.span); + let constness = match (*constness, alt_const_trait_span) { + (Const::Yes(span), _) | (Const::No, Some(span)) => Const::Yes(span), + (Const::No, None) => Const::No, + }; if *is_auto == IsAuto::Yes { // Auto traits cannot have generics, super traits nor contain items. self.deny_generic_params(generics, ident.span); @@ -1145,13 +1153,13 @@ impl<'a> Visitor<'a> for AstValidator<'a> { // Equivalent of `visit::walk_item` for `ItemKind::Trait` that inserts a bound // context for the supertraits. - let disallowed = - is_const_trait.is_none().then(|| TildeConstReason::Trait { span: item.span }); + let disallowed = matches!(constness, ast::Const::No) + .then(|| TildeConstReason::Trait { span: item.span }); self.with_tilde_const(disallowed, |this| { this.visit_generics(generics); walk_list!(this, visit_param_bound, bounds, BoundKind::SuperTraits) }); - self.with_in_trait(item.span, is_const_trait, |this| { + self.with_in_trait(item.span, constness, |this| { walk_list!(this, visit_assoc_item, items, AssocCtxt::Trait); }); } diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index 3b2730d4ff9..c1ebd025c7a 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -590,7 +590,7 @@ pub(crate) struct ConstBoundTraitObject { } // FIXME(const_trait_impl): Consider making the note/reason the message of the diagnostic. -// FIXME(const_trait_impl): Provide structured suggestions (e.g., add `const` / `#[const_trait]` here). +// FIXME(const_trait_impl): Provide structured suggestions (e.g., add `const` here). #[derive(Diagnostic)] #[diag(ast_passes_tilde_const_disallowed)] pub(crate) struct TildeConstDisallowed { diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs index 6c442553976..11c97a552c6 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -357,6 +357,7 @@ impl<'a> State<'a> { self.bclose(item.span, empty, cb); } ast::ItemKind::Trait(box ast::Trait { + constness, safety, is_auto, ident, @@ -366,6 +367,7 @@ impl<'a> State<'a> { }) => { let (cb, ib) = self.head(""); self.print_visibility(&item.vis); + self.print_constness(*constness); self.print_safety(*safety); self.print_is_auto(*is_auto); self.word_nbsp("trait"); diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs index 3dedeb1b372..6542cbf4ba2 100644 --- a/compiler/rustc_attr_data_structures/src/attributes.rs +++ b/compiler/rustc_attr_data_structures/src/attributes.rs @@ -420,6 +420,9 @@ pub enum AttributeKind { /// Represents `#[rustc_unsafe_specialization_marker]`. UnsafeSpecializationMarker(Span), + /// Represents `#[unstable_feature_bound]`. + UnstableFeatureBound(ThinVec<(Symbol, Span)>), + /// Represents `#[used]` Used { used_by: UsedBy, span: Span }, // tidy-alphabetical-end diff --git a/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs b/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs index 3e2dc0a15b2..6b54827c473 100644 --- a/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs +++ b/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs @@ -71,6 +71,7 @@ impl AttributeKind { TrackCaller(..) => Yes, TypeConst(..) => Yes, UnsafeSpecializationMarker(..) => No, + UnstableFeatureBound(..) => No, Used { .. } => No, // tidy-alphabetical-end } diff --git a/compiler/rustc_attr_parsing/messages.ftl b/compiler/rustc_attr_parsing/messages.ftl index 8d0ead63a8d..35ff48cb5f2 100644 --- a/compiler/rustc_attr_parsing/messages.ftl +++ b/compiler/rustc_attr_parsing/messages.ftl @@ -136,6 +136,9 @@ attr_parsing_unrecognized_repr_hint = attr_parsing_unstable_cfg_target_compact = compact `cfg(target(..))` is experimental and subject to change +attr_parsing_unstable_feature_bound_incompatible_stability = Item annotated with `#[unstable_feature_bound]` should not be stable + .help = If this item is meant to be stable, do not use any functions annotated with `#[unstable_feature_bound]`. Otherwise, mark this item as unstable with `#[unstable]` + attr_parsing_unsupported_literal_cfg_boolean = literal in `cfg` predicate value must be a boolean attr_parsing_unsupported_literal_cfg_string = diff --git a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs index 1c51c3eee4e..a6bd2306ec5 100644 --- a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs +++ b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs @@ -27,6 +27,26 @@ impl<S: Stage> CombineAttributeParser<S> for AllowInternalUnstableParser { } } +pub(crate) struct UnstableFeatureBoundParser; +impl<S: Stage> CombineAttributeParser<S> for UnstableFeatureBoundParser { + const PATH: &'static [rustc_span::Symbol] = &[sym::unstable_feature_bound]; + type Item = (Symbol, Span); + const CONVERT: ConvertFn<Self::Item> = |items, _| AttributeKind::UnstableFeatureBound(items); + const TEMPLATE: AttributeTemplate = template!(Word, List: "feat1, feat2, ..."); + + fn extend<'c>( + cx: &'c mut AcceptContext<'_, '_, S>, + args: &'c ArgParser<'_>, + ) -> impl IntoIterator<Item = Self::Item> { + if !cx.features().staged_api() { + cx.emit_err(session_diagnostics::StabilityOutsideStd { span: cx.attr_span }); + } + parse_unstable(cx, args, <Self as CombineAttributeParser<S>>::PATH[0]) + .into_iter() + .zip(iter::repeat(cx.attr_span)) + } +} + pub(crate) struct AllowConstFnUnstableParser; impl<S: Stage> CombineAttributeParser<S> for AllowConstFnUnstableParser { const PATH: &[Symbol] = &[sym::rustc_allow_const_fn_unstable]; diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg.rs b/compiler/rustc_attr_parsing/src/attributes/cfg.rs index a56855b3bd3..6373cf6e08a 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg.rs @@ -9,7 +9,7 @@ use rustc_session::parse::feature_err; use rustc_span::{Span, Symbol, sym}; use thin_vec::ThinVec; -use crate::context::{AcceptContext, Stage}; +use crate::context::{AcceptContext, ShouldEmit, Stage}; use crate::parser::{ArgParser, MetaItemListParser, MetaItemOrLitParser, NameValueParser}; use crate::{ CfgMatchesLintEmitter, fluent_generated, parse_version, session_diagnostics, try_gate_cfg, @@ -90,7 +90,7 @@ fn parse_cfg_entry_version<S: Stage>( list: &MetaItemListParser<'_>, meta_span: Span, ) -> Option<CfgEntry> { - try_gate_cfg(sym::version, meta_span, cx.sess(), Some(cx.features())); + try_gate_cfg(sym::version, meta_span, cx.sess(), cx.features_option()); let Some(version) = list.single() else { cx.emit_err(session_diagnostics::ExpectedSingleVersionLiteral { span: list.span }); return None; @@ -119,7 +119,9 @@ fn parse_cfg_entry_target<S: Stage>( list: &MetaItemListParser<'_>, meta_span: Span, ) -> Option<CfgEntry> { - if !cx.features().cfg_target_compact() { + if let Some(features) = cx.features_option() + && !features.cfg_target_compact() + { feature_err( cx.sess(), sym::cfg_target_compact, @@ -186,12 +188,13 @@ pub fn eval_config_entry( cfg_entry: &CfgEntry, id: NodeId, features: Option<&Features>, + emit_lints: ShouldEmit, ) -> EvalConfigResult { match cfg_entry { CfgEntry::All(subs, ..) => { let mut all = None; for sub in subs { - let res = eval_config_entry(sess, sub, id, features); + let res = eval_config_entry(sess, sub, id, features, emit_lints); // We cannot short-circuit because `eval_config_entry` emits some lints if !res.as_bool() { all.get_or_insert(res); @@ -202,7 +205,7 @@ pub fn eval_config_entry( CfgEntry::Any(subs, span) => { let mut any = None; for sub in subs { - let res = eval_config_entry(sess, sub, id, features); + let res = eval_config_entry(sess, sub, id, features, emit_lints); // We cannot short-circuit because `eval_config_entry` emits some lints if res.as_bool() { any.get_or_insert(res); @@ -214,7 +217,7 @@ pub fn eval_config_entry( }) } CfgEntry::Not(sub, span) => { - if eval_config_entry(sess, sub, id, features).as_bool() { + if eval_config_entry(sess, sub, id, features, emit_lints).as_bool() { EvalConfigResult::False { reason: cfg_entry.clone(), reason_span: *span } } else { EvalConfigResult::True @@ -228,24 +231,28 @@ pub fn eval_config_entry( } } CfgEntry::NameValue { name, name_span, value, span } => { - match sess.psess.check_config.expecteds.get(name) { - Some(ExpectedValues::Some(values)) if !values.contains(&value.map(|(v, _)| v)) => { - id.emit_span_lint( - sess, - UNEXPECTED_CFGS, - *span, - BuiltinLintDiag::UnexpectedCfgValue((*name, *name_span), *value), - ); + if let ShouldEmit::ErrorsAndLints = emit_lints { + match sess.psess.check_config.expecteds.get(name) { + Some(ExpectedValues::Some(values)) + if !values.contains(&value.map(|(v, _)| v)) => + { + id.emit_span_lint( + sess, + UNEXPECTED_CFGS, + *span, + BuiltinLintDiag::UnexpectedCfgValue((*name, *name_span), *value), + ); + } + None if sess.psess.check_config.exhaustive_names => { + id.emit_span_lint( + sess, + UNEXPECTED_CFGS, + *span, + BuiltinLintDiag::UnexpectedCfgName((*name, *name_span), *value), + ); + } + _ => { /* not unexpected */ } } - None if sess.psess.check_config.exhaustive_names => { - id.emit_span_lint( - sess, - UNEXPECTED_CFGS, - *span, - BuiltinLintDiag::UnexpectedCfgName((*name, *name_span), *value), - ); - } - _ => { /* not unexpected */ } } if sess.psess.config.contains(&(*name, value.map(|(v, _)| v))) { diff --git a/compiler/rustc_attr_parsing/src/attributes/stability.rs b/compiler/rustc_attr_parsing/src/attributes/stability.rs index 6bccd0042a8..8f405e5aad9 100644 --- a/compiler/rustc_attr_parsing/src/attributes/stability.rs +++ b/compiler/rustc_attr_parsing/src/attributes/stability.rs @@ -98,6 +98,16 @@ impl<S: Stage> AttributeParser<S> for StabilityParser { } } + if let Some((Stability { level: StabilityLevel::Stable { .. }, .. }, _)) = self.stability { + for other_attr in cx.all_attrs { + if other_attr.word_is(sym::unstable_feature_bound) { + cx.emit_err(session_diagnostics::UnstableFeatureBoundIncompatibleStability { + span: cx.target_span, + }); + } + } + } + let (stability, span) = self.stability?; Some(AttributeKind::Stability { stability, span }) diff --git a/compiler/rustc_attr_parsing/src/attributes/traits.rs b/compiler/rustc_attr_parsing/src/attributes/traits.rs index d5e088effd5..e69a533699b 100644 --- a/compiler/rustc_attr_parsing/src/attributes/traits.rs +++ b/compiler/rustc_attr_parsing/src/attributes/traits.rs @@ -91,6 +91,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for DoNotImplementViaObjectParser { const CREATE: fn(Span) -> AttributeKind = AttributeKind::DoNotImplementViaObject; } +// FIXME(const_trait_impl): remove this // Const traits pub(crate) struct ConstTraitParser; diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 567341d1517..1449680e35b 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -13,7 +13,9 @@ use rustc_hir::{AttrArgs, AttrItem, AttrPath, Attribute, HashIgnoredAttrId, HirI use rustc_session::Session; use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym}; -use crate::attributes::allow_unstable::{AllowConstFnUnstableParser, AllowInternalUnstableParser}; +use crate::attributes::allow_unstable::{ + AllowConstFnUnstableParser, AllowInternalUnstableParser, UnstableFeatureBoundParser, +}; use crate::attributes::codegen_attrs::{ ColdParser, ExportNameParser, NakedParser, NoMangleParser, OmitGdbPrettyPrinterSectionParser, OptimizeParser, TargetFeatureParser, TrackCallerParser, UsedParser, @@ -133,6 +135,7 @@ attribute_parsers!( Combine<AllowInternalUnstableParser>, Combine<ReprParser>, Combine<TargetFeatureParser>, + Combine<UnstableFeatureBoundParser>, // tidy-alphabetical-end // tidy-alphabetical-start @@ -223,7 +226,7 @@ impl Stage for Early { sess: &'sess Session, diag: impl for<'x> Diagnostic<'x>, ) -> ErrorGuaranteed { - if self.emit_errors { + if self.emit_errors.should_emit() { sess.dcx().emit_err(diag) } else { sess.dcx().create_err(diag).delay_as_bug() @@ -254,7 +257,7 @@ pub struct Early { /// Whether to emit errors or delay them as a bug /// For most attributes, the attribute will be parsed again in the `Late` stage and in this case the errors should be delayed /// But for some, such as `cfg`, the attribute will be removed before the `Late` stage so errors must be emitted - pub emit_errors: bool, + pub emit_errors: ShouldEmit, } /// used when parsing attributes during ast lowering pub struct Late; @@ -555,6 +558,25 @@ pub enum OmitDoc { Skip, } +#[derive(Copy, Clone)] +pub enum ShouldEmit { + /// The operation will emit errors and lints. + /// This is usually what you need. + ErrorsAndLints, + /// The operation will emit *not* errors and lints. + /// Use this if you are *sure* that this operation will be called at a different time with `ShouldEmit::Emit`. + Nothing, +} + +impl ShouldEmit { + pub fn should_emit(&self) -> bool { + match self { + ShouldEmit::ErrorsAndLints => true, + ShouldEmit::Nothing => false, + } + } +} + /// Context created once, for example as part of the ast lowering /// context, through which all attributes can be lowered. pub struct AttributeParser<'sess, S: Stage = Late> { @@ -597,7 +619,7 @@ impl<'sess> AttributeParser<'sess, Early> { tools: Vec::new(), parse_only: Some(sym), sess, - stage: Early { emit_errors: false }, + stage: Early { emit_errors: ShouldEmit::Nothing }, }; let mut parsed = p.parse_attribute_list( attrs, @@ -620,7 +642,7 @@ impl<'sess> AttributeParser<'sess, Early> { target_span: Span, target_node_id: NodeId, features: Option<&'sess Features>, - emit_errors: bool, + emit_errors: ShouldEmit, parse_fn: fn(cx: &mut AcceptContext<'_, '_, Early>, item: &ArgParser<'_>) -> T, template: &AttributeTemplate, ) -> T { diff --git a/compiler/rustc_attr_parsing/src/lib.rs b/compiler/rustc_attr_parsing/src/lib.rs index 2102a26108b..dc54cb6b840 100644 --- a/compiler/rustc_attr_parsing/src/lib.rs +++ b/compiler/rustc_attr_parsing/src/lib.rs @@ -95,7 +95,7 @@ pub use attributes::cfg_old::*; pub use attributes::util::{ find_crate_name, is_builtin_attr, is_doc_alias_attrs_contain_symbol, parse_version, }; -pub use context::{AttributeParser, Early, Late, OmitDoc}; +pub use context::{AttributeParser, Early, Late, OmitDoc, ShouldEmit}; pub use lints::emit_attribute_lint; rustc_fluent_macro::fluent_messages! { "../messages.ftl" } diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index 97bf3d1c549..5b0bf0e6662 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -504,6 +504,14 @@ pub(crate) struct UnrecognizedReprHint { } #[derive(Diagnostic)] +#[diag(attr_parsing_unstable_feature_bound_incompatible_stability)] +#[help] +pub(crate) struct UnstableFeatureBoundIncompatibleStability { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] #[diag(attr_parsing_naked_functions_incompatible_attribute, code = E0736)] pub(crate) struct NakedFunctionIncompatibleAttribute { #[primary_span] diff --git a/compiler/rustc_builtin_macros/src/source_util.rs b/compiler/rustc_builtin_macros/src/source_util.rs index cebfffa1e16..ecfd46a84ec 100644 --- a/compiler/rustc_builtin_macros/src/source_util.rs +++ b/compiler/rustc_builtin_macros/src/source_util.rs @@ -4,8 +4,8 @@ use std::sync::Arc; use rustc_ast as ast; use rustc_ast::ptr::P; -use rustc_ast::token; use rustc_ast::tokenstream::TokenStream; +use rustc_ast::{join_path_idents, token}; use rustc_ast_pretty::pprust; use rustc_expand::base::{ DummyResult, ExpandResult, ExtCtxt, MacEager, MacResult, MacroExpanderResult, resolve_path, @@ -100,7 +100,7 @@ pub(crate) fn expand_mod( let sp = cx.with_def_site_ctxt(sp); check_zero_tts(cx, sp, tts, "module_path!"); let mod_path = &cx.current_expansion.module.mod_path; - let string = mod_path.iter().map(|x| x.to_string()).collect::<Vec<String>>().join("::"); + let string = join_path_idents(mod_path); ExpandResult::Ready(MacEager::expr(cx.expr_str(sp, Symbol::intern(&string)))) } diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs index b067578794b..ba3d8368b2a 100644 --- a/compiler/rustc_builtin_macros/src/test.rs +++ b/compiler/rustc_builtin_macros/src/test.rs @@ -5,7 +5,7 @@ use std::assert_matches::assert_matches; use std::iter; use rustc_ast::ptr::P; -use rustc_ast::{self as ast, GenericParamKind, attr}; +use rustc_ast::{self as ast, GenericParamKind, attr, join_path_idents}; use rustc_ast_pretty::pprust; use rustc_errors::{Applicability, Diag, Level}; use rustc_expand::base::*; @@ -446,12 +446,7 @@ fn get_location_info(cx: &ExtCtxt<'_>, fn_: &ast::Fn) -> (Symbol, usize, usize, } fn item_path(mod_path: &[Ident], item_ident: &Ident) -> String { - mod_path - .iter() - .chain(iter::once(item_ident)) - .map(|x| x.to_string()) - .collect::<Vec<String>>() - .join("::") + join_path_idents(mod_path.iter().chain(iter::once(item_ident))) } enum ShouldPanic { diff --git a/compiler/rustc_codegen_gcc/src/back/lto.rs b/compiler/rustc_codegen_gcc/src/back/lto.rs index 10fce860b77..e554dd2500b 100644 --- a/compiler/rustc_codegen_gcc/src/back/lto.rs +++ b/compiler/rustc_codegen_gcc/src/back/lto.rs @@ -24,7 +24,7 @@ use std::sync::Arc; use gccjit::{Context, OutputKind}; use object::read::archive::ArchiveFile; -use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule, ThinShared}; +use rustc_codegen_ssa::back::lto::{SerializedModule, ThinModule, ThinShared}; use rustc_codegen_ssa::back::symbol_export; use rustc_codegen_ssa::back::write::{CodegenContext, FatLtoInput}; use rustc_codegen_ssa::traits::*; @@ -176,7 +176,7 @@ pub(crate) fn run_fat( cgcx: &CodegenContext<GccCodegenBackend>, modules: Vec<FatLtoInput<GccCodegenBackend>>, cached_modules: Vec<(SerializedModule<ModuleBuffer>, WorkProduct)>, -) -> Result<LtoModuleCodegen<GccCodegenBackend>, FatalError> { +) -> Result<ModuleCodegen<GccContext>, FatalError> { let dcx = cgcx.create_dcx(); let dcx = dcx.handle(); let lto_data = prepare_lto(cgcx, dcx)?; @@ -201,7 +201,7 @@ fn fat_lto( mut serialized_modules: Vec<(SerializedModule<ModuleBuffer>, CString)>, tmp_path: TempDir, //symbols_below_threshold: &[String], -) -> Result<LtoModuleCodegen<GccCodegenBackend>, FatalError> { +) -> Result<ModuleCodegen<GccContext>, FatalError> { let _timer = cgcx.prof.generic_activity("GCC_fat_lto_build_monolithic_module"); info!("going for a fat lto"); @@ -334,7 +334,7 @@ fn fat_lto( // of now. module.module_llvm.temp_dir = Some(tmp_path); - Ok(LtoModuleCodegen::Fat(module)) + Ok(module) } pub struct ModuleBuffer(PathBuf); @@ -358,7 +358,7 @@ pub(crate) fn run_thin( cgcx: &CodegenContext<GccCodegenBackend>, modules: Vec<(String, ThinBuffer)>, cached_modules: Vec<(SerializedModule<ModuleBuffer>, WorkProduct)>, -) -> Result<(Vec<LtoModuleCodegen<GccCodegenBackend>>, Vec<WorkProduct>), FatalError> { +) -> Result<(Vec<ThinModule<GccCodegenBackend>>, Vec<WorkProduct>), FatalError> { let dcx = cgcx.create_dcx(); let dcx = dcx.handle(); let lto_data = prepare_lto(cgcx, dcx)?; @@ -427,7 +427,7 @@ fn thin_lto( tmp_path: TempDir, cached_modules: Vec<(SerializedModule<ModuleBuffer>, WorkProduct)>, //_symbols_below_threshold: &[String], -) -> Result<(Vec<LtoModuleCodegen<GccCodegenBackend>>, Vec<WorkProduct>), FatalError> { +) -> Result<(Vec<ThinModule<GccCodegenBackend>>, Vec<WorkProduct>), FatalError> { let _timer = cgcx.prof.generic_activity("LLVM_thin_lto_global_analysis"); info!("going for that thin, thin LTO"); @@ -573,8 +573,7 @@ fn thin_lto( }*/ info!(" - {}: re-compiled", module_name); - opt_jobs - .push(LtoModuleCodegen::Thin(ThinModule { shared: shared.clone(), idx: module_index })); + opt_jobs.push(ThinModule { shared: shared.clone(), idx: module_index }); } // Save the current ThinLTO import information for the next compilation diff --git a/compiler/rustc_codegen_gcc/src/back/write.rs b/compiler/rustc_codegen_gcc/src/back/write.rs index d03d063bdac..113abe70805 100644 --- a/compiler/rustc_codegen_gcc/src/back/write.rs +++ b/compiler/rustc_codegen_gcc/src/back/write.rs @@ -16,10 +16,12 @@ use crate::{GccCodegenBackend, GccContext}; pub(crate) fn codegen( cgcx: &CodegenContext<GccCodegenBackend>, - dcx: DiagCtxtHandle<'_>, module: ModuleCodegen<GccContext>, config: &ModuleConfig, ) -> Result<CompiledModule, FatalError> { + let dcx = cgcx.create_dcx(); + let dcx = dcx.handle(); + let _timer = cgcx.prof.generic_activity_with_arg("GCC_module_codegen", &*module.name); { let context = &module.module_llvm.context; diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index d8fae1ca47d..d81bcc59775 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -93,7 +93,7 @@ use gccjit::{CType, Context, OptimizationLevel}; use gccjit::{TargetInfo, Version}; use rustc_ast::expand::allocator::AllocatorKind; use rustc_ast::expand::autodiff_attrs::AutoDiffItem; -use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule}; +use rustc_codegen_ssa::back::lto::{SerializedModule, ThinModule}; use rustc_codegen_ssa::back::write::{ CodegenContext, FatLtoInput, ModuleConfig, TargetMachineFactoryFn, }; @@ -353,11 +353,16 @@ impl WriteBackendMethods for GccCodegenBackend { type ThinData = ThinData; type ThinBuffer = ThinBuffer; - fn run_fat_lto( + fn run_and_optimize_fat_lto( cgcx: &CodegenContext<Self>, modules: Vec<FatLtoInput<Self>>, cached_modules: Vec<(SerializedModule<Self::ModuleBuffer>, WorkProduct)>, - ) -> Result<LtoModuleCodegen<Self>, FatalError> { + diff_fncs: Vec<AutoDiffItem>, + ) -> Result<ModuleCodegen<Self::Module>, FatalError> { + if !diff_fncs.is_empty() { + unimplemented!(); + } + back::lto::run_fat(cgcx, modules, cached_modules) } @@ -365,7 +370,7 @@ impl WriteBackendMethods for GccCodegenBackend { cgcx: &CodegenContext<Self>, modules: Vec<(String, Self::ThinBuffer)>, cached_modules: Vec<(SerializedModule<Self::ModuleBuffer>, WorkProduct)>, - ) -> Result<(Vec<LtoModuleCodegen<Self>>, Vec<WorkProduct>), FatalError> { + ) -> Result<(Vec<ThinModule<Self>>, Vec<WorkProduct>), FatalError> { back::lto::run_thin(cgcx, modules, cached_modules) } @@ -387,14 +392,6 @@ impl WriteBackendMethods for GccCodegenBackend { Ok(()) } - fn optimize_fat( - _cgcx: &CodegenContext<Self>, - _module: &mut ModuleCodegen<Self::Module>, - ) -> Result<(), FatalError> { - // TODO(antoyo) - Ok(()) - } - fn optimize_thin( cgcx: &CodegenContext<Self>, thin: ThinModule<Self>, @@ -404,11 +401,10 @@ impl WriteBackendMethods for GccCodegenBackend { fn codegen( cgcx: &CodegenContext<Self>, - dcx: DiagCtxtHandle<'_>, module: ModuleCodegen<Self::Module>, config: &ModuleConfig, ) -> Result<CompiledModule, FatalError> { - back::write::codegen(cgcx, dcx, module, config) + back::write::codegen(cgcx, module, config) } fn prepare_thin( @@ -429,15 +425,6 @@ impl WriteBackendMethods for GccCodegenBackend { ) -> Result<ModuleCodegen<Self::Module>, FatalError> { back::write::link(cgcx, dcx, modules) } - - fn autodiff( - _cgcx: &CodegenContext<Self>, - _module: &ModuleCodegen<Self::Module>, - _diff_functions: Vec<AutoDiffItem>, - _config: &ModuleConfig, - ) -> Result<(), FatalError> { - unimplemented!() - } } /// This is the entrypoint for a hot plugged rustc_codegen_gccjit diff --git a/compiler/rustc_codegen_llvm/messages.ftl b/compiler/rustc_codegen_llvm/messages.ftl index 3885f18271f..f197ea74473 100644 --- a/compiler/rustc_codegen_llvm/messages.ftl +++ b/compiler/rustc_codegen_llvm/messages.ftl @@ -1,5 +1,4 @@ codegen_llvm_autodiff_without_enable = using the autodiff feature requires -Z autodiff=Enable -codegen_llvm_autodiff_without_lto = using the autodiff feature requires using fat-lto codegen_llvm_copy_bitcode = failed to copy bitcode to object file: {$err} diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index 74418adc43c..655e1c95373 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -7,7 +7,7 @@ use std::sync::Arc; use std::{io, iter, slice}; use object::read::archive::ArchiveFile; -use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule, ThinShared}; +use rustc_codegen_ssa::back::lto::{SerializedModule, ThinModule, ThinShared}; use rustc_codegen_ssa::back::symbol_export; use rustc_codegen_ssa::back::write::{CodegenContext, FatLtoInput}; use rustc_codegen_ssa::traits::*; @@ -201,7 +201,7 @@ pub(crate) fn run_fat( cgcx: &CodegenContext<LlvmCodegenBackend>, modules: Vec<FatLtoInput<LlvmCodegenBackend>>, cached_modules: Vec<(SerializedModule<ModuleBuffer>, WorkProduct)>, -) -> Result<LtoModuleCodegen<LlvmCodegenBackend>, FatalError> { +) -> Result<ModuleCodegen<ModuleLlvm>, FatalError> { let dcx = cgcx.create_dcx(); let dcx = dcx.handle(); let (symbols_below_threshold, upstream_modules) = prepare_lto(cgcx, dcx)?; @@ -217,7 +217,7 @@ pub(crate) fn run_thin( cgcx: &CodegenContext<LlvmCodegenBackend>, modules: Vec<(String, ThinBuffer)>, cached_modules: Vec<(SerializedModule<ModuleBuffer>, WorkProduct)>, -) -> Result<(Vec<LtoModuleCodegen<LlvmCodegenBackend>>, Vec<WorkProduct>), FatalError> { +) -> Result<(Vec<ThinModule<LlvmCodegenBackend>>, Vec<WorkProduct>), FatalError> { let dcx = cgcx.create_dcx(); let dcx = dcx.handle(); let (symbols_below_threshold, upstream_modules) = prepare_lto(cgcx, dcx)?; @@ -248,7 +248,7 @@ fn fat_lto( cached_modules: Vec<(SerializedModule<ModuleBuffer>, WorkProduct)>, mut serialized_modules: Vec<(SerializedModule<ModuleBuffer>, CString)>, symbols_below_threshold: &[*const libc::c_char], -) -> Result<LtoModuleCodegen<LlvmCodegenBackend>, FatalError> { +) -> Result<ModuleCodegen<ModuleLlvm>, FatalError> { let _timer = cgcx.prof.generic_activity("LLVM_fat_lto_build_monolithic_module"); info!("going for a fat lto"); @@ -366,7 +366,7 @@ fn fat_lto( save_temp_bitcode(cgcx, &module, "lto.after-restriction"); } - Ok(LtoModuleCodegen::Fat(module)) + Ok(module) } pub(crate) struct Linker<'a>(&'a mut llvm::Linker<'a>); @@ -436,7 +436,7 @@ fn thin_lto( serialized_modules: Vec<(SerializedModule<ModuleBuffer>, CString)>, cached_modules: Vec<(SerializedModule<ModuleBuffer>, WorkProduct)>, symbols_below_threshold: &[*const libc::c_char], -) -> Result<(Vec<LtoModuleCodegen<LlvmCodegenBackend>>, Vec<WorkProduct>), FatalError> { +) -> Result<(Vec<ThinModule<LlvmCodegenBackend>>, Vec<WorkProduct>), FatalError> { let _timer = cgcx.prof.generic_activity("LLVM_thin_lto_global_analysis"); unsafe { info!("going for that thin, thin LTO"); @@ -568,10 +568,7 @@ fn thin_lto( } info!(" - {}: re-compiled", module_name); - opt_jobs.push(LtoModuleCodegen::Thin(ThinModule { - shared: Arc::clone(&shared), - idx: module_index, - })); + opt_jobs.push(ThinModule { shared: Arc::clone(&shared), idx: module_index }); } // Save the current ThinLTO import information for the next compilation diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 313bf6d20a6..68279008c03 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -817,10 +817,12 @@ pub(crate) fn link( pub(crate) fn codegen( cgcx: &CodegenContext<LlvmCodegenBackend>, - dcx: DiagCtxtHandle<'_>, module: ModuleCodegen<ModuleLlvm>, config: &ModuleConfig, ) -> Result<CompiledModule, FatalError> { + let dcx = cgcx.create_dcx(); + let dcx = dcx.handle(); + let _timer = cgcx.prof.generic_activity_with_arg("LLVM_module_codegen", &*module.name); { let llmod = module.module_llvm.llmod(); diff --git a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs index dff68472847..829b3c513c2 100644 --- a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs +++ b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs @@ -2,7 +2,6 @@ use std::ptr; use rustc_ast::expand::autodiff_attrs::{AutoDiffAttrs, AutoDiffItem, DiffActivity, DiffMode}; use rustc_codegen_ssa::ModuleCodegen; -use rustc_codegen_ssa::back::write::ModuleConfig; use rustc_codegen_ssa::common::TypeKind; use rustc_codegen_ssa::traits::BaseTypeCodegenMethods; use rustc_errors::FatalError; @@ -461,7 +460,6 @@ pub(crate) fn differentiate<'ll>( module: &'ll ModuleCodegen<ModuleLlvm>, cgcx: &CodegenContext<LlvmCodegenBackend>, diff_items: Vec<AutoDiffItem>, - _config: &ModuleConfig, ) -> Result<(), FatalError> { for item in &diff_items { trace!("{}", item); diff --git a/compiler/rustc_codegen_llvm/src/errors.rs b/compiler/rustc_codegen_llvm/src/errors.rs index d50ad8a1a9c..31d49e86319 100644 --- a/compiler/rustc_codegen_llvm/src/errors.rs +++ b/compiler/rustc_codegen_llvm/src/errors.rs @@ -38,10 +38,6 @@ impl<G: EmissionGuarantee> Diagnostic<'_, G> for ParseTargetMachineConfig<'_> { } #[derive(Diagnostic)] -#[diag(codegen_llvm_autodiff_without_lto)] -pub(crate) struct AutoDiffWithoutLTO; - -#[derive(Diagnostic)] #[diag(codegen_llvm_autodiff_without_enable)] pub(crate) struct AutoDiffWithoutEnable; diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 63ca51b006d..6db4e122ad6 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -26,11 +26,11 @@ use std::mem::ManuallyDrop; use back::owned_target_machine::OwnedTargetMachine; use back::write::{create_informational_target_machine, create_target_machine}; use context::SimpleCx; -use errors::{AutoDiffWithoutLTO, ParseTargetMachineConfig}; +use errors::ParseTargetMachineConfig; use llvm_util::target_config; use rustc_ast::expand::allocator::AllocatorKind; use rustc_ast::expand::autodiff_attrs::AutoDiffItem; -use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule}; +use rustc_codegen_ssa::back::lto::{SerializedModule, ThinModule}; use rustc_codegen_ssa::back::write::{ CodegenContext, FatLtoInput, ModuleConfig, TargetMachineFactoryConfig, TargetMachineFactoryFn, }; @@ -43,7 +43,7 @@ use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; use rustc_middle::ty::TyCtxt; use rustc_middle::util::Providers; use rustc_session::Session; -use rustc_session::config::{Lto, OptLevel, OutputFilenames, PrintKind, PrintRequest}; +use rustc_session::config::{OptLevel, OutputFilenames, PrintKind, PrintRequest}; use rustc_span::Symbol; mod back { @@ -174,18 +174,29 @@ impl WriteBackendMethods for LlvmCodegenBackend { ) -> Result<ModuleCodegen<Self::Module>, FatalError> { back::write::link(cgcx, dcx, modules) } - fn run_fat_lto( + fn run_and_optimize_fat_lto( cgcx: &CodegenContext<Self>, modules: Vec<FatLtoInput<Self>>, cached_modules: Vec<(SerializedModule<Self::ModuleBuffer>, WorkProduct)>, - ) -> Result<LtoModuleCodegen<Self>, FatalError> { - back::lto::run_fat(cgcx, modules, cached_modules) + diff_fncs: Vec<AutoDiffItem>, + ) -> Result<ModuleCodegen<Self::Module>, FatalError> { + let mut module = back::lto::run_fat(cgcx, modules, cached_modules)?; + + if !diff_fncs.is_empty() { + builder::autodiff::differentiate(&module, cgcx, diff_fncs)?; + } + + let dcx = cgcx.create_dcx(); + let dcx = dcx.handle(); + back::lto::run_pass_manager(cgcx, dcx, &mut module, false)?; + + Ok(module) } fn run_thin_lto( cgcx: &CodegenContext<Self>, modules: Vec<(String, Self::ThinBuffer)>, cached_modules: Vec<(SerializedModule<Self::ModuleBuffer>, WorkProduct)>, - ) -> Result<(Vec<LtoModuleCodegen<Self>>, Vec<WorkProduct>), FatalError> { + ) -> Result<(Vec<ThinModule<Self>>, Vec<WorkProduct>), FatalError> { back::lto::run_thin(cgcx, modules, cached_modules) } fn optimize( @@ -196,14 +207,6 @@ impl WriteBackendMethods for LlvmCodegenBackend { ) -> Result<(), FatalError> { back::write::optimize(cgcx, dcx, module, config) } - fn optimize_fat( - cgcx: &CodegenContext<Self>, - module: &mut ModuleCodegen<Self::Module>, - ) -> Result<(), FatalError> { - let dcx = cgcx.create_dcx(); - let dcx = dcx.handle(); - back::lto::run_pass_manager(cgcx, dcx, module, false) - } fn optimize_thin( cgcx: &CodegenContext<Self>, thin: ThinModule<Self>, @@ -212,11 +215,10 @@ impl WriteBackendMethods for LlvmCodegenBackend { } fn codegen( cgcx: &CodegenContext<Self>, - dcx: DiagCtxtHandle<'_>, module: ModuleCodegen<Self::Module>, config: &ModuleConfig, ) -> Result<CompiledModule, FatalError> { - back::write::codegen(cgcx, dcx, module, config) + back::write::codegen(cgcx, module, config) } fn prepare_thin( module: ModuleCodegen<Self::Module>, @@ -227,19 +229,6 @@ impl WriteBackendMethods for LlvmCodegenBackend { fn serialize_module(module: ModuleCodegen<Self::Module>) -> (String, Self::ModuleBuffer) { (module.name, back::lto::ModuleBuffer::new(module.module_llvm.llmod())) } - /// Generate autodiff rules - fn autodiff( - cgcx: &CodegenContext<Self>, - module: &ModuleCodegen<Self::Module>, - diff_fncs: Vec<AutoDiffItem>, - config: &ModuleConfig, - ) -> Result<(), FatalError> { - if cgcx.lto != Lto::Fat { - let dcx = cgcx.create_dcx(); - return Err(dcx.handle().emit_almost_fatal(AutoDiffWithoutLTO)); - } - builder::autodiff::differentiate(module, cgcx, diff_fncs, config) - } } impl LlvmCodegenBackend { diff --git a/compiler/rustc_codegen_ssa/src/back/lto.rs b/compiler/rustc_codegen_ssa/src/back/lto.rs index ce6fe8a191b..b49b6783bbd 100644 --- a/compiler/rustc_codegen_ssa/src/back/lto.rs +++ b/compiler/rustc_codegen_ssa/src/back/lto.rs @@ -1,13 +1,8 @@ use std::ffi::CString; use std::sync::Arc; -use rustc_ast::expand::autodiff_attrs::AutoDiffItem; use rustc_data_structures::memmap::Mmap; -use rustc_errors::FatalError; -use super::write::CodegenContext; -use crate::ModuleCodegen; -use crate::back::write::ModuleConfig; use crate::traits::*; pub struct ThinModule<B: WriteBackendMethods> { @@ -42,61 +37,6 @@ pub struct ThinShared<B: WriteBackendMethods> { pub module_names: Vec<CString>, } -pub enum LtoModuleCodegen<B: WriteBackendMethods> { - Fat(ModuleCodegen<B::Module>), - Thin(ThinModule<B>), -} - -impl<B: WriteBackendMethods> LtoModuleCodegen<B> { - pub fn name(&self) -> &str { - match *self { - LtoModuleCodegen::Fat(_) => "everything", - LtoModuleCodegen::Thin(ref m) => m.name(), - } - } - - /// Optimize this module within the given codegen context. - pub fn optimize( - self, - cgcx: &CodegenContext<B>, - ) -> Result<ModuleCodegen<B::Module>, FatalError> { - match self { - LtoModuleCodegen::Fat(mut module) => { - B::optimize_fat(cgcx, &mut module)?; - Ok(module) - } - LtoModuleCodegen::Thin(thin) => B::optimize_thin(cgcx, thin), - } - } - - /// A "gauge" of how costly it is to optimize this module, used to sort - /// biggest modules first. - pub fn cost(&self) -> u64 { - match *self { - // Only one module with fat LTO, so the cost doesn't matter. - LtoModuleCodegen::Fat(_) => 0, - LtoModuleCodegen::Thin(ref m) => m.cost(), - } - } - - /// Run autodiff on Fat LTO module - pub fn autodiff( - self, - cgcx: &CodegenContext<B>, - diff_fncs: Vec<AutoDiffItem>, - config: &ModuleConfig, - ) -> Result<LtoModuleCodegen<B>, FatalError> { - match &self { - LtoModuleCodegen::Fat(module) => { - B::autodiff(cgcx, &module, diff_fncs, config)?; - } - _ => panic!("autodiff called with non-fat LTO module"), - } - - Ok(self) - } -} - pub enum SerializedModule<M: ModuleBufferMethods> { Local(M), FromRlib(Vec<u8>), diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index d2a64ec2993..50a7cba300b 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -397,50 +397,31 @@ impl<B: WriteBackendMethods> CodegenContext<B> { } } -fn generate_lto_work<B: ExtraBackendMethods>( +fn generate_thin_lto_work<B: ExtraBackendMethods>( cgcx: &CodegenContext<B>, - autodiff: Vec<AutoDiffItem>, - needs_fat_lto: Vec<FatLtoInput<B>>, needs_thin_lto: Vec<(String, B::ThinBuffer)>, import_only_modules: Vec<(SerializedModule<B::ModuleBuffer>, WorkProduct)>, ) -> Vec<(WorkItem<B>, u64)> { - let _prof_timer = cgcx.prof.generic_activity("codegen_generate_lto_work"); - - if !needs_fat_lto.is_empty() { - assert!(needs_thin_lto.is_empty()); - let mut module = - B::run_fat_lto(cgcx, needs_fat_lto, import_only_modules).unwrap_or_else(|e| e.raise()); - if cgcx.lto == Lto::Fat && !autodiff.is_empty() { - let config = cgcx.config(ModuleKind::Regular); - module = module.autodiff(cgcx, autodiff, config).unwrap_or_else(|e| e.raise()); - } - // We are adding a single work item, so the cost doesn't matter. - vec![(WorkItem::LTO(module), 0)] - } else { - if !autodiff.is_empty() { - let dcx = cgcx.create_dcx(); - dcx.handle().emit_fatal(AutodiffWithoutLto {}); - } - assert!(needs_fat_lto.is_empty()); - let (lto_modules, copy_jobs) = B::run_thin_lto(cgcx, needs_thin_lto, import_only_modules) - .unwrap_or_else(|e| e.raise()); - lto_modules - .into_iter() - .map(|module| { - let cost = module.cost(); - (WorkItem::LTO(module), cost) - }) - .chain(copy_jobs.into_iter().map(|wp| { - ( - WorkItem::CopyPostLtoArtifacts(CachedModuleCodegen { - name: wp.cgu_name.clone(), - source: wp, - }), - 0, // copying is very cheap - ) - })) - .collect() - } + let _prof_timer = cgcx.prof.generic_activity("codegen_thin_generate_lto_work"); + + let (lto_modules, copy_jobs) = + B::run_thin_lto(cgcx, needs_thin_lto, import_only_modules).unwrap_or_else(|e| e.raise()); + lto_modules + .into_iter() + .map(|module| { + let cost = module.cost(); + (WorkItem::ThinLto(module), cost) + }) + .chain(copy_jobs.into_iter().map(|wp| { + ( + WorkItem::CopyPostLtoArtifacts(CachedModuleCodegen { + name: wp.cgu_name.clone(), + source: wp, + }), + 0, // copying is very cheap + ) + })) + .collect() } struct CompiledModules { @@ -470,6 +451,7 @@ pub(crate) fn start_async_codegen<B: ExtraBackendMethods>( backend: B, tcx: TyCtxt<'_>, target_cpu: String, + autodiff_items: &[AutoDiffItem], ) -> OngoingCodegen<B> { let (coordinator_send, coordinator_receive) = channel(); @@ -488,6 +470,7 @@ pub(crate) fn start_async_codegen<B: ExtraBackendMethods>( backend.clone(), tcx, &crate_info, + autodiff_items, shared_emitter, codegen_worker_send, coordinator_receive, @@ -736,15 +719,23 @@ pub(crate) enum WorkItem<B: WriteBackendMethods> { /// Copy the post-LTO artifacts from the incremental cache to the output /// directory. CopyPostLtoArtifacts(CachedModuleCodegen), - /// Performs (Thin)LTO on the given module. - LTO(lto::LtoModuleCodegen<B>), + /// Performs fat LTO on the given module. + FatLto { + needs_fat_lto: Vec<FatLtoInput<B>>, + import_only_modules: Vec<(SerializedModule<B::ModuleBuffer>, WorkProduct)>, + autodiff: Vec<AutoDiffItem>, + }, + /// Performs thin-LTO on the given module. + ThinLto(lto::ThinModule<B>), } impl<B: WriteBackendMethods> WorkItem<B> { fn module_kind(&self) -> ModuleKind { match *self { WorkItem::Optimize(ref m) => m.kind, - WorkItem::CopyPostLtoArtifacts(_) | WorkItem::LTO(_) => ModuleKind::Regular, + WorkItem::CopyPostLtoArtifacts(_) | WorkItem::FatLto { .. } | WorkItem::ThinLto(_) => { + ModuleKind::Regular + } } } @@ -792,7 +783,8 @@ impl<B: WriteBackendMethods> WorkItem<B> { match self { WorkItem::Optimize(m) => desc("opt", "optimize module", &m.name), WorkItem::CopyPostLtoArtifacts(m) => desc("cpy", "copy LTO artifacts for", &m.name), - WorkItem::LTO(m) => desc("lto", "LTO module", m.name()), + WorkItem::FatLto { .. } => desc("lto", "fat LTO module", "everything"), + WorkItem::ThinLto(m) => desc("lto", "thin-LTO module", m.name()), } } } @@ -996,12 +988,24 @@ fn execute_copy_from_cache_work_item<B: ExtraBackendMethods>( }) } -fn execute_lto_work_item<B: ExtraBackendMethods>( +fn execute_fat_lto_work_item<B: ExtraBackendMethods>( + cgcx: &CodegenContext<B>, + needs_fat_lto: Vec<FatLtoInput<B>>, + import_only_modules: Vec<(SerializedModule<B::ModuleBuffer>, WorkProduct)>, + autodiff: Vec<AutoDiffItem>, + module_config: &ModuleConfig, +) -> Result<WorkItemResult<B>, FatalError> { + let module = B::run_and_optimize_fat_lto(cgcx, needs_fat_lto, import_only_modules, autodiff)?; + let module = B::codegen(cgcx, module, module_config)?; + Ok(WorkItemResult::Finished(module)) +} + +fn execute_thin_lto_work_item<B: ExtraBackendMethods>( cgcx: &CodegenContext<B>, - module: lto::LtoModuleCodegen<B>, + module: lto::ThinModule<B>, module_config: &ModuleConfig, ) -> Result<WorkItemResult<B>, FatalError> { - let module = module.optimize(cgcx)?; + let module = B::optimize_thin(cgcx, module)?; finish_intra_module_work(cgcx, module, module_config) } @@ -1010,11 +1014,8 @@ fn finish_intra_module_work<B: ExtraBackendMethods>( module: ModuleCodegen<B::Module>, module_config: &ModuleConfig, ) -> Result<WorkItemResult<B>, FatalError> { - let dcx = cgcx.create_dcx(); - let dcx = dcx.handle(); - if !cgcx.opts.unstable_opts.combine_cgu || module.kind == ModuleKind::Allocator { - let module = B::codegen(cgcx, dcx, module, module_config)?; + let module = B::codegen(cgcx, module, module_config)?; Ok(WorkItemResult::Finished(module)) } else { Ok(WorkItemResult::NeedsLink(module)) @@ -1031,9 +1032,6 @@ pub(crate) enum Message<B: WriteBackendMethods> { /// Sent from a backend worker thread. WorkItem { result: Result<WorkItemResult<B>, Option<WorkerFatalError>>, worker_id: usize }, - /// A vector containing all the AutoDiff tasks that we have to pass to Enzyme. - AddAutoDiffItems(Vec<AutoDiffItem>), - /// The frontend has finished generating something (backend IR or a /// post-LTO artifact) for a codegen unit, and it should be passed to the /// backend. Sent from the main thread. @@ -1100,6 +1098,7 @@ fn start_executing_work<B: ExtraBackendMethods>( backend: B, tcx: TyCtxt<'_>, crate_info: &CrateInfo, + autodiff_items: &[AutoDiffItem], shared_emitter: SharedEmitter, codegen_worker_send: Sender<CguMessage>, coordinator_receive: Receiver<Box<dyn Any + Send>>, @@ -1109,6 +1108,7 @@ fn start_executing_work<B: ExtraBackendMethods>( ) -> thread::JoinHandle<Result<CompiledModules, ()>> { let coordinator_send = tx_to_llvm_workers; let sess = tcx.sess; + let autodiff_items = autodiff_items.to_vec(); let mut each_linked_rlib_for_lto = Vec::new(); drop(link::each_linked_rlib(crate_info, None, &mut |cnum, path| { @@ -1362,7 +1362,6 @@ fn start_executing_work<B: ExtraBackendMethods>( // This is where we collect codegen units that have gone all the way // through codegen and LLVM. - let mut autodiff_items = Vec::new(); let mut compiled_modules = vec![]; let mut compiled_allocator_module = None; let mut needs_link = Vec::new(); @@ -1474,20 +1473,37 @@ fn start_executing_work<B: ExtraBackendMethods>( let needs_thin_lto = mem::take(&mut needs_thin_lto); let import_only_modules = mem::take(&mut lto_import_only_modules); - for (work, cost) in generate_lto_work( - &cgcx, - autodiff_items.clone(), - needs_fat_lto, - needs_thin_lto, - import_only_modules, - ) { - let insertion_index = work_items - .binary_search_by_key(&cost, |&(_, cost)| cost) - .unwrap_or_else(|e| e); - work_items.insert(insertion_index, (work, cost)); + if !needs_fat_lto.is_empty() { + assert!(needs_thin_lto.is_empty()); + + work_items.push(( + WorkItem::FatLto { + needs_fat_lto, + import_only_modules, + autodiff: autodiff_items.clone(), + }, + 0, + )); if cgcx.parallel { helper.request_token(); } + } else { + if !autodiff_items.is_empty() { + let dcx = cgcx.create_dcx(); + dcx.handle().emit_fatal(AutodiffWithoutLto {}); + } + + for (work, cost) in + generate_thin_lto_work(&cgcx, needs_thin_lto, import_only_modules) + { + let insertion_index = work_items + .binary_search_by_key(&cost, |&(_, cost)| cost) + .unwrap_or_else(|e| e); + work_items.insert(insertion_index, (work, cost)); + if cgcx.parallel { + helper.request_token(); + } + } } } @@ -1616,10 +1632,6 @@ fn start_executing_work<B: ExtraBackendMethods>( main_thread_state = MainThreadState::Idle; } - Message::AddAutoDiffItems(mut items) => { - autodiff_items.append(&mut items); - } - Message::CodegenComplete => { if codegen_state != Aborted { codegen_state = Completed; @@ -1702,7 +1714,7 @@ fn start_executing_work<B: ExtraBackendMethods>( let dcx = dcx.handle(); let module = B::run_link(&cgcx, dcx, needs_link).map_err(|_| ())?; let module = - B::codegen(&cgcx, dcx, module, cgcx.config(ModuleKind::Regular)).map_err(|_| ())?; + B::codegen(&cgcx, module, cgcx.config(ModuleKind::Regular)).map_err(|_| ())?; compiled_modules.push(module); } @@ -1842,10 +1854,22 @@ fn spawn_work<'a, B: ExtraBackendMethods>( ); Ok(execute_copy_from_cache_work_item(&cgcx, m, module_config)) } - WorkItem::LTO(m) => { + WorkItem::FatLto { needs_fat_lto, import_only_modules, autodiff } => { + let _timer = cgcx + .prof + .generic_activity_with_arg("codegen_module_perform_lto", "everything"); + execute_fat_lto_work_item( + &cgcx, + needs_fat_lto, + import_only_modules, + autodiff, + module_config, + ) + } + WorkItem::ThinLto(m) => { let _timer = cgcx.prof.generic_activity_with_arg("codegen_module_perform_lto", m.name()); - execute_lto_work_item(&cgcx, m, module_config) + execute_thin_lto_work_item(&cgcx, m, module_config) } }) }; @@ -2082,10 +2106,6 @@ impl<B: ExtraBackendMethods> OngoingCodegen<B> { drop(self.coordinator.sender.send(Box::new(Message::CodegenComplete::<B>))); } - pub(crate) fn submit_autodiff_items(&self, items: Vec<AutoDiffItem>) { - drop(self.coordinator.sender.send(Box::new(Message::<B>::AddAutoDiffItems(items)))); - } - pub(crate) fn check_for_errors(&self, sess: &Session) { self.shared_emitter_main.check(sess, false); } diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 18581f854b6..833456abb8a 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -647,7 +647,7 @@ pub fn codegen_crate<B: ExtraBackendMethods>( ) -> OngoingCodegen<B> { // Skip crate items and just output metadata in -Z no-codegen mode. if tcx.sess.opts.unstable_opts.no_codegen || !tcx.sess.opts.output_types.should_codegen() { - let ongoing_codegen = start_async_codegen(backend, tcx, target_cpu); + let ongoing_codegen = start_async_codegen(backend, tcx, target_cpu, &[]); ongoing_codegen.codegen_finished(tcx); @@ -667,7 +667,6 @@ pub fn codegen_crate<B: ExtraBackendMethods>( // codegen units. let MonoItemPartitions { codegen_units, autodiff_items, .. } = tcx.collect_and_partition_mono_items(()); - let autodiff_fncs = autodiff_items.to_vec(); // Force all codegen_unit queries so they are already either red or green // when compile_codegen_unit accesses them. We are not able to re-execute @@ -680,7 +679,7 @@ pub fn codegen_crate<B: ExtraBackendMethods>( } } - let ongoing_codegen = start_async_codegen(backend.clone(), tcx, target_cpu); + let ongoing_codegen = start_async_codegen(backend.clone(), tcx, target_cpu, autodiff_items); // Codegen an allocator shim, if necessary. if let Some(kind) = allocator_kind_for_codegen(tcx) { @@ -710,10 +709,6 @@ pub fn codegen_crate<B: ExtraBackendMethods>( ); } - if !autodiff_fncs.is_empty() { - ongoing_codegen.submit_autodiff_items(autodiff_fncs); - } - // For better throughput during parallel processing by LLVM, we used to sort // CGUs largest to smallest. This would lead to better thread utilization // by, for example, preventing a large CGU from being processed last and diff --git a/compiler/rustc_codegen_ssa/src/traits/write.rs b/compiler/rustc_codegen_ssa/src/traits/write.rs index 07a0609fda1..5e993640472 100644 --- a/compiler/rustc_codegen_ssa/src/traits/write.rs +++ b/compiler/rustc_codegen_ssa/src/traits/write.rs @@ -2,7 +2,7 @@ use rustc_ast::expand::autodiff_attrs::AutoDiffItem; use rustc_errors::{DiagCtxtHandle, FatalError}; use rustc_middle::dep_graph::WorkProduct; -use crate::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule}; +use crate::back::lto::{SerializedModule, ThinModule}; use crate::back::write::{CodegenContext, FatLtoInput, ModuleConfig}; use crate::{CompiledModule, ModuleCodegen}; @@ -20,13 +20,14 @@ pub trait WriteBackendMethods: Clone + 'static { dcx: DiagCtxtHandle<'_>, modules: Vec<ModuleCodegen<Self::Module>>, ) -> Result<ModuleCodegen<Self::Module>, FatalError>; - /// Performs fat LTO by merging all modules into a single one and returning it - /// for further optimization. - fn run_fat_lto( + /// Performs fat LTO by merging all modules into a single one, running autodiff + /// if necessary and running any further optimizations + fn run_and_optimize_fat_lto( cgcx: &CodegenContext<Self>, modules: Vec<FatLtoInput<Self>>, cached_modules: Vec<(SerializedModule<Self::ModuleBuffer>, WorkProduct)>, - ) -> Result<LtoModuleCodegen<Self>, FatalError>; + diff_fncs: Vec<AutoDiffItem>, + ) -> Result<ModuleCodegen<Self::Module>, FatalError>; /// Performs thin LTO by performing necessary global analysis and returning two /// lists, one of the modules that need optimization and another for modules that /// can simply be copied over from the incr. comp. cache. @@ -34,7 +35,7 @@ pub trait WriteBackendMethods: Clone + 'static { cgcx: &CodegenContext<Self>, modules: Vec<(String, Self::ThinBuffer)>, cached_modules: Vec<(SerializedModule<Self::ModuleBuffer>, WorkProduct)>, - ) -> Result<(Vec<LtoModuleCodegen<Self>>, Vec<WorkProduct>), FatalError>; + ) -> Result<(Vec<ThinModule<Self>>, Vec<WorkProduct>), FatalError>; fn print_pass_timings(&self); fn print_statistics(&self); fn optimize( @@ -43,17 +44,12 @@ pub trait WriteBackendMethods: Clone + 'static { module: &mut ModuleCodegen<Self::Module>, config: &ModuleConfig, ) -> Result<(), FatalError>; - fn optimize_fat( - cgcx: &CodegenContext<Self>, - llmod: &mut ModuleCodegen<Self::Module>, - ) -> Result<(), FatalError>; fn optimize_thin( cgcx: &CodegenContext<Self>, thin: ThinModule<Self>, ) -> Result<ModuleCodegen<Self::Module>, FatalError>; fn codegen( cgcx: &CodegenContext<Self>, - dcx: DiagCtxtHandle<'_>, module: ModuleCodegen<Self::Module>, config: &ModuleConfig, ) -> Result<CompiledModule, FatalError>; @@ -62,12 +58,6 @@ pub trait WriteBackendMethods: Clone + 'static { want_summary: bool, ) -> (String, Self::ThinBuffer); fn serialize_module(module: ModuleCodegen<Self::Module>) -> (String, Self::ModuleBuffer); - fn autodiff( - cgcx: &CodegenContext<Self>, - module: &ModuleCodegen<Self::Module>, - diff_fncs: Vec<AutoDiffItem>, - config: &ModuleConfig, - ) -> Result<(), FatalError>; } pub trait ThinBufferMethods: Send + Sync { diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl index c9b7356432d..aa0bc42d448 100644 --- a/compiler/rustc_const_eval/messages.ftl +++ b/compiler/rustc_const_eval/messages.ftl @@ -56,6 +56,17 @@ const_eval_const_context = {$kind -> *[other] {""} } +const_eval_const_heap_ptr_in_final = encountered `const_allocate` pointer in final value that was not made global + .note = use `const_make_global` to make allocated pointers immutable before returning + +const_eval_const_make_global_ptr_already_made_global = attempting to call `const_make_global` twice on the same allocation {$alloc} + +const_eval_const_make_global_ptr_is_non_heap = pointer passed to `const_make_global` does not point to a heap allocation: {$ptr} + +const_eval_const_make_global_with_dangling_ptr = pointer passed to `const_make_global` is dangling: {$ptr} + +const_eval_const_make_global_with_offset = making {$ptr} global which does not point to the beginning of an object + const_eval_copy_nonoverlapping_overlapping = `copy_nonoverlapping` called on overlapping ranges diff --git a/compiler/rustc_const_eval/src/check_consts/mod.rs b/compiler/rustc_const_eval/src/check_consts/mod.rs index 9ab8e0692e1..ebf18c6f2ac 100644 --- a/compiler/rustc_const_eval/src/check_consts/mod.rs +++ b/compiler/rustc_const_eval/src/check_consts/mod.rs @@ -93,7 +93,7 @@ pub fn rustc_allow_const_fn_unstable( /// world into two functions: those that are safe to expose on stable (and hence may not use /// unstable features, not even recursively), and those that are not. pub fn is_fn_or_trait_safe_to_expose_on_stable(tcx: TyCtxt<'_>, def_id: DefId) -> bool { - // A default body in a `#[const_trait]` is const-stable when the trait is const-stable. + // A default body in a `const trait` is const-stable when the trait is const-stable. if tcx.is_const_default_method(def_id) { return is_fn_or_trait_safe_to_expose_on_stable(tcx, tcx.parent(def_id)); } diff --git a/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs b/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs index b6e2682af36..438aed41b8b 100644 --- a/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs @@ -49,7 +49,6 @@ impl HasStaticRootDefId for DummyMachine { impl<'tcx> interpret::Machine<'tcx> for DummyMachine { interpret::compile_time_machine!(<'tcx>); - type MemoryKind = !; const PANIC_ON_ALLOC_FAIL: bool = true; // We want to just eval random consts in the program, so `eval_mir_const` can fail. diff --git a/compiler/rustc_const_eval/src/const_eval/error.rs b/compiler/rustc_const_eval/src/const_eval/error.rs index 08fc03d9c46..3e880d02001 100644 --- a/compiler/rustc_const_eval/src/const_eval/error.rs +++ b/compiler/rustc_const_eval/src/const_eval/error.rs @@ -2,7 +2,7 @@ use std::mem; use rustc_errors::{Diag, DiagArgName, DiagArgValue, DiagMessage, IntoDiagArg}; use rustc_middle::mir::AssertKind; -use rustc_middle::mir::interpret::{Provenance, ReportedErrorInfo}; +use rustc_middle::mir::interpret::{AllocId, Provenance, ReportedErrorInfo}; use rustc_middle::query::TyCtxtAt; use rustc_middle::ty::layout::LayoutError; use rustc_middle::ty::{ConstInt, TyCtxt}; @@ -11,8 +11,8 @@ use rustc_span::{Span, Symbol}; use super::CompileTimeMachine; use crate::errors::{self, FrameNote, ReportErrorExt}; use crate::interpret::{ - ErrorHandled, Frame, InterpErrorInfo, InterpErrorKind, MachineStopType, err_inval, - err_machine_stop, + CtfeProvenance, ErrorHandled, Frame, InterpErrorInfo, InterpErrorKind, MachineStopType, + Pointer, err_inval, err_machine_stop, }; /// The CTFE machine has some custom error kinds. @@ -22,8 +22,22 @@ pub enum ConstEvalErrKind { ModifiedGlobal, RecursiveStatic, AssertFailure(AssertKind<ConstInt>), - Panic { msg: Symbol, line: u32, col: u32, file: Symbol }, + Panic { + msg: Symbol, + line: u32, + col: u32, + file: Symbol, + }, WriteThroughImmutablePointer, + /// Called `const_make_global` twice. + ConstMakeGlobalPtrAlreadyMadeGlobal(AllocId), + /// Called `const_make_global` on a non-heap pointer. + ConstMakeGlobalPtrIsNonHeap(Pointer<Option<CtfeProvenance>>), + /// Called `const_make_global` on a dangling pointer. + ConstMakeGlobalWithDanglingPtr(Pointer<Option<CtfeProvenance>>), + /// Called `const_make_global` on a pointer that does not start at the + /// beginning of an object. + ConstMakeGlobalWithOffset(Pointer<Option<CtfeProvenance>>), } impl MachineStopType for ConstEvalErrKind { @@ -38,6 +52,12 @@ impl MachineStopType for ConstEvalErrKind { RecursiveStatic => const_eval_recursive_static, AssertFailure(x) => x.diagnostic_message(), WriteThroughImmutablePointer => const_eval_write_through_immutable_pointer, + ConstMakeGlobalPtrAlreadyMadeGlobal { .. } => { + const_eval_const_make_global_ptr_already_made_global + } + ConstMakeGlobalPtrIsNonHeap(_) => const_eval_const_make_global_ptr_is_non_heap, + ConstMakeGlobalWithDanglingPtr(_) => const_eval_const_make_global_with_dangling_ptr, + ConstMakeGlobalWithOffset(_) => const_eval_const_make_global_with_offset, } } fn add_args(self: Box<Self>, adder: &mut dyn FnMut(DiagArgName, DiagArgValue)) { @@ -51,6 +71,14 @@ impl MachineStopType for ConstEvalErrKind { Panic { msg, .. } => { adder("msg".into(), msg.into_diag_arg(&mut None)); } + ConstMakeGlobalPtrIsNonHeap(ptr) + | ConstMakeGlobalWithOffset(ptr) + | ConstMakeGlobalWithDanglingPtr(ptr) => { + adder("ptr".into(), format!("{ptr:?}").into_diag_arg(&mut None)); + } + ConstMakeGlobalPtrAlreadyMadeGlobal(alloc) => { + adder("alloc".into(), alloc.into_diag_arg(&mut None)); + } } } } diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index 4bd4b493009..ce72d59b8b0 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -18,7 +18,7 @@ use tracing::{debug, instrument, trace}; use super::{CanAccessMutGlobal, CompileTimeInterpCx, CompileTimeMachine}; use crate::const_eval::CheckAlignment; use crate::interpret::{ - CtfeValidationMode, GlobalId, Immediate, InternKind, InternResult, InterpCx, InterpErrorKind, + CtfeValidationMode, GlobalId, Immediate, InternError, InternKind, InterpCx, InterpErrorKind, InterpResult, MPlaceTy, MemoryKind, OpTy, RefTracking, ReturnContinuation, create_static_alloc, intern_const_alloc_recursive, interp_ok, throw_exhaust, }; @@ -93,25 +93,30 @@ fn eval_body_using_ecx<'tcx, R: InterpretationResult<'tcx>>( // Since evaluation had no errors, validate the resulting constant. const_validate_mplace(ecx, &ret, cid)?; - // Only report this after validation, as validaiton produces much better diagnostics. + // Only report this after validation, as validation produces much better diagnostics. // FIXME: ensure validation always reports this and stop making interning care about it. match intern_result { Ok(()) => {} - Err(InternResult::FoundDanglingPointer) => { + Err(InternError::DanglingPointer) => { throw_inval!(AlreadyReported(ReportedErrorInfo::non_const_eval_error( ecx.tcx .dcx() .emit_err(errors::DanglingPtrInFinal { span: ecx.tcx.span, kind: intern_kind }), ))); } - Err(InternResult::FoundBadMutablePointer) => { + Err(InternError::BadMutablePointer) => { throw_inval!(AlreadyReported(ReportedErrorInfo::non_const_eval_error( ecx.tcx .dcx() .emit_err(errors::MutablePtrInFinal { span: ecx.tcx.span, kind: intern_kind }), ))); } + Err(InternError::ConstAllocNotGlobal) => { + throw_inval!(AlreadyReported(ReportedErrorInfo::non_const_eval_error( + ecx.tcx.dcx().emit_err(errors::ConstHeapPtrInFinal { span: ecx.tcx.span }), + ))); + } } interp_ok(R::make_result(ret, ecx)) diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 52fc898192a..f24fb18f83b 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -169,13 +169,19 @@ pub type CompileTimeInterpCx<'tcx> = InterpCx<'tcx, CompileTimeMachine<'tcx>>; #[derive(Debug, PartialEq, Eq, Copy, Clone)] pub enum MemoryKind { - Heap, + Heap { + /// Indicates whether `make_global` was called on this allocation. + /// If this is `true`, the allocation must be immutable. + was_made_global: bool, + }, } impl fmt::Display for MemoryKind { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - MemoryKind::Heap => write!(f, "heap allocation"), + MemoryKind::Heap { was_made_global } => { + write!(f, "heap allocation{}", if *was_made_global { " (made global)" } else { "" }) + } } } } @@ -184,7 +190,7 @@ impl interpret::MayLeak for MemoryKind { #[inline(always)] fn may_leak(self) -> bool { match self { - MemoryKind::Heap => false, + MemoryKind::Heap { was_made_global } => was_made_global, } } } @@ -314,8 +320,6 @@ impl<'tcx> CompileTimeMachine<'tcx> { impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { compile_time_machine!(<'tcx>); - type MemoryKind = MemoryKind; - const PANIC_ON_ALLOC_FAIL: bool = false; // will be raised as a proper error #[inline(always)] @@ -359,8 +363,8 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { if let ty::InstanceKind::Item(def) = instance.def { // Execution might have wandered off into other crates, so we cannot do a stability- // sensitive check here. But we can at least rule out functions that are not const at - // all. That said, we have to allow calling functions inside a trait marked with - // #[const_trait]. These *are* const-checked! + // all. That said, we have to allow calling functions inside a `const trait`. These + // *are* const-checked! if !ecx.tcx.is_const_fn(def) || ecx.tcx.has_attr(def, sym::rustc_do_not_const_check) { // We certainly do *not* want to actually call the fn // though, so be sure we return here. @@ -420,7 +424,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { let ptr = ecx.allocate_ptr( Size::from_bytes(size), align, - interpret::MemoryKind::Machine(MemoryKind::Heap), + interpret::MemoryKind::Machine(MemoryKind::Heap { was_made_global: false }), AllocInit::Uninit, )?; ecx.write_pointer(ptr, dest)?; @@ -453,10 +457,17 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { ecx.deallocate_ptr( ptr, Some((size, align)), - interpret::MemoryKind::Machine(MemoryKind::Heap), + interpret::MemoryKind::Machine(MemoryKind::Heap { was_made_global: false }), )?; } } + + sym::const_make_global => { + let ptr = ecx.read_pointer(&args[0])?; + ecx.make_const_heap_ptr_global(ptr)?; + ecx.write_pointer(ptr, dest)?; + } + // The intrinsic represents whether the value is known to the optimizer (LLVM). // We're not doing any optimizations here, so there is no optimizer that could know the value. // (We know the value here in the machine of course, but this is the runtime of that code, diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs index 49cd7138748..b6a64035261 100644 --- a/compiler/rustc_const_eval/src/errors.rs +++ b/compiler/rustc_const_eval/src/errors.rs @@ -44,6 +44,14 @@ pub(crate) struct MutablePtrInFinal { } #[derive(Diagnostic)] +#[diag(const_eval_const_heap_ptr_in_final)] +#[note] +pub(crate) struct ConstHeapPtrInFinal { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] #[diag(const_eval_unstable_in_stable_exposed)] pub(crate) struct UnstableInStableExposed { pub gate: String, diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs index f0f958d069e..bb59b9f5418 100644 --- a/compiler/rustc_const_eval/src/interpret/intern.rs +++ b/compiler/rustc_const_eval/src/interpret/intern.rs @@ -26,21 +26,18 @@ use rustc_middle::ty::layout::TyAndLayout; use rustc_span::def_id::LocalDefId; use tracing::{instrument, trace}; -use super::{ - AllocId, Allocation, InterpCx, MPlaceTy, Machine, MemoryKind, PlaceTy, err_ub, interp_ok, -}; -use crate::const_eval; +use super::{AllocId, Allocation, InterpCx, MPlaceTy, Machine, MemoryKind, PlaceTy, interp_ok}; use crate::const_eval::DummyMachine; -use crate::errors::NestedStaticInThreadLocal; +use crate::{const_eval, errors}; -pub trait CompileTimeMachine<'tcx, T> = Machine< +pub trait CompileTimeMachine<'tcx> = Machine< 'tcx, - MemoryKind = T, + MemoryKind = const_eval::MemoryKind, Provenance = CtfeProvenance, ExtraFnVal = !, FrameExtra = (), AllocExtra = (), - MemoryMap = FxIndexMap<AllocId, (MemoryKind<T>, Allocation)>, + MemoryMap = FxIndexMap<AllocId, (MemoryKind<const_eval::MemoryKind>, Allocation)>, > + HasStaticRootDefId; pub trait HasStaticRootDefId { @@ -62,18 +59,32 @@ impl HasStaticRootDefId for const_eval::CompileTimeMachine<'_> { /// already mutable (as a sanity check). /// /// Returns an iterator over all relocations referred to by this allocation. -fn intern_shallow<'tcx, T, M: CompileTimeMachine<'tcx, T>>( +fn intern_shallow<'tcx, M: CompileTimeMachine<'tcx>>( ecx: &mut InterpCx<'tcx, M>, alloc_id: AllocId, mutability: Mutability, disambiguator: Option<&mut DisambiguatorState>, -) -> Result<impl Iterator<Item = CtfeProvenance> + 'tcx, ()> { +) -> Result<impl Iterator<Item = CtfeProvenance> + 'tcx, InternError> { trace!("intern_shallow {:?}", alloc_id); // remove allocation // FIXME(#120456) - is `swap_remove` correct? - let Some((_kind, mut alloc)) = ecx.memory.alloc_map.swap_remove(&alloc_id) else { - return Err(()); + let Some((kind, mut alloc)) = ecx.memory.alloc_map.swap_remove(&alloc_id) else { + return Err(InternError::DanglingPointer); }; + + match kind { + MemoryKind::Machine(const_eval::MemoryKind::Heap { was_made_global }) => { + if !was_made_global { + // Attempting to intern a `const_allocate`d pointer that was not made global via + // `const_make_global`. We want to error here, but we have to first put the + // allocation back into the `alloc_map` to keep things in a consistent state. + ecx.memory.alloc_map.insert(alloc_id, (kind, alloc)); + return Err(InternError::ConstAllocNotGlobal); + } + } + MemoryKind::Stack | MemoryKind::CallerLocation => {} + } + // Set allocation mutability as appropriate. This is used by LLVM to put things into // read-only memory, and also by Miri when evaluating other globals that // access this one. @@ -99,7 +110,7 @@ fn intern_shallow<'tcx, T, M: CompileTimeMachine<'tcx, T>>( } else { ecx.tcx.set_alloc_id_memory(alloc_id, alloc); } - Ok(alloc.0.0.provenance().ptrs().iter().map(|&(_, prov)| prov)) + Ok(alloc.inner().provenance().ptrs().iter().map(|&(_, prov)| prov)) } /// Creates a new `DefId` and feeds all the right queries to make this `DefId` @@ -125,7 +136,7 @@ fn intern_as_new_static<'tcx>( tcx.set_nested_alloc_id_static(alloc_id, feed.def_id()); if tcx.is_thread_local_static(static_id.into()) { - tcx.dcx().emit_err(NestedStaticInThreadLocal { span: tcx.def_span(static_id) }); + tcx.dcx().emit_err(errors::NestedStaticInThreadLocal { span: tcx.def_span(static_id) }); } // These do not inherit the codegen attrs of the parent static allocation, since @@ -151,9 +162,10 @@ pub enum InternKind { } #[derive(Debug)] -pub enum InternResult { - FoundBadMutablePointer, - FoundDanglingPointer, +pub enum InternError { + BadMutablePointer, + DanglingPointer, + ConstAllocNotGlobal, } /// Intern `ret` and everything it references. @@ -163,11 +175,11 @@ pub enum InternResult { /// /// For `InternKind::Static` the root allocation will not be interned, but must be handled by the caller. #[instrument(level = "debug", skip(ecx))] -pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx, const_eval::MemoryKind>>( +pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx>>( ecx: &mut InterpCx<'tcx, M>, intern_kind: InternKind, ret: &MPlaceTy<'tcx>, -) -> Result<(), InternResult> { +) -> Result<(), InternError> { let mut disambiguator = DisambiguatorState::new(); // We are interning recursively, and for mutability we are distinguishing the "root" allocation @@ -181,7 +193,7 @@ pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx, const_eval } InternKind::Static(Mutability::Not) => { ( - // Outermost allocation is mutable if `!Freeze`. + // Outermost allocation is mutable if `!Freeze` i.e. contains interior mutable types. if ret.layout.ty.is_freeze(*ecx.tcx, ecx.typing_env) { Mutability::Not } else { @@ -224,6 +236,7 @@ pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx, const_eval // We want to first report "dangling" and then "mutable", so we need to delay reporting these // errors. let mut result = Ok(()); + let mut found_bad_mutable_ptr = false; // Keep interning as long as there are things to intern. // We show errors if there are dangling pointers, or mutable pointers in immutable contexts @@ -278,18 +291,7 @@ pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx, const_eval // when there is memory there that someone might expect to be mutable, but we make it immutable. let dangling = !is_already_global && !ecx.memory.alloc_map.contains_key(&alloc_id); if !dangling { - // Found a mutable pointer inside a const where inner allocations should be - // immutable. - if !ecx.tcx.sess.opts.unstable_opts.unleash_the_miri_inside_of_you { - span_bug!( - ecx.tcx.span, - "the static const safety checks accepted a mutable pointer they should not have accepted" - ); - } - // Prefer dangling pointer errors over mutable pointer errors - if result.is_ok() { - result = Err(InternResult::FoundBadMutablePointer); - } + found_bad_mutable_ptr = true; } } if ecx.tcx.try_get_global_alloc(alloc_id).is_some() { @@ -310,18 +312,31 @@ pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx, const_eval just_interned.insert(alloc_id); match intern_shallow(ecx, alloc_id, inner_mutability, Some(&mut disambiguator)) { Ok(nested) => todo.extend(nested), - Err(()) => { - ecx.tcx.dcx().delayed_bug("found dangling pointer during const interning"); - result = Err(InternResult::FoundDanglingPointer); + Err(err) => { + ecx.tcx.dcx().delayed_bug("error during const interning"); + result = Err(err); } } } + if found_bad_mutable_ptr && result.is_ok() { + // We found a mutable pointer inside a const where inner allocations should be immutable, + // and there was no other error. This should usually never happen! However, this can happen + // in unleash-miri mode, so report it as a normal error then. + if ecx.tcx.sess.opts.unstable_opts.unleash_the_miri_inside_of_you { + result = Err(InternError::BadMutablePointer); + } else { + span_bug!( + ecx.tcx.span, + "the static const safety checks accepted a mutable pointer they should not have accepted" + ); + } + } result } /// Intern `ret`. This function assumes that `ret` references no other allocation. #[instrument(level = "debug", skip(ecx))] -pub fn intern_const_alloc_for_constprop<'tcx, T, M: CompileTimeMachine<'tcx, T>>( +pub fn intern_const_alloc_for_constprop<'tcx, M: CompileTimeMachine<'tcx>>( ecx: &mut InterpCx<'tcx, M>, alloc_id: AllocId, ) -> InterpResult<'tcx, ()> { @@ -330,10 +345,7 @@ pub fn intern_const_alloc_for_constprop<'tcx, T, M: CompileTimeMachine<'tcx, T>> return interp_ok(()); } // Move allocation to `tcx`. - if let Some(_) = intern_shallow(ecx, alloc_id, Mutability::Not, None) - .map_err(|()| err_ub!(DeadLocal))? - .next() - { + if let Some(_) = intern_shallow(ecx, alloc_id, Mutability::Not, None).unwrap().next() { // We are not doing recursive interning, so we don't currently support provenance. // (If this assertion ever triggers, we should just implement a // proper recursive interning loop -- or just call `intern_const_alloc_recursive`. diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index 22d29eda913..e24a355891d 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -4,8 +4,9 @@ use std::assert_matches::assert_matches; -use rustc_abi::{FieldIdx, Size}; +use rustc_abi::{FieldIdx, HasDataLayout, Size}; use rustc_apfloat::ieee::{Double, Half, Quad, Single}; +use rustc_middle::mir::interpret::{read_target_uint, write_target_uint}; use rustc_middle::mir::{self, BinOp, ConstValue, NonDivergingIntrinsic}; use rustc_middle::ty::layout::TyAndLayout; use rustc_middle::ty::{Ty, TyCtxt}; @@ -30,7 +31,7 @@ pub(crate) fn alloc_type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ConstAll } impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { /// Generates a value of `TypeId` for `ty` in-place. - pub(crate) fn write_type_id( + fn write_type_id( &mut self, ty: Ty<'tcx>, dest: &PlaceTy<'tcx, M::Provenance>, @@ -48,8 +49,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // Here we rely on `TypeId` being a newtype around an array of pointers, so we // first project to its only field and then the array elements. let alloc_id = tcx.reserve_and_set_type_id_alloc(ty); - let first = self.project_field(dest, FieldIdx::ZERO)?; - let mut elem_iter = self.project_array_fields(&first)?; + let arr = self.project_field(dest, FieldIdx::ZERO)?; + let mut elem_iter = self.project_array_fields(&arr)?; while let Some((_, elem)) = elem_iter.next(self)? { // Decorate this part of the hash with provenance; leave the integer part unchanged. let hash_fragment = self.read_scalar(&elem)?.to_target_usize(&tcx)?; @@ -61,6 +62,52 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { interp_ok(()) } + /// Read a value of type `TypeId`, returning the type it represents. + pub(crate) fn read_type_id( + &self, + op: &OpTy<'tcx, M::Provenance>, + ) -> InterpResult<'tcx, Ty<'tcx>> { + // `TypeId` is a newtype around an array of pointers. All pointers must have the same + // provenance, and that provenance represents the type. + let ptr_size = self.pointer_size().bytes_usize(); + let arr = self.project_field(op, FieldIdx::ZERO)?; + + let mut ty_and_hash = None; + let mut elem_iter = self.project_array_fields(&arr)?; + while let Some((idx, elem)) = elem_iter.next(self)? { + let elem = self.read_pointer(&elem)?; + let (elem_ty, elem_hash) = self.get_ptr_type_id(elem)?; + // If this is the first element, remember the type and its hash. + // If this is not the first element, ensure it is consistent with the previous ones. + let full_hash = match ty_and_hash { + None => { + let hash = self.tcx.type_id_hash(elem_ty).as_u128(); + let mut hash_bytes = [0u8; 16]; + write_target_uint(self.data_layout().endian, &mut hash_bytes, hash).unwrap(); + ty_and_hash = Some((elem_ty, hash_bytes)); + hash_bytes + } + Some((ty, hash_bytes)) => { + if ty != elem_ty { + throw_ub_format!( + "invalid `TypeId` value: not all bytes carry the same type id metadata" + ); + } + hash_bytes + } + }; + // Ensure the elem_hash matches the corresponding part of the full hash. + let hash_frag = &full_hash[(idx as usize) * ptr_size..][..ptr_size]; + if read_target_uint(self.data_layout().endian, hash_frag).unwrap() != elem_hash.into() { + throw_ub_format!( + "invalid `TypeId` value: the hash does not match the type id metadata" + ); + } + } + + interp_ok(ty_and_hash.unwrap().0) + } + /// Returns `true` if emulation happened. /// Here we implement the intrinsics that are common to all Miri instances; individual machines can add their own /// intrinsic handling. @@ -97,47 +144,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { self.write_type_id(tp_ty, dest)?; } sym::type_id_eq => { - // Both operands are `TypeId`, which is a newtype around an array of pointers. - // Project until we have the array elements. - let a_fields = self.project_field(&args[0], FieldIdx::ZERO)?; - let b_fields = self.project_field(&args[1], FieldIdx::ZERO)?; - - let mut a_fields = self.project_array_fields(&a_fields)?; - let mut b_fields = self.project_array_fields(&b_fields)?; - - let mut provenance_a = None; - let mut provenance_b = None; - let mut provenance_matches = true; - - while let Some((i, a)) = a_fields.next(self)? { - let (_, b) = b_fields.next(self)?.unwrap(); - - let a = self.deref_pointer(&a)?; - let (a, offset_a) = self.get_ptr_type_id(a.ptr())?; - - let b = self.deref_pointer(&b)?; - let (b, offset_b) = self.get_ptr_type_id(b.ptr())?; - - if *provenance_a.get_or_insert(a) != a { - throw_ub_format!( - "type_id_eq: the first TypeId argument is invalid, the provenance of chunk {i} does not match the first chunk's" - ) - } - if *provenance_b.get_or_insert(b) != b { - throw_ub_format!( - "type_id_eq: the second TypeId argument is invalid, the provenance of chunk {i} does not match the first chunk's" - ) - } - provenance_matches &= a == b; - - if offset_a != offset_b && provenance_matches { - throw_ub_format!( - "type_id_eq: one of the TypeId arguments is invalid, chunk {i} of the hash does not match the type it represents" - ) - } - } - - self.write_scalar(Scalar::from_bool(provenance_matches), dest)?; + let a_ty = self.read_type_id(&args[0])?; + let b_ty = self.read_type_id(&args[1])?; + self.write_scalar(Scalar::from_bool(a_ty == b_ty), dest)?; } sym::variant_count => { let tp_ty = instance.args.type_at(0); diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs index d150ed69250..e981f3973ae 100644 --- a/compiler/rustc_const_eval/src/interpret/machine.rs +++ b/compiler/rustc_const_eval/src/interpret/machine.rs @@ -649,6 +649,7 @@ pub macro compile_time_machine(<$tcx: lifetime>) { type ExtraFnVal = !; + type MemoryKind = $crate::const_eval::MemoryKind; type MemoryMap = rustc_data_structures::fx::FxIndexMap<AllocId, (MemoryKind<Self::MemoryKind>, Allocation)>; const GLOBAL_KIND: Option<Self::MemoryKind> = None; // no copying of globals from `tcx` to machine memory diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index 6414821e21d..b2cbbc21430 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -26,6 +26,7 @@ use super::{ Misalignment, Pointer, PointerArithmetic, Provenance, Scalar, alloc_range, err_ub, err_ub_custom, interp_ok, throw_ub, throw_ub_custom, throw_unsup, throw_unsup_format, }; +use crate::const_eval::ConstEvalErrKind; use crate::fluent_generated as fluent; #[derive(Debug, PartialEq, Copy, Clone)] @@ -311,6 +312,51 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { interp_ok(new_ptr) } + /// Mark the `const_allocate`d allocation `ptr` points to as immutable so we can intern it. + pub fn make_const_heap_ptr_global( + &mut self, + ptr: Pointer<Option<CtfeProvenance>>, + ) -> InterpResult<'tcx> + where + M: Machine<'tcx, MemoryKind = crate::const_eval::MemoryKind, Provenance = CtfeProvenance>, + { + let (alloc_id, offset, _) = self.ptr_get_alloc_id(ptr, 0)?; + if offset.bytes() != 0 { + return Err(ConstEvalErrKind::ConstMakeGlobalWithOffset(ptr)).into(); + } + + if matches!(self.tcx.try_get_global_alloc(alloc_id), Some(_)) { + // This points to something outside the current interpreter. + return Err(ConstEvalErrKind::ConstMakeGlobalPtrIsNonHeap(ptr)).into(); + } + + // If we can't find it in `alloc_map` it must be dangling (because we don't use + // `extra_fn_ptr_map` in const-eval). + let (kind, alloc) = self + .memory + .alloc_map + .get_mut_or(alloc_id, || Err(ConstEvalErrKind::ConstMakeGlobalWithDanglingPtr(ptr)))?; + + // Ensure this is actually a *heap* allocation, and record it as made-global. + match kind { + MemoryKind::Stack | MemoryKind::CallerLocation => { + return Err(ConstEvalErrKind::ConstMakeGlobalPtrIsNonHeap(ptr)).into(); + } + MemoryKind::Machine(crate::const_eval::MemoryKind::Heap { was_made_global }) => { + if *was_made_global { + return Err(ConstEvalErrKind::ConstMakeGlobalPtrAlreadyMadeGlobal(alloc_id)) + .into(); + } + *was_made_global = true; + } + } + + // Prevent further mutation, this is now an immutable global. + alloc.mutability = Mutability::Not; + + interp_ok(()) + } + #[instrument(skip(self), level = "debug")] pub fn deallocate_ptr( &mut self, @@ -951,12 +997,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { pub fn get_ptr_type_id( &self, ptr: Pointer<Option<M::Provenance>>, - ) -> InterpResult<'tcx, (Ty<'tcx>, Size)> { + ) -> InterpResult<'tcx, (Ty<'tcx>, u64)> { let (alloc_id, offset, _meta) = self.ptr_get_alloc_id(ptr, 0)?; let GlobalAlloc::TypeId { ty } = self.tcx.global_alloc(alloc_id) else { - throw_ub_format!("type_id_eq: `TypeId` provenance is not a type id") + throw_ub_format!("invalid `TypeId` value: not all bytes carry type id metadata") }; - interp_ok((ty, offset)) + interp_ok((ty, offset.bytes())) } pub fn get_ptr_fn( diff --git a/compiler/rustc_const_eval/src/interpret/mod.rs b/compiler/rustc_const_eval/src/interpret/mod.rs index 2fc372dd019..2f365ec77b3 100644 --- a/compiler/rustc_const_eval/src/interpret/mod.rs +++ b/compiler/rustc_const_eval/src/interpret/mod.rs @@ -26,7 +26,7 @@ pub use self::call::FnArg; pub use self::eval_context::{InterpCx, format_interp_error}; use self::eval_context::{from_known_layout, mir_assign_valid_types}; pub use self::intern::{ - HasStaticRootDefId, InternKind, InternResult, intern_const_alloc_for_constprop, + HasStaticRootDefId, InternError, InternKind, intern_const_alloc_for_constprop, intern_const_alloc_recursive, }; pub use self::machine::{AllocMap, Machine, MayLeak, ReturnAction, compile_time_machine}; diff --git a/compiler/rustc_const_eval/src/interpret/stack.rs b/compiler/rustc_const_eval/src/interpret/stack.rs index b6ba069526c..2e99bb4209f 100644 --- a/compiler/rustc_const_eval/src/interpret/stack.rs +++ b/compiler/rustc_const_eval/src/interpret/stack.rs @@ -12,6 +12,7 @@ use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::{bug, mir}; use rustc_mir_dataflow::impls::always_storage_live_locals; use rustc_span::Span; +use tracing::field::Empty; use tracing::{info_span, instrument, trace}; use super::{ @@ -396,7 +397,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // Finish things up. M::after_stack_push(self)?; self.frame_mut().loc = Left(mir::Location::START); - let span = info_span!("frame", "{}", instance); + // `tracing_separate_thread` is used to instruct the chrome_tracing [tracing::Layer] in Miri + // to put the "frame" span on a separate trace thread/line than other spans, to make the + // visualization in https://ui.perfetto.dev easier to interpret. It is set to a value of + // [tracing::field::Empty] so that other tracing layers (e.g. the logger) will ignore it. + let span = info_span!("frame", tracing_separate_thread = Empty, "{}", instance); self.frame_mut().tracing_span.enter(span); interp_ok(()) diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index fc44490c96d..62f591ceaa9 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -558,7 +558,15 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { { // Everything should be already interned. let Some(global_alloc) = self.ecx.tcx.try_get_global_alloc(alloc_id) else { - assert!(self.ecx.memory.alloc_map.get(alloc_id).is_none()); + if self.ecx.memory.alloc_map.contains_key(&alloc_id) { + // This can happen when interning didn't complete due to, e.g. + // missing `make_global`. This must mean other errors are already + // being reported. + self.ecx.tcx.dcx().delayed_bug( + "interning did not complete, there should be an error", + ); + return interp_ok(()); + } // We can't have *any* references to non-existing allocations in const-eval // as the rest of rustc isn't happy with them... so we throw an error, even // though for zero-sized references this isn't really UB. diff --git a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs index 4ca39bbc68e..b1f29598750 100644 --- a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs +++ b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs @@ -52,9 +52,9 @@ fn check_validity_requirement_strict<'tcx>( let mut cx = InterpCx::new(cx.tcx(), DUMMY_SP, cx.typing_env, machine); - let allocated = cx - .allocate(ty, MemoryKind::Machine(crate::const_eval::MemoryKind::Heap)) - .expect("OOM: failed to allocate for uninit check"); + // It doesn't really matter which `MemoryKind` we use here, `Stack` is the least wrong. + let allocated = + cx.allocate(ty, MemoryKind::Stack).expect("OOM: failed to allocate for uninit check"); if kind == ValidityRequirement::Zero { cx.write_bytes_ptr( @@ -184,9 +184,10 @@ pub(crate) fn validate_scalar_in_layout<'tcx>( let Ok(layout) = cx.layout_of(ty) else { bug!("could not compute layout of {scalar:?}:{ty:?}") }; - let allocated = cx - .allocate(layout, MemoryKind::Machine(crate::const_eval::MemoryKind::Heap)) - .expect("OOM: failed to allocate for uninit check"); + + // It doesn't really matter which `MemoryKind` we use here, `Stack` is the least wrong. + let allocated = + cx.allocate(layout, MemoryKind::Stack).expect("OOM: failed to allocate for uninit check"); cx.write_scalar(scalar, &allocated).unwrap(); diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index ce3006c2604..1928cfd9048 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -1062,7 +1062,7 @@ pub trait ResolverExpand { fn next_node_id(&mut self) -> NodeId; fn invocation_parent(&self, id: LocalExpnId) -> LocalDefId; - fn resolve_dollar_crates(&mut self); + fn resolve_dollar_crates(&self); fn visit_ast_fragment_with_placeholders( &mut self, expn_id: LocalExpnId, diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index 6922ddfd6bd..83a8d601afe 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -12,7 +12,7 @@ use rustc_ast::{ }; use rustc_attr_parsing as attr; use rustc_attr_parsing::{ - AttributeParser, CFG_TEMPLATE, EvalConfigResult, eval_config_entry, parse_cfg_attr, + AttributeParser, CFG_TEMPLATE, EvalConfigResult, ShouldEmit, eval_config_entry, parse_cfg_attr, }; use rustc_data_structures::flat_map_in_place::FlatMapInPlace; use rustc_feature::{ @@ -167,7 +167,9 @@ pub fn pre_configure_attrs(sess: &Session, attrs: &[Attribute]) -> ast::AttrVec .flat_map(|attr| strip_unconfigured.process_cfg_attr(attr)) .take_while(|attr| { !is_cfg(attr) - || strip_unconfigured.cfg_true(attr, strip_unconfigured.lint_node_id).as_bool() + || strip_unconfigured + .cfg_true(attr, strip_unconfigured.lint_node_id, ShouldEmit::Nothing) + .as_bool() }) .collect() } @@ -401,10 +403,18 @@ impl<'a> StripUnconfigured<'a> { /// Determines if a node with the given attributes should be included in this configuration. fn in_cfg(&self, attrs: &[Attribute]) -> bool { - attrs.iter().all(|attr| !is_cfg(attr) || self.cfg_true(attr, self.lint_node_id).as_bool()) + attrs.iter().all(|attr| { + !is_cfg(attr) + || self.cfg_true(attr, self.lint_node_id, ShouldEmit::ErrorsAndLints).as_bool() + }) } - pub(crate) fn cfg_true(&self, attr: &Attribute, node: NodeId) -> EvalConfigResult { + pub(crate) fn cfg_true( + &self, + attr: &Attribute, + node: NodeId, + emit_errors: ShouldEmit, + ) -> EvalConfigResult { // We need to run this to do basic validation of the attribute, such as that lits are valid, etc // FIXME(jdonszelmann) this should not be necessary in the future match validate_attr::parse_meta(&self.sess.psess, attr) { @@ -428,7 +438,7 @@ impl<'a> StripUnconfigured<'a> { attr.span, node, self.features, - true, + emit_errors, parse_cfg_attr, &CFG_TEMPLATE, ) else { @@ -436,7 +446,7 @@ impl<'a> StripUnconfigured<'a> { return EvalConfigResult::True; }; - eval_config_entry(self.sess, &cfg, self.lint_node_id, self.features) + eval_config_entry(self.sess, &cfg, self.lint_node_id, self.features, emit_errors) } /// If attributes are not allowed on expressions, emit an error for `attr` diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index f99060e9a21..79ec79a2fdf 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -13,7 +13,7 @@ use rustc_ast::{ MetaItemKind, ModKind, NodeId, PatKind, StmtKind, TyKind, token, }; use rustc_ast_pretty::pprust; -use rustc_attr_parsing::EvalConfigResult; +use rustc_attr_parsing::{EvalConfigResult, ShouldEmit}; use rustc_data_structures::flat_map_in_place::FlatMapInPlace; use rustc_errors::PResult; use rustc_feature::Features; @@ -2171,7 +2171,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { attr: ast::Attribute, pos: usize, ) -> EvalConfigResult { - let res = self.cfg().cfg_true(&attr, node.node_id()); + let res = self.cfg().cfg_true(&attr, node.node_id(), ShouldEmit::ErrorsAndLints); if res.as_bool() { // A trace attribute left in AST in place of the original `cfg` attribute. // It can later be used by lints or other diagnostics. diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 7d9915d7f68..74872504b79 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -614,6 +614,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ ), // RFC 2632 + // FIXME(const_trait_impl) remove this gated!( const_trait, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No, const_trait_impl, "`const_trait` is a temporary placeholder for marking a trait that is suitable for `const` \ @@ -684,6 +685,10 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ EncodeCrossCrate::Yes ), ungated!( + unstable_feature_bound, Normal, template!(Word, List: "feat1, feat2, ..."), + DuplicatesOk, EncodeCrossCrate::No, + ), + ungated!( rustc_const_unstable, Normal, template!(List: r#"feature = "name""#), DuplicatesOk, EncodeCrossCrate::Yes ), diff --git a/compiler/rustc_hir/src/definitions.rs b/compiler/rustc_hir/src/definitions.rs index f93b9e5af53..698406d53a4 100644 --- a/compiler/rustc_hir/src/definitions.rs +++ b/compiler/rustc_hir/src/definitions.rs @@ -140,7 +140,9 @@ impl DefKey { pub(crate) fn compute_stable_hash(&self, parent: DefPathHash) -> DefPathHash { let mut hasher = StableHasher::new(); - parent.hash(&mut hasher); + // The new path is in the same crate as `parent`, and will contain the stable_crate_id. + // Therefore, we only need to include information of the parent's local hash. + parent.local_hash().hash(&mut hasher); let DisambiguatedDefPathData { ref data, disambiguator } = self.disambiguated_data; @@ -181,32 +183,26 @@ pub struct DisambiguatedDefPathData { } impl DisambiguatedDefPathData { - pub fn fmt_maybe_verbose(&self, writer: &mut impl Write, verbose: bool) -> fmt::Result { + pub fn as_sym(&self, verbose: bool) -> Symbol { match self.data.name() { DefPathDataName::Named(name) => { if verbose && self.disambiguator != 0 { - write!(writer, "{}#{}", name, self.disambiguator) + Symbol::intern(&format!("{}#{}", name, self.disambiguator)) } else { - writer.write_str(name.as_str()) + name } } DefPathDataName::Anon { namespace } => { if let DefPathData::AnonAssocTy(method) = self.data { - write!(writer, "{}::{{{}#{}}}", method, namespace, self.disambiguator) + Symbol::intern(&format!("{}::{{{}#{}}}", method, namespace, self.disambiguator)) } else { - write!(writer, "{{{}#{}}}", namespace, self.disambiguator) + Symbol::intern(&format!("{{{}#{}}}", namespace, self.disambiguator)) } } } } } -impl fmt::Display for DisambiguatedDefPathData { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.fmt_maybe_verbose(f, true) - } -} - #[derive(Clone, Debug, Encodable, Decodable)] pub struct DefPath { /// The path leading from the crate root to the item. @@ -250,7 +246,7 @@ impl DefPath { let mut s = String::with_capacity(self.data.len() * 16); for component in &self.data { - write!(s, "::{component}").unwrap(); + write!(s, "::{}", component.as_sym(true)).unwrap(); } s @@ -266,7 +262,7 @@ impl DefPath { for component in &self.data { s.extend(opt_delimiter); opt_delimiter = Some('-'); - write!(s, "{component}").unwrap(); + write!(s, "{}", component.as_sym(true)).unwrap(); } s @@ -361,8 +357,16 @@ impl Definitions { }, }; - let parent_hash = DefPathHash::new(stable_crate_id, Hash64::ZERO); - let def_path_hash = key.compute_stable_hash(parent_hash); + // We want *both* halves of a DefPathHash to depend on the crate-id of the defining crate. + // The crate-id can be more easily changed than the DefPath of an item, so, in the case of + // a crate-local DefPathHash collision, the user can simply "roll the dice again" for all + // DefPathHashes in the crate by changing the crate disambiguator (e.g. via bumping the + // crate's version number). + // + // Children paths will only hash the local portion, and still inherit the change to the + // root hash. + let def_path_hash = + DefPathHash::new(stable_crate_id, Hash64::new(stable_crate_id.as_u64())); // Create the root definition. let mut table = DefPathTable::new(stable_crate_id); diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 159518a8d87..e7898648c2b 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -7,7 +7,7 @@ use rustc_ast::token::CommentKind; use rustc_ast::util::parser::ExprPrecedence; use rustc_ast::{ self as ast, FloatTy, InlineAsmOptions, InlineAsmTemplatePiece, IntTy, Label, LitIntType, - LitKind, TraitObjectSyntax, UintTy, UnsafeBinderCastKind, + LitKind, TraitObjectSyntax, UintTy, UnsafeBinderCastKind, join_path_idents, }; pub use rustc_ast::{ AssignOp, AssignOpKind, AttrId, AttrStyle, BinOp, BinOpKind, BindingMode, BorrowKind, @@ -1168,7 +1168,7 @@ impl AttrPath { impl fmt::Display for AttrPath { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.segments.iter().map(|i| i.to_string()).collect::<Vec<_>>().join("::")) + write!(f, "{}", join_path_idents(&self.segments)) } } @@ -4163,6 +4163,7 @@ impl<'hir> Item<'hir> { expect_trait, ( + Constness, IsAuto, Safety, Ident, @@ -4170,8 +4171,8 @@ impl<'hir> Item<'hir> { GenericBounds<'hir>, &'hir [TraitItemId] ), - ItemKind::Trait(is_auto, safety, ident, generics, bounds, items), - (*is_auto, *safety, *ident, generics, bounds, items); + ItemKind::Trait(constness, is_auto, safety, ident, generics, bounds, items), + (*constness, *is_auto, *safety, *ident, generics, bounds, items); expect_trait_alias, (Ident, &'hir Generics<'hir>, GenericBounds<'hir>), ItemKind::TraitAlias(ident, generics, bounds), (*ident, generics, bounds); @@ -4341,7 +4342,15 @@ pub enum ItemKind<'hir> { /// A union definition, e.g., `union Foo<A, B> {x: A, y: B}`. Union(Ident, &'hir Generics<'hir>, VariantData<'hir>), /// A trait definition. - Trait(IsAuto, Safety, Ident, &'hir Generics<'hir>, GenericBounds<'hir>, &'hir [TraitItemId]), + Trait( + Constness, + IsAuto, + Safety, + Ident, + &'hir Generics<'hir>, + GenericBounds<'hir>, + &'hir [TraitItemId], + ), /// A trait alias. TraitAlias(Ident, &'hir Generics<'hir>, GenericBounds<'hir>), @@ -4385,7 +4394,7 @@ impl ItemKind<'_> { | ItemKind::Enum(ident, ..) | ItemKind::Struct(ident, ..) | ItemKind::Union(ident, ..) - | ItemKind::Trait(_, _, ident, ..) + | ItemKind::Trait(_, _, _, ident, ..) | ItemKind::TraitAlias(ident, ..) => Some(ident), ItemKind::Use(_, UseKind::Glob | UseKind::ListStem) @@ -4403,7 +4412,7 @@ impl ItemKind<'_> { | ItemKind::Enum(_, generics, _) | ItemKind::Struct(_, generics, _) | ItemKind::Union(_, generics, _) - | ItemKind::Trait(_, _, _, generics, _, _) + | ItemKind::Trait(_, _, _, _, generics, _, _) | ItemKind::TraitAlias(_, generics, _) | ItemKind::Impl(Impl { generics, .. }) => generics, _ => return None, diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 3edb94c28da..f33915d5b07 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -618,7 +618,15 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V:: try_visit!(visitor.visit_generics(generics)); try_visit!(visitor.visit_variant_data(struct_definition)); } - ItemKind::Trait(_is_auto, _safety, ident, ref generics, bounds, trait_item_refs) => { + ItemKind::Trait( + _constness, + _is_auto, + _safety, + ident, + ref generics, + bounds, + trait_item_refs, + ) => { try_visit!(visitor.visit_ident(ident)); try_visit!(visitor.visit_generics(generics)); walk_list!(visitor, visit_param_bound, bounds); diff --git a/compiler/rustc_hir/src/tests.rs b/compiler/rustc_hir/src/tests.rs index 18c2bfdac8c..3b797c1f103 100644 --- a/compiler/rustc_hir/src/tests.rs +++ b/compiler/rustc_hir/src/tests.rs @@ -28,7 +28,8 @@ fn def_path_hash_depends_on_crate_id() { assert_ne!(h0.local_hash(), h1.local_hash()); fn mk_test_hash(stable_crate_id: StableCrateId) -> DefPathHash { - let parent_hash = DefPathHash::new(stable_crate_id, Hash64::ZERO); + let parent_hash = + DefPathHash::new(stable_crate_id, Hash64::new(stable_crate_id.as_u64())); let key = DefKey { parent: None, diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index 529d3578985..a20becbe7e8 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -117,15 +117,15 @@ hir_analysis_coercion_between_struct_same_note = expected coercion between the s hir_analysis_coercion_between_struct_single_note = expected a single field to be coerced, none found -hir_analysis_const_bound_for_non_const_trait = `{$modifier}` can only be applied to `#[const_trait]` traits +hir_analysis_const_bound_for_non_const_trait = `{$modifier}` can only be applied to `const` traits .label = can't be applied to `{$trait_name}` - .note = `{$trait_name}` can't be used with `{$modifier}` because it isn't annotated with `#[const_trait]` - .suggestion = {$suggestion_pre}mark `{$trait_name}` as `#[const_trait]` to allow it to have `const` implementations + .note = `{$trait_name}` can't be used with `{$modifier}` because it isn't `const` + .suggestion = {$suggestion_pre}mark `{$trait_name}` as `const` to allow it to have `const` implementations -hir_analysis_const_impl_for_non_const_trait = const `impl` for trait `{$trait_name}` which is not marked with `#[const_trait]` +hir_analysis_const_impl_for_non_const_trait = const `impl` for trait `{$trait_name}` which is not `const` .label = this trait is not `const` - .suggestion = {$suggestion_pre}mark `{$trait_name}` as `#[const_trait]` to allow it to have `const` implementations - .note = marking a trait with `#[const_trait]` ensures all default method bodies are `const` + .suggestion = {$suggestion_pre}mark `{$trait_name}` as `const` to allow it to have `const` implementations + .note = marking a trait with `const` ensures all default method bodies are `const` .adding = adding a non-const method body in the future would be a breaking change hir_analysis_const_param_ty_impl_on_non_adt = diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 70fbb8a543e..03c026cd6c8 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -889,8 +889,6 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), tcx.ensure_ok().predicates_of(def_id); tcx.ensure_ok().explicit_item_bounds(def_id); tcx.ensure_ok().explicit_item_self_bounds(def_id); - tcx.ensure_ok().item_bounds(def_id); - tcx.ensure_ok().item_self_bounds(def_id); if tcx.is_conditionally_const(def_id) { tcx.ensure_ok().explicit_implied_const_bounds(def_id); tcx.ensure_ok().const_conditions(def_id); @@ -1044,8 +1042,12 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), let has_type = match assoc_item.container { ty::AssocItemContainer::Impl => true, ty::AssocItemContainer::Trait => { - tcx.ensure_ok().item_bounds(def_id); - tcx.ensure_ok().item_self_bounds(def_id); + tcx.ensure_ok().explicit_item_bounds(def_id); + tcx.ensure_ok().explicit_item_self_bounds(def_id); + if tcx.is_conditionally_const(def_id) { + tcx.ensure_ok().explicit_implied_const_bounds(def_id); + tcx.ensure_ok().const_conditions(def_id); + } res = res.and(check_trait_item(tcx, def_id)); assoc_item.defaultness(tcx).has_value() } diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index dcab6ef1c5a..6e5fe3823ab 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -422,6 +422,9 @@ pub(crate) fn check_intrinsic_type( vec![Ty::new_mut_ptr(tcx, tcx.types.u8), tcx.types.usize, tcx.types.usize], tcx.types.unit, ), + sym::const_make_global => { + (0, 0, vec![Ty::new_mut_ptr(tcx, tcx.types.u8)], Ty::new_imm_ptr(tcx, tcx.types.u8)) + } sym::ptr_offset_from => ( 1, diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 607028f4d9a..14ec82ede1c 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -2212,12 +2212,16 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> { let implied_obligations = traits::elaborate(tcx, predicates_with_span); for (pred, obligation_span) in implied_obligations { - // We lower empty bounds like `Vec<dyn Copy>:` as - // `WellFormed(Vec<dyn Copy>)`, which will later get checked by - // regular WF checking - if let ty::ClauseKind::WellFormed(..) = pred.kind().skip_binder() { - continue; + match pred.kind().skip_binder() { + // We lower empty bounds like `Vec<dyn Copy>:` as + // `WellFormed(Vec<dyn Copy>)`, which will later get checked by + // regular WF checking + ty::ClauseKind::WellFormed(..) + // Unstable feature goals cannot be proven in an empty environment so skip them + | ty::ClauseKind::UnstableFeature(..) => continue, + _ => {} } + // Match the existing behavior. if pred.is_global() && !pred.has_type_flags(TypeFlags::HAS_BINDER_VARS) { let pred = self.normalize(span, None, pred); diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 28a8758178f..0728b24eb14 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -844,15 +844,20 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AdtDef<'_> { fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef { let item = tcx.hir_expect_item(def_id); - let (is_alias, is_auto, safety) = match item.kind { - hir::ItemKind::Trait(is_auto, safety, ..) => (false, is_auto == hir::IsAuto::Yes, safety), - hir::ItemKind::TraitAlias(..) => (true, false, hir::Safety::Safe), + let (constness, is_alias, is_auto, safety) = match item.kind { + hir::ItemKind::Trait(constness, is_auto, safety, ..) => { + (constness, false, is_auto == hir::IsAuto::Yes, safety) + } + hir::ItemKind::TraitAlias(..) => (hir::Constness::NotConst, true, false, hir::Safety::Safe), _ => span_bug!(item.span, "trait_def_of_item invoked on non-trait"), }; let attrs = tcx.get_all_attrs(def_id); // Only regular traits can be const. - let constness = if !is_alias && find_attr!(attrs, AttributeKind::ConstTrait(_)) { + // FIXME(const_trait_impl): remove this + let constness = if constness == hir::Constness::Const + || !is_alias && find_attr!(attrs, AttributeKind::ConstTrait(_)) + { hir::Constness::Const } else { hir::Constness::NotConst diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index e51ef46afb7..548ba343aae 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -38,12 +38,13 @@ fn associated_type_bounds<'tcx>( let icx = ItemCtxt::new(tcx, assoc_item_def_id); let mut bounds = Vec::new(); icx.lowerer().lower_bounds(item_ty, hir_bounds, &mut bounds, ty::List::empty(), filter); - // Implicit bounds are added to associated types unless a `?Trait` bound is found + match filter { PredicateFilter::All | PredicateFilter::SelfOnly | PredicateFilter::SelfTraitThatDefines(_) | PredicateFilter::SelfAndAssociatedTypeBounds => { + // Implicit bounds are added to associated types unless a `?Trait` bound is found. icx.lowerer().add_sizedness_bounds( &mut bounds, item_ty, @@ -53,37 +54,48 @@ fn associated_type_bounds<'tcx>( span, ); icx.lowerer().add_default_traits(&mut bounds, item_ty, hir_bounds, None, span); + + // Also collect `where Self::Assoc: Trait` from the parent trait's where clauses. + let trait_def_id = tcx.local_parent(assoc_item_def_id); + let trait_predicates = tcx.trait_explicit_predicates_and_bounds(trait_def_id); + + let item_trait_ref = + ty::TraitRef::identity(tcx, tcx.parent(assoc_item_def_id.to_def_id())); + bounds.extend(trait_predicates.predicates.iter().copied().filter_map( + |(clause, span)| { + remap_gat_vars_and_recurse_into_nested_projections( + tcx, + filter, + item_trait_ref, + assoc_item_def_id, + span, + clause, + ) + }, + )); } // `ConstIfConst` is only interested in `[const]` bounds. - PredicateFilter::ConstIfConst | PredicateFilter::SelfConstIfConst => {} + PredicateFilter::ConstIfConst | PredicateFilter::SelfConstIfConst => { + // FIXME(const_trait_impl): We *could* uplift the + // `where Self::Assoc: [const] Trait` bounds from the parent trait + // here too, but we'd need to split `const_conditions` into two + // queries (like we do for `trait_explicit_predicates_and_bounds`) + // since we need to also filter the predicates *out* of the const + // conditions or they lead to cycles in the trait solver when + // utilizing these bounds. For now, let's do nothing. + } } - let trait_def_id = tcx.local_parent(assoc_item_def_id); - let trait_predicates = tcx.trait_explicit_predicates_and_bounds(trait_def_id); - - let item_trait_ref = ty::TraitRef::identity(tcx, tcx.parent(assoc_item_def_id.to_def_id())); - let bounds_from_parent = - trait_predicates.predicates.iter().copied().filter_map(|(clause, span)| { - remap_gat_vars_and_recurse_into_nested_projections( - tcx, - filter, - item_trait_ref, - assoc_item_def_id, - span, - clause, - ) - }); - - let all_bounds = tcx.arena.alloc_from_iter(bounds.into_iter().chain(bounds_from_parent)); + let bounds = tcx.arena.alloc_from_iter(bounds); debug!( "associated_type_bounds({}) = {:?}", tcx.def_path_str(assoc_item_def_id.to_def_id()), - all_bounds + bounds ); - assert_only_contains_predicates_from(filter, all_bounds, item_ty); + assert_only_contains_predicates_from(filter, bounds, item_ty); - all_bounds + bounds }) } @@ -112,6 +124,7 @@ fn remap_gat_vars_and_recurse_into_nested_projections<'tcx>( ty::ClauseKind::Trait(tr) => tr.self_ty(), ty::ClauseKind::Projection(proj) => proj.projection_term.self_ty(), ty::ClauseKind::TypeOutlives(outlives) => outlives.0, + ty::ClauseKind::HostEffect(host) => host.self_ty(), _ => return None, }; diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index a93e58b101f..f2f1560d8b2 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -1,6 +1,7 @@ use std::assert_matches::assert_matches; use hir::Node; +use rustc_attr_data_structures::{AttributeKind, find_attr}; use rustc_data_structures::fx::FxIndexSet; use rustc_hir as hir; use rustc_hir::def::DefKind; @@ -162,7 +163,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen .map(|t| ty::Binder::dummy(t.instantiate_identity())); } } - ItemKind::Trait(_, _, _, _, self_bounds, ..) + ItemKind::Trait(_, _, _, _, _, self_bounds, ..) | ItemKind::TraitAlias(_, _, self_bounds) => { is_trait = Some((self_bounds, item.span)); } @@ -333,6 +334,19 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen predicates.extend(const_evaluatable_predicates_of(tcx, def_id, &predicates)); } + let attrs = tcx.hir_attrs(tcx.local_def_id_to_hir_id(def_id)); + // FIXME(staged_api): We might want to look at the normal stability attributes too but + // first we would need a way to let std/core use APIs with unstable feature bounds from + // within stable APIs. + let allow_unstable_feature_attr = + find_attr!(attrs, AttributeKind::UnstableFeatureBound(i) => i) + .map(|i| i.as_slice()) + .unwrap_or_default(); + + for (feat_name, span) in allow_unstable_feature_attr { + predicates.insert((ty::ClauseKind::UnstableFeature(*feat_name).upcast(tcx), *span)); + } + let mut predicates: Vec<_> = predicates.into_iter().collect(); // Subtle: before we store the predicates into the tcx, we @@ -764,6 +778,7 @@ pub(super) fn assert_only_contains_predicates_from<'tcx>( ty::ClauseKind::RegionOutlives(_) | ty::ClauseKind::ConstArgHasType(_, _) | ty::ClauseKind::WellFormed(_) + | ty::ClauseKind::UnstableFeature(_) | ty::ClauseKind::ConstEvaluatable(_) => { bug!( "unexpected non-`Self` predicate when computing \ @@ -791,6 +806,7 @@ pub(super) fn assert_only_contains_predicates_from<'tcx>( | ty::ClauseKind::ConstArgHasType(_, _) | ty::ClauseKind::WellFormed(_) | ty::ClauseKind::ConstEvaluatable(_) + | ty::ClauseKind::UnstableFeature(_) | ty::ClauseKind::HostEffect(..) => { bug!( "unexpected non-`Self` predicate when computing \ @@ -1006,7 +1022,7 @@ pub(super) fn const_conditions<'tcx>( Node::Item(item) => match item.kind { hir::ItemKind::Impl(impl_) => (impl_.generics, None, false), hir::ItemKind::Fn { generics, .. } => (generics, None, false), - hir::ItemKind::Trait(_, _, _, generics, supertraits, _) => { + hir::ItemKind::Trait(_, _, _, _, generics, supertraits, _) => { (generics, Some((item.owner_id.def_id, supertraits)), false) } _ => bug!("const_conditions called on wrong item: {def_id:?}"), diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index 8d7ac7db67b..77e63e38c8c 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -634,7 +634,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { | hir::ItemKind::Enum(_, generics, _) | hir::ItemKind::Struct(_, generics, _) | hir::ItemKind::Union(_, generics, _) - | hir::ItemKind::Trait(_, _, _, generics, ..) + | hir::ItemKind::Trait(_, _, _, _, generics, ..) | hir::ItemKind::TraitAlias(_, generics, ..) | hir::ItemKind::Impl(&hir::Impl { generics, .. }) => { // These kinds of items have only early-bound lifetime parameters. diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index c1c82839212..eb65050c17c 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -525,6 +525,7 @@ pub(crate) struct ConstImplForNonConstTrait { pub trait_name: String, #[suggestion( applicability = "machine-applicable", + // FIXME(const_trait_impl) fix this suggestion code = "#[const_trait] ", style = "verbose" )] @@ -548,6 +549,7 @@ pub(crate) struct ConstBoundForNonConstTrait { pub suggestion_pre: &'static str, #[suggestion( applicability = "machine-applicable", + // FIXME(const_trait_impl) fix this suggestion code = "#[const_trait] ", style = "verbose" )] diff --git a/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs b/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs index 3f928fd056e..2d60c9561a9 100644 --- a/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs +++ b/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs @@ -635,7 +635,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { self.suggest_adding_type_and_const_args(err); } ExcessTypesOrConsts { .. } => { - // this can happen with `[const] T` where T isn't a const_trait. + // this can happen with `[const] T` where T isn't a `const trait`. } _ => unreachable!(), } diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs index 4784cfb5235..9a752aeccdd 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -334,7 +334,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { }; let (trait_generics, trait_bounds) = match parent_trait.kind { - hir::ItemKind::Trait(_, _, _, generics, supertraits, _) => (generics, supertraits), + hir::ItemKind::Trait(_, _, _, _, generics, supertraits, _) => (generics, supertraits), hir::ItemKind::TraitAlias(_, generics, supertraits) => (generics, supertraits), _ => unreachable!(), }; diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs index 574d19a5aa5..0043f0c7117 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs @@ -499,6 +499,7 @@ fn trait_specialization_kind<'tcx>( | ty::ClauseKind::ConstArgHasType(..) | ty::ClauseKind::WellFormed(_) | ty::ClauseKind::ConstEvaluatable(..) + | ty::ClauseKind::UnstableFeature(_) | ty::ClauseKind::HostEffect(..) => None, } } diff --git a/compiler/rustc_hir_analysis/src/outlives/explicit.rs b/compiler/rustc_hir_analysis/src/outlives/explicit.rs index 2c1d443f951..d3a57a4d8e5 100644 --- a/compiler/rustc_hir_analysis/src/outlives/explicit.rs +++ b/compiler/rustc_hir_analysis/src/outlives/explicit.rs @@ -54,6 +54,7 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> { | ty::ClauseKind::ConstArgHasType(_, _) | ty::ClauseKind::WellFormed(_) | ty::ClauseKind::ConstEvaluatable(_) + | ty::ClauseKind::UnstableFeature(_) | ty::ClauseKind::HostEffect(..) => {} } } diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 2c13c9ef438..bda02042aa6 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -735,8 +735,17 @@ impl<'a> State<'a> { } self.bclose(item.span, cb); } - hir::ItemKind::Trait(is_auto, safety, ident, generics, bounds, trait_items) => { + hir::ItemKind::Trait( + constness, + is_auto, + safety, + ident, + generics, + bounds, + trait_items, + ) => { let (cb, ib) = self.head(""); + self.print_constness(constness); self.print_is_auto(is_auto); self.print_safety(safety); self.word_nbsp("trait"); diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs index e4c62bf027b..367e2b6b372 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs @@ -54,6 +54,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) | ty::PredicateKind::ConstEquate(..) | ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(_)) | ty::PredicateKind::Ambiguous => false, } } diff --git a/compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs b/compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs index 0037d5ac042..38413cca633 100644 --- a/compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs +++ b/compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs @@ -2,6 +2,7 @@ use std::fmt::Write; use hir::def_id::DefId; use hir::{HirId, ItemKind}; +use rustc_ast::join_path_idents; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::{ARRAY_INTO_ITER, BOXED_SLICE_INTO_ITER}; @@ -383,13 +384,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // All that is left is `_`! We need to use the full path. It doesn't matter which one we // pick, so just take the first one. match import_items[0].kind { - ItemKind::Use(path, _) => Some( - path.segments - .iter() - .map(|segment| segment.ident.to_string()) - .collect::<Vec<_>>() - .join("::"), - ), + ItemKind::Use(path, _) => { + Some(join_path_idents(path.segments.iter().map(|seg| seg.ident))) + } _ => { span_bug!(span, "unexpected item kind, expected a use: {:?}", import_items[0].kind); } diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 94c93e73627..3261327a9fd 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -921,6 +921,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { | ty::ClauseKind::ConstArgHasType(_, _) | ty::ClauseKind::WellFormed(_) | ty::ClauseKind::ConstEvaluatable(_) + | ty::ClauseKind::UnstableFeature(_) | ty::ClauseKind::HostEffect(..) => None, } }); diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 2815621ffde..dbfa7e6273c 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -1189,7 +1189,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { entry.1.insert((self_ty.span, "")); } Some(Node::Item(hir::Item { - kind: hir::ItemKind::Trait(rustc_ast::ast::IsAuto::Yes, ..), + kind: hir::ItemKind::Trait(_, rustc_ast::ast::IsAuto::Yes, ..), span: item_span, .. })) => { @@ -1201,7 +1201,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Some( Node::Item(hir::Item { kind: - hir::ItemKind::Trait(_, _, ident, ..) + hir::ItemKind::Trait(_, _, _, ident, ..) | hir::ItemKind::TraitAlias(ident, ..), .. }) @@ -4084,7 +4084,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return; } Node::Item(hir::Item { - kind: hir::ItemKind::Trait(_, _, ident, _, bounds, _), + kind: hir::ItemKind::Trait(_, _, _, ident, _, bounds, _), .. }) => { let (sp, sep, article) = if bounds.is_empty() { diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 8d9f2385b71..1a1cfc9fa6f 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -440,6 +440,7 @@ lint_invalid_asm_label_named = avoid using named labels in inline assembly .help = only local labels of the form `<number>:` should be used in inline asm .note = see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information lint_invalid_asm_label_no_span = the label may be declared in the expansion of a macro + lint_invalid_crate_type_value = invalid `crate_type` value .suggestion = did you mean @@ -508,27 +509,50 @@ lint_metavariable_still_repeating = variable `{$name}` is still repeating at thi lint_metavariable_wrong_operator = meta-variable repeats with different Kleene operator -lint_mismatched_lifetime_syntaxes = - lifetime flowing from input to output with different syntax can be confusing - .label_mismatched_lifetime_syntaxes_inputs = - {$n_inputs -> - [one] this lifetime flows - *[other] these lifetimes flow - } to the output - .label_mismatched_lifetime_syntaxes_outputs = - the {$n_outputs -> - [one] lifetime gets - *[other] lifetimes get - } resolved as `{$lifetime_name}` +lint_mismatched_lifetime_syntaxes_eliding_while_named = + eliding a lifetime that's named elsewhere is confusing + +lint_mismatched_lifetime_syntaxes_help = + the same lifetime is referred to in inconsistent ways, making the signature confusing + +lint_mismatched_lifetime_syntaxes_hiding_and_eliding_while_named = + hiding or eliding a lifetime that's named elsewhere is confusing + +lint_mismatched_lifetime_syntaxes_hiding_while_elided = + hiding a lifetime that's elided elsewhere is confusing + +lint_mismatched_lifetime_syntaxes_hiding_while_named = + hiding a lifetime that's named elsewhere is confusing + +lint_mismatched_lifetime_syntaxes_input_elided = + the lifetime is elided here + +lint_mismatched_lifetime_syntaxes_input_hidden = + the lifetime is hidden here + +lint_mismatched_lifetime_syntaxes_input_named = + the lifetime is named here + +lint_mismatched_lifetime_syntaxes_output_elided = + the same lifetime is elided here + +lint_mismatched_lifetime_syntaxes_output_hidden = + the same lifetime is hidden here + +lint_mismatched_lifetime_syntaxes_output_named = + the same lifetime is named here lint_mismatched_lifetime_syntaxes_suggestion_explicit = - one option is to consistently use `{$lifetime_name}` + consistently use `{$lifetime_name}` lint_mismatched_lifetime_syntaxes_suggestion_implicit = - one option is to consistently remove the lifetime + remove the lifetime name from references lint_mismatched_lifetime_syntaxes_suggestion_mixed = - one option is to remove the lifetime for references and use the anonymous lifetime for paths + remove the lifetime name from references and use `'_` for type paths + +lint_mismatched_lifetime_syntaxes_suggestion_mixed_only_paths = + use `'_` for type paths lint_missing_unsafe_on_extern = extern blocks should be unsafe .suggestion = needs `unsafe` before the extern keyword @@ -744,6 +768,9 @@ lint_redundant_semicolons_suggestion = remove {$multiple_semicolons -> *[false] this semicolon } +lint_reexport_private_dependency = + {$kind} `{$name}` from private dependency '{$krate}' is re-exported + lint_remove_mut_from_pattern = remove `mut` from the parameter lint_removed_lint = lint `{$name}` has been removed: {$reason} @@ -790,6 +817,9 @@ lint_supertrait_as_deref_target = this `Deref` implementation is covered by an i .label2 = target type is a supertrait of `{$self_ty}` .help = consider removing this implementation or replacing it with a method instead +lint_surrogate_char_cast = surrogate values are not valid for `char` + .note = `0xD800..=0xDFFF` are reserved for Unicode surrogates and are not valid `char` values + lint_suspicious_double_ref_clone = using `.clone()` on a double reference, which returns `{$ty}` instead of cloning the inner type @@ -799,6 +829,9 @@ lint_suspicious_double_ref_deref = lint_symbol_intern_string_literal = using `Symbol::intern` on a string literal .help = consider adding the symbol to `compiler/rustc_span/src/symbol.rs` +lint_too_large_char_cast = value exceeds maximum `char` value + .note = maximum valid `char` value is `0x10FFFF` + lint_trailing_semi_macro = trailing semicolon in macro used in expression position .note1 = macro invocations at the end of a block are treated as expressions .note2 = to ignore the value produced by the macro, add a semicolon after the invocation of `{$name}` diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 255ff56f62b..8244f0bed4c 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -1519,8 +1519,9 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints { ClauseKind::TypeOutlives(..) | ClauseKind::RegionOutlives(..) => "lifetime", + ClauseKind::UnstableFeature(_) // `ConstArgHasType` is never global as `ct` is always a param - ClauseKind::ConstArgHasType(..) + | ClauseKind::ConstArgHasType(..) // Ignore projections, as they can only be global // if the trait bound is global | ClauseKind::Projection(..) diff --git a/compiler/rustc_lint/src/early/diagnostics.rs b/compiler/rustc_lint/src/early/diagnostics.rs index 653559009cc..f0fbf5bc81e 100644 --- a/compiler/rustc_lint/src/early/diagnostics.rs +++ b/compiler/rustc_lint/src/early/diagnostics.rs @@ -351,6 +351,9 @@ pub fn decorate_builtin_lint( } .decorate_lint(diag); } + BuiltinLintDiag::ReexportPrivateDependency { name, kind, krate } => { + lints::ReexportPrivateDependency { name, kind, krate }.decorate_lint(diag); + } BuiltinLintDiag::UnusedQualifications { removal_span } => { lints::UnusedQualifications { removal_span }.decorate_lint(diag); } diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 419124d5144..f06757b3c23 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -55,7 +55,7 @@ mod invalid_from_utf8; mod late; mod let_underscore; mod levels; -mod lifetime_syntax; +pub mod lifetime_syntax; mod lints; mod macro_expr_fragment_specifier_2024_migration; mod map_unit_fn; diff --git a/compiler/rustc_lint/src/lifetime_syntax.rs b/compiler/rustc_lint/src/lifetime_syntax.rs index 5465968e984..2a5a34cdc6e 100644 --- a/compiler/rustc_lint/src/lifetime_syntax.rs +++ b/compiler/rustc_lint/src/lifetime_syntax.rs @@ -140,43 +140,115 @@ fn report_mismatches<'tcx>( } } -fn lifetimes_use_matched_syntax(input_info: &[Info<'_>], output_info: &[Info<'_>]) -> bool { - // Categorize lifetimes into source/syntax buckets. - let mut n_hidden = 0; - let mut n_elided = 0; - let mut n_named = 0; +#[derive(Debug, Copy, Clone, PartialEq)] +enum LifetimeSyntaxCategory { + Hidden, + Elided, + Named, +} - for info in input_info.iter().chain(output_info) { +impl LifetimeSyntaxCategory { + fn new(syntax_source: (hir::LifetimeSyntax, LifetimeSource)) -> Option<Self> { use LifetimeSource::*; use hir::LifetimeSyntax::*; - let syntax_source = (info.lifetime.syntax, info.lifetime.source); - match syntax_source { - // Ignore any other kind of lifetime. - (_, Other) => continue, - // E.g. `&T`. - (Implicit, Reference | OutlivesBound | PreciseCapturing) | + (Implicit, Reference) | // E.g. `&'_ T`. - (ExplicitAnonymous, Reference | OutlivesBound | PreciseCapturing) | + (ExplicitAnonymous, Reference) | // E.g. `ContainsLifetime<'_>`. - (ExplicitAnonymous, Path { .. }) => n_elided += 1, + (ExplicitAnonymous, Path { .. }) | + // E.g. `+ '_`, `+ use<'_>`. + (ExplicitAnonymous, OutlivesBound | PreciseCapturing) => { + Some(Self::Elided) + } // E.g. `ContainsLifetime`. - (Implicit, Path { .. }) => n_hidden += 1, + (Implicit, Path { .. }) => { + Some(Self::Hidden) + } // E.g. `&'a T`. - (ExplicitBound, Reference | OutlivesBound | PreciseCapturing) | + (ExplicitBound, Reference) | // E.g. `ContainsLifetime<'a>`. - (ExplicitBound, Path { .. }) => n_named += 1, - }; + (ExplicitBound, Path { .. }) | + // E.g. `+ 'a`, `+ use<'a>`. + (ExplicitBound, OutlivesBound | PreciseCapturing) => { + Some(Self::Named) + } + + (Implicit, OutlivesBound | PreciseCapturing) | + (_, Other) => { + None + } + } + } +} + +#[derive(Debug, Default)] +pub struct LifetimeSyntaxCategories<T> { + pub hidden: T, + pub elided: T, + pub named: T, +} + +impl<T> LifetimeSyntaxCategories<T> { + fn select(&mut self, category: LifetimeSyntaxCategory) -> &mut T { + use LifetimeSyntaxCategory::*; + + match category { + Elided => &mut self.elided, + Hidden => &mut self.hidden, + Named => &mut self.named, + } + } +} + +impl<T> LifetimeSyntaxCategories<Vec<T>> { + pub fn len(&self) -> LifetimeSyntaxCategories<usize> { + LifetimeSyntaxCategories { + hidden: self.hidden.len(), + elided: self.elided.len(), + named: self.named.len(), + } + } + + pub fn flatten(&self) -> impl Iterator<Item = &T> { + let Self { hidden, elided, named } = self; + [hidden.iter(), elided.iter(), named.iter()].into_iter().flatten() + } +} + +impl std::ops::Add for LifetimeSyntaxCategories<usize> { + type Output = Self; + + fn add(self, rhs: Self) -> Self::Output { + Self { + hidden: self.hidden + rhs.hidden, + elided: self.elided + rhs.elided, + named: self.named + rhs.named, + } + } +} + +fn lifetimes_use_matched_syntax(input_info: &[Info<'_>], output_info: &[Info<'_>]) -> bool { + let mut syntax_counts = LifetimeSyntaxCategories::<usize>::default(); + + for info in input_info.iter().chain(output_info) { + if let Some(category) = info.lifetime_syntax_category() { + *syntax_counts.select(category) += 1; + } } - let syntax_counts = (n_hidden, n_elided, n_named); tracing::debug!(?syntax_counts); - matches!(syntax_counts, (_, 0, 0) | (0, _, 0) | (0, 0, _)) + matches!( + syntax_counts, + LifetimeSyntaxCategories { hidden: _, elided: 0, named: 0 } + | LifetimeSyntaxCategories { hidden: 0, elided: _, named: 0 } + | LifetimeSyntaxCategories { hidden: 0, elided: 0, named: _ } + ) } fn emit_mismatch_diagnostic<'tcx>( @@ -238,7 +310,7 @@ fn emit_mismatch_diagnostic<'tcx>( use LifetimeSource::*; use hir::LifetimeSyntax::*; - let syntax_source = (info.lifetime.syntax, info.lifetime.source); + let syntax_source = info.syntax_source(); if let (_, Other) = syntax_source { // Ignore any other kind of lifetime. @@ -259,7 +331,6 @@ fn emit_mismatch_diagnostic<'tcx>( // E.g. `&'_ T`. (ExplicitAnonymous, Reference) => { suggest_change_to_implicit.push(info); - suggest_change_to_mixed_implicit.push(info); suggest_change_to_explicit_bound.push(info); } @@ -319,12 +390,22 @@ fn emit_mismatch_diagnostic<'tcx>( } } + let categorize = |infos: &[Info<'_>]| { + let mut categories = LifetimeSyntaxCategories::<Vec<_>>::default(); + for info in infos { + if let Some(category) = info.lifetime_syntax_category() { + categories.select(category).push(info.reporting_span()); + } + } + categories + }; + + let inputs = categorize(input_info); + let outputs = categorize(output_info); + let make_implicit_suggestions = |infos: &[&Info<'_>]| infos.iter().map(|i| i.removing_span()).collect::<Vec<_>>(); - let inputs = input_info.iter().map(|info| info.reporting_span()).collect(); - let outputs = output_info.iter().map(|info| info.reporting_span()).collect(); - let explicit_bound_suggestion = bound_lifetime.map(|info| { build_mismatch_suggestion(info.lifetime_name(), &suggest_change_to_explicit_bound) }); @@ -399,8 +480,6 @@ fn emit_mismatch_diagnostic<'tcx>( ?explicit_anonymous_suggestion, ); - let lifetime_name = bound_lifetime.map(|info| info.lifetime_name()).unwrap_or("'_").to_owned(); - // We can produce a number of suggestions which may overwhelm // the user. Instead, we order the suggestions based on Rust // idioms. The "best" choice is shown to the user and the @@ -413,8 +492,8 @@ fn emit_mismatch_diagnostic<'tcx>( cx.emit_span_lint( MISMATCHED_LIFETIME_SYNTAXES, - Vec::clone(&inputs), - lints::MismatchedLifetimeSyntaxes { lifetime_name, inputs, outputs, suggestions }, + inputs.flatten().copied().collect::<Vec<_>>(), + lints::MismatchedLifetimeSyntaxes { inputs, outputs, suggestions }, ); } @@ -422,12 +501,12 @@ fn build_mismatch_suggestion( lifetime_name: &str, infos: &[&Info<'_>], ) -> lints::MismatchedLifetimeSyntaxesSuggestion { - let lifetime_name_sugg = lifetime_name.to_owned(); + let lifetime_name = lifetime_name.to_owned(); let suggestions = infos.iter().map(|info| info.suggestion(&lifetime_name)).collect(); lints::MismatchedLifetimeSyntaxesSuggestion::Explicit { - lifetime_name_sugg, + lifetime_name, suggestions, tool_only: false, } @@ -441,6 +520,14 @@ struct Info<'tcx> { } impl<'tcx> Info<'tcx> { + fn syntax_source(&self) -> (hir::LifetimeSyntax, LifetimeSource) { + (self.lifetime.syntax, self.lifetime.source) + } + + fn lifetime_syntax_category(&self) -> Option<LifetimeSyntaxCategory> { + LifetimeSyntaxCategory::new(self.syntax_source()) + } + fn lifetime_name(&self) -> &str { self.lifetime.ident.as_str() } diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 21148833eaf..fd8d0f832aa 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -21,6 +21,7 @@ use rustc_span::{Ident, MacroRulesNormalizedIdent, Span, Symbol, sym}; use crate::builtin::{InitError, ShorthandAssocTyCollector, TypeAliasBounds}; use crate::errors::{OverruledAttributeSub, RequestedLevel}; +use crate::lifetime_syntax::LifetimeSyntaxCategories; use crate::{LateContext, fluent_generated as fluent}; // array_into_iter.rs @@ -1747,6 +1748,20 @@ pub(crate) struct OverflowingLiteral<'a> { } #[derive(LintDiagnostic)] +#[diag(lint_surrogate_char_cast)] +#[note] +pub(crate) struct SurrogateCharCast { + pub literal: u128, +} + +#[derive(LintDiagnostic)] +#[diag(lint_too_large_char_cast)] +#[note] +pub(crate) struct TooLargeCharCast { + pub literal: u128, +} + +#[derive(LintDiagnostic)] #[diag(lint_uses_power_alignment)] pub(crate) struct UsesPowerAlignment; @@ -3081,6 +3096,14 @@ pub(crate) struct HiddenGlobReexports { } #[derive(LintDiagnostic)] +#[diag(lint_reexport_private_dependency)] +pub(crate) struct ReexportPrivateDependency { + pub name: String, + pub kind: String, + pub krate: Symbol, +} + +#[derive(LintDiagnostic)] #[diag(lint_unnecessary_qualification)] pub(crate) struct UnusedQualifications { #[suggestion(style = "verbose", code = "", applicability = "machine-applicable")] @@ -3194,31 +3217,60 @@ pub(crate) struct ReservedMultihash { #[derive(Debug)] pub(crate) struct MismatchedLifetimeSyntaxes { - pub lifetime_name: String, - pub inputs: Vec<Span>, - pub outputs: Vec<Span>, + pub inputs: LifetimeSyntaxCategories<Vec<Span>>, + pub outputs: LifetimeSyntaxCategories<Vec<Span>>, pub suggestions: Vec<MismatchedLifetimeSyntaxesSuggestion>, } impl<'a, G: EmissionGuarantee> LintDiagnostic<'a, G> for MismatchedLifetimeSyntaxes { fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, G>) { - diag.primary_message(fluent::lint_mismatched_lifetime_syntaxes); + let counts = self.inputs.len() + self.outputs.len(); + let message = match counts { + LifetimeSyntaxCategories { hidden: 0, elided: 0, named: 0 } => { + panic!("No lifetime mismatch detected") + } - diag.arg("lifetime_name", self.lifetime_name); + LifetimeSyntaxCategories { hidden: _, elided: _, named: 0 } => { + fluent::lint_mismatched_lifetime_syntaxes_hiding_while_elided + } + + LifetimeSyntaxCategories { hidden: _, elided: 0, named: _ } => { + fluent::lint_mismatched_lifetime_syntaxes_hiding_while_named + } + + LifetimeSyntaxCategories { hidden: 0, elided: _, named: _ } => { + fluent::lint_mismatched_lifetime_syntaxes_eliding_while_named + } + + LifetimeSyntaxCategories { hidden: _, elided: _, named: _ } => { + fluent::lint_mismatched_lifetime_syntaxes_hiding_and_eliding_while_named + } + }; + diag.primary_message(message); - diag.arg("n_inputs", self.inputs.len()); - for input in self.inputs { - let a = diag.eagerly_translate(fluent::lint_label_mismatched_lifetime_syntaxes_inputs); - diag.span_label(input, a); + for s in self.inputs.hidden { + diag.span_label(s, fluent::lint_mismatched_lifetime_syntaxes_input_hidden); + } + for s in self.inputs.elided { + diag.span_label(s, fluent::lint_mismatched_lifetime_syntaxes_input_elided); + } + for s in self.inputs.named { + diag.span_label(s, fluent::lint_mismatched_lifetime_syntaxes_input_named); } - diag.arg("n_outputs", self.outputs.len()); - for output in self.outputs { - let a = diag.eagerly_translate(fluent::lint_label_mismatched_lifetime_syntaxes_outputs); - diag.span_label(output, a); + for s in self.outputs.hidden { + diag.span_label(s, fluent::lint_mismatched_lifetime_syntaxes_output_hidden); + } + for s in self.outputs.elided { + diag.span_label(s, fluent::lint_mismatched_lifetime_syntaxes_output_elided); + } + for s in self.outputs.named { + diag.span_label(s, fluent::lint_mismatched_lifetime_syntaxes_output_named); } + diag.help(fluent::lint_mismatched_lifetime_syntaxes_help); + let mut suggestions = self.suggestions.into_iter(); if let Some(s) = suggestions.next() { diag.subdiagnostic(s); @@ -3245,7 +3297,7 @@ pub(crate) enum MismatchedLifetimeSyntaxesSuggestion { }, Explicit { - lifetime_name_sugg: String, + lifetime_name: String, suggestions: Vec<(Span, String)>, tool_only: bool, }, @@ -3285,6 +3337,12 @@ impl Subdiagnostic for MismatchedLifetimeSyntaxesSuggestion { } Mixed { implicit_suggestions, explicit_anonymous_suggestions, tool_only } => { + let message = if implicit_suggestions.is_empty() { + fluent::lint_mismatched_lifetime_syntaxes_suggestion_mixed_only_paths + } else { + fluent::lint_mismatched_lifetime_syntaxes_suggestion_mixed + }; + let implicit_suggestions = implicit_suggestions.into_iter().map(|s| (s, String::new())); @@ -3292,19 +3350,19 @@ impl Subdiagnostic for MismatchedLifetimeSyntaxesSuggestion { implicit_suggestions.chain(explicit_anonymous_suggestions).collect(); diag.multipart_suggestion_with_style( - fluent::lint_mismatched_lifetime_syntaxes_suggestion_mixed, + message, suggestions, Applicability::MaybeIncorrect, style(tool_only), ); } - Explicit { lifetime_name_sugg, suggestions, tool_only } => { - diag.arg("lifetime_name_sugg", lifetime_name_sugg); + Explicit { lifetime_name, suggestions, tool_only } => { + diag.arg("lifetime_name", lifetime_name); let msg = diag.eagerly_translate( fluent::lint_mismatched_lifetime_syntaxes_suggestion_explicit, ); - diag.remove_arg("lifetime_name_sugg"); + diag.remove_arg("lifetime_name"); diag.multipart_suggestion_with_style( msg, suggestions, diff --git a/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs b/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs index 3cc55eaa0f2..5513c703f1d 100644 --- a/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs +++ b/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs @@ -39,7 +39,7 @@ impl<'tcx> LateLintPass<'tcx> for MultipleSupertraitUpcastable { let def_id = item.owner_id.to_def_id(); // NOTE(nbdd0121): use `dyn_compatibility_violations` instead of `is_dyn_compatible` because // the latter will report `where_clause_object_safety` lint. - if let hir::ItemKind::Trait(_, _, ident, ..) = item.kind + if let hir::ItemKind::Trait(_, _, _, ident, ..) = item.kind && cx.tcx.is_dyn_compatible(def_id) { let direct_super_traits_iter = cx diff --git a/compiler/rustc_lint/src/types/literal.rs b/compiler/rustc_lint/src/types/literal.rs index d44f45177bd..2bac58ba23d 100644 --- a/compiler/rustc_lint/src/types/literal.rs +++ b/compiler/rustc_lint/src/types/literal.rs @@ -12,7 +12,7 @@ use crate::context::LintContext; use crate::lints::{ OnlyCastu8ToChar, OverflowingBinHex, OverflowingBinHexSign, OverflowingBinHexSignBitSub, OverflowingBinHexSub, OverflowingInt, OverflowingIntHelp, OverflowingLiteral, OverflowingUInt, - RangeEndpointOutOfRange, UseInclusiveRange, + RangeEndpointOutOfRange, SurrogateCharCast, TooLargeCharCast, UseInclusiveRange, }; use crate::types::{OVERFLOWING_LITERALS, TypeLimits}; @@ -38,12 +38,18 @@ fn lint_overflowing_range_endpoint<'tcx>( // We only want to handle exclusive (`..`) ranges, // which are represented as `ExprKind::Struct`. - let Node::ExprField(field) = cx.tcx.parent_hir_node(hir_id) else { return false }; - let Node::Expr(struct_expr) = cx.tcx.parent_hir_node(field.hir_id) else { return false }; + let Node::ExprField(field) = cx.tcx.parent_hir_node(hir_id) else { + return false; + }; + let Node::Expr(struct_expr) = cx.tcx.parent_hir_node(field.hir_id) else { + return false; + }; if !is_range_literal(struct_expr) { return false; }; - let ExprKind::Struct(_, [start, end], _) = &struct_expr.kind else { return false }; + let ExprKind::Struct(_, [start, end], _) = &struct_expr.kind else { + return false; + }; // We can suggest using an inclusive range // (`..=`) instead only if it is the `end` that is @@ -61,7 +67,9 @@ fn lint_overflowing_range_endpoint<'tcx>( }; let sub_sugg = if span.lo() == lit_span.lo() { - let Ok(start) = cx.sess().source_map().span_to_snippet(start.span) else { return false }; + let Ok(start) = cx.sess().source_map().span_to_snippet(start.span) else { + return false; + }; UseInclusiveRange::WithoutParen { sugg: struct_expr.span.shrink_to_lo().to(lit_span.shrink_to_hi()), start, @@ -316,11 +324,25 @@ fn lint_uint_literal<'tcx>( match par_e.kind { hir::ExprKind::Cast(..) => { if let ty::Char = cx.typeck_results().expr_ty(par_e).kind() { - cx.emit_span_lint( - OVERFLOWING_LITERALS, - par_e.span, - OnlyCastu8ToChar { span: par_e.span, literal: lit_val }, - ); + if lit_val > 0x10FFFF { + cx.emit_span_lint( + OVERFLOWING_LITERALS, + par_e.span, + TooLargeCharCast { literal: lit_val }, + ); + } else if (0xD800..=0xDFFF).contains(&lit_val) { + cx.emit_span_lint( + OVERFLOWING_LITERALS, + par_e.span, + SurrogateCharCast { literal: lit_val }, + ); + } else { + cx.emit_span_lint( + OVERFLOWING_LITERALS, + par_e.span, + OnlyCastu8ToChar { span: par_e.span, literal: lit_val }, + ); + } return; } } diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index cd402c9234f..fe068d96b74 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -739,6 +739,11 @@ pub enum BuiltinLintDiag { /// The local binding that shadows the glob reexport. private_item_span: Span, }, + ReexportPrivateDependency { + name: String, + kind: String, + krate: Symbol, + }, UnusedQualifications { /// The span of the unnecessarily-qualified path to remove. removal_span: Span, diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index b50453cb0df..5cd98038fc6 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1131,7 +1131,7 @@ fn should_encode_mir( && reachable_set.contains(&def_id) && (generics.requires_monomorphization(tcx) || tcx.cross_crate_inlinable(def_id))); - // The function has a `const` modifier or is in a `#[const_trait]`. + // The function has a `const` modifier or is in a `const trait`. let is_const_fn = tcx.is_const_fn(def_id.to_def_id()) || tcx.is_const_default_method(def_id.to_def_id()); (is_const_fn, opt) diff --git a/compiler/rustc_middle/src/hir/map.rs b/compiler/rustc_middle/src/hir/map.rs index 84710e5e636..42a1e7377f4 100644 --- a/compiler/rustc_middle/src/hir/map.rs +++ b/compiler/rustc_middle/src/hir/map.rs @@ -940,7 +940,7 @@ impl<'tcx> TyCtxt<'tcx> { }) => until_within(*outer_span, ty.span), // With generics and bounds. Node::Item(Item { - kind: ItemKind::Trait(_, _, _, generics, bounds, _), + kind: ItemKind::Trait(_, _, _, _, generics, bounds, _), span: outer_span, .. }) diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index 71e0c943fbb..3e68afbfabd 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -257,7 +257,7 @@ pub enum InvalidProgramInfo<'tcx> { /// Details of why a pointer had to be in-bounds. #[derive(Debug, Copy, Clone)] pub enum CheckInAllocMsg { - /// We are access memory. + /// We are accessing memory. MemoryAccess, /// We are doing pointer arithmetic. InboundsPointerArithmetic, diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 98b2ce01d89..915b062417f 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -137,6 +137,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> { type FnInputTys = &'tcx [Ty<'tcx>]; type ParamTy = ParamTy; type BoundTy = ty::BoundTy; + type Symbol = Symbol; type PlaceholderTy = ty::PlaceholderType; type ErrorGuaranteed = ErrorGuaranteed; @@ -833,6 +834,13 @@ impl<'tcx> rustc_type_ir::inherent::Features<TyCtxt<'tcx>> for &'tcx rustc_featu fn associated_const_equality(self) -> bool { self.associated_const_equality() } + + fn feature_bound_holds_in_crate(self, symbol: Symbol) -> bool { + // We don't consider feature bounds to hold in the crate when `staged_api` feature is + // enabled, even if it is enabled through `#[feature]`. + // This is to prevent accidentally leaking unstable APIs to stable. + !self.staged_api() && self.enabled(symbol) + } } impl<'tcx> rustc_type_ir::inherent::Span<TyCtxt<'tcx>> for Span { diff --git a/compiler/rustc_middle/src/ty/predicate.rs b/compiler/rustc_middle/src/ty/predicate.rs index bc2ac42b6b1..ec2224877a8 100644 --- a/compiler/rustc_middle/src/ty/predicate.rs +++ b/compiler/rustc_middle/src/ty/predicate.rs @@ -131,6 +131,7 @@ impl<'tcx> Predicate<'tcx> { | PredicateKind::Clause(ClauseKind::TypeOutlives(_)) | PredicateKind::Clause(ClauseKind::Projection(_)) | PredicateKind::Clause(ClauseKind::ConstArgHasType(..)) + | PredicateKind::Clause(ClauseKind::UnstableFeature(_)) | PredicateKind::DynCompatible(_) | PredicateKind::Subtype(_) | PredicateKind::Coerce(_) @@ -649,6 +650,7 @@ impl<'tcx> Predicate<'tcx> { PredicateKind::Clause(ClauseKind::Projection(..)) | PredicateKind::Clause(ClauseKind::HostEffect(..)) | PredicateKind::Clause(ClauseKind::ConstArgHasType(..)) + | PredicateKind::Clause(ClauseKind::UnstableFeature(_)) | PredicateKind::NormalizesTo(..) | PredicateKind::AliasRelate(..) | PredicateKind::Subtype(..) @@ -670,6 +672,7 @@ impl<'tcx> Predicate<'tcx> { PredicateKind::Clause(ClauseKind::Trait(..)) | PredicateKind::Clause(ClauseKind::HostEffect(..)) | PredicateKind::Clause(ClauseKind::ConstArgHasType(..)) + | PredicateKind::Clause(ClauseKind::UnstableFeature(_)) | PredicateKind::NormalizesTo(..) | PredicateKind::AliasRelate(..) | PredicateKind::Subtype(..) diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 8f0f9b21dc1..2eb530f328d 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -2430,7 +2430,7 @@ impl<'tcx> Printer<'tcx> for FmtPrinter<'_, 'tcx> { } let verbose = self.should_print_verbose(); - disambiguated_data.fmt_maybe_verbose(self, verbose)?; + write!(self, "{}", disambiguated_data.as_sym(verbose))?; self.empty_path = false; @@ -3237,6 +3237,7 @@ define_print! { ty::ClauseKind::ConstEvaluatable(ct) => { p!("the constant `", print(ct), "` can be evaluated") } + ty::ClauseKind::UnstableFeature(symbol) => p!("unstable feature: ", write("`{}`", symbol)), } } diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs index ea25ce65f77..59e2b2a034d 100644 --- a/compiler/rustc_middle/src/ty/trait_def.rs +++ b/compiler/rustc_middle/src/ty/trait_def.rs @@ -20,7 +20,7 @@ pub struct TraitDef { pub safety: hir::Safety, - /// Whether this trait has been annotated with `#[const_trait]`. + /// Whether this trait is `const`. pub constness: hir::Constness, /// If `true`, then this trait had the `#[rustc_paren_sugar]` diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index b42587618b5..ce9b794d40d 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -22,6 +22,7 @@ use crate::delegate::SolverDelegate; use crate::placeholder::BoundVarReplacer; use crate::solve::inspect::{self, ProofTreeBuilder}; use crate::solve::search_graph::SearchGraph; +use crate::solve::ty::may_use_unstable_feature; use crate::solve::{ CanonicalInput, Certainty, FIXPOINT_STEP_LIMIT, Goal, GoalEvaluation, GoalEvaluationKind, GoalSource, GoalStalledOn, HasChanged, NestedNormalizationGoals, NoSolution, QueryInput, @@ -550,6 +551,9 @@ where ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => { self.compute_const_arg_has_type_goal(Goal { param_env, predicate: (ct, ty) }) } + ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(symbol)) => { + self.compute_unstable_feature_goal(param_env, symbol) + } ty::PredicateKind::Subtype(predicate) => { self.compute_subtype_goal(Goal { param_env, predicate }) } @@ -1177,6 +1181,14 @@ where ) -> T { BoundVarReplacer::replace_bound_vars(&**self.delegate, universes, t).0 } + + pub(super) fn may_use_unstable_feature( + &self, + param_env: I::ParamEnv, + symbol: I::Symbol, + ) -> bool { + may_use_unstable_feature(&**self.delegate, param_env, symbol) + } } /// Eagerly replace aliases with inference variables, emitting `AliasRelate` diff --git a/compiler/rustc_next_trait_solver/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs index e68ea22c7a2..5ea3f0d1061 100644 --- a/compiler/rustc_next_trait_solver/src/solve/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs @@ -148,6 +148,20 @@ where } } + fn compute_unstable_feature_goal( + &mut self, + param_env: <I as Interner>::ParamEnv, + symbol: <I as Interner>::Symbol, + ) -> QueryResult<I> { + if self.may_use_unstable_feature(param_env, symbol) { + self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + } else { + self.evaluate_added_goals_and_make_canonical_response(Certainty::Maybe( + MaybeCause::Ambiguity, + )) + } + } + #[instrument(level = "trace", skip(self))] fn compute_const_evaluatable_goal( &mut self, diff --git a/compiler/rustc_parse/Cargo.toml b/compiler/rustc_parse/Cargo.toml index c4a0ae2ce9d..a92012f8329 100644 --- a/compiler/rustc_parse/Cargo.toml +++ b/compiler/rustc_parse/Cargo.toml @@ -6,7 +6,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start bitflags = "2.4.1" -rustc-literal-escaper = "0.0.4" +rustc-literal-escaper = "0.0.5" rustc_ast = { path = "../rustc_ast" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } rustc_data_structures = { path = "../rustc_data_structures" } diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index af9f8735549..859118a4ade 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -855,6 +855,7 @@ parse_trailing_vert_not_allowed = a trailing `|` is not allowed in an or-pattern .suggestion = remove the `{$token}` parse_trait_alias_cannot_be_auto = trait aliases cannot be `auto` +parse_trait_alias_cannot_be_const = trait aliases cannot be `const` parse_trait_alias_cannot_be_unsafe = trait aliases cannot be `unsafe` parse_transpose_dyn_or_impl = `for<...>` expected after `{$kw}`, not before diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 7f1b0991f0c..4aaaba01fae 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -1962,6 +1962,14 @@ pub(crate) struct TraitAliasCannotBeAuto { } #[derive(Diagnostic)] +#[diag(parse_trait_alias_cannot_be_const)] +pub(crate) struct TraitAliasCannotBeConst { + #[primary_span] + #[label(parse_trait_alias_cannot_be_const)] + pub span: Span, +} + +#[derive(Diagnostic)] #[diag(parse_trait_alias_cannot_be_unsafe)] pub(crate) struct TraitAliasCannotBeUnsafe { #[primary_span] diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index d6cc98d505c..b767b0fcf99 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -244,6 +244,9 @@ impl<'a> Parser<'a> { self.bump(); // `static` let mutability = self.parse_mutability(); self.parse_static_item(safety, mutability)? + } else if self.check_keyword(exp!(Trait)) || self.check_trait_front_matter() { + // TRAIT ITEM + self.parse_item_trait(attrs, lo)? } else if let Const::Yes(const_span) = self.parse_constness(Case::Sensitive) { // CONST ITEM if self.token.is_keyword(kw::Impl) { @@ -262,9 +265,6 @@ impl<'a> Parser<'a> { define_opaque: None, })) } - } else if self.check_keyword(exp!(Trait)) || self.check_auto_or_unsafe_trait_item() { - // TRAIT ITEM - self.parse_item_trait(attrs, lo)? } else if self.check_keyword(exp!(Impl)) || self.check_keyword(exp!(Unsafe)) && self.is_keyword_ahead(1, &[kw::Impl]) { @@ -373,7 +373,7 @@ impl<'a> Parser<'a> { pub(super) fn is_path_start_item(&mut self) -> bool { self.is_kw_followed_by_ident(kw::Union) // no: `union::b`, yes: `union U { .. }` || self.is_reuse_path_item() - || self.check_auto_or_unsafe_trait_item() // no: `auto::b`, yes: `auto trait X { .. }` + || self.check_trait_front_matter() // no: `auto::b`, yes: `auto trait X { .. }` || self.is_async_fn() // no(2015): `async::b`, yes: `async fn` || matches!(self.is_macro_rules_item(), IsMacroRulesItem::Yes{..}) // no: `macro_rules::b`, yes: `macro_rules! mac` } @@ -872,16 +872,19 @@ impl<'a> Parser<'a> { } } - /// Is this an `(unsafe auto? | auto) trait` item? - fn check_auto_or_unsafe_trait_item(&mut self) -> bool { + /// Is this an `(const unsafe? auto?| unsafe auto? | auto) trait` item? + fn check_trait_front_matter(&mut self) -> bool { // auto trait self.check_keyword(exp!(Auto)) && self.is_keyword_ahead(1, &[kw::Trait]) // unsafe auto trait || self.check_keyword(exp!(Unsafe)) && self.is_keyword_ahead(1, &[kw::Trait, kw::Auto]) + || self.check_keyword(exp!(Const)) && ((self.is_keyword_ahead(1, &[kw::Trait]) || self.is_keyword_ahead(1, &[kw::Auto]) && self.is_keyword_ahead(2, &[kw::Trait])) + || self.is_keyword_ahead(1, &[kw::Unsafe]) && self.is_keyword_ahead(2, &[kw::Trait, kw::Auto])) } /// Parses `unsafe? auto? trait Foo { ... }` or `trait Foo = Bar;`. fn parse_item_trait(&mut self, attrs: &mut AttrVec, lo: Span) -> PResult<'a, ItemKind> { + let constness = self.parse_constness(Case::Sensitive); let safety = self.parse_safety(Case::Sensitive); // Parse optional `auto` prefix. let is_auto = if self.eat_keyword(exp!(Auto)) { @@ -913,6 +916,9 @@ impl<'a> Parser<'a> { self.expect_semi()?; let whole_span = lo.to(self.prev_token.span); + if let Const::Yes(_) = constness { + self.dcx().emit_err(errors::TraitAliasCannotBeConst { span: whole_span }); + } if is_auto == IsAuto::Yes { self.dcx().emit_err(errors::TraitAliasCannotBeAuto { span: whole_span }); } @@ -927,7 +933,15 @@ impl<'a> Parser<'a> { // It's a normal trait. generics.where_clause = self.parse_where_clause()?; let items = self.parse_item_list(attrs, |p| p.parse_trait_item(ForceCollect::No))?; - Ok(ItemKind::Trait(Box::new(Trait { is_auto, safety, ident, generics, bounds, items }))) + Ok(ItemKind::Trait(Box::new(Trait { + constness, + is_auto, + safety, + ident, + generics, + bounds, + items, + }))) } } diff --git a/compiler/rustc_parse_format/Cargo.toml b/compiler/rustc_parse_format/Cargo.toml index 0666ae29409..d178fcda1fb 100644 --- a/compiler/rustc_parse_format/Cargo.toml +++ b/compiler/rustc_parse_format/Cargo.toml @@ -5,7 +5,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -rustc-literal-escaper = "0.0.4" +rustc-literal-escaper = "0.0.5" rustc_lexer = { path = "../rustc_lexer" } # tidy-alphabetical-end diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 3418d997b83..d1b856ca415 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -667,6 +667,10 @@ passes_rustc_std_internal_symbol = attribute should be applied to functions or statics .label = not a function or static +passes_rustc_unstable_feature_bound = + attribute should be applied to `impl` or free function outside of any `impl` or trait + .label = not an `impl` or free function + passes_should_be_applied_to_fn = attribute should be applied to a function definition .label = {$on_crate -> @@ -780,7 +784,7 @@ passes_unused_capture_maybe_capture_ref = value captured by `{$name}` is never r .help = did you mean to capture by reference instead? passes_unused_default_method_body_const_note = - `default_method_body_is_const` has been replaced with `#[const_trait]` on traits + `default_method_body_is_const` has been replaced with `const` on traits passes_unused_duplicate = unused attribute diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 2009ddc1e2d..d8ffcedeb88 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -10,7 +10,7 @@ use std::collections::hash_map::Entry; use std::slice; use rustc_abi::{Align, ExternAbi, Size}; -use rustc_ast::{AttrStyle, LitKind, MetaItemInner, MetaItemKind, ast}; +use rustc_ast::{AttrStyle, LitKind, MetaItemInner, MetaItemKind, ast, join_path_syms}; use rustc_attr_data_structures::{AttributeKind, InlineAttr, ReprAttr, find_attr}; use rustc_attr_parsing::{AttributeParser, Late}; use rustc_data_structures::fx::FxHashMap; @@ -247,6 +247,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> { &Attribute::Parsed(AttributeKind::FfiPure(attr_span)) => { self.check_ffi_pure(attr_span, attrs, target) } + Attribute::Parsed(AttributeKind::UnstableFeatureBound(syms)) => { + self.check_unstable_feature_bound(syms.first().unwrap().1, span, target) + } Attribute::Parsed( AttributeKind::BodyStability { .. } | AttributeKind::ConstStabilityIndirect @@ -678,9 +681,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { allowed_target: Target, ) { if target != allowed_target { - let path = attr.path(); - let path: Vec<_> = path.iter().map(|s| s.as_str()).collect(); - let attr_name = path.join("::"); + let attr_name = join_path_syms(attr.path()); self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, @@ -1159,7 +1160,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { match item.kind { ItemKind::Enum(_, generics, _) | ItemKind::Struct(_, generics, _) if generics.params.len() != 0 => {} - ItemKind::Trait(_, _, _, generics, _, items) + ItemKind::Trait(_, _, _, _, generics, _, items) if generics.params.len() != 0 || items.iter().any(|item| { matches!(self.tcx.def_kind(item.owner_id), DefKind::AssocTy) @@ -2267,6 +2268,47 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } + fn check_unstable_feature_bound(&self, attr_span: Span, span: Span, target: Target) { + match target { + // FIXME(staged_api): There's no reason we can't support more targets here. We're just + // being conservative to begin with. + Target::Fn | Target::Impl => {} + Target::ExternCrate + | Target::Use + | Target::Static + | Target::Const + | Target::Closure + | Target::Mod + | Target::ForeignMod + | Target::GlobalAsm + | Target::TyAlias + | Target::Enum + | Target::Variant + | Target::Struct + | Target::Field + | Target::Union + | Target::Trait + | Target::TraitAlias + | Target::Expression + | Target::Statement + | Target::Arm + | Target::AssocConst + | Target::Method(_) + | Target::AssocTy + | Target::ForeignFn + | Target::ForeignStatic + | Target::ForeignTy + | Target::GenericParam(_) + | Target::MacroDef + | Target::Param + | Target::PatField + | Target::ExprField + | Target::WherePredicate => { + self.tcx.dcx().emit_err(errors::RustcUnstableFeatureBound { attr_span, span }); + } + } + } + fn check_rustc_std_internal_symbol(&self, attr_span: Span, span: Span, target: Target) { match target { Target::Fn | Target::Static | Target::ForeignFn | Target::ForeignStatic => {} diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 093a2b38804..37330c0ed6e 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -687,6 +687,15 @@ pub(crate) struct RustcAllowConstFnUnstable { } #[derive(Diagnostic)] +#[diag(passes_rustc_unstable_feature_bound)] +pub(crate) struct RustcUnstableFeatureBound { + #[primary_span] + pub attr_span: Span, + #[label] + pub span: Span, +} + +#[derive(Diagnostic)] #[diag(passes_rustc_std_internal_symbol)] pub(crate) struct RustcStdInternalSymbol { #[primary_span] diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index adda94fda8f..e5530d52686 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -802,12 +802,28 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> { // FIXME(jdonszelmann): make it impossible to miss the or_else in the typesystem let const_stab = attrs::find_attr!(attrs, AttributeKind::ConstStability{stability, ..} => *stability); + let unstable_feature_stab = + find_attr!(attrs, AttributeKind::UnstableFeatureBound(i) => i) + .map(|i| i.as_slice()) + .unwrap_or_default(); + // If this impl block has an #[unstable] attribute, give an // error if all involved types and traits are stable, because // it will have no effect. // See: https://github.com/rust-lang/rust/issues/55436 + // + // The exception is when there are both #[unstable_feature_bound(..)] and + // #![unstable(feature = "..", issue = "..")] that have the same symbol because + // that can effectively mark an impl as unstable. + // + // For example: + // ``` + // #[unstable_feature_bound(feat_foo)] + // #[unstable(feature = "feat_foo", issue = "none")] + // impl Foo for Bar {} + // ``` if let Some(( - Stability { level: attrs::StabilityLevel::Unstable { .. }, .. }, + Stability { level: attrs::StabilityLevel::Unstable { .. }, feature }, span, )) = stab { @@ -815,9 +831,21 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> { c.visit_ty_unambig(self_ty); c.visit_trait_ref(t); + // Skip the lint if the impl is marked as unstable using + // #[unstable_feature_bound(..)] + let mut unstable_feature_bound_in_effect = false; + for (unstable_bound_feat_name, _) in unstable_feature_stab { + if *unstable_bound_feat_name == feature { + unstable_feature_bound_in_effect = true; + } + } + // do not lint when the trait isn't resolved, since resolution error should // be fixed first - if t.path.res != Res::Err && c.fully_stable { + if t.path.res != Res::Err + && c.fully_stable + && !unstable_feature_bound_in_effect + { self.tcx.emit_node_span_lint( INEFFECTIVE_UNSTABLE_TRAIT_IMPL, item.hir_id(), diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index ab2433234aa..9dd80bc9964 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -156,6 +156,7 @@ where } ty::ClauseKind::ConstEvaluatable(ct) => ct.visit_with(self), ty::ClauseKind::WellFormed(term) => term.visit_with(self), + ty::ClauseKind::UnstableFeature(_) => V::Result::output(), } } @@ -1623,6 +1624,10 @@ impl<'tcx> PrivateItemsInPublicInterfacesChecker<'_, 'tcx> { self.check(def_id, item_visibility, effective_vis).generics().predicates(); for assoc_item in tcx.associated_items(id.owner_id).in_definition_order() { + if assoc_item.is_impl_trait_in_trait() { + continue; + } + self.check_assoc_item(assoc_item, item_visibility, effective_vis); if assoc_item.is_type() { @@ -1735,6 +1740,10 @@ impl<'tcx> PrivateItemsInPublicInterfacesChecker<'_, 'tcx> { check.ty().trait_ref(); for assoc_item in tcx.associated_items(id.owner_id).in_definition_order() { + if assoc_item.is_impl_trait_in_trait() { + continue; + } + let impl_item_vis = if !of_trait { min(tcx.local_visibility(assoc_item.def_id.expect_local()), impl_vis, tcx) } else { diff --git a/compiler/rustc_proc_macro/Cargo.toml b/compiler/rustc_proc_macro/Cargo.toml index 748fa944e28..762acf9a1eb 100644 --- a/compiler/rustc_proc_macro/Cargo.toml +++ b/compiler/rustc_proc_macro/Cargo.toml @@ -15,7 +15,7 @@ test = false doctest = false [dependencies] -rustc-literal-escaper = "0.0.4" +rustc-literal-escaper = "0.0.5" [features] rustc-dep-of-std = [] diff --git a/compiler/rustc_public/src/unstable/convert/stable/ty.rs b/compiler/rustc_public/src/unstable/convert/stable/ty.rs index 75c29788787..6b226b8a24d 100644 --- a/compiler/rustc_public/src/unstable/convert/stable/ty.rs +++ b/compiler/rustc_public/src/unstable/convert/stable/ty.rs @@ -764,6 +764,9 @@ impl<'tcx> Stable<'tcx> for ty::ClauseKind<'tcx> { ClauseKind::HostEffect(..) => { todo!() } + ClauseKind::UnstableFeature(_) => { + todo!() + } } } } diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 5a1be618cee..e56aabfd414 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -85,7 +85,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// Reachable macros with block module parents exist due to `#[macro_export] macro_rules!`, /// but they cannot use def-site hygiene, so the assumption holds /// (<https://github.com/rust-lang/rust/pull/77984#issuecomment-712445508>). - pub(crate) fn get_nearest_non_block_module(&mut self, mut def_id: DefId) -> Module<'ra> { + pub(crate) fn get_nearest_non_block_module(&self, mut def_id: DefId) -> Module<'ra> { loop { match self.get_module(def_id) { Some(module) => return module, @@ -94,44 +94,47 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } - pub(crate) fn expect_module(&mut self, def_id: DefId) -> Module<'ra> { + pub(crate) fn expect_module(&self, def_id: DefId) -> Module<'ra> { self.get_module(def_id).expect("argument `DefId` is not a module") } /// If `def_id` refers to a module (in resolver's sense, i.e. a module item, crate root, enum, /// or trait), then this function returns that module's resolver representation, otherwise it /// returns `None`. - pub(crate) fn get_module(&mut self, def_id: DefId) -> Option<Module<'ra>> { - if let module @ Some(..) = self.module_map.get(&def_id) { - return module.copied(); - } + pub(crate) fn get_module(&self, def_id: DefId) -> Option<Module<'ra>> { + match def_id.as_local() { + Some(local_def_id) => self.local_module_map.get(&local_def_id).copied(), + None => { + if let module @ Some(..) = self.extern_module_map.borrow().get(&def_id) { + return module.copied(); + } - if !def_id.is_local() { - // Query `def_kind` is not used because query system overhead is too expensive here. - let def_kind = self.cstore().def_kind_untracked(def_id); - if def_kind.is_module_like() { - let parent = self - .tcx - .opt_parent(def_id) - .map(|parent_id| self.get_nearest_non_block_module(parent_id)); - // Query `expn_that_defined` is not used because - // hashing spans in its result is expensive. - let expn_id = self.cstore().expn_that_defined_untracked(def_id, self.tcx.sess); - return Some(self.new_module( - parent, - ModuleKind::Def(def_kind, def_id, Some(self.tcx.item_name(def_id))), - expn_id, - self.def_span(def_id), - // FIXME: Account for `#[no_implicit_prelude]` attributes. - parent.is_some_and(|module| module.no_implicit_prelude), - )); + // Query `def_kind` is not used because query system overhead is too expensive here. + let def_kind = self.cstore().def_kind_untracked(def_id); + if def_kind.is_module_like() { + let parent = self + .tcx + .opt_parent(def_id) + .map(|parent_id| self.get_nearest_non_block_module(parent_id)); + // Query `expn_that_defined` is not used because + // hashing spans in its result is expensive. + let expn_id = self.cstore().expn_that_defined_untracked(def_id, self.tcx.sess); + return Some(self.new_extern_module( + parent, + ModuleKind::Def(def_kind, def_id, Some(self.tcx.item_name(def_id))), + expn_id, + self.def_span(def_id), + // FIXME: Account for `#[no_implicit_prelude]` attributes. + parent.is_some_and(|module| module.no_implicit_prelude), + )); + } + + None } } - - None } - pub(crate) fn expn_def_scope(&mut self, expn_id: ExpnId) -> Module<'ra> { + pub(crate) fn expn_def_scope(&self, expn_id: ExpnId) -> Module<'ra> { match expn_id.expn_data().macro_def_id { Some(def_id) => self.macro_def_scope(def_id), None => expn_id @@ -141,7 +144,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } - pub(crate) fn macro_def_scope(&mut self, def_id: DefId) -> Module<'ra> { + pub(crate) fn macro_def_scope(&self, def_id: DefId) -> Module<'ra> { if let Some(id) = def_id.as_local() { self.local_macro_def_scopes[&id] } else { @@ -403,7 +406,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { self.r.field_visibility_spans.insert(def_id, field_vis); } - fn block_needs_anonymous_module(&mut self, block: &Block) -> bool { + fn block_needs_anonymous_module(&self, block: &Block) -> bool { // If any statements are items, we need to create an anonymous module block .stmts @@ -758,7 +761,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { if let ast::ModKind::Loaded(_, _, _, Err(_)) = mod_kind { self.r.mods_with_parse_errors.insert(def_id); } - self.parent_scope.module = self.r.new_module( + self.parent_scope.module = self.r.new_local_module( Some(parent), ModuleKind::Def(def_kind, def_id, Some(ident.name)), expansion.to_expn_id(), @@ -790,7 +793,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { ItemKind::Enum(ident, _, _) | ItemKind::Trait(box ast::Trait { ident, .. }) => { self.r.define(parent, ident, TypeNS, res, vis, sp, expansion); - self.parent_scope.module = self.r.new_module( + self.parent_scope.module = self.r.new_local_module( Some(parent), ModuleKind::Def(def_kind, def_id, Some(ident.name)), expansion.to_expn_id(), @@ -986,7 +989,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { let parent = self.parent_scope.module; let expansion = self.parent_scope.expansion; if self.block_needs_anonymous_module(block) { - let module = self.r.new_module( + let module = self.r.new_local_module( Some(parent), ModuleKind::Block, expansion.to_expn_id(), @@ -1118,7 +1121,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { } /// Returns `true` if this attribute list contains `macro_use`. - fn contains_macro_use(&mut self, attrs: &[ast::Attribute]) -> bool { + fn contains_macro_use(&self, attrs: &[ast::Attribute]) -> bool { for attr in attrs { if attr.has_name(sym::macro_escape) { let inner_attribute = matches!(attr.style, ast::AttrStyle::Inner); diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index 781e2ce9704..7d51fef28d3 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -2,7 +2,7 @@ use std::mem; use rustc_ast::visit::FnKind; use rustc_ast::*; -use rustc_attr_parsing::{AttributeParser, Early, OmitDoc}; +use rustc_attr_parsing::{AttributeParser, Early, OmitDoc, ShouldEmit}; use rustc_expand::expand::AstFragment; use rustc_hir as hir; use rustc_hir::def::{CtorKind, CtorOf, DefKind}; @@ -132,7 +132,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { &self.resolver.tcx.sess, self.resolver.tcx.features(), Vec::new(), - Early { emit_errors: false }, + Early { emit_errors: ShouldEmit::Nothing }, ); let attrs = parser.parse_attribute_list( &i.attrs, diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 11e4a729ae2..f6f45adabe9 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1,6 +1,8 @@ use rustc_ast::ptr::P; use rustc_ast::visit::{self, Visitor}; -use rustc_ast::{self as ast, CRATE_NODE_ID, Crate, ItemKind, ModKind, NodeId, Path}; +use rustc_ast::{ + self as ast, CRATE_NODE_ID, Crate, ItemKind, ModKind, NodeId, Path, join_path_idents, +}; use rustc_ast_pretty::pprust; use rustc_attr_data_structures::{ self as attr, AttributeKind, CfgEntry, Stability, StrippedCfgItem, find_attr, @@ -2018,7 +2020,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } - let mut sugg_paths = vec![]; + let mut sugg_paths: Vec<(Vec<Ident>, bool)> = vec![]; if let Some(mut def_id) = res.opt_def_id() { // We can't use `def_path_str` in resolve. let mut path = vec![def_id]; @@ -2031,16 +2033,16 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } // We will only suggest importing directly if it is accessible through that path. - let path_names: Option<Vec<String>> = path + let path_names: Option<Vec<Ident>> = path .iter() .rev() .map(|def_id| { - self.tcx.opt_item_name(*def_id).map(|n| { - if def_id.is_top_level_module() { - "crate".to_string() + self.tcx.opt_item_name(*def_id).map(|name| { + Ident::with_dummy_span(if def_id.is_top_level_module() { + kw::Crate } else { - n.to_string() - } + name + }) }) }) .collect(); @@ -2084,13 +2086,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { match binding.kind { NameBindingKind::Import { import, .. } => { for segment in import.module_path.iter().skip(1) { - path.push(segment.ident.to_string()); + path.push(segment.ident); } sugg_paths.push(( - path.iter() - .cloned() - .chain(vec![ident.to_string()].into_iter()) - .collect::<Vec<_>>(), + path.iter().cloned().chain(std::iter::once(ident)).collect::<Vec<_>>(), true, // re-export )); } @@ -2126,7 +2125,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { err.subdiagnostic(note); } // We prioritize shorter paths, non-core imports and direct imports over the alternatives. - sugg_paths.sort_by_key(|(p, reexport)| (p.len(), p[0] == "core", *reexport)); + sugg_paths.sort_by_key(|(p, reexport)| (p.len(), p[0].name == sym::core, *reexport)); for (sugg, reexport) in sugg_paths { if not_publicly_reexported { break; @@ -2136,7 +2135,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // `tests/ui/imports/issue-55884-2.rs` continue; } - let path = sugg.join("::"); + let path = join_path_idents(sugg); let sugg = if reexport { errors::ImportIdent::ThroughReExport { span: dedup_span, ident, path } } else { @@ -2150,7 +2149,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } pub(crate) fn find_similarly_named_module_or_crate( - &mut self, + &self, ident: Symbol, current_module: Module<'ra>, ) -> Option<Symbol> { @@ -2159,7 +2158,16 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { .keys() .map(|ident| ident.name) .chain( - self.module_map + self.local_module_map + .iter() + .filter(|(_, module)| { + current_module.is_ancestor_of(**module) && current_module != **module + }) + .flat_map(|(_, module)| module.kind.name()), + ) + .chain( + self.extern_module_map + .borrow() .iter() .filter(|(_, module)| { current_module.is_ancestor_of(**module) && current_module != **module @@ -2435,7 +2443,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } fn undeclared_module_suggest_declare( - &mut self, + &self, ident: Ident, path: std::path::PathBuf, ) -> Option<(Vec<(Span, String)>, String, Applicability)> { @@ -2450,7 +2458,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { )) } - fn undeclared_module_exists(&mut self, ident: Ident) -> Option<std::path::PathBuf> { + fn undeclared_module_exists(&self, ident: Ident) -> Option<std::path::PathBuf> { let map = self.tcx.sess.source_map(); let src = map.span_to_filename(ident.span).into_local_path()?; @@ -2809,24 +2817,23 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { return cached; } visited.insert(parent_module, false); - let res = r.module_map.get(&parent_module).is_some_and(|m| { - for importer in m.glob_importers.borrow().iter() { - if let Some(next_parent_module) = importer.parent_scope.module.opt_def_id() + let m = r.expect_module(parent_module); + let mut res = false; + for importer in m.glob_importers.borrow().iter() { + if let Some(next_parent_module) = importer.parent_scope.module.opt_def_id() { + if next_parent_module == module + || comes_from_same_module_for_glob( + r, + next_parent_module, + module, + visited, + ) { - if next_parent_module == module - || comes_from_same_module_for_glob( - r, - next_parent_module, - module, - visited, - ) - { - return true; - } + res = true; + break; } } - false - }); + } visited.insert(parent_module, res); res } diff --git a/compiler/rustc_resolve/src/effective_visibilities.rs b/compiler/rustc_resolve/src/effective_visibilities.rs index 5de80de3f8d..34d1e9552fd 100644 --- a/compiler/rustc_resolve/src/effective_visibilities.rs +++ b/compiler/rustc_resolve/src/effective_visibilities.rs @@ -38,11 +38,11 @@ pub(crate) struct EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> { } impl Resolver<'_, '_> { - fn nearest_normal_mod(&mut self, def_id: LocalDefId) -> LocalDefId { + fn nearest_normal_mod(&self, def_id: LocalDefId) -> LocalDefId { self.get_nearest_non_block_module(def_id.to_def_id()).nearest_parent_mod().expect_local() } - fn private_vis_import(&mut self, binding: NameBinding<'_>) -> Visibility { + fn private_vis_import(&self, binding: NameBinding<'_>) -> Visibility { let NameBindingKind::Import { import, .. } = binding.kind else { unreachable!() }; Visibility::Restricted( import @@ -52,7 +52,7 @@ impl Resolver<'_, '_> { ) } - fn private_vis_def(&mut self, def_id: LocalDefId) -> Visibility { + fn private_vis_def(&self, def_id: LocalDefId) -> Visibility { // For mod items `nearest_normal_mod` returns its argument, but we actually need its parent. let normal_mod_id = self.nearest_normal_mod(def_id); if normal_mod_id == def_id { @@ -113,8 +113,7 @@ impl<'a, 'ra, 'tcx> EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> { /// Update effective visibilities of bindings in the given module, /// including their whole reexport chains. fn set_bindings_effective_visibilities(&mut self, module_id: LocalDefId) { - assert!(self.r.module_map.contains_key(&module_id.to_def_id())); - let module = self.r.get_module(module_id.to_def_id()).unwrap(); + let module = self.r.expect_module(module_id.to_def_id()); let resolutions = self.r.resolutions(module); for (_, name_resolution) in resolutions.borrow().iter() { diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 84d66c15f00..34941398a2b 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -219,7 +219,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } fn hygienic_lexical_parent( - &mut self, + &self, module: Module<'ra>, ctxt: &mut SyntaxContext, derive_fallback_lint_id: Option<NodeId>, @@ -841,7 +841,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if ns == TypeNS { if ident.name == kw::Crate || ident.name == kw::DollarCrate { let module = self.resolve_crate_root(ident); - return Ok(self.module_self_bindings[&module]); + return Ok(module.self_binding.unwrap()); } else if ident.name == kw::Super || ident.name == kw::SelfLower { // FIXME: Implement these with renaming requirements so that e.g. // `use super;` doesn't work, but `use super as name;` does. @@ -885,7 +885,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ); } - let check_usable = |this: &mut Self, binding: NameBinding<'ra>| { + let check_usable = |this: &Self, binding: NameBinding<'ra>| { let usable = this.is_accessible_from(binding.vis, parent_scope.module); if usable { Ok(binding) } else { Err((Determined, Weak::No)) } }; diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 9a031ee03e0..0a4c25b0eb0 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -15,8 +15,8 @@ use rustc_middle::span_bug; use rustc_middle::ty::Visibility; use rustc_session::lint::BuiltinLintDiag; use rustc_session::lint::builtin::{ - AMBIGUOUS_GLOB_REEXPORTS, HIDDEN_GLOB_REEXPORTS, PUB_USE_OF_PRIVATE_EXTERN_CRATE, - REDUNDANT_IMPORTS, UNUSED_IMPORTS, + AMBIGUOUS_GLOB_REEXPORTS, EXPORTED_PRIVATE_DEPENDENCIES, HIDDEN_GLOB_REEXPORTS, + PUB_USE_OF_PRIVATE_EXTERN_CRATE, REDUNDANT_IMPORTS, UNUSED_IMPORTS, }; use rustc_session::parse::feature_err; use rustc_span::edit_distance::find_best_match_for_name; @@ -456,7 +456,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { f: F, ) -> T where - F: FnOnce(&mut Resolver<'ra, 'tcx>, &mut NameResolution<'ra>) -> T, + F: FnOnce(&Resolver<'ra, 'tcx>, &mut NameResolution<'ra>) -> T, { // Ensure that `resolution` isn't borrowed when defining in the module's glob importers, // during which the resolution might end up getting re-defined via a glob cycle. @@ -635,10 +635,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } - pub(crate) fn check_hidden_glob_reexports( - &mut self, - exported_ambiguities: FxHashSet<NameBinding<'ra>>, - ) { + pub(crate) fn lint_reexports(&mut self, exported_ambiguities: FxHashSet<NameBinding<'ra>>) { for module in self.arenas.local_modules().iter() { for (key, resolution) in self.resolutions(*module).borrow().iter() { let resolution = resolution.borrow(); @@ -697,6 +694,27 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } } + + if let NameBindingKind::Import { import, .. } = binding.kind + && let Some(binding_id) = import.id() + && let import_def_id = self.local_def_id(binding_id) + && self.effective_visibilities.is_exported(import_def_id) + && let Res::Def(reexported_kind, reexported_def_id) = binding.res() + && !matches!(reexported_kind, DefKind::Ctor(..)) + && !reexported_def_id.is_local() + && self.tcx.is_private_dep(reexported_def_id.krate) + { + self.lint_buffer.buffer_lint( + EXPORTED_PRIVATE_DEPENDENCIES, + binding_id, + binding.span, + BuiltinLintDiag::ReexportPrivateDependency { + kind: binding.res().descr().to_string(), + name: key.ident.name.to_string(), + krate: self.tcx.crate_name(reexported_def_id.krate), + }, + ); + } } } } diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 3ef98100d09..753b9365cd8 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -2491,7 +2491,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { /// Searches the current set of local scopes for labels. Returns the `NodeId` of the resolved /// label and reports an error if the label is not found or is unreachable. - fn resolve_label(&mut self, mut label: Ident) -> Result<(NodeId, Span), ResolutionError<'ra>> { + fn resolve_label(&self, mut label: Ident) -> Result<(NodeId, Span), ResolutionError<'ra>> { let mut suggestion = None; for i in (0..self.label_ribs.len()).rev() { diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index a4601cb44eb..ee462d90764 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -926,7 +926,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { continue; }; if let Res::Def(DefKind::Mod, module) = res.expect_full_res() - && let Some(module) = self.r.get_module(module) + && let module = self.r.expect_module(module) && let item = path[idx + 1].ident && let Some(did) = find_doc_alias_name(self.r, module, item.name) { @@ -939,7 +939,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { } fn suggest_trait_and_bounds( - &mut self, + &self, err: &mut Diag<'_>, source: PathSource<'_, '_, '_>, res: Option<Res>, @@ -1140,7 +1140,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { /// Emit special messages for unresolved `Self` and `self`. fn suggest_self_ty( - &mut self, + &self, err: &mut Diag<'_>, source: PathSource<'_, '_, '_>, path: &[Segment], @@ -1256,7 +1256,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { } fn detect_missing_binding_available_from_pattern( - &mut self, + &self, err: &mut Diag<'_>, path: &[Segment], following_seg: Option<&Segment>, @@ -1302,11 +1302,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { } } - fn suggest_at_operator_in_slice_pat_with_range( - &mut self, - err: &mut Diag<'_>, - path: &[Segment], - ) { + fn suggest_at_operator_in_slice_pat_with_range(&self, err: &mut Diag<'_>, path: &[Segment]) { let Some(pat) = self.diag_metadata.current_pat else { return }; let (bound, side, range) = match &pat.kind { ast::PatKind::Range(Some(bound), None, range) => (bound, Side::Start, range), @@ -1367,7 +1363,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { } fn explain_functions_in_pattern( - &mut self, + &self, err: &mut Diag<'_>, res: Option<Res>, source: PathSource<'_, '_, '_>, @@ -1379,7 +1375,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { } fn suggest_changing_type_to_const_param( - &mut self, + &self, err: &mut Diag<'_>, res: Option<Res>, source: PathSource<'_, '_, '_>, @@ -1429,7 +1425,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { } fn suggest_pattern_match_with_let( - &mut self, + &self, err: &mut Diag<'_>, source: PathSource<'_, '_, '_>, span: Span, @@ -1485,7 +1481,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { } /// Given `where <T as Bar>::Baz: String`, suggest `where T: Bar<Baz = String>`. - fn restrict_assoc_type_in_where_clause(&mut self, span: Span, err: &mut Diag<'_>) -> bool { + fn restrict_assoc_type_in_where_clause(&self, span: Span, err: &mut Diag<'_>) -> bool { // Detect that we are actually in a `where` predicate. let (bounded_ty, bounds, where_span) = if let Some(ast::WherePredicate { kind: @@ -1633,7 +1629,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { let ns = source.namespace(); let is_expected = &|res| source.is_expected(res); - let path_sep = |this: &mut Self, err: &mut Diag<'_>, expr: &Expr, kind: DefKind| { + let path_sep = |this: &Self, err: &mut Diag<'_>, expr: &Expr, kind: DefKind| { const MESSAGE: &str = "use the path separator to refer to an item"; let (lhs_span, rhs_span) = match &expr.kind { @@ -2531,16 +2527,14 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { // FIXME: this is not totally accurate, but mostly works suggestion.candidate != following_seg.ident.name } - Res::Def(DefKind::Mod, def_id) => self.r.get_module(def_id).map_or_else( - || false, - |module| { - self.r - .resolutions(module) - .borrow() - .iter() - .any(|(key, _)| key.ident.name == following_seg.ident.name) - }, - ), + Res::Def(DefKind::Mod, def_id) => { + let module = self.r.expect_module(def_id); + self.r + .resolutions(module) + .borrow() + .iter() + .any(|(key, _)| key.ident.name == following_seg.ident.name) + } _ => true, }); } @@ -2589,7 +2583,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { // try to give a suggestion for this pattern: `name = blah`, which is common in other languages // suggest `let name = blah` to introduce a new binding - fn let_binding_suggestion(&mut self, err: &mut Diag<'_>, ident_span: Span) -> bool { + fn let_binding_suggestion(&self, err: &mut Diag<'_>, ident_span: Span) -> bool { if ident_span.from_expansion() { return false; } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index b0b29bc2eae..dae30b77ec1 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -585,6 +585,10 @@ struct ModuleData<'ra> { span: Span, expansion: ExpnId, + + /// Binding for implicitly declared names that come with a module, + /// like `self` (not yet used), or `crate`/`$crate` (for root modules). + self_binding: Option<NameBinding<'ra>>, } /// All modules are unique and allocated on a same arena, @@ -613,6 +617,7 @@ impl<'ra> ModuleData<'ra> { expansion: ExpnId, span: Span, no_implicit_prelude: bool, + self_binding: Option<NameBinding<'ra>>, ) -> Self { let is_foreign = match kind { ModuleKind::Def(_, def_id, _) => !def_id.is_local(), @@ -630,6 +635,7 @@ impl<'ra> ModuleData<'ra> { traits: RefCell::new(None), span, expansion, + self_binding, } } } @@ -1075,7 +1081,10 @@ pub struct Resolver<'ra, 'tcx> { /// some AST passes can generate identifiers that only resolve to local or /// lang items. empty_module: Module<'ra>, - module_map: FxIndexMap<DefId, Module<'ra>>, + /// Eagerly populated map of all local non-block modules. + local_module_map: FxIndexMap<LocalDefId, Module<'ra>>, + /// Lazily populated cache of modules loaded from external crates. + extern_module_map: RefCell<FxIndexMap<DefId, Module<'ra>>>, binding_parent_modules: FxHashMap<NameBinding<'ra>, Module<'ra>>, underscore_disambiguator: u32, @@ -1101,17 +1110,14 @@ pub struct Resolver<'ra, 'tcx> { builtin_types_bindings: FxHashMap<Symbol, NameBinding<'ra>>, builtin_attrs_bindings: FxHashMap<Symbol, NameBinding<'ra>>, registered_tool_bindings: FxHashMap<Ident, NameBinding<'ra>>, - /// Binding for implicitly declared names that come with a module, - /// like `self` (not yet used), or `crate`/`$crate` (for root modules). - module_self_bindings: FxHashMap<Module<'ra>, NameBinding<'ra>>, - used_extern_options: FxHashSet<Symbol>, macro_names: FxHashSet<Ident>, builtin_macros: FxHashMap<Symbol, SyntaxExtensionKind>, registered_tools: &'tcx RegisteredTools, macro_use_prelude: FxIndexMap<Symbol, NameBinding<'ra>>, + /// Eagerly populated map of all local macro definitions. local_macro_map: FxHashMap<LocalDefId, &'ra MacroData>, - /// Lazily populated cache of macros loaded from external crates. + /// Lazily populated cache of macro definitions loaded from external crates. extern_macro_map: RefCell<FxHashMap<DefId, &'ra MacroData>>, dummy_ext_bang: Arc<SyntaxExtension>, dummy_ext_derive: Arc<SyntaxExtension>, @@ -1263,26 +1269,25 @@ impl<'ra> ResolverArenas<'ra> { expn_id: ExpnId, span: Span, no_implicit_prelude: bool, - module_map: &mut FxIndexMap<DefId, Module<'ra>>, - module_self_bindings: &mut FxHashMap<Module<'ra>, NameBinding<'ra>>, ) -> Module<'ra> { + let (def_id, self_binding) = match kind { + ModuleKind::Def(def_kind, def_id, _) => ( + Some(def_id), + Some(self.new_pub_res_binding(Res::Def(def_kind, def_id), span, LocalExpnId::ROOT)), + ), + ModuleKind::Block => (None, None), + }; let module = Module(Interned::new_unchecked(self.modules.alloc(ModuleData::new( parent, kind, expn_id, span, no_implicit_prelude, + self_binding, )))); - let def_id = module.opt_def_id(); if def_id.is_none_or(|def_id| def_id.is_local()) { self.local_modules.borrow_mut().push(module); } - if let Some(def_id) = def_id { - module_map.insert(def_id, module); - let res = module.res().unwrap(); - let binding = self.new_pub_res_binding(res, module.span, LocalExpnId::ROOT); - module_self_bindings.insert(module, binding); - } module } fn local_modules(&'ra self) -> std::cell::Ref<'ra, Vec<Module<'ra>>> { @@ -1423,25 +1428,21 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { arenas: &'ra ResolverArenas<'ra>, ) -> Resolver<'ra, 'tcx> { let root_def_id = CRATE_DEF_ID.to_def_id(); - let mut module_map = FxIndexMap::default(); - let mut module_self_bindings = FxHashMap::default(); + let mut local_module_map = FxIndexMap::default(); let graph_root = arenas.new_module( None, ModuleKind::Def(DefKind::Mod, root_def_id, None), ExpnId::root(), crate_span, attr::contains_name(attrs, sym::no_implicit_prelude), - &mut module_map, - &mut module_self_bindings, ); + local_module_map.insert(CRATE_DEF_ID, graph_root); let empty_module = arenas.new_module( None, ModuleKind::Def(DefKind::Mod, root_def_id, None), ExpnId::root(), DUMMY_SP, true, - &mut Default::default(), - &mut Default::default(), ); let mut node_id_to_def_id = NodeMap::default(); @@ -1502,7 +1503,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { trait_map: NodeMap::default(), underscore_disambiguator: 0, empty_module, - module_map, + local_module_map, + extern_module_map: Default::default(), block_map: Default::default(), binding_parent_modules: FxHashMap::default(), ast_transform_scopes: FxHashMap::default(), @@ -1544,8 +1546,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { (*ident, binding) }) .collect(), - module_self_bindings, - used_extern_options: Default::default(), macro_names: FxHashSet::default(), builtin_macros: Default::default(), @@ -1608,7 +1608,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { resolver } - fn new_module( + fn new_local_module( &mut self, parent: Option<Module<'ra>>, kind: ModuleKind, @@ -1616,17 +1616,24 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { span: Span, no_implicit_prelude: bool, ) -> Module<'ra> { - let module_map = &mut self.module_map; - let module_self_bindings = &mut self.module_self_bindings; - self.arenas.new_module( - parent, - kind, - expn_id, - span, - no_implicit_prelude, - module_map, - module_self_bindings, - ) + let module = self.arenas.new_module(parent, kind, expn_id, span, no_implicit_prelude); + if let Some(def_id) = module.opt_def_id() { + self.local_module_map.insert(def_id.expect_local(), module); + } + module + } + + fn new_extern_module( + &self, + parent: Option<Module<'ra>>, + kind: ModuleKind, + expn_id: ExpnId, + span: Span, + no_implicit_prelude: bool, + ) -> Module<'ra> { + let module = self.arenas.new_module(parent, kind, expn_id, span, no_implicit_prelude); + self.extern_module_map.borrow_mut().insert(module.def_id(), module); + module } fn new_local_macro(&mut self, def_id: LocalDefId, macro_data: MacroData) -> &'ra MacroData { @@ -1773,9 +1780,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let exported_ambiguities = self.tcx.sess.time("compute_effective_visibilities", || { EffectiveVisibilitiesVisitor::compute_effective_visibilities(self, krate) }); - self.tcx.sess.time("check_hidden_glob_reexports", || { - self.check_hidden_glob_reexports(exported_ambiguities) - }); + self.tcx.sess.time("lint_reexports", || self.lint_reexports(exported_ambiguities)); self.tcx .sess .time("finalize_macro_resolutions", || self.finalize_macro_resolutions(krate)); @@ -2014,7 +2019,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } - fn resolve_crate_root(&mut self, ident: Ident) -> Module<'ra> { + fn resolve_crate_root(&self, ident: Ident) -> Module<'ra> { debug!("resolve_crate_root({:?})", ident); let mut ctxt = ident.span.ctxt(); let mark = if ident.name == kw::DollarCrate { @@ -2087,7 +2092,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { module } - fn resolve_self(&mut self, ctxt: &mut SyntaxContext, module: Module<'ra>) -> Module<'ra> { + fn resolve_self(&self, ctxt: &mut SyntaxContext, module: Module<'ra>) -> Module<'ra> { let mut module = self.expect_module(module.nearest_parent_mod()); while module.span.ctxt().normalize_to_macros_2_0() != *ctxt { let parent = module.parent.unwrap_or_else(|| self.expn_def_scope(ctxt.remove_mark())); diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index c17d74659db..77ef7f56c09 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -170,7 +170,7 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { self.invocation_parents[&id].parent_def } - fn resolve_dollar_crates(&mut self) { + fn resolve_dollar_crates(&self) { hygiene::update_dollar_crate_names(|ctxt| { let ident = Ident::new(kw::DollarCrate, DUMMY_SP.with_ctxt(ctxt)); match self.resolve_crate_root(ident).kind { @@ -835,7 +835,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } pub(crate) fn finalize_macro_resolutions(&mut self, krate: &Crate) { - let check_consistency = |this: &mut Self, + let check_consistency = |this: &Self, path: &[Segment], span, kind: MacroKind, diff --git a/compiler/rustc_resolve/src/rustdoc.rs b/compiler/rustc_resolve/src/rustdoc.rs index f61cd1f0adf..24e15ded94f 100644 --- a/compiler/rustc_resolve/src/rustdoc.rs +++ b/compiler/rustc_resolve/src/rustdoc.rs @@ -7,6 +7,7 @@ use pulldown_cmark::{ }; use rustc_ast as ast; use rustc_ast::attr::AttributeExt; +use rustc_ast::join_path_syms; use rustc_ast::util::comments::beautify_doc_string; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::unord::UnordSet; @@ -259,7 +260,7 @@ pub fn main_body_opts() -> Options { | Options::ENABLE_SMART_PUNCTUATION } -fn strip_generics_from_path_segment(segment: Vec<char>) -> Result<String, MalformedGenerics> { +fn strip_generics_from_path_segment(segment: Vec<char>) -> Result<Symbol, MalformedGenerics> { let mut stripped_segment = String::new(); let mut param_depth = 0; @@ -284,7 +285,7 @@ fn strip_generics_from_path_segment(segment: Vec<char>) -> Result<String, Malfor } if param_depth == 0 { - Ok(stripped_segment) + Ok(Symbol::intern(&stripped_segment)) } else { // The segment has unbalanced angle brackets, e.g. `Vec<T` or `Vec<T>>` Err(MalformedGenerics::UnbalancedAngleBrackets) @@ -346,9 +347,8 @@ pub fn strip_generics_from_path(path_str: &str) -> Result<Box<str>, MalformedGen debug!("path_str: {path_str:?}\nstripped segments: {stripped_segments:?}"); - let stripped_path = stripped_segments.join("::"); - - if !stripped_path.is_empty() { + if !stripped_segments.is_empty() { + let stripped_path = join_path_syms(stripped_segments); Ok(stripped_path.into()) } else { Err(MalformedGenerics::MissingType) diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs index 0118cdb1fc2..9097b27b86c 100644 --- a/compiler/rustc_session/src/parse.rs +++ b/compiler/rustc_session/src/parse.rs @@ -205,6 +205,46 @@ pub fn add_feature_diagnostics_for_issue<G: EmissionGuarantee>( } } +/// This is only used by unstable_feature_bound as it does not have issue number information for now. +/// This is basically the same as `feature_err_issue` +/// but without the feature issue note. If we can do a lookup for issue number from feature name, +/// then we should directly use `feature_err_issue` for ambiguity error of +/// `#[unstable_feature_bound]`. +#[track_caller] +pub fn feature_err_unstable_feature_bound( + sess: &Session, + feature: Symbol, + span: impl Into<MultiSpan>, + explain: impl Into<DiagMessage>, +) -> Diag<'_> { + let span = span.into(); + + // Cancel an earlier warning for this same error, if it exists. + if let Some(span) = span.primary_span() { + if let Some(err) = sess.dcx().steal_non_err(span, StashKey::EarlySyntaxWarning) { + err.cancel() + } + } + + let mut err = sess.dcx().create_err(FeatureGateError { span, explain: explain.into() }); + + // #23973: do not suggest `#![feature(...)]` if we are in beta/stable + if sess.psess.unstable_features.is_nightly_build() { + err.subdiagnostic(FeatureDiagnosticHelp { feature }); + + if feature == sym::rustc_attrs { + // We're unlikely to stabilize something out of `rustc_attrs` + // without at least renaming it, so pointing out how old + // the compiler is will do little good. + } else if sess.opts.unstable_opts.ui_testing { + err.subdiagnostic(SuggestUpgradeCompiler::ui_testing()); + } else if let Some(suggestion) = SuggestUpgradeCompiler::new() { + err.subdiagnostic(suggestion); + } + } + err +} + /// Info about a parsing session. pub struct ParseSess { dcx: DiagCtxt, diff --git a/compiler/rustc_span/src/def_id.rs b/compiler/rustc_span/src/def_id.rs index 641bac88ad0..77f01548bca 100644 --- a/compiler/rustc_span/src/def_id.rs +++ b/compiler/rustc_span/src/def_id.rs @@ -110,6 +110,7 @@ impl DefPathHash { /// Builds a new [DefPathHash] with the given [StableCrateId] and /// `local_hash`, where `local_hash` must be unique within its crate. + #[inline] pub fn new(stable_crate_id: StableCrateId, local_hash: Hash64) -> DefPathHash { DefPathHash(Fingerprint::new(stable_crate_id.0, local_hash)) } @@ -404,21 +405,21 @@ rustc_data_structures::define_id_collections!( impl<CTX: HashStableContext> HashStable<CTX> for DefId { #[inline] fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { - self.to_stable_hash_key(hcx).hash_stable(hcx, hasher); + hcx.def_path_hash(*self).hash_stable(hcx, hasher); } } impl<CTX: HashStableContext> HashStable<CTX> for LocalDefId { #[inline] fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { - self.to_stable_hash_key(hcx).hash_stable(hcx, hasher); + hcx.def_path_hash(self.to_def_id()).local_hash().hash_stable(hcx, hasher); } } impl<CTX: HashStableContext> HashStable<CTX> for CrateNum { #[inline] fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { - self.to_stable_hash_key(hcx).hash_stable(hcx, hasher); + self.as_def_id().to_stable_hash_key(hcx).stable_crate_id().hash_stable(hcx, hasher); } } @@ -464,30 +465,36 @@ macro_rules! typed_def_id { pub struct $Name(DefId); impl $Name { + #[inline] pub const fn new_unchecked(def_id: DefId) -> Self { Self(def_id) } + #[inline] pub fn to_def_id(self) -> DefId { self.into() } + #[inline] pub fn is_local(self) -> bool { self.0.is_local() } + #[inline] pub fn as_local(self) -> Option<$LocalName> { self.0.as_local().map($LocalName::new_unchecked) } } impl From<$LocalName> for $Name { + #[inline] fn from(local: $LocalName) -> Self { Self(local.0.to_def_id()) } } impl From<$Name> for DefId { + #[inline] fn from(typed: $Name) -> Self { typed.0 } @@ -500,26 +507,31 @@ macro_rules! typed_def_id { impl !PartialOrd for $LocalName {} impl $LocalName { + #[inline] pub const fn new_unchecked(def_id: LocalDefId) -> Self { Self(def_id) } + #[inline] pub fn to_def_id(self) -> DefId { self.0.into() } + #[inline] pub fn to_local_def_id(self) -> LocalDefId { self.0 } } impl From<$LocalName> for LocalDefId { + #[inline] fn from(typed: $LocalName) -> Self { typed.0 } } impl From<$LocalName> for DefId { + #[inline] fn from(typed: $LocalName) -> Self { typed.0.into() } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 8b12edf426c..7147f37efc1 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -715,6 +715,7 @@ symbols! { const_indexing, const_let, const_loop, + const_make_global, const_mut_refs, const_panic, const_panic_fmt, @@ -2284,6 +2285,7 @@ symbols! { unsized_locals, unsized_tuple_coercion, unstable, + unstable_feature_bound, unstable_location_reason_default: "this crate is being loaded from the sysroot, an \ unstable location; did you mean to load this crate \ from crates.io via `Cargo.toml` instead?", diff --git a/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_muslabi64.rs b/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_muslabi64.rs index fd509503053..f95ce756354 100644 --- a/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_muslabi64.rs +++ b/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_muslabi64.rs @@ -5,7 +5,7 @@ use crate::spec::{Target, TargetMetadata, TargetOptions, base}; pub(crate) fn target() -> Target { let mut base = base::linux_musl::opts(); base.cpu = "mips64r2".into(); - base.features = "+mips64r2".into(); + base.features = "+mips64r2,+xgot".into(); base.max_atomic_width = Some(64); Target { // LLVM doesn't recognize "muslabi64" yet. diff --git a/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_muslabi64.rs b/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_muslabi64.rs index aa087b1a35a..d42e097b0fd 100644 --- a/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_muslabi64.rs +++ b/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_muslabi64.rs @@ -3,7 +3,7 @@ use crate::spec::{Target, TargetMetadata, TargetOptions, base}; pub(crate) fn target() -> Target { let mut base = base::linux_musl::opts(); base.cpu = "mips64r2".into(); - base.features = "+mips64r2".into(); + base.features = "+mips64r2,+xgot".into(); base.max_atomic_width = Some(64); // FIXME(compiler-team#422): musl targets should be dynamically linked by default. base.crt_static_default = true; diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs index bc464b099e2..b9acadc406e 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs @@ -51,6 +51,7 @@ use std::path::PathBuf; use std::{cmp, fmt, iter}; use rustc_abi::ExternAbi; +use rustc_ast::join_path_syms; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_errors::{ Applicability, Diag, DiagStyledString, IntoDiagArg, MultiSpan, StringPart, pluralize, @@ -73,7 +74,7 @@ use rustc_middle::ty::{ TypeVisitableExt, }; use rustc_span::def_id::LOCAL_CRATE; -use rustc_span::{BytePos, DUMMY_SP, DesugaringKind, Pos, Span, sym}; +use rustc_span::{BytePos, DUMMY_SP, DesugaringKind, Pos, Span, Symbol, sym}; use tracing::{debug, instrument}; use crate::error_reporting::TypeErrCtxt; @@ -225,7 +226,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { struct AbsolutePathPrinter<'tcx> { tcx: TyCtxt<'tcx>, - segments: Vec<String>, + segments: Vec<Symbol>, } impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> { @@ -253,7 +254,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } fn path_crate(&mut self, cnum: CrateNum) -> Result<(), PrintError> { - self.segments = vec![self.tcx.crate_name(cnum).to_string()]; + self.segments = vec![self.tcx.crate_name(cnum)]; Ok(()) } fn path_qualified( @@ -279,7 +280,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { disambiguated_data: &DisambiguatedDefPathData, ) -> Result<(), PrintError> { print_prefix(self)?; - self.segments.push(disambiguated_data.to_string()); + self.segments.push(disambiguated_data.as_sym(true)); Ok(()) } fn path_generic_args( @@ -314,7 +315,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // known" by the same name, we use the "absolute path" which uses the original // crate name instead. let (expected, found) = if expected_str == found_str { - (expected_abs.join("::"), found_abs.join("::")) + (join_path_syms(&expected_abs), join_path_syms(&found_abs)) } else { (expected_str.clone(), found_str.clone()) }; diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs index 712e88300ff..98f67257fd1 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs @@ -12,6 +12,7 @@ use rustc_infer::traits::{ Obligation, ObligationCause, ObligationCauseCode, PolyTraitObligation, PredicateObligation, }; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable as _, TypeVisitableExt as _}; +use rustc_session::parse::feature_err_unstable_feature_bound; use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span}; use tracing::{debug, instrument}; @@ -611,6 +612,30 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ) .with_span_label(span, format!("cannot normalize `{alias}`")) } + ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(sym)) => { + if let Some(e) = self.tainted_by_errors() { + return e; + } + + let mut err; + + if self.tcx.features().staged_api() { + err = self.dcx().struct_span_err( + span, + format!("unstable feature `{sym}` is used without being enabled."), + ); + + err.help(format!("The feature can be enabled by marking the current item with `#[unstable_feature_bound({sym})]`")); + } else { + err = feature_err_unstable_feature_bound( + &self.tcx.sess, + sym, + span, + format!("use of unstable library feature `{sym}`"), + ); + } + err + } _ => { if let Some(e) = self.tainted_by_errors() { diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index cd3e6c4bc54..1ac309da101 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -647,6 +647,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { | ty::PredicateKind::ConstEquate { .. } // Ambiguous predicates should never error | ty::PredicateKind::Ambiguous + // We never return Err when proving UnstableFeature goal. + | ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature{ .. }) | ty::PredicateKind::NormalizesTo { .. } | ty::PredicateKind::AliasRelate { .. } | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType { .. }) => { diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs index d4cc1ceb280..1d8b934cef3 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs @@ -453,7 +453,7 @@ pub fn report_dyn_incompatibility<'tcx>( let trait_str = tcx.def_path_str(trait_def_id); let trait_span = tcx.hir_get_if_local(trait_def_id).and_then(|node| match node { hir::Node::Item(item) => match item.kind { - hir::ItemKind::Trait(_, _, ident, ..) | hir::ItemKind::TraitAlias(ident, _, _) => { + hir::ItemKind::Trait(_, _, _, ident, ..) | hir::ItemKind::TraitAlias(ident, _, _) => { Some(ident.span) } _ => unreachable!(), diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index bd1d29826e6..bf7d4257b62 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -22,6 +22,7 @@ use rustc_hir::{ expr_needs_parens, is_range_literal, }; use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferCtxt, InferOk}; +use rustc_middle::middle::privacy::Level; use rustc_middle::traits::IsConstable; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::print::{ @@ -267,7 +268,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let node = self.tcx.hir_node_by_def_id(body_id); match node { hir::Node::Item(hir::Item { - kind: hir::ItemKind::Trait(_, _, ident, generics, bounds, _), + kind: hir::ItemKind::Trait(_, _, _, ident, generics, bounds, _), .. }) if self_ty == self.tcx.types.self_param => { assert!(param_ty); @@ -330,7 +331,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } hir::Node::Item(hir::Item { kind: - hir::ItemKind::Trait(_, _, _, generics, ..) + hir::ItemKind::Trait(_, _, _, _, generics, ..) | hir::ItemKind::Impl(hir::Impl { generics, .. }), .. }) if projection.is_some() => { @@ -354,7 +355,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { hir::ItemKind::Struct(_, generics, _) | hir::ItemKind::Enum(_, generics, _) | hir::ItemKind::Union(_, generics, _) - | hir::ItemKind::Trait(_, _, _, generics, ..) + | hir::ItemKind::Trait(_, _, _, _, generics, ..) | hir::ItemKind::Impl(hir::Impl { generics, .. }) | hir::ItemKind::Fn { generics, .. } | hir::ItemKind::TyAlias(_, generics, _) @@ -414,7 +415,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { hir::ItemKind::Struct(_, generics, _) | hir::ItemKind::Enum(_, generics, _) | hir::ItemKind::Union(_, generics, _) - | hir::ItemKind::Trait(_, _, _, generics, ..) + | hir::ItemKind::Trait(_, _, _, _, generics, ..) | hir::ItemKind::Impl(hir::Impl { generics, .. }) | hir::ItemKind::Fn { generics, .. } | hir::ItemKind::TyAlias(_, generics, _) @@ -2870,11 +2871,20 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ty::ClauseKind::Trait(trait_pred) => { let def_id = trait_pred.def_id(); let visible_item = if let Some(local) = def_id.as_local() { - // Check for local traits being reachable. - let vis = &tcx.resolutions(()).effective_visibilities; - // Account for non-`pub` traits in the root of the local crate. - let is_locally_reachable = tcx.parent(def_id).is_crate_root(); - vis.is_reachable(local) || is_locally_reachable + let ty = trait_pred.self_ty(); + // when `TraitA: TraitB` and `S` only impl TraitA, + // we check if `TraitB` can be reachable from `S` + // to determine whether to note `TraitA` is sealed trait. + if let ty::Adt(adt, _) = ty.kind() { + let visibilities = tcx.effective_visibilities(()); + visibilities.effective_vis(local).is_none_or(|v| { + v.at_level(Level::Reexported) + .is_accessible_from(adt.did(), tcx) + }) + } else { + // FIXME(xizheyin): if the type is not ADT, we should not suggest it + true + } } else { // Check for foreign traits being reachable. tcx.visible_parent_map(()).get(&def_id).is_some() @@ -3436,7 +3446,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let mut is_auto_trait = false; match tcx.hir_get_if_local(data.impl_or_alias_def_id) { Some(Node::Item(hir::Item { - kind: hir::ItemKind::Trait(is_auto, _, ident, ..), + kind: hir::ItemKind::Trait(_, is_auto, _, ident, ..), .. })) => { // FIXME: we should do something else so that it works even on crate foreign diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs index 90cdf75265d..7901d52dffb 100644 --- a/compiler/rustc_trait_selection/src/errors.rs +++ b/compiler/rustc_trait_selection/src/errors.rs @@ -534,7 +534,7 @@ impl Subdiagnostic for AddLifetimeParamsSuggestion<'_> { match self.tcx.parent_hir_node(self.tcx.local_def_id_to_hir_id(anon_reg.scope)) { hir::Node::Item(hir::Item { - kind: hir::ItemKind::Trait(_, _, _, generics, ..), + kind: hir::ItemKind::Trait(_, _, _, _, generics, ..), .. }) | hir::Node::Item(hir::Item { diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index 3ae908ec16b..759db1d18c0 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -800,6 +800,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { // FIXME(generic_const_exprs): you can absolutely add this as a where clauses | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) | ty::PredicateKind::Coerce(..) + | ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(_)) | ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(..)) => {} ty::PredicateKind::Ambiguous => return false, }; diff --git a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs index 9a4f3887bbb..ea1eed95723 100644 --- a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs +++ b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs @@ -238,6 +238,7 @@ fn predicate_references_self<'tcx>( // FIXME(generic_const_exprs): this can mention `Self` | ty::ClauseKind::ConstEvaluatable(..) | ty::ClauseKind::HostEffect(..) + | ty::ClauseKind::UnstableFeature(_) => None, } } @@ -278,6 +279,7 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool { | ty::ClauseKind::ConstArgHasType(_, _) | ty::ClauseKind::WellFormed(_) | ty::ClauseKind::ConstEvaluatable(_) + | ty::ClauseKind::UnstableFeature(_) | ty::ClauseKind::HostEffect(..) => false, }) } diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 64a51e0550b..2b5a41ef5a7 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -11,7 +11,9 @@ use rustc_infer::traits::{ use rustc_middle::bug; use rustc_middle::ty::abstract_const::NotConstEvaluatable; use rustc_middle::ty::error::{ExpectedFound, TypeError}; -use rustc_middle::ty::{self, Binder, Const, GenericArgsRef, TypeVisitableExt, TypingMode}; +use rustc_middle::ty::{ + self, Binder, Const, GenericArgsRef, TypeVisitableExt, TypingMode, may_use_unstable_feature, +}; use thin_vec::{ThinVec, thin_vec}; use tracing::{debug, debug_span, instrument}; @@ -404,6 +406,9 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { ty::PredicateKind::AliasRelate(..) => { bug!("AliasRelate is only used by the new solver") } + ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(_)) => { + unreachable!("unexpected higher ranked `UnstableFeature` goal") + } }, Some(pred) => match pred { ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) => { @@ -767,6 +772,13 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { } } } + ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(symbol)) => { + if may_use_unstable_feature(self.selcx.infcx, obligation.param_env, symbol) { + ProcessResult::Changed(Default::default()) + } else { + ProcessResult::Unchanged + } + } }, } } diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs index e294f7839aa..7540cbe3fd1 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs @@ -110,6 +110,7 @@ pub fn compute_implied_outlives_bounds_inner<'tcx>( | ty::PredicateKind::ConstEquate(..) | ty::PredicateKind::Ambiguous | ty::PredicateKind::NormalizesTo(..) + | ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(_)) | ty::PredicateKind::AliasRelate(..) => {} // We need to search through *all* WellFormed predicates diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 2e65750db25..10bcf861d35 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -28,7 +28,7 @@ use rustc_middle::ty::error::TypeErrorToStringExt; use rustc_middle::ty::print::{PrintTraitRefExt as _, with_no_trimmed_paths}; use rustc_middle::ty::{ self, DeepRejectCtxt, GenericArgsRef, PolyProjectionPredicate, SizedTraitKind, Ty, TyCtxt, - TypeFoldable, TypeVisitableExt, TypingMode, Upcast, elaborate, + TypeFoldable, TypeVisitableExt, TypingMode, Upcast, elaborate, may_use_unstable_feature, }; use rustc_span::{Symbol, sym}; use tracing::{debug, instrument, trace}; @@ -832,6 +832,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } + ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(symbol)) => { + if may_use_unstable_feature(self.infcx, obligation.param_env, symbol) { + Ok(EvaluatedToOk) + } else { + Ok(EvaluatedToAmbig) + } + } + ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(uv)) => { match const_evaluatable::is_const_evaluatable( self.infcx, diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs index 141454bfe37..0c14b124e25 100644 --- a/compiler/rustc_trait_selection/src/traits/util.rs +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -80,6 +80,7 @@ pub fn expand_trait_aliases<'tcx>( | ty::ClauseKind::ConstArgHasType(_, _) | ty::ClauseKind::WellFormed(_) | ty::ClauseKind::ConstEvaluatable(_) + | ty::ClauseKind::UnstableFeature(_) | ty::ClauseKind::HostEffect(..) => {} } } @@ -378,6 +379,13 @@ pub fn sizedness_fast_path<'tcx>(tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tc _ => return false, }; + // FIXME(sized_hierarchy): this temporarily reverts the `sized_hierarchy` feature + // while a proper fix for `tests/ui/sized-hierarchy/incomplete-inference-issue-143992.rs` + // is pending a proper fix + if !tcx.features().sized_hierarchy() && matches!(sizedness, SizedTraitKind::MetaSized) { + return true; + } + if trait_pred.self_ty().has_trivial_sizedness(tcx, sizedness) { debug!("fast path -- trivial sizedness"); return true; diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index fed9f254cdf..adce9850b59 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -197,6 +197,7 @@ pub fn clause_obligations<'tcx>( ty::ClauseKind::ConstEvaluatable(ct) => { wf.add_wf_preds_for_term(ct.into()); } + ty::ClauseKind::UnstableFeature(_) => {} } wf.normalize(infcx) @@ -1095,6 +1096,7 @@ pub fn object_region_bounds<'tcx>( | ty::ClauseKind::Projection(_) | ty::ClauseKind::ConstArgHasType(_, _) | ty::ClauseKind::WellFormed(_) + | ty::ClauseKind::UnstableFeature(_) | ty::ClauseKind::ConstEvaluatable(_) => None, } }) diff --git a/compiler/rustc_traits/src/normalize_erasing_regions.rs b/compiler/rustc_traits/src/normalize_erasing_regions.rs index 68ff66bbce7..c1b848a2e79 100644 --- a/compiler/rustc_traits/src/normalize_erasing_regions.rs +++ b/compiler/rustc_traits/src/normalize_erasing_regions.rs @@ -57,6 +57,7 @@ fn not_outlives_predicate(p: ty::Predicate<'_>) -> bool { | ty::PredicateKind::Clause(ty::ClauseKind::Projection(..)) | ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(..)) | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(_)) | ty::PredicateKind::NormalizesTo(..) | ty::PredicateKind::AliasRelate(..) | ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(..)) diff --git a/compiler/rustc_ty_utils/src/opaque_types.rs b/compiler/rustc_ty_utils/src/opaque_types.rs index 3b313edea6f..4a7263d0ccd 100644 --- a/compiler/rustc_ty_utils/src/opaque_types.rs +++ b/compiler/rustc_ty_utils/src/opaque_types.rs @@ -223,7 +223,10 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for OpaqueTypeCollector<'tcx> { } // Skips type aliases, as they are meant to be transparent. // FIXME(type_alias_impl_trait): can we require mentioning nested type aliases explicitly? - ty::Alias(ty::Free, alias_ty) if alias_ty.def_id.is_local() => { + ty::Alias(ty::Free, alias_ty) if let Some(def_id) = alias_ty.def_id.as_local() => { + if !self.seen.insert(def_id) { + return; + } self.tcx .type_of(alias_ty.def_id) .instantiate(self.tcx, alias_ty.args) @@ -256,16 +259,16 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for OpaqueTypeCollector<'tcx> { return; } - let impl_args = alias_ty.args.rebase_onto( + let alias_args = alias_ty.args.rebase_onto( self.tcx, impl_trait_ref.def_id, ty::GenericArgs::identity_for_item(self.tcx, parent), ); - if self.tcx.check_args_compatible(assoc.def_id, impl_args) { + if self.tcx.check_args_compatible(assoc.def_id, alias_args) { self.tcx .type_of(assoc.def_id) - .instantiate(self.tcx, impl_args) + .instantiate(self.tcx, alias_args) .visit_with(self); return; } else { diff --git a/compiler/rustc_type_ir/src/elaborate.rs b/compiler/rustc_type_ir/src/elaborate.rs index 7ffcf7b5d96..38008248757 100644 --- a/compiler/rustc_type_ir/src/elaborate.rs +++ b/compiler/rustc_type_ir/src/elaborate.rs @@ -234,6 +234,9 @@ impl<I: Interner, O: Elaboratable<I>> Elaborator<I, O> { ty::ClauseKind::ConstArgHasType(..) => { // Nothing to elaborate } + ty::ClauseKind::UnstableFeature(_) => { + // Nothing to elaborate + } } } } diff --git a/compiler/rustc_type_ir/src/flags.rs b/compiler/rustc_type_ir/src/flags.rs index 37cc2baa402..a231908f874 100644 --- a/compiler/rustc_type_ir/src/flags.rs +++ b/compiler/rustc_type_ir/src/flags.rs @@ -401,7 +401,6 @@ impl<I: Interner> FlagComputation<I> { self.add_const(expected); self.add_const(found); } - ty::PredicateKind::Ambiguous => {} ty::PredicateKind::NormalizesTo(ty::NormalizesTo { alias, term }) => { self.add_alias_term(alias); self.add_term(term); @@ -410,6 +409,8 @@ impl<I: Interner> FlagComputation<I> { self.add_term(t1); self.add_term(t2); } + ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(_sym)) => {} + ty::PredicateKind::Ambiguous => {} } } diff --git a/compiler/rustc_type_ir/src/infer_ctxt.rs b/compiler/rustc_type_ir/src/infer_ctxt.rs index 6c77a90250a..e86a2305e23 100644 --- a/compiler/rustc_type_ir/src/infer_ctxt.rs +++ b/compiler/rustc_type_ir/src/infer_ctxt.rs @@ -285,3 +285,40 @@ pub trait InferCtxtLike: Sized { fn reset_opaque_types(&self); } + +pub fn may_use_unstable_feature<'a, I: Interner, Infcx>( + infcx: &'a Infcx, + param_env: I::ParamEnv, + symbol: I::Symbol, +) -> bool +where + Infcx: InferCtxtLike<Interner = I>, +{ + // Iterate through all goals in param_env to find the one that has the same symbol. + for pred in param_env.caller_bounds().iter() { + if let ty::ClauseKind::UnstableFeature(sym) = pred.kind().skip_binder() { + if sym == symbol { + return true; + } + } + } + + // During codegen we must assume that all feature bounds hold as we may be + // monomorphizing a body from an upstream crate which had an unstable feature + // enabled that we do not. + // + // Coherence should already report overlap errors involving unstable impls + // as the affected code would otherwise break when stabilizing this feature. + // It is also easily possible to accidentally cause unsoundness this way as + // we have to always enable unstable impls during codegen. + // + // Return ambiguity can also prevent people from writing code which depends on inference guidance + // that might no longer work after the impl is stabilised, + // tests/ui/unstable-feature-bound/unstable_impl_method_selection.rs is one of the example. + // + // Note: `feature_bound_holds_in_crate` does not consider a feature to be enabled + // if we are in std/core even if there is a corresponding `feature` attribute on the crate. + + (infcx.typing_mode() == TypingMode::PostAnalysis) + || infcx.cx().features().feature_bound_holds_in_crate(symbol) +} diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index 2754d40fd36..0e307e15d5b 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -630,6 +630,8 @@ pub trait Features<I: Interner>: Copy { fn coroutine_clone(self) -> bool; fn associated_const_equality(self) -> bool; + + fn feature_bound_holds_in_crate(self, symbol: I::Symbol) -> bool; } pub trait DefId<I: Interner>: Copy + Debug + Hash + Eq + TypeFoldable<I> { diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index dd3cf1fc181..0ec326d2116 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -106,6 +106,7 @@ pub trait Interner: type ParamTy: ParamLike; type BoundTy: BoundVarLike<Self>; type PlaceholderTy: PlaceholderLike<Self, Bound = Self::BoundTy>; + type Symbol: Copy + Hash + PartialEq + Eq + Debug; // Things stored inside of tys type ErrorGuaranteed: Copy + Debug + Hash + Eq; diff --git a/compiler/rustc_type_ir/src/predicate_kind.rs b/compiler/rustc_type_ir/src/predicate_kind.rs index 4e41fd16ffd..8bc15ec4ff5 100644 --- a/compiler/rustc_type_ir/src/predicate_kind.rs +++ b/compiler/rustc_type_ir/src/predicate_kind.rs @@ -46,6 +46,13 @@ pub enum ClauseKind<I: Interner> { /// corresponding trait clause; this just enforces the *constness* of that /// implementation. HostEffect(ty::HostEffectPredicate<I>), + + /// Support marking impl as unstable. + UnstableFeature( + #[type_foldable(identity)] + #[type_visitable(ignore)] + I::Symbol, + ), } #[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)] @@ -134,6 +141,9 @@ impl<I: Interner> fmt::Debug for ClauseKind<I> { ClauseKind::ConstEvaluatable(ct) => { write!(f, "ConstEvaluatable({ct:?})") } + ClauseKind::UnstableFeature(feature_name) => { + write!(f, "UnstableFeature({feature_name:?})") + } } } } diff --git a/library/Cargo.lock b/library/Cargo.lock index c681c5935df..8b5275e5065 100644 --- a/library/Cargo.lock +++ b/library/Cargo.lock @@ -271,9 +271,9 @@ dependencies = [ [[package]] name = "rustc-literal-escaper" -version = "0.0.4" +version = "0.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab03008eb631b703dd16978282ae36c73282e7922fe101a4bd072a40ecea7b8b" +checksum = "e4ee29da77c5a54f42697493cd4c9b9f31b74df666a6c04dfc4fde77abe0438b" dependencies = [ "rustc-std-workspace-core", "rustc-std-workspace-std", diff --git a/library/alloc/src/boxed/thin.rs b/library/alloc/src/boxed/thin.rs index 21425b9846e..1cce36606d2 100644 --- a/library/alloc/src/boxed/thin.rs +++ b/library/alloc/src/boxed/thin.rs @@ -5,7 +5,7 @@ use core::error::Error; use core::fmt::{self, Debug, Display, Formatter}; #[cfg(not(no_global_oom_handling))] -use core::intrinsics::const_allocate; +use core::intrinsics::{const_allocate, const_make_global}; use core::marker::PhantomData; #[cfg(not(no_global_oom_handling))] use core::marker::Unsize; @@ -340,9 +340,10 @@ impl<H> WithHeader<H> { alloc.add(metadata_offset).cast(); // SAFETY: `*metadata_ptr` is within the allocation. metadata_ptr.write(ptr::metadata::<Dyn>(ptr::dangling::<T>() as *const Dyn)); - + // SAFETY: valid heap allocation + const_make_global(alloc); // SAFETY: we have just written the metadata. - &*(metadata_ptr) + &*metadata_ptr } }; diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs index 881a7a24083..c43f3834630 100644 --- a/library/core/src/ffi/c_str.rs +++ b/library/core/src/ffi/c_str.rs @@ -135,16 +135,20 @@ pub enum FromBytesWithNulError { } #[stable(feature = "frombyteswithnulerror_impls", since = "1.17.0")] -impl Error for FromBytesWithNulError { - #[allow(deprecated)] - fn description(&self) -> &str { +impl fmt::Display for FromBytesWithNulError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - Self::InteriorNul { .. } => "data provided contains an interior nul byte", - Self::NotNulTerminated => "data provided is not nul terminated", + Self::InteriorNul { position } => { + write!(f, "data provided contains an interior nul byte at byte position {position}") + } + Self::NotNulTerminated => write!(f, "data provided is not nul terminated"), } } } +#[stable(feature = "frombyteswithnulerror_impls", since = "1.17.0")] +impl Error for FromBytesWithNulError {} + /// An error indicating that no nul byte was present. /// /// A slice used to create a [`CStr`] must contain a nul byte somewhere @@ -181,18 +185,6 @@ impl Default for &CStr { } } -#[stable(feature = "frombyteswithnulerror_impls", since = "1.17.0")] -impl fmt::Display for FromBytesWithNulError { - #[allow(deprecated, deprecated_in_future)] - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(self.description())?; - if let Self::InteriorNul { position } = self { - write!(f, " at byte pos {position}")?; - } - Ok(()) - } -} - impl CStr { /// Wraps a raw C string with a safe C string wrapper. /// diff --git a/library/core/src/fmt/num.rs b/library/core/src/fmt/num.rs index e1381ace441..7d41ae45093 100644 --- a/library/core/src/fmt/num.rs +++ b/library/core/src/fmt/num.rs @@ -358,7 +358,7 @@ macro_rules! impl_Display { } #[cfg(feature = "optimize_for_size")] { - offset = _inner_slow_integer_to_str(self.unsigned_abs().$conv_fn(), &mut buf.buf); + offset = ${concat(_inner_slow_integer_to_str, $gen_name)}(self.unsigned_abs().$conv_fn(), &mut buf.buf); } // Only difference between signed and unsigned are these 4 lines. if self < 0 { @@ -401,7 +401,7 @@ macro_rules! impl_Display { } #[cfg(feature = "optimize_for_size")] { - offset = _inner_slow_integer_to_str(self.$conv_fn(), &mut buf.buf); + offset = ${concat(_inner_slow_integer_to_str, $gen_name)}(self.$conv_fn(), &mut buf.buf); } // SAFETY: Starting from `offset`, all elements of the slice have been set. unsafe { slice_buffer_to_str(&buf.buf, offset) } @@ -412,7 +412,7 @@ macro_rules! impl_Display { )* #[cfg(feature = "optimize_for_size")] - fn _inner_slow_integer_to_str(mut n: $u, buf: &mut [MaybeUninit::<u8>]) -> usize { + fn ${concat(_inner_slow_integer_to_str, $gen_name)}(mut n: $u, buf: &mut [MaybeUninit::<u8>]) -> usize { let mut curr = buf.len(); // SAFETY: To show that it's OK to copy into `buf_ptr`, notice that at the beginning @@ -437,7 +437,7 @@ macro_rules! impl_Display { const MAX_DEC_N: usize = $u::MAX.ilog(10) as usize + 1; let mut buf = [MaybeUninit::<u8>::uninit(); MAX_DEC_N]; - let offset = _inner_slow_integer_to_str(n, &mut buf); + let offset = ${concat(_inner_slow_integer_to_str, $gen_name)}(n, &mut buf); // SAFETY: Starting from `offset`, all elements of the slice have been set. let buf_slice = unsafe { slice_buffer_to_str(&buf, offset) }; f.pad_integral(is_nonnegative, "", buf_slice) diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index 1ece3d9bd5e..fa27acac217 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -2533,6 +2533,15 @@ pub const unsafe fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) // Runtime NOP } +#[rustc_const_unstable(feature = "const_heap", issue = "79597")] +#[rustc_nounwind] +#[rustc_intrinsic] +#[miri::intrinsic_fallback_is_spec] +pub const unsafe fn const_make_global(ptr: *mut u8) -> *const u8 { + // const eval overrides this function; at runtime, it is a NOP. + ptr +} + /// Returns whether we should perform contract-checking at runtime. /// /// This is meant to be similar to the ub_checks intrinsic, in terms diff --git a/library/core/src/io/borrowed_buf.rs b/library/core/src/io/borrowed_buf.rs index b5dfe6dbd71..088dea78129 100644 --- a/library/core/src/io/borrowed_buf.rs +++ b/library/core/src/io/borrowed_buf.rs @@ -149,7 +149,6 @@ impl<'data> BorrowedBuf<'data> { #[inline] pub fn unfilled<'this>(&'this mut self) -> BorrowedCursor<'this> { BorrowedCursor { - start: self.filled, // SAFETY: we never assign into `BorrowedCursor::buf`, so treating its // lifetime covariantly is safe. buf: unsafe { @@ -205,9 +204,6 @@ pub struct BorrowedCursor<'a> { // we create a `BorrowedCursor`. This is only safe if we never replace `buf` by assigning into // it, so don't do that! buf: &'a mut BorrowedBuf<'a>, - /// The length of the filled portion of the underlying buffer at the time of the cursor's - /// creation. - start: usize, } impl<'a> BorrowedCursor<'a> { @@ -225,7 +221,6 @@ impl<'a> BorrowedCursor<'a> { self.buf, ) }, - start: self.start, } } @@ -235,23 +230,12 @@ impl<'a> BorrowedCursor<'a> { self.buf.capacity() - self.buf.filled } - /// Returns the number of bytes written to this cursor since it was created from a `BorrowedBuf`. + /// Returns the number of bytes written to the `BorrowedBuf` this cursor was created from. /// - /// Note that if this cursor is a reborrowed clone of another, then the count returned is the - /// count written via either cursor, not the count since the cursor was reborrowed. + /// In particular, the count returned is shared by all reborrows of the cursor. #[inline] pub fn written(&self) -> usize { - self.buf.filled - self.start - } - - /// Returns a shared reference to the initialized portion of the cursor. - #[inline] - pub fn init_ref(&self) -> &[u8] { - // SAFETY: We only slice the initialized part of the buffer, which is always valid - unsafe { - let buf = self.buf.buf.get_unchecked(self.buf.filled..self.buf.init); - buf.assume_init_ref() - } + self.buf.filled } /// Returns a mutable reference to the initialized portion of the cursor. @@ -264,15 +248,6 @@ impl<'a> BorrowedCursor<'a> { } } - /// Returns a mutable reference to the uninitialized part of the cursor. - /// - /// It is safe to uninitialize any of these bytes. - #[inline] - pub fn uninit_mut(&mut self) -> &mut [MaybeUninit<u8>] { - // SAFETY: always in bounds - unsafe { self.buf.buf.get_unchecked_mut(self.buf.init..) } - } - /// Returns a mutable reference to the whole cursor. /// /// # Safety @@ -325,7 +300,9 @@ impl<'a> BorrowedCursor<'a> { /// Initializes all bytes in the cursor. #[inline] pub fn ensure_init(&mut self) -> &mut Self { - let uninit = self.uninit_mut(); + // SAFETY: always in bounds and we never uninitialize these bytes. + let uninit = unsafe { self.buf.buf.get_unchecked_mut(self.buf.init..) }; + // SAFETY: 0 is a valid value for MaybeUninit<u8> and the length matches the allocation // since it is comes from a slice reference. unsafe { diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 2f701171505..e08edde3b38 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -160,6 +160,7 @@ #![feature(lang_items)] #![feature(link_llvm_intrinsics)] #![feature(macro_metavar_expr)] +#![feature(macro_metavar_expr_concat)] #![feature(marker_trait_attr)] #![feature(min_specialization)] #![feature(multiple_supertrait_upcastable)] diff --git a/library/coretests/tests/io/borrowed_buf.rs b/library/coretests/tests/io/borrowed_buf.rs index 73dbfaf5ee9..4074148436c 100644 --- a/library/coretests/tests/io/borrowed_buf.rs +++ b/library/coretests/tests/io/borrowed_buf.rs @@ -61,7 +61,7 @@ fn clear() { assert_eq!(rbuf.filled().len(), 0); assert_eq!(rbuf.unfilled().capacity(), 16); - assert_eq!(rbuf.unfilled().init_ref(), [255; 16]); + assert_eq!(rbuf.unfilled().init_mut(), [255; 16]); } #[test] @@ -124,7 +124,7 @@ fn reborrow_written() { assert_eq!(cursor2.written(), 32); assert_eq!(cursor.written(), 32); - assert_eq!(buf.unfilled().written(), 0); + assert_eq!(buf.unfilled().written(), 32); assert_eq!(buf.init_len(), 32); assert_eq!(buf.filled().len(), 32); let filled = buf.filled(); @@ -142,9 +142,7 @@ fn cursor_set_init() { } assert_eq!(rbuf.init_len(), 8); - assert_eq!(rbuf.unfilled().init_ref().len(), 8); assert_eq!(rbuf.unfilled().init_mut().len(), 8); - assert_eq!(rbuf.unfilled().uninit_mut().len(), 8); assert_eq!(unsafe { rbuf.unfilled().as_mut().len() }, 16); rbuf.unfilled().advance(4); @@ -160,9 +158,7 @@ fn cursor_set_init() { } assert_eq!(rbuf.init_len(), 12); - assert_eq!(rbuf.unfilled().init_ref().len(), 8); assert_eq!(rbuf.unfilled().init_mut().len(), 8); - assert_eq!(rbuf.unfilled().uninit_mut().len(), 4); assert_eq!(unsafe { rbuf.unfilled().as_mut().len() }, 12); } diff --git a/library/proc_macro/Cargo.toml b/library/proc_macro/Cargo.toml index 8ea92088a84..0042a6e8ece 100644 --- a/library/proc_macro/Cargo.toml +++ b/library/proc_macro/Cargo.toml @@ -9,7 +9,7 @@ std = { path = "../std" } # `core` when resolving doc links. Without this line a different `core` will be # loaded from sysroot causing duplicate lang items and other similar errors. core = { path = "../core" } -rustc-literal-escaper = { version = "0.0.4", features = ["rustc-dep-of-std"] } +rustc-literal-escaper = { version = "0.0.5", features = ["rustc-dep-of-std"] } [features] default = ["rustc-dep-of-std"] diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs index ff326342989..162b4fdcc8a 100644 --- a/library/proc_macro/src/lib.rs +++ b/library/proc_macro/src/lib.rs @@ -1471,11 +1471,11 @@ impl Literal { let mut error = None; let mut buf = Vec::with_capacity(symbol.len()); - unescape_c_str(symbol, |_span, c| match c { + unescape_c_str(symbol, |_span, res| match res { Ok(MixedUnit::Char(c)) => { - buf.extend_from_slice(c.encode_utf8(&mut [0; 4]).as_bytes()) + buf.extend_from_slice(c.get().encode_utf8(&mut [0; 4]).as_bytes()) } - Ok(MixedUnit::HighByte(b)) => buf.push(b), + Ok(MixedUnit::HighByte(b)) => buf.push(b.get()), Err(err) => { if err.is_fatal() { error = Some(ConversionErrorKind::FailedToUnescape(err)); diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 86d23df5238..5c3132a7375 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -23,7 +23,7 @@ unwind = { path = "../unwind" } hashbrown = { version = "0.15", default-features = false, features = [ 'rustc-dep-of-std', ] } -std_detect = { path = "../stdarch/crates/std_detect", default-features = false, features = [ +std_detect = { path = "../stdarch/crates/std_detect", public = true, default-features = false, features = [ 'rustc-dep-of-std', ] } diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 17c32d7a571..d351ee5e739 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -489,7 +489,7 @@ pub(crate) fn default_read_to_end<R: Read + ?Sized>( } }; - let unfilled_but_initialized = cursor.init_ref().len(); + let unfilled_but_initialized = cursor.init_mut().len(); let bytes_read = cursor.written(); let was_fully_initialized = read_buf.init_len() == buf_len; @@ -3053,7 +3053,7 @@ impl<T: Read> Read for Take<T> { // The condition above guarantees that `self.limit` fits in `usize`. let limit = self.limit as usize; - let extra_init = cmp::min(limit, buf.init_ref().len()); + let extra_init = cmp::min(limit, buf.init_mut().len()); // SAFETY: no uninit data is written to ibuf let ibuf = unsafe { &mut buf.as_mut()[..limit] }; @@ -3068,7 +3068,7 @@ impl<T: Read> Read for Take<T> { let mut cursor = sliced_buf.unfilled(); let result = self.inner.read_buf(cursor.reborrow()); - let new_init = cursor.init_ref().len(); + let new_init = cursor.init_mut().len(); let filled = sliced_buf.len(); // cursor / sliced_buf / ibuf must drop here diff --git a/library/std/src/sync/poison.rs b/library/std/src/sync/poison.rs index 571f0d14248..0c05f152ef8 100644 --- a/library/std/src/sync/poison.rs +++ b/library/std/src/sync/poison.rs @@ -10,7 +10,7 @@ //! (some invariant is not being upheld). //! //! The specifics of how this "poisoned" state affects other threads -//! depend on the primitive. See [#Overview] bellow. +//! depend on the primitive. See [#Overview] below. //! //! For the alternative implementations that do not employ poisoning, //! see `std::sync::nonpoisoning`. diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs index eee169d410a..edac5262a4e 100644 --- a/library/std/src/sys/pal/windows/c.rs +++ b/library/std/src/sys/pal/windows/c.rs @@ -197,7 +197,7 @@ compat_fn_optional! { pub fn WakeByAddressSingle(address: *const c_void); } -#[cfg(any(target_vendor = "win7", target_vendor = "uwp"))] +#[cfg(any(target_vendor = "win7"))] compat_fn_with_fallback! { pub static NTDLL: &CStr = c"ntdll"; @@ -228,65 +228,14 @@ compat_fn_with_fallback! { ) -> NTSTATUS { panic!("keyed events not available") } +} - // These functions are available on UWP when lazily loaded. They will fail WACK if loaded statically. - #[cfg(target_vendor = "uwp")] - pub fn NtCreateFile( - filehandle: *mut HANDLE, - desiredaccess: FILE_ACCESS_RIGHTS, - objectattributes: *const OBJECT_ATTRIBUTES, - iostatusblock: *mut IO_STATUS_BLOCK, - allocationsize: *const i64, - fileattributes: FILE_FLAGS_AND_ATTRIBUTES, - shareaccess: FILE_SHARE_MODE, - createdisposition: NTCREATEFILE_CREATE_DISPOSITION, - createoptions: NTCREATEFILE_CREATE_OPTIONS, - eabuffer: *const c_void, - ealength: u32 - ) -> NTSTATUS { - STATUS_NOT_IMPLEMENTED - } - #[cfg(target_vendor = "uwp")] - pub fn NtOpenFile( - filehandle: *mut HANDLE, - desiredaccess: u32, - objectattributes: *const OBJECT_ATTRIBUTES, - iostatusblock: *mut IO_STATUS_BLOCK, - shareaccess: u32, - openoptions: u32 - ) -> NTSTATUS { - STATUS_NOT_IMPLEMENTED - } - #[cfg(target_vendor = "uwp")] - pub fn NtReadFile( - filehandle: HANDLE, - event: HANDLE, - apcroutine: PIO_APC_ROUTINE, - apccontext: *const c_void, - iostatusblock: *mut IO_STATUS_BLOCK, - buffer: *mut c_void, - length: u32, - byteoffset: *const i64, - key: *const u32 - ) -> NTSTATUS { - STATUS_NOT_IMPLEMENTED - } - #[cfg(target_vendor = "uwp")] - pub fn NtWriteFile( - filehandle: HANDLE, - event: HANDLE, - apcroutine: PIO_APC_ROUTINE, - apccontext: *const c_void, - iostatusblock: *mut IO_STATUS_BLOCK, - buffer: *const c_void, - length: u32, - byteoffset: *const i64, - key: *const u32 - ) -> NTSTATUS { - STATUS_NOT_IMPLEMENTED - } - #[cfg(target_vendor = "uwp")] - pub fn RtlNtStatusToDosError(Status: NTSTATUS) -> u32 { - Status as u32 +cfg_if::cfg_if! { + if #[cfg(target_vendor = "uwp")] { + windows_targets::link_raw_dylib!("ntdll.dll" "system" fn NtCreateFile(filehandle : *mut HANDLE, desiredaccess : FILE_ACCESS_RIGHTS, objectattributes : *const OBJECT_ATTRIBUTES, iostatusblock : *mut IO_STATUS_BLOCK, allocationsize : *const i64, fileattributes : FILE_FLAGS_AND_ATTRIBUTES, shareaccess : FILE_SHARE_MODE, createdisposition : NTCREATEFILE_CREATE_DISPOSITION, createoptions : NTCREATEFILE_CREATE_OPTIONS, eabuffer : *const core::ffi::c_void, ealength : u32) -> NTSTATUS); + windows_targets::link_raw_dylib!("ntdll.dll" "system" fn NtOpenFile(filehandle : *mut HANDLE, desiredaccess : u32, objectattributes : *const OBJECT_ATTRIBUTES, iostatusblock : *mut IO_STATUS_BLOCK, shareaccess : u32, openoptions : u32) -> NTSTATUS); + windows_targets::link_raw_dylib!("ntdll.dll" "system" fn NtReadFile(filehandle : HANDLE, event : HANDLE, apcroutine : PIO_APC_ROUTINE, apccontext : *const core::ffi::c_void, iostatusblock : *mut IO_STATUS_BLOCK, buffer : *mut core::ffi::c_void, length : u32, byteoffset : *const i64, key : *const u32) -> NTSTATUS); + windows_targets::link_raw_dylib!("ntdll.dll" "system" fn NtWriteFile(filehandle : HANDLE, event : HANDLE, apcroutine : PIO_APC_ROUTINE, apccontext : *const core::ffi::c_void, iostatusblock : *mut IO_STATUS_BLOCK, buffer : *const core::ffi::c_void, length : u32, byteoffset : *const i64, key : *const u32) -> NTSTATUS); + windows_targets::link_raw_dylib!("ntdll.dll" "system" fn RtlNtStatusToDosError(status : NTSTATUS) -> u32); } } diff --git a/library/windows_targets/src/lib.rs b/library/windows_targets/src/lib.rs index bce54c5ffce..9e82e6a7200 100644 --- a/library/windows_targets/src/lib.rs +++ b/library/windows_targets/src/lib.rs @@ -7,8 +7,7 @@ #![feature(decl_macro)] #![feature(no_core)] -#[cfg(feature = "windows_raw_dylib")] -pub macro link { +pub macro link_raw_dylib { ($library:literal $abi:literal $($link_name:literal)? $(#[$doc:meta])? fn $($function:tt)*) => ( #[cfg_attr(not(target_arch = "x86"), link(name = $library, kind = "raw-dylib", modifiers = "+verbatim"))] #[cfg_attr(target_arch = "x86", link(name = $library, kind = "raw-dylib", modifiers = "+verbatim", import_name_type = "undecorated"))] @@ -18,6 +17,26 @@ pub macro link { } ) } + +pub macro link_dylib { + ($library:literal $abi:literal $($link_name:literal)? $(#[$doc:meta])? fn $($function:tt)*) => ( + // Note: the windows-targets crate uses a pre-built Windows.lib import library which we don't + // have in this repo. So instead we always link kernel32.lib and add the rest of the import + // libraries below by using an empty extern block. This works because extern blocks are not + // connected to the library given in the #[link] attribute. + #[link(name = "kernel32")] + unsafe extern $abi { + $(#[link_name=$link_name])? + pub fn $($function)*; + } + ) +} + +#[cfg(feature = "windows_raw_dylib")] +pub macro link($($tt:tt)*) { + $crate::link_raw_dylib!($($tt)*) +} + #[cfg(not(feature = "windows_raw_dylib"))] pub macro link { ($library:literal $abi:literal $($link_name:literal)? $(#[$doc:meta])? fn $($function:tt)*) => ( diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 28958b60fc3..22a75183404 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -697,7 +697,7 @@ impl Config { config.change_id = toml.change_id.inner; let Build { - mut description, + description, build, host, target, @@ -749,7 +749,7 @@ impl Config { compiletest_diff_tool, compiletest_use_stage0_libtest, tidy_extra_checks, - mut ccache, + ccache, exclude, } = toml.build.unwrap_or_default(); @@ -942,7 +942,7 @@ impl Config { config.rust_profile_use = flags_rust_profile_use; config.rust_profile_generate = flags_rust_profile_generate; - config.apply_rust_config(toml.rust, flags_warnings, &mut description); + config.apply_rust_config(toml.rust, flags_warnings); config.reproducible_artifacts = flags_reproducible_artifact; config.description = description; @@ -963,7 +963,7 @@ impl Config { config.channel = channel; } - config.apply_llvm_config(toml.llvm, &mut ccache); + config.apply_llvm_config(toml.llvm); config.apply_gcc_config(toml.gcc); diff --git a/src/bootstrap/src/core/config/toml/llvm.rs b/src/bootstrap/src/core/config/toml/llvm.rs index 4774e202bd8..1f0cecd145c 100644 --- a/src/bootstrap/src/core/config/toml/llvm.rs +++ b/src/bootstrap/src/core/config/toml/llvm.rs @@ -17,8 +17,6 @@ define_config! { tests: Option<bool> = "tests", enzyme: Option<bool> = "enzyme", plugins: Option<bool> = "plugins", - // FIXME: Remove this field at Q2 2025, it has been replaced by build.ccache - ccache: Option<StringOrBool> = "ccache", static_libstdcpp: Option<bool> = "static-libstdcpp", libzstd: Option<bool> = "libzstd", ninja: Option<bool> = "ninja", @@ -97,7 +95,6 @@ pub fn check_incompatible_options_for_ci_llvm( assertions: _, tests: _, plugins, - ccache: _, static_libstdcpp: _, libzstd, ninja: _, @@ -149,11 +146,7 @@ pub fn check_incompatible_options_for_ci_llvm( } impl Config { - pub fn apply_llvm_config( - &mut self, - toml_llvm: Option<Llvm>, - ccache: &mut Option<StringOrBool>, - ) { + pub fn apply_llvm_config(&mut self, toml_llvm: Option<Llvm>) { let mut llvm_tests = None; let mut llvm_enzyme = None; let mut llvm_offload = None; @@ -168,7 +161,6 @@ impl Config { tests, enzyme, plugins, - ccache: llvm_ccache, static_libstdcpp, libzstd, ninja, @@ -191,13 +183,7 @@ impl Config { download_ci_llvm, build_config, } = llvm; - if llvm_ccache.is_some() { - eprintln!("Warning: llvm.ccache is deprecated. Use build.ccache instead."); - } - if ccache.is_none() { - *ccache = llvm_ccache; - } set(&mut self.ninja_in_file, ninja); llvm_tests = tests; llvm_enzyme = enzyme; diff --git a/src/bootstrap/src/core/config/toml/rust.rs b/src/bootstrap/src/core/config/toml/rust.rs index 0fae235bb93..307aa52294b 100644 --- a/src/bootstrap/src/core/config/toml/rust.rs +++ b/src/bootstrap/src/core/config/toml/rust.rs @@ -36,8 +36,6 @@ define_config! { incremental: Option<bool> = "incremental", default_linker: Option<String> = "default-linker", channel: Option<String> = "channel", - // FIXME: Remove this field at Q2 2025, it has been replaced by build.description - description: Option<String> = "description", musl_root: Option<String> = "musl-root", rpath: Option<bool> = "rpath", strip: Option<bool> = "strip", @@ -320,7 +318,6 @@ pub fn check_incompatible_options_for_ci_rustc( jemalloc, rpath, channel, - description, default_linker, std_features, @@ -388,7 +385,6 @@ pub fn check_incompatible_options_for_ci_rustc( err!(current_rust_config.std_features, std_features, "rust"); warn!(current_rust_config.channel, channel, "rust"); - warn!(current_rust_config.description, description, "rust"); Ok(()) } @@ -415,12 +411,7 @@ pub(crate) fn validate_codegen_backends(backends: Vec<String>, section: &str) -> } impl Config { - pub fn apply_rust_config( - &mut self, - toml_rust: Option<Rust>, - warnings: Warnings, - description: &mut Option<String>, - ) { + pub fn apply_rust_config(&mut self, toml_rust: Option<Rust>, warnings: Warnings) { let mut debug = None; let mut rustc_debug_assertions = None; let mut std_debug_assertions = None; @@ -459,7 +450,6 @@ impl Config { randomize_layout, default_linker, channel: _, // already handled above - description: rust_description, musl_root, rpath, verbose_tests, @@ -552,14 +542,6 @@ impl Config { set(&mut self.jemalloc, jemalloc); set(&mut self.test_compare_mode, test_compare_mode); set(&mut self.backtrace, backtrace); - if rust_description.is_some() { - eprintln!( - "Warning: rust.description is deprecated. Use build.description instead." - ); - } - if description.is_none() { - *description = rust_description; - } set(&mut self.rust_dist_src, dist_src); set(&mut self.verbose_tests, verbose_tests); // in the case "false" is set explicitly, do not overwrite the command line args diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs index d888a7863bc..f802640a42d 100644 --- a/src/bootstrap/src/utils/change_tracker.rs +++ b/src/bootstrap/src/utils/change_tracker.rs @@ -481,4 +481,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[ severity: ChangeSeverity::Warning, summary: "The current `./x suggest` implementation has been removed due to it being quite broken and a lack of maintenance bandwidth, with no prejudice against re-implementing it in a more maintainable form.", }, + ChangeInfo { + change_id: 143926, + severity: ChangeSeverity::Warning, + summary: "Removed `rust.description` and `llvm.ccache` as it was deprecated in #137723 and #136941 long time ago.", + }, ]; diff --git a/src/build_helper/src/lib.rs b/src/build_helper/src/lib.rs index 05de8fd2d42..266eedc6245 100644 --- a/src/build_helper/src/lib.rs +++ b/src/build_helper/src/lib.rs @@ -5,6 +5,7 @@ pub mod drop_bomb; pub mod fs; pub mod git; pub mod metrics; +pub mod npm; pub mod stage0_parser; pub mod targets; pub mod util; diff --git a/src/build_helper/src/npm.rs b/src/build_helper/src/npm.rs new file mode 100644 index 00000000000..dedef40978d --- /dev/null +++ b/src/build_helper/src/npm.rs @@ -0,0 +1,30 @@ +use std::error::Error; +use std::path::{Path, PathBuf}; +use std::process::Command; +use std::{fs, io}; + +/// Install an exact package version, and return the path of `node_modules`. +pub fn install_one( + out_dir: &Path, + npm_bin: &Path, + pkg_name: &str, + pkg_version: &str, +) -> Result<PathBuf, io::Error> { + let nm_path = out_dir.join("node_modules"); + let _ = fs::create_dir(&nm_path); + let mut child = Command::new(npm_bin) + .arg("install") + .arg("--audit=false") + .arg("--fund=false") + .arg(format!("{pkg_name}@{pkg_version}")) + .current_dir(out_dir) + .spawn()?; + let exit_status = child.wait()?; + if !exit_status.success() { + eprintln!("npm install did not exit successfully"); + return Err(io::Error::other(Box::<dyn Error + Send + Sync>::from(format!( + "npm install returned exit code {exit_status}" + )))); + } + Ok(nm_path) +} diff --git a/src/ci/docker/host-aarch64/aarch64-gnu-llvm-19/Dockerfile b/src/ci/docker/host-aarch64/aarch64-gnu-llvm-19/Dockerfile index 2f9d0010573..e73fbe506f7 100644 --- a/src/ci/docker/host-aarch64/aarch64-gnu-llvm-19/Dockerfile +++ b/src/ci/docker/host-aarch64/aarch64-gnu-llvm-19/Dockerfile @@ -50,9 +50,7 @@ ENV RUST_CONFIGURE_ARGS \ COPY scripts/shared.sh /scripts/ -ARG SCRIPT_ARG +COPY scripts/stage_2_test_set1.sh /scripts/ +COPY scripts/stage_2_test_set2.sh /scripts/ -COPY scripts/stage_2_test_set1.sh /tmp/ -COPY scripts/stage_2_test_set2.sh /tmp/ - -ENV SCRIPT "/tmp/${SCRIPT_ARG}" +ENV SCRIPT "Must specify DOCKER_SCRIPT for this image" diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile index 44f6a8d2a15..01f19eac1d2 100644 --- a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile @@ -96,12 +96,10 @@ ENV RUST_CONFIGURE_ARGS \ --set rust.lto=thin \ --set rust.codegen-units=1 -ARG SCRIPT_ARG - COPY host-x86_64/dist-x86_64-linux/dist.sh /scripts/ COPY host-x86_64/dist-x86_64-linux/dist-alt.sh /scripts/ -ENV SCRIPT /scripts/${SCRIPT_ARG} +ENV SCRIPT "Must specify DOCKER_SCRIPT for this image" ENV CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER=clang diff --git a/src/ci/docker/host-x86_64/i686-gnu-nopt/Dockerfile b/src/ci/docker/host-x86_64/i686-gnu-nopt/Dockerfile index 58e66fd637a..be3df9d4036 100644 --- a/src/ci/docker/host-x86_64/i686-gnu-nopt/Dockerfile +++ b/src/ci/docker/host-x86_64/i686-gnu-nopt/Dockerfile @@ -23,7 +23,7 @@ COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh ENV RUST_CONFIGURE_ARGS --build=i686-unknown-linux-gnu --disable-optimize-tests -ARG SCRIPT_ARG COPY scripts/stage_2_test_set1.sh /scripts/ COPY scripts/stage_2_test_set2.sh /scripts/ -ENV SCRIPT ${SCRIPT_ARG} +COPY scripts/i686-gnu-nopt-2.sh /scripts/ +ENV SCRIPT "Must specify DOCKER_SCRIPT for this image" diff --git a/src/ci/docker/host-x86_64/i686-gnu/Dockerfile b/src/ci/docker/host-x86_64/i686-gnu/Dockerfile index a715f7182d2..00cd24b89db 100644 --- a/src/ci/docker/host-x86_64/i686-gnu/Dockerfile +++ b/src/ci/docker/host-x86_64/i686-gnu/Dockerfile @@ -24,7 +24,6 @@ COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh ENV RUST_CONFIGURE_ARGS --build=i686-unknown-linux-gnu -ARG SCRIPT_ARG COPY scripts/stage_2_test_set1.sh /scripts/ COPY scripts/stage_2_test_set2.sh /scripts/ -ENV SCRIPT /scripts/${SCRIPT_ARG} +ENV SCRIPT "Must specify DOCKER_SCRIPT for this image" diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-19/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-19/Dockerfile index c09be047c6a..5cba7c564f1 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-19/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-19/Dockerfile @@ -57,12 +57,10 @@ ENV RUST_CONFIGURE_ARGS \ COPY scripts/shared.sh /scripts/ -ARG SCRIPT_ARG +COPY scripts/x86_64-gnu-llvm.sh /scripts/ +COPY scripts/x86_64-gnu-llvm2.sh /scripts/ +COPY scripts/x86_64-gnu-llvm3.sh /scripts/ +COPY scripts/stage_2_test_set1.sh /scripts/ +COPY scripts/stage_2_test_set2.sh /scripts/ -COPY scripts/x86_64-gnu-llvm.sh /tmp/ -COPY scripts/x86_64-gnu-llvm2.sh /tmp/ -COPY scripts/x86_64-gnu-llvm3.sh /tmp/ -COPY scripts/stage_2_test_set1.sh /tmp/ -COPY scripts/stage_2_test_set2.sh /tmp/ - -ENV SCRIPT "/tmp/${SCRIPT_ARG}" +ENV SCRIPT "Must specify DOCKER_SCRIPT for this image" diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-20/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-20/Dockerfile index 83a3bfb37a5..92c2631000f 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-20/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-20/Dockerfile @@ -57,12 +57,10 @@ ENV RUST_CONFIGURE_ARGS \ COPY scripts/shared.sh /scripts/ -ARG SCRIPT_ARG +COPY scripts/x86_64-gnu-llvm.sh /scripts/ +COPY scripts/x86_64-gnu-llvm2.sh /scripts/ +COPY scripts/x86_64-gnu-llvm3.sh /scripts/ +COPY scripts/stage_2_test_set1.sh /scripts/ +COPY scripts/stage_2_test_set2.sh /scripts/ -COPY scripts/x86_64-gnu-llvm.sh /tmp/ -COPY scripts/x86_64-gnu-llvm2.sh /tmp/ -COPY scripts/x86_64-gnu-llvm3.sh /tmp/ -COPY scripts/stage_2_test_set1.sh /tmp/ -COPY scripts/stage_2_test_set2.sh /tmp/ - -ENV SCRIPT "/tmp/${SCRIPT_ARG}" +ENV SCRIPT "Must specify DOCKER_SCRIPT for this image" diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-miri/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-miri/Dockerfile index b937bc3e678..ad2ee85c7bb 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-miri/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-miri/Dockerfile @@ -46,12 +46,4 @@ ENV HOST_TARGET x86_64-unknown-linux-gnu COPY scripts/shared.sh /scripts/ -# For now, we need to use `--unsafe-perm=true` to go around an issue when npm tries -# to create a new folder. For reference: -# https://github.com/puppeteer/puppeteer/issues/375 -# -# We also specify the version in case we need to update it to go around cache limitations. -# -# The `browser-ui-test.version` file is also used by bootstrap to emit warnings in case -# the local version of the package is different than the one used by the CI. ENV SCRIPT /tmp/check-miri.sh ../x.py diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile index e770c58bd9c..95357d22937 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile @@ -76,8 +76,6 @@ COPY scripts/nodejs.sh /scripts/ RUN sh /scripts/nodejs.sh /node ENV PATH="/node/bin:${PATH}" -COPY host-x86_64/x86_64-gnu-tools/browser-ui-test.version /tmp/ - ENV RUST_CONFIGURE_ARGS \ --build=x86_64-unknown-linux-gnu \ --save-toolstates=/tmp/toolstate/toolstates.json \ @@ -91,15 +89,6 @@ ENV HOST_TARGET x86_64-unknown-linux-gnu COPY scripts/shared.sh /scripts/ -# For now, we need to use `--unsafe-perm=true` to go around an issue when npm tries -# to create a new folder. For reference: -# https://github.com/puppeteer/puppeteer/issues/375 -# -# We also specify the version in case we need to update it to go around cache limitations. -# -# The `browser-ui-test.version` file is also used by bootstrap to emit warnings in case -# the local version of the package is different than the one used by the CI. ENV SCRIPT /tmp/checktools.sh ../x.py && \ - npm install browser-ui-test@$(head -n 1 /tmp/browser-ui-test.version) --unsafe-perm=true && \ python3 ../x.py check compiletest --set build.compiletest-use-stage0-libtest=true && \ python3 ../x.py test tests/rustdoc-gui --stage 2 --test-args "'--jobs 1'" diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version b/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version deleted file mode 100644 index b9f8e558df4..00000000000 --- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version +++ /dev/null @@ -1 +0,0 @@ -0.21.1 \ No newline at end of file diff --git a/src/ci/docker/run.sh b/src/ci/docker/run.sh index da7d084d48d..044f5a8fff3 100755 --- a/src/ci/docker/run.sh +++ b/src/ci/docker/run.sh @@ -114,14 +114,6 @@ if [ -f "$docker_dir/$image/Dockerfile" ]; then "$context" ) - # If the environment variable DOCKER_SCRIPT is defined, - # set the build argument SCRIPT_ARG to DOCKER_SCRIPT. - # In this way, we run the script defined in CI, - # instead of the one defined in the Dockerfile. - if [ -n "${DOCKER_SCRIPT+x}" ]; then - build_args+=("--build-arg" "SCRIPT_ARG=${DOCKER_SCRIPT}") - fi - GHCR_BUILDKIT_IMAGE="ghcr.io/rust-lang/buildkit:buildx-stable-1" # On non-CI jobs, we try to download a pre-built image from the rust-lang-ci # ghcr.io registry. If it is not possible, we fall back to building the image @@ -341,6 +333,10 @@ if [ "$ENABLE_GCC_CODEGEN" = "1" ]; then echo "Setting extra environment values for docker: $extra_env" fi +if [ -n "${DOCKER_SCRIPT}" ]; then + extra_env="$extra_env --env SCRIPT=\"/scripts/${DOCKER_SCRIPT}\"" +fi + docker \ run \ --workdir /checkout/obj \ diff --git a/src/ci/docker/scripts/i686-gnu-nopt-2.sh b/src/ci/docker/scripts/i686-gnu-nopt-2.sh new file mode 100755 index 00000000000..4c171739daf --- /dev/null +++ b/src/ci/docker/scripts/i686-gnu-nopt-2.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +set -ex + +python3 ../x.py test --stage 1 --set rust.optimize=false library/std && +/scripts/stage_2_test_set2.sh diff --git a/src/ci/docker/scripts/x86_64-gnu-llvm2.sh b/src/ci/docker/scripts/x86_64-gnu-llvm2.sh index fe5382aaa48..0060b9bfd23 100755 --- a/src/ci/docker/scripts/x86_64-gnu-llvm2.sh +++ b/src/ci/docker/scripts/x86_64-gnu-llvm2.sh @@ -4,7 +4,7 @@ set -ex ##### Test stage 2 ##### -/tmp/stage_2_test_set1.sh +/scripts/stage_2_test_set1.sh # Run the `mir-opt` tests again but this time for a 32-bit target. # This enforces that tests using `// EMIT_MIR_FOR_EACH_BIT_WIDTH` have diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index 445fc0dd018..6c5e37b51ef 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -315,16 +315,14 @@ auto: - name: i686-gnu-nopt-1 env: IMAGE: i686-gnu-nopt - DOCKER_SCRIPT: /scripts/stage_2_test_set1.sh + DOCKER_SCRIPT: stage_2_test_set1.sh <<: *job-linux-4c # Skip tests that run in i686-gnu-nopt-1 - name: i686-gnu-nopt-2 env: IMAGE: i686-gnu-nopt - DOCKER_SCRIPT: >- - python3 ../x.py test --stage 1 --set rust.optimize=false library/std && - /scripts/stage_2_test_set2.sh + DOCKER_SCRIPT: i686-gnu-nopt-2.sh <<: *job-linux-4c - name: pr-check-1 diff --git a/src/doc/rustc-dev-guide/src/effects.md b/src/doc/rustc-dev-guide/src/effects.md index c7aa2714668..87b0103a7bc 100644 --- a/src/doc/rustc-dev-guide/src/effects.md +++ b/src/doc/rustc-dev-guide/src/effects.md @@ -67,10 +67,8 @@ in [`wfcheck::check_impl`]. Here's an example: ```rust -#[const_trait] -trait Bar {} -#[const_trait] -trait Foo: ~const Bar {} +const trait Bar {} +const trait Foo: ~const Bar {} // `const_conditions` contains `HostEffect(Self: Bar, maybe)` impl const Bar for () {} @@ -85,8 +83,7 @@ predicates of the trait method, and we attempt to prove the predicates of the impl method. We do the same for `const_conditions`: ```rust -#[const_trait] -trait Foo { +const trait Foo { fn hi<T: ~const Default>(); } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index e7a1f4d8397..1265a39d27b 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -390,7 +390,8 @@ pub(crate) fn clean_predicate<'tcx>( ty::ClauseKind::ConstEvaluatable(..) | ty::ClauseKind::WellFormed(..) | ty::ClauseKind::ConstArgHasType(..) - // FIXME(const_trait_impl): We can probably use this `HostEffect` pred to render `[const]`. + | ty::ClauseKind::UnstableFeature(..) + // FIXME(const_trait_impl): We can probably use this `HostEffect` pred to render `~const`. | ty::ClauseKind::HostEffect(_) => None, } } @@ -2864,7 +2865,7 @@ fn clean_maybe_renamed_item<'tcx>( ItemKind::Fn { ref sig, generics, body: body_id, .. } => { clean_fn_or_proc_macro(item, sig, generics, body_id, &mut name, cx) } - ItemKind::Trait(_, _, _, generics, bounds, item_ids) => { + ItemKind::Trait(_, _, _, _, generics, bounds, item_ids) => { let items = item_ids .iter() .map(|&ti| clean_trait_item(cx.tcx.hir_trait_item(ti), cx)) diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 20babc6168b..09647492d93 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -648,7 +648,7 @@ impl Item { let sig = tcx.fn_sig(def_id).skip_binder(); let constness = if tcx.is_const_fn(def_id) { // rustc's `is_const_fn` returns `true` for associated functions that have an `impl const` parent - // or that have a `#[const_trait]` parent. Do not display those as `const` in rustdoc because we + // or that have a `const trait` parent. Do not display those as `const` in rustdoc because we // won't be printing correct syntax plus the syntax is unstable. match tcx.opt_associated_item(def_id) { Some(ty::AssocItem { diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index bf3f7607274..fd1b17b6476 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -3,6 +3,7 @@ use std::fmt::{self, Display, Write as _}; use std::sync::LazyLock as Lazy; use std::{ascii, mem}; +use rustc_ast::join_path_idents; use rustc_ast::tokenstream::TokenTree; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId}; @@ -24,7 +25,7 @@ use crate::clean::{ clean_middle_ty, inline, }; use crate::core::DocContext; -use crate::display::{Joined as _, MaybeDisplay as _}; +use crate::display::Joined as _; #[cfg(test)] mod tests; @@ -251,13 +252,7 @@ pub(crate) fn qpath_to_string(p: &hir::QPath<'_>) -> String { hir::QPath::LangItem(lang_item, ..) => return lang_item.name().to_string(), }; - fmt::from_fn(|f| { - segments - .iter() - .map(|seg| (seg.ident.name != kw::PathRoot).then_some(seg.ident).maybe_display()) - .joined("::", f) - }) - .to_string() + join_path_idents(segments.iter().map(|seg| seg.ident)) } pub(crate) fn build_deref_target_impls( diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index 4989bd718c9..5191120ebdb 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -1,5 +1,6 @@ use std::mem; +use rustc_ast::join_path_syms; use rustc_attr_data_structures::StabilityLevel; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIdSet}; @@ -13,7 +14,6 @@ use crate::core::DocContext; use crate::fold::DocFolder; use crate::formats::Impl; use crate::formats::item_type::ItemType; -use crate::html::format::join_with_double_colon; use crate::html::markdown::short_markdown_summary; use crate::html::render::IndexItem; use crate::html::render::search_index::get_function_type_for_search; @@ -558,7 +558,7 @@ fn add_item_to_search_index(tcx: TyCtxt<'_>, cache: &mut Cache, item: &clean::It clean::ItemKind::ImportItem(import) => import.source.did.unwrap_or(item_def_id), _ => item_def_id, }; - let path = join_with_double_colon(parent_path); + let path = join_path_syms(parent_path); let impl_id = if let Some(ParentStackItem::Impl { item_id, .. }) = cache.parent_stack.last() { item_id.as_def_id() } else { diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index bcb3e57c844..b16485107a0 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -14,6 +14,7 @@ use std::slice; use itertools::{Either, Itertools}; use rustc_abi::ExternAbi; +use rustc_ast::join_path_syms; use rustc_attr_data_structures::{ConstStability, StabilityLevel, StableSince}; use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; @@ -25,7 +26,7 @@ use rustc_span::symbol::kw; use rustc_span::{Symbol, sym}; use tracing::{debug, trace}; -use super::url_parts_builder::{UrlPartsBuilder, estimate_item_path_byte_length}; +use super::url_parts_builder::UrlPartsBuilder; use crate::clean::types::ExternalLocation; use crate::clean::utils::find_nearest_parent_module; use crate::clean::{self, ExternalCrate, PrimitiveType}; @@ -369,18 +370,6 @@ pub(crate) enum HrefError { NotInExternalCache, } -// Panics if `syms` is empty. -pub(crate) fn join_with_double_colon(syms: &[Symbol]) -> String { - let mut s = String::with_capacity(estimate_item_path_byte_length(syms.len())); - // NOTE: using `Joined::joined` here causes a noticeable perf regression - s.push_str(syms[0].as_str()); - for sym in &syms[1..] { - s.push_str("::"); - s.push_str(sym.as_str()); - } - s -} - /// This function is to get the external macro path because they are not in the cache used in /// `href_with_root_path`. fn generate_macro_def_id_path( @@ -672,7 +661,7 @@ pub(crate) fn link_tooltip( write!(f, "{}", cx.tcx().item_name(id))?; } else if !fqp.is_empty() { write!(f, "{shortty} ")?; - fqp.iter().joined("::", f)?; + write!(f, "{}", join_path_syms(fqp))?; } Ok(()) }) @@ -703,7 +692,7 @@ fn resolved_path( write!( f, "{path}::{anchor}", - path = join_with_double_colon(&fqp[..fqp.len() - 1]), + path = join_path_syms(&fqp[..fqp.len() - 1]), anchor = print_anchor(did, *fqp.last().unwrap(), cx) ) } else { @@ -835,7 +824,7 @@ pub(crate) fn print_anchor(did: DefId, text: Symbol, cx: &Context<'_>) -> impl D write!( f, r#"<a class="{short_ty}" href="{url}" title="{short_ty} {path}">{text}</a>"#, - path = join_with_double_colon(&fqp), + path = join_path_syms(fqp), text = EscapeBodyText(text.as_str()), ) } else { @@ -1095,7 +1084,7 @@ impl clean::QPathData { title=\"type {path}::{name}\">{name}</a>", shortty = ItemType::AssocType, name = assoc.name, - path = join_with_double_colon(&path), + path = join_path_syms(path), ) } else { write!(f, "{}", assoc.name) diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs index 3b4dae841ee..7b814701a73 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs @@ -6,6 +6,7 @@ use std::path::{Path, PathBuf}; use std::sync::mpsc::{Receiver, channel}; use askama::Template; +use rustc_ast::join_path_syms; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; use rustc_hir::def_id::{DefIdMap, LOCAL_CRATE}; use rustc_middle::ty::TyCtxt; @@ -27,7 +28,6 @@ use crate::formats::FormatRenderer; use crate::formats::cache::Cache; use crate::formats::item_type::ItemType; use crate::html::escape::Escape; -use crate::html::format::join_with_double_colon; use crate::html::markdown::{self, ErrorCodes, IdMap, plain_text_summary}; use crate::html::render::write_shared::write_shared; use crate::html::url_parts_builder::UrlPartsBuilder; @@ -211,7 +211,7 @@ impl<'tcx> Context<'tcx> { title.push_str(" in "); } // No need to include the namespace for primitive types and keywords - title.push_str(&join_with_double_colon(&self.current)); + title.push_str(&join_path_syms(&self.current)); }; title.push_str(" - Rust"); let tyname = it.type_(); diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 06de4944d97..d8c37137bbc 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -49,6 +49,7 @@ use std::{fs, str}; use askama::Template; use itertools::Either; +use rustc_ast::join_path_syms; use rustc_attr_data_structures::{ ConstStability, DeprecatedSince, Deprecation, RustcVersion, StabilityLevel, StableSince, }; @@ -74,9 +75,9 @@ use crate::formats::cache::Cache; use crate::formats::item_type::ItemType; use crate::html::escape::Escape; use crate::html::format::{ - Ending, HrefError, PrintWithSpace, href, join_with_double_colon, print_abi_with_space, - print_constness_with_space, print_default_space, print_generic_bounds, print_where_clause, - visibility_print_with_space, write_str, + Ending, HrefError, PrintWithSpace, href, print_abi_with_space, print_constness_with_space, + print_default_space, print_generic_bounds, print_where_clause, visibility_print_with_space, + write_str, }; use crate::html::markdown::{ HeadingOffset, IdMap, Markdown, MarkdownItemInfo, MarkdownSummaryLine, @@ -2555,7 +2556,7 @@ fn collect_paths_for_type(first_ty: &clean::Type, cache: &Cache) -> Vec<String> let fqp = cache.exact_paths.get(&did).or_else(get_extern); if let Some(path) = fqp { - out.push(join_with_double_colon(path)); + out.push(join_path_syms(path)); } }; diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 667d39e9bc2..5fbda4797cc 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -4,6 +4,7 @@ use std::iter; use askama::Template; use rustc_abi::VariantIdx; +use rustc_ast::join_path_syms; use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; use rustc_hir as hir; use rustc_hir::def::CtorKind; @@ -30,8 +31,8 @@ use crate::formats::Impl; use crate::formats::item_type::ItemType; use crate::html::escape::{Escape, EscapeBodyTextWithWbr}; use crate::html::format::{ - Ending, PrintWithSpace, join_with_double_colon, print_abi_with_space, - print_constness_with_space, print_where_clause, visibility_print_with_space, + Ending, PrintWithSpace, print_abi_with_space, print_constness_with_space, print_where_clause, + visibility_print_with_space, }; use crate::html::markdown::{HeadingOffset, MarkdownSummaryLine}; use crate::html::render::{document_full, document_item_info}; @@ -1424,7 +1425,7 @@ fn item_type_alias(cx: &Context<'_>, it: &clean::Item, t: &clean::TypeAlias) -> iter::repeat_n("..", cx.current.len()).chain(iter::once("type.impl")).collect(); js_src_path.extend(target_fqp[..target_fqp.len() - 1].iter().copied()); js_src_path.push_fmt(format_args!("{target_type}.{}.js", target_fqp.last().unwrap())); - let self_path = fmt::from_fn(|f| self_fqp.iter().joined("::", f)); + let self_path = join_path_syms(self_fqp); write!( w, "<script src=\"{src}\" data-self-path=\"{self_path}\" async></script>", @@ -2256,7 +2257,7 @@ pub(crate) fn compare_names(left: &str, right: &str) -> Ordering { } pub(super) fn full_path(cx: &Context<'_>, item: &clean::Item) -> String { - let mut s = join_with_double_colon(&cx.current); + let mut s = join_path_syms(&cx.current); s.push_str("::"); s.push_str(item.name.unwrap().as_str()); s diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs index aff8684ee3a..80a59fa218c 100644 --- a/src/librustdoc/html/render/search_index.rs +++ b/src/librustdoc/html/render/search_index.rs @@ -4,6 +4,7 @@ use std::collections::hash_map::Entry; use std::collections::{BTreeMap, VecDeque}; use encode::{bitmap_to_string, write_vlqhex_to_string}; +use rustc_ast::join_path_syms; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_middle::ty::TyCtxt; use rustc_span::def_id::DefId; @@ -17,7 +18,6 @@ use crate::clean::types::{Function, Generics, ItemId, Type, WherePredicate}; use crate::clean::{self, utils}; use crate::formats::cache::{Cache, OrphanImplItem}; use crate::formats::item_type::ItemType; -use crate::html::format::join_with_double_colon; use crate::html::markdown::short_markdown_summary; use crate::html::render::ordered_json::OrderedJson; use crate::html::render::{self, IndexItem, IndexItemFunctionType, RenderType, RenderTypeId}; @@ -78,7 +78,7 @@ pub(crate) fn build_index( ty: item.type_(), defid: item.item_id.as_def_id(), name: item.name.unwrap(), - path: join_with_double_colon(&fqp[..fqp.len() - 1]), + path: join_path_syms(&fqp[..fqp.len() - 1]), desc, parent: Some(parent), parent_idx: None, @@ -416,7 +416,7 @@ pub(crate) fn build_index( if fqp.len() < 2 { return None; } - join_with_double_colon(&fqp[..fqp.len() - 1]) + join_path_syms(&fqp[..fqp.len() - 1]) }; if path == item.path { return None; @@ -427,10 +427,10 @@ pub(crate) fn build_index( let i = <isize as TryInto<usize>>::try_into(parent_idx).unwrap(); item.path = { let p = &crate_paths[i].1; - join_with_double_colon(&p[..p.len() - 1]) + join_path_syms(&p[..p.len() - 1]) }; item.exact_path = - crate_paths[i].2.as_ref().map(|xp| join_with_double_colon(&xp[..xp.len() - 1])); + crate_paths[i].2.as_ref().map(|xp| join_path_syms(&xp[..xp.len() - 1])); } // Omit the parent path if it is same to that of the prior item. @@ -549,11 +549,11 @@ pub(crate) fn build_index( }); continue; } - let full_path = join_with_double_colon(&path[..path.len() - 1]); + let full_path = join_path_syms(&path[..path.len() - 1]); let full_exact_path = exact .as_ref() .filter(|exact| exact.last() == path.last() && exact.len() >= 2) - .map(|exact| join_with_double_colon(&exact[..exact.len() - 1])); + .map(|exact| join_path_syms(&exact[..exact.len() - 1])); let exact_path = extra_paths.len() + self.items.len(); let exact_path = full_exact_path.as_ref().map(|full_exact_path| match extra_paths .entry(full_exact_path.clone()) diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs index 0078671fcc5..1f691392b17 100644 --- a/src/librustdoc/html/render/write_shared.rs +++ b/src/librustdoc/html/render/write_shared.rs @@ -26,6 +26,7 @@ use std::{fmt, fs}; use indexmap::IndexMap; use regex::Regex; +use rustc_ast::join_path_syms; use rustc_data_structures::flock; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_middle::ty::TyCtxt; @@ -43,7 +44,6 @@ use crate::docfs::PathError; use crate::error::Error; use crate::formats::Impl; use crate::formats::item_type::ItemType; -use crate::html::format::join_with_double_colon; use crate::html::layout; use crate::html::render::ordered_json::{EscapedJson, OrderedJson}; use crate::html::render::search_index::{SerializedSearchIndex, build_index}; @@ -608,7 +608,7 @@ impl TypeAliasPart { for &(type_alias_fqp, type_alias_item) in type_aliases { cx.id_map.borrow_mut().clear(); cx.deref_id_map.borrow_mut().clear(); - let type_alias_fqp = join_with_double_colon(&type_alias_fqp); + let type_alias_fqp = join_path_syms(type_alias_fqp); if let Some(ret) = &mut ret { ret.aliases.push(type_alias_fqp); } else { diff --git a/src/librustdoc/html/url_parts_builder.rs b/src/librustdoc/html/url_parts_builder.rs index 9a533827441..705fa498e8d 100644 --- a/src/librustdoc/html/url_parts_builder.rs +++ b/src/librustdoc/html/url_parts_builder.rs @@ -117,7 +117,7 @@ impl UrlPartsBuilder { /// This is just a guess at the average length of a URL part, /// used for [`String::with_capacity`] calls in the [`FromIterator`] -/// and [`Extend`] impls, and for [estimating item path lengths]. +/// and [`Extend`] impls. /// /// The value `8` was chosen for two main reasons: /// @@ -125,18 +125,8 @@ impl UrlPartsBuilder { /// * jemalloc's size classes are all multiples of eight, /// which means that the amount of memory it allocates will often match /// the amount requested, avoiding wasted bytes. -/// -/// [estimating item path lengths]: estimate_item_path_byte_length const AVG_PART_LENGTH: usize = 8; -/// Estimate the number of bytes in an item's path, based on how many segments it has. -/// -/// **Note:** This is only to be used with, e.g., [`String::with_capacity()`]; -/// the return value is just a rough estimate. -pub(crate) const fn estimate_item_path_byte_length(segment_count: usize) -> usize { - AVG_PART_LENGTH * segment_count -} - impl<'a> FromIterator<&'a str> for UrlPartsBuilder { fn from_iter<T: IntoIterator<Item = &'a str>>(iter: T) -> Self { let iter = iter.into_iter(); diff --git a/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs b/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs index 07df893ae3c..a9d3015ce5c 100644 --- a/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs +++ b/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs @@ -306,7 +306,7 @@ impl<'tcx> LateLintPass<'tcx> for ArbitrarySourceItemOrdering { cur_f = Some(field); } }, - ItemKind::Trait(is_auto, _safety, _ident, _generics, _generic_bounds, item_ref) + ItemKind::Trait(_constness, is_auto, _safety, _ident, _generics, _generic_bounds, item_ref) if self.enable_ordering_for_trait && *is_auto == IsAuto::No => { let mut cur_t: Option<(TraitItemId, Ident)> = None; diff --git a/src/tools/clippy/clippy_lints/src/doc/mod.rs b/src/tools/clippy/clippy_lints/src/doc/mod.rs index 2bf52216b83..22b781b8929 100644 --- a/src/tools/clippy/clippy_lints/src/doc/mod.rs +++ b/src/tools/clippy/clippy_lints/src/doc/mod.rs @@ -740,7 +740,7 @@ impl<'tcx> LateLintPass<'tcx> for Documentation { ); } }, - ItemKind::Trait(_, unsafety, ..) => match (headers.safety, unsafety) { + ItemKind::Trait(_, _, unsafety, ..) => match (headers.safety, unsafety) { (false, Safety::Unsafe) => span_lint( cx, MISSING_SAFETY_DOC, diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs index d32017a8b41..1bf03480c82 100644 --- a/src/tools/clippy/clippy_lints/src/len_zero.rs +++ b/src/tools/clippy/clippy_lints/src/len_zero.rs @@ -125,7 +125,7 @@ declare_lint_pass!(LenZero => [LEN_ZERO, LEN_WITHOUT_IS_EMPTY, COMPARISON_TO_EMP impl<'tcx> LateLintPass<'tcx> for LenZero { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { - if let ItemKind::Trait(_, _, ident, _, _, trait_items) = item.kind + if let ItemKind::Trait(_, _, _, ident, _, _, trait_items) = item.kind && !item.span.from_expansion() { check_trait_items(cx, item, ident, trait_items); diff --git a/src/tools/clippy/clippy_lints/src/methods/from_iter_instead_of_collect.rs b/src/tools/clippy/clippy_lints/src/methods/from_iter_instead_of_collect.rs index 045363058d1..d664eaaac70 100644 --- a/src/tools/clippy/clippy_lints/src/methods/from_iter_instead_of_collect.rs +++ b/src/tools/clippy/clippy_lints/src/methods/from_iter_instead_of_collect.rs @@ -4,6 +4,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::implements_trait; use clippy_utils::{is_path_diagnostic_item, sugg}; +use rustc_ast::join_path_idents; use rustc_errors::Applicability; use rustc_hir::def::Res; use rustc_hir::{self as hir, Expr, ExprKind, GenericArg, QPath, TyKind}; @@ -47,7 +48,7 @@ fn build_full_type(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, app: &mut Applica && let QPath::Resolved(None, ty_path) = &ty_qpath && let Res::Def(_, ty_did) = ty_path.res { - let mut ty_str = itertools::join(ty_path.segments.iter().map(|s| s.ident), "::"); + let mut ty_str = join_path_idents(ty_path.segments.iter().map(|seg| seg.ident)); let mut first = true; let mut append = |arg: &str| { write!(&mut ty_str, "{}{arg}", [", ", "<"][usize::from(first)]).unwrap(); diff --git a/src/tools/clippy/clippy_lints/src/missing_inline.rs b/src/tools/clippy/clippy_lints/src/missing_inline.rs index 329f7193437..c4a3d10299b 100644 --- a/src/tools/clippy/clippy_lints/src/missing_inline.rs +++ b/src/tools/clippy/clippy_lints/src/missing_inline.rs @@ -101,7 +101,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingInline { let attrs = cx.tcx.hir_attrs(it.hir_id()); check_missing_inline_attrs(cx, attrs, it.span, desc); }, - hir::ItemKind::Trait(ref _is_auto, ref _unsafe, _ident, _generics, _bounds, trait_items) => { + hir::ItemKind::Trait(ref _constness, ref _is_auto, ref _unsafe, _ident, _generics, _bounds, trait_items) => { // note: we need to check if the trait is exported so we can't use // `LateLintPass::check_trait_item` here. for &tit in trait_items { diff --git a/src/tools/clippy/clippy_lints/src/trait_bounds.rs b/src/tools/clippy/clippy_lints/src/trait_bounds.rs index 45e54302e32..9182a55081f 100644 --- a/src/tools/clippy/clippy_lints/src/trait_bounds.rs +++ b/src/tools/clippy/clippy_lints/src/trait_bounds.rs @@ -112,7 +112,7 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds { // special handling for self trait bounds as these are not considered generics // ie. trait Foo: Display {} if let Item { - kind: ItemKind::Trait(_, _, _, _, bounds, ..), + kind: ItemKind::Trait(_, _, _, _, _, bounds, ..), .. } = item { @@ -133,7 +133,7 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds { .. }) = segments.first() && let Some(Node::Item(Item { - kind: ItemKind::Trait(_, _, _, _, self_bounds, _), + kind: ItemKind::Trait(_, _, _, _, _, self_bounds, _), .. })) = cx.tcx.hir_get_if_local(*def_id) { diff --git a/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs b/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs index 02281b9e922..944cd91a7fd 100644 --- a/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs +++ b/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs @@ -131,7 +131,7 @@ impl LateLintPass<'_> for UpperCaseAcronyms { return; } match it.kind { - ItemKind::TyAlias(ident, ..) | ItemKind::Struct(ident, ..) | ItemKind::Trait(_, _, ident, ..) => { + ItemKind::TyAlias(ident, ..) | ItemKind::Struct(ident, ..) | ItemKind::Trait(_, _, _, ident, ..) => { check_ident(cx, &ident, it.hir_id(), self.upper_case_acronyms_aggressive); }, ItemKind::Enum(ident, _, ref enumdef) => { diff --git a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs index 42254ec8e92..96f0273c439 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs @@ -444,6 +444,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { }, ( Trait(box ast::Trait { + constness: lc, is_auto: la, safety: lu, ident: li, @@ -452,6 +453,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { items: lis, }), Trait(box ast::Trait { + constness: rc, is_auto: ra, safety: ru, ident: ri, @@ -460,7 +462,8 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { items: ris, }), ) => { - la == ra + matches!(lc, ast::Const::No) == matches!(rc, ast::Const::No) + && la == ra && matches!(lu, Safety::Default) == matches!(ru, Safety::Default) && eq_id(*li, *ri) && eq_generics(lg, rg) diff --git a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs index ce61fffe0de..dc31ed08fb7 100644 --- a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs +++ b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs @@ -252,11 +252,11 @@ fn item_search_pat(item: &Item<'_>) -> (Pat, Pat) { ItemKind::Struct(_, _, VariantData::Struct { .. }) => (Pat::Str("struct"), Pat::Str("}")), ItemKind::Struct(..) => (Pat::Str("struct"), Pat::Str(";")), ItemKind::Union(..) => (Pat::Str("union"), Pat::Str("}")), - ItemKind::Trait(_, Safety::Unsafe, ..) + ItemKind::Trait(_, _, Safety::Unsafe, ..) | ItemKind::Impl(Impl { safety: Safety::Unsafe, .. }) => (Pat::Str("unsafe"), Pat::Str("}")), - ItemKind::Trait(IsAuto::Yes, ..) => (Pat::Str("auto"), Pat::Str("}")), + ItemKind::Trait(_, IsAuto::Yes, ..) => (Pat::Str("auto"), Pat::Str("}")), ItemKind::Trait(..) => (Pat::Str("trait"), Pat::Str("}")), ItemKind::Impl(_) => (Pat::Str("impl"), Pat::Str("}")), _ => return (Pat::Str(""), Pat::Str("")), diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index ad8c816e204..ff1ee663f9b 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -89,6 +89,7 @@ use std::sync::{Mutex, MutexGuard, OnceLock}; use itertools::Itertools; use rustc_abi::Integer; +use rustc_ast::join_path_syms; use rustc_ast::ast::{self, LitKind, RangeLimits}; use rustc_attr_data_structures::{AttributeKind, find_attr}; use rustc_data_structures::fx::FxHashMap; @@ -3245,8 +3246,8 @@ fn maybe_get_relative_path(from: &DefPath, to: &DefPath, max_super: usize) -> St // a::b::c ::d::sym refers to // e::f::sym:: :: // result should be super::super::super::super::e::f - if let DefPathData::TypeNs(s) = l { - path.push(s.to_string()); + if let DefPathData::TypeNs(sym) = l { + path.push(sym); } if let DefPathData::TypeNs(_) = r { go_up_by += 1; @@ -3256,7 +3257,7 @@ fn maybe_get_relative_path(from: &DefPath, to: &DefPath, max_super: usize) -> St // a::b::sym:: :: refers to // c::d::e ::f::sym // when looking at `f` - Left(DefPathData::TypeNs(sym)) => path.push(sym.to_string()), + Left(DefPathData::TypeNs(sym)) => path.push(sym), // consider: // a::b::c ::d::sym refers to // e::f::sym:: :: @@ -3268,17 +3269,17 @@ fn maybe_get_relative_path(from: &DefPath, to: &DefPath, max_super: usize) -> St if go_up_by > max_super { // `super` chain would be too long, just use the absolute path instead - once(String::from("crate")) - .chain(to.data.iter().filter_map(|el| { + join_path_syms( + once(kw::Crate).chain(to.data.iter().filter_map(|el| { if let DefPathData::TypeNs(sym) = el.data { - Some(sym.to_string()) + Some(sym) } else { None } })) - .join("::") + ) } else { - repeat_n(String::from("super"), go_up_by).chain(path).join("::") + join_path_syms(repeat_n(kw::Super, go_up_by).chain(path)) } } diff --git a/src/tools/clippy/tests/ui/assign_ops.fixed b/src/tools/clippy/tests/ui/assign_ops.fixed index 99beea850a2..eee61f949e7 100644 --- a/src/tools/clippy/tests/ui/assign_ops.fixed +++ b/src/tools/clippy/tests/ui/assign_ops.fixed @@ -84,8 +84,7 @@ mod issue14871 { const ONE: Self; } - #[const_trait] - pub trait NumberConstants { + pub const trait NumberConstants { fn constant(value: usize) -> Self; } diff --git a/src/tools/clippy/tests/ui/assign_ops.rs b/src/tools/clippy/tests/ui/assign_ops.rs index 900d5ad38e0..13ffcee0a3c 100644 --- a/src/tools/clippy/tests/ui/assign_ops.rs +++ b/src/tools/clippy/tests/ui/assign_ops.rs @@ -84,8 +84,7 @@ mod issue14871 { const ONE: Self; } - #[const_trait] - pub trait NumberConstants { + pub const trait NumberConstants { fn constant(value: usize) -> Self; } diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.fixed b/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.fixed index f1d5579a723..c113c1caaa6 100644 --- a/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.fixed +++ b/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.fixed @@ -3,8 +3,7 @@ // Reduced test case from https://github.com/rust-lang/rust-clippy/issues/14658 -#[const_trait] -trait ConstTrait { +const trait ConstTrait { fn method(self); } diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.rs b/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.rs index d495759526d..69248bc52d5 100644 --- a/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.rs +++ b/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.rs @@ -3,8 +3,7 @@ // Reduced test case from https://github.com/rust-lang/rust-clippy/issues/14658 -#[const_trait] -trait ConstTrait { +const trait ConstTrait { fn method(self); } diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.stderr b/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.stderr index b994b88fac6..7ea009cfc9b 100644 --- a/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.stderr +++ b/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.stderr @@ -1,5 +1,5 @@ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/const_trait.rs:24:1 + --> tests/ui/missing_const_for_fn/const_trait.rs:23:1 | LL | / fn can_be_const() { LL | | 0u64.method(); diff --git a/src/tools/clippy/tests/ui/ptr_arg.rs b/src/tools/clippy/tests/ui/ptr_arg.rs index 65f3f05d6cb..578641e910d 100644 --- a/src/tools/clippy/tests/ui/ptr_arg.rs +++ b/src/tools/clippy/tests/ui/ptr_arg.rs @@ -312,7 +312,7 @@ mod issue_9218 { // Inferred to be `&'a str`, afaik. fn cow_good_ret_ty<'a>(input: &'a Cow<'a, str>) -> &str { - //~^ ERROR: lifetime flowing from input to output with different syntax + //~^ ERROR: eliding a lifetime that's named elsewhere is confusing todo!() } } diff --git a/src/tools/clippy/tests/ui/ptr_arg.stderr b/src/tools/clippy/tests/ui/ptr_arg.stderr index 600343754e1..fd9ceddfe11 100644 --- a/src/tools/clippy/tests/ui/ptr_arg.stderr +++ b/src/tools/clippy/tests/ui/ptr_arg.stderr @@ -231,18 +231,19 @@ error: writing `&String` instead of `&str` involves a new object where a slice w LL | fn good(v1: &String, v2: &String) { | ^^^^^^^ help: change this to: `&str` -error: lifetime flowing from input to output with different syntax can be confusing +error: eliding a lifetime that's named elsewhere is confusing --> tests/ui/ptr_arg.rs:314:36 | LL | fn cow_good_ret_ty<'a>(input: &'a Cow<'a, str>) -> &str { - | ^^ ^^ ---- the lifetime gets resolved as `'a` + | ^^ ^^ ---- the same lifetime is elided here | | | - | | these lifetimes flow to the output - | these lifetimes flow to the output + | | the lifetime is named here + | the lifetime is named here | + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing = note: `-D mismatched-lifetime-syntaxes` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(mismatched_lifetime_syntaxes)]` -help: one option is to consistently use `'a` +help: consistently use `'a` | LL | fn cow_good_ret_ty<'a>(input: &'a Cow<'a, str>) -> &'a str { | ++ diff --git a/src/tools/clippy/tests/ui/trait_duplication_in_bounds.fixed b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.fixed index cf52ecf2f03..88ba5f810b4 100644 --- a/src/tools/clippy/tests/ui/trait_duplication_in_bounds.fixed +++ b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.fixed @@ -167,8 +167,7 @@ where } // #13476 -#[const_trait] -trait ConstTrait {} +const trait ConstTrait {} const fn const_trait_bounds_good<T: ConstTrait + [const] ConstTrait>() {} const fn const_trait_bounds_bad<T: [const] ConstTrait>() {} diff --git a/src/tools/clippy/tests/ui/trait_duplication_in_bounds.rs b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.rs index 955562f08dc..19a4e70e294 100644 --- a/src/tools/clippy/tests/ui/trait_duplication_in_bounds.rs +++ b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.rs @@ -167,8 +167,7 @@ where } // #13476 -#[const_trait] -trait ConstTrait {} +const trait ConstTrait {} const fn const_trait_bounds_good<T: ConstTrait + [const] ConstTrait>() {} const fn const_trait_bounds_bad<T: [const] ConstTrait + [const] ConstTrait>() {} diff --git a/src/tools/clippy/tests/ui/trait_duplication_in_bounds.stderr b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.stderr index ab31721ef51..a56a683de97 100644 --- a/src/tools/clippy/tests/ui/trait_duplication_in_bounds.stderr +++ b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.stderr @@ -59,19 +59,19 @@ LL | fn bad_trait_object(arg0: &(dyn Any + Send + Send)) { | ^^^^^^^^^^^^^^^^^ help: try: `Any + Send` error: these bounds contain repeated elements - --> tests/ui/trait_duplication_in_bounds.rs:174:36 + --> tests/ui/trait_duplication_in_bounds.rs:173:36 | LL | const fn const_trait_bounds_bad<T: [const] ConstTrait + [const] ConstTrait>() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `[const] ConstTrait` error: these where clauses contain repeated elements - --> tests/ui/trait_duplication_in_bounds.rs:181:8 + --> tests/ui/trait_duplication_in_bounds.rs:180:8 | LL | T: IntoIterator<Item = U::Owned> + IntoIterator<Item = U::Owned>, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `IntoIterator<Item = U::Owned>` error: these where clauses contain repeated elements - --> tests/ui/trait_duplication_in_bounds.rs:203:8 + --> tests/ui/trait_duplication_in_bounds.rs:202:8 | LL | T: AssocConstTrait<ASSOC = 0> + AssocConstTrait<ASSOC = 0>, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `AssocConstTrait<ASSOC = 0>` diff --git a/src/tools/lint-docs/Cargo.toml b/src/tools/lint-docs/Cargo.toml index e914a2df2ba..6e1ab84ed18 100644 --- a/src/tools/lint-docs/Cargo.toml +++ b/src/tools/lint-docs/Cargo.toml @@ -7,7 +7,7 @@ description = "A script to extract the lint documentation for the rustc book." # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -rustc-literal-escaper = "0.0.4" +rustc-literal-escaper = "0.0.5" serde_json = "1.0.57" tempfile = "3.1.0" walkdir = "2.3.1" diff --git a/src/tools/miri/src/bin/log/tracing_chrome.rs b/src/tools/miri/src/bin/log/tracing_chrome.rs index 459acea6f0b..5a96633c99e 100644 --- a/src/tools/miri/src/bin/log/tracing_chrome.rs +++ b/src/tools/miri/src/bin/log/tracing_chrome.rs @@ -1,8 +1,18 @@ // SPDX-License-Identifier: MIT // SPDX-FileCopyrightText: Copyright (c) 2020 Thoren Paulson -//! This file is taken unmodified from the following link, except for file attributes and -//! `extern crate` at the top. -//! https://github.com/thoren-d/tracing-chrome/blob/7e2625ab4aeeef2f0ef9bde9d6258dd181c04472/src/lib.rs +//! This file was initially taken from the following link: +//! <https://github.com/thoren-d/tracing-chrome/blob/7e2625ab4aeeef2f0ef9bde9d6258dd181c04472/src/lib.rs> +//! +//! The precise changes that were made to the original file can be found in git history +//! (`git log -- path/to/tracing_chrome.rs`), but in summary: +//! - the file attributes were changed and `extern crate` was added at the top +//! - if a tracing span has a field called "tracing_separate_thread", it will be given a separate +//! span ID even in [TraceStyle::Threaded] mode, to make it appear on a separate line when viewing +//! the trace in <https://ui.perfetto.dev>. This is the syntax to trigger this behavior: +//! ```rust +//! tracing::info_span!("my_span", tracing_separate_thread = tracing::field::Empty, /* ... */) +//! ``` +//! //! Depending on the tracing-chrome crate from crates.io is unfortunately not possible, since it //! depends on `tracing_core` which conflicts with rustc_private's `tracing_core` (meaning it would //! not be possible to use the [ChromeLayer] in a context that expects a [Layer] from @@ -79,14 +89,26 @@ where } /// Decides how traces will be recorded. +/// Also see <https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview#heading=h.jh64i9l3vwa1> #[derive(Default)] pub enum TraceStyle { - /// Traces will be recorded as a group of threads. + /// Traces will be recorded as a group of threads, and all spans on the same thread will appear + /// on a single trace line in <https://ui.perfetto.dev>. /// In this style, spans should be entered and exited on the same thread. + /// + /// If a tracing span has a field called "tracing_separate_thread", it will be given a separate + /// span ID even in this mode, to make it appear on a separate line when viewing the trace in + /// <https://ui.perfetto.dev>. This is the syntax to trigger this behavior: + /// ```rust + /// tracing::info_span!("my_span", tracing_separate_thread = tracing::field::Empty, /* ... */) + /// ``` + /// [tracing::field::Empty] is used so that other tracing layers (e.g. the logger) will ignore + /// the "tracing_separate_thread" argument and not print out anything for it. #[default] Threaded, - /// Traces will recorded as a group of asynchronous operations. + /// Traces will recorded as a group of asynchronous operations. All spans will be given separate + /// span IDs and will appear on separate trace lines in <https://ui.perfetto.dev>. Async, } @@ -497,31 +519,39 @@ where } } - fn get_root_id(span: SpanRef<S>) -> u64 { - span.scope() - .from_root() - .take(1) - .next() - .unwrap_or(span) - .id() - .into_u64() + fn get_root_id(&self, span: SpanRef<S>) -> Option<u64> { + match self.trace_style { + TraceStyle::Threaded => { + if span.fields().field("tracing_separate_thread").is_some() { + // assign an independent "id" to spans with argument "tracing_separate_thread", + // so they appear a separate trace line in trace visualization tools, see + // https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview#heading=h.jh64i9l3vwa1 + Some(span.id().into_u64()) + } else { + None + } + }, + TraceStyle::Async => Some( + span.scope() + .from_root() + .take(1) + .next() + .unwrap_or(span) + .id() + .into_u64() + ), + } } fn enter_span(&self, span: SpanRef<S>, ts: f64) { let callsite = self.get_callsite(EventOrSpan::Span(&span)); - let root_id = match self.trace_style { - TraceStyle::Async => Some(ChromeLayer::get_root_id(span)), - _ => None, - }; + let root_id = self.get_root_id(span); self.send_message(Message::Enter(ts, callsite, root_id)); } fn exit_span(&self, span: SpanRef<S>, ts: f64) { let callsite = self.get_callsite(EventOrSpan::Span(&span)); - let root_id = match self.trace_style { - TraceStyle::Async => Some(ChromeLayer::get_root_id(span)), - _ => None, - }; + let root_id = self.get_root_id(span); self.send_message(Message::Exit(ts, callsite, root_id)); } diff --git a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs index dc1eba1a1ab..e5d8f78d948 100644 --- a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs +++ b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs @@ -1011,8 +1011,7 @@ pub mod ops { } #[lang = "add_assign"] - #[const_trait] - pub trait AddAssign<Rhs = Self> { + pub const trait AddAssign<Rhs = Self> { fn add_assign(&mut self, rhs: Rhs); } diff --git a/src/tools/rustdoc-gui-test/src/main.rs b/src/tools/rustdoc-gui-test/src/main.rs index 0e35861fbf7..5b86bea8932 100644 --- a/src/tools/rustdoc-gui-test/src/main.rs +++ b/src/tools/rustdoc-gui-test/src/main.rs @@ -1,63 +1,15 @@ +use std::env; use std::path::{Path, PathBuf}; use std::process::Command; use std::sync::Arc; -use std::{env, fs}; +use build_helper::npm; use build_helper::util::try_run; use compiletest::directives::TestProps; use config::Config; mod config; -fn get_browser_ui_test_version_inner(npm: &Path, global: bool) -> Option<String> { - let mut command = Command::new(&npm); - command.arg("list").arg("--parseable").arg("--long").arg("--depth=0"); - if global { - command.arg("--global"); - } - let lines = match command.output() { - Ok(output) => String::from_utf8_lossy(&output.stdout).into_owned(), - Err(e) => { - eprintln!( - "path to npm can be wrong, provided path: {npm:?}. Try to set npm path \ - in bootstrap.toml in [build.npm]", - ); - panic!("{:?}", e) - } - }; - lines - .lines() - .find_map(|l| l.rsplit(':').next()?.strip_prefix("browser-ui-test@")) - .map(|v| v.to_owned()) -} - -fn get_browser_ui_test_version(npm: &Path) -> Option<String> { - get_browser_ui_test_version_inner(npm, false) - .or_else(|| get_browser_ui_test_version_inner(npm, true)) -} - -fn compare_browser_ui_test_version(installed_version: &str, src: &Path) { - match fs::read_to_string( - src.join("src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version"), - ) { - Ok(v) => { - if v.trim() != installed_version { - eprintln!( - "⚠️ Installed version of browser-ui-test (`{}`) is different than the \ - one used in the CI (`{}`)", - installed_version, v - ); - eprintln!( - "You can install this version using `npm update browser-ui-test` or by using \ - `npm install browser-ui-test@{}`", - v, - ); - } - } - Err(e) => eprintln!("Couldn't find the CI browser-ui-test version: {:?}", e), - } -} - fn find_librs<P: AsRef<Path>>(path: P) -> Option<PathBuf> { for entry in walkdir::WalkDir::new(path) { let entry = entry.ok()?; @@ -71,27 +23,6 @@ fn find_librs<P: AsRef<Path>>(path: P) -> Option<PathBuf> { fn main() -> Result<(), ()> { let config = Arc::new(Config::from_args(env::args().collect())); - // The goal here is to check if the necessary packages are installed, and if not, we - // panic. - match get_browser_ui_test_version(&config.npm) { - Some(version) => { - // We also check the version currently used in CI and emit a warning if it's not the - // same one. - compare_browser_ui_test_version(&version, &config.rust_src); - } - None => { - eprintln!( - r#" -error: rustdoc-gui test suite cannot be run because npm `browser-ui-test` dependency is missing. - -If you want to install the `browser-ui-test` dependency, run `npm install browser-ui-test` -"#, - ); - - panic!("Cannot run rustdoc-gui tests"); - } - } - let src_path = config.rust_src.join("tests/rustdoc-gui/src"); for entry in src_path.read_dir().expect("read_dir call failed") { if let Ok(entry) = entry { @@ -134,16 +65,12 @@ If you want to install the `browser-ui-test` dependency, run `npm install browse } } - let mut command = Command::new(&config.nodejs); + // FIXME(binarycat): once we get package.json in version control, this should be updated to install via that instead + let local_node_modules = + npm::install_one(&config.out_dir, &config.npm, "browser-ui-test", "0.21.1") + .expect("unable to install browser-ui-test"); - if let Ok(current_dir) = env::current_dir() { - let local_node_modules = current_dir.join("node_modules"); - if local_node_modules.exists() { - // Link the local node_modules if exists. - // This is useful when we run rustdoc-gui-test from outside of the source root. - env::set_var("NODE_PATH", local_node_modules); - } - } + let mut command = Command::new(&config.nodejs); command .arg(config.rust_src.join("src/tools/rustdoc-gui/tester.js")) @@ -154,6 +81,12 @@ If you want to install the `browser-ui-test` dependency, run `npm install browse .arg("--tests-folder") .arg(config.rust_src.join("tests/rustdoc-gui")); + if local_node_modules.exists() { + // Link the local node_modules if exists. + // This is useful when we run rustdoc-gui-test from outside of the source root. + command.env("NODE_PATH", local_node_modules); + } + for file in &config.goml_files { command.arg("--file").arg(file); } diff --git a/src/tools/rustfmt/src/items.rs b/src/tools/rustfmt/src/items.rs index 1a3897b51cb..7084639aca9 100644 --- a/src/tools/rustfmt/src/items.rs +++ b/src/tools/rustfmt/src/items.rs @@ -1172,6 +1172,7 @@ pub(crate) fn format_trait( unreachable!(); }; let ast::Trait { + constness, is_auto, safety, ident, @@ -1182,7 +1183,8 @@ pub(crate) fn format_trait( let mut result = String::with_capacity(128); let header = format!( - "{}{}{}trait ", + "{}{}{}{}trait ", + format_constness(constness), format_visibility(context, &item.vis), format_safety(safety), format_auto(is_auto), diff --git a/tests/codegen/fn-parameters-on-different-lines-debuginfo.rs b/tests/codegen/fn-parameters-on-different-lines-debuginfo.rs new file mode 100644 index 00000000000..2097567f322 --- /dev/null +++ b/tests/codegen/fn-parameters-on-different-lines-debuginfo.rs @@ -0,0 +1,22 @@ +//! Make sure that line debuginfo of function parameters are correct even if +//! they are not on the same line. Regression test for +// <https://github.com/rust-lang/rust/issues/45010>. + +//@ compile-flags: -g -Copt-level=0 + +#[rustfmt::skip] // Having parameters on different lines is crucial for this test. +pub fn foo( + x_parameter_not_in_std: i32, + y_parameter_not_in_std: i32, +) -> i32 { + x_parameter_not_in_std + y_parameter_not_in_std +} + +fn main() { + foo(42, 43); // Ensure `wasm32-wasip1` keeps `foo()` (even if `-Copt-level=0`) +} + +// CHECK: !DILocalVariable(name: "x_parameter_not_in_std", arg: 1, +// CHECK-SAME: line: 9 +// CHECK: !DILocalVariable(name: "y_parameter_not_in_std", arg: 2, +// CHECK-SAME: line: 10 diff --git a/tests/crashes/117629.rs b/tests/crashes/117629.rs index d8b5f328545..f63365395c6 100644 --- a/tests/crashes/117629.rs +++ b/tests/crashes/117629.rs @@ -3,8 +3,7 @@ #![feature(const_trait_impl)] -#[const_trait] -trait Tr { +const trait Tr { async fn ft1() {} } diff --git a/tests/crashes/133275-1.rs b/tests/crashes/133275-1.rs deleted file mode 100644 index 73c04f5d6e4..00000000000 --- a/tests/crashes/133275-1.rs +++ /dev/null @@ -1,13 +0,0 @@ -//@ known-bug: #133275 -#![feature(const_trait_impl)] -#![feature(associated_type_defaults)] - -#[const_trait] -trait Foo3<T> -where - Self::Baz: Clone, -{ - type Baz = T; -} - -pub fn main() {} diff --git a/tests/crashes/133275-2.rs b/tests/crashes/133275-2.rs deleted file mode 100644 index a774b3cdb69..00000000000 --- a/tests/crashes/133275-2.rs +++ /dev/null @@ -1,15 +0,0 @@ -//@ known-bug: #133275 -#![feature(const_trait_impl)] -#[const_trait] -pub trait Owo<X = <IntEnum as Uwu>::T> {} - -#[const_trait] -trait Foo3<T> -where - Self::Bar: Clone, - Self::Baz: Clone, -{ - type Bar = Vec<Self::Baz>; - type Baz = T; - //~^ ERROR the trait bound `T: Clone` is not satisfied -} diff --git a/tests/crashes/const_mut_ref_check_bypass.rs b/tests/crashes/const_mut_ref_check_bypass.rs deleted file mode 100644 index 6234536c72b..00000000000 --- a/tests/crashes/const_mut_ref_check_bypass.rs +++ /dev/null @@ -1,11 +0,0 @@ -// Version of `tests/ui/consts/const-eval/heap/alloc_intrinsic_untyped.rs` without the flag that -// suppresses the ICE. -//@ known-bug: #129233 -#![feature(core_intrinsics)] -#![feature(const_heap)] -#![feature(const_mut_refs)] -use std::intrinsics; - -const BAR: *mut i32 = unsafe { intrinsics::const_allocate(4, 4) as *mut i32 }; - -fn main() {} diff --git a/tests/mir-opt/inline/cycle.rs b/tests/mir-opt/inline/cycle.rs index 383d0796a88..6e0f45bb3e9 100644 --- a/tests/mir-opt/inline/cycle.rs +++ b/tests/mir-opt/inline/cycle.rs @@ -13,7 +13,7 @@ fn f(g: impl Fn()) { #[inline(always)] fn g() { // CHECK-LABEL: fn g( - // CHECK-NOT: (inlined f::<fn() {main}>) + // CHECK-NOT: inlined f(main); } diff --git a/tests/run-make/const-trait-stable-toolchain/const-super-trait-nightly-disabled.stderr b/tests/run-make/const-trait-stable-toolchain/const-super-trait-nightly-disabled.stderr index 5ce815b9aed..464208f989e 100644 --- a/tests/run-make/const-trait-stable-toolchain/const-super-trait-nightly-disabled.stderr +++ b/tests/run-make/const-trait-stable-toolchain/const-super-trait-nightly-disabled.stderr @@ -4,7 +4,7 @@ error: `[const]` is not allowed here LL | trait Bar: ~const Foo {} | ^^^^^^ | -note: this trait is not a `#[const_trait]`, so it cannot have `[const]` trait bounds +note: this trait is not `const`, so it cannot have `[const]` trait bounds --> const-super-trait.rs:7:1 | LL | trait Bar: ~const Foo {} @@ -30,24 +30,24 @@ LL | const fn foo<T: ~const Bar>(x: &T) { = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> const-super-trait.rs:7:12 | LL | trait Bar: ~const Foo {} | ^^^^^^ can't be applied to `Foo` | -help: enable `#![feature(const_trait_impl)]` in your crate and mark `Foo` as `#[const_trait]` to allow it to have `const` implementations +help: enable `#![feature(const_trait_impl)]` in your crate and mark `Foo` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Foo { | ++++++++++++++ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> const-super-trait.rs:9:17 | LL | const fn foo<T: ~const Bar>(x: &T) { | ^^^^^^ can't be applied to `Bar` | -help: enable `#![feature(const_trait_impl)]` in your crate and mark `Bar` as `#[const_trait]` to allow it to have `const` implementations +help: enable `#![feature(const_trait_impl)]` in your crate and mark `Bar` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Bar: ~const Foo {} | ++++++++++++++ diff --git a/tests/run-make/const-trait-stable-toolchain/const-super-trait-nightly-enabled.stderr b/tests/run-make/const-trait-stable-toolchain/const-super-trait-nightly-enabled.stderr index ef764a62b06..569e559186f 100644 --- a/tests/run-make/const-trait-stable-toolchain/const-super-trait-nightly-enabled.stderr +++ b/tests/run-make/const-trait-stable-toolchain/const-super-trait-nightly-enabled.stderr @@ -4,30 +4,30 @@ error: `[const]` is not allowed here LL | trait Bar: ~const Foo {} | ^^^^^^ | -note: this trait is not a `#[const_trait]`, so it cannot have `[const]` trait bounds +note: this trait is not `const`, so it cannot have `[const]` trait bounds --> const-super-trait.rs:7:1 | LL | trait Bar: ~const Foo {} | ^^^^^^^^^^^^^^^^^^^^^^^^ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> const-super-trait.rs:7:12 | LL | trait Bar: ~const Foo {} | ^^^^^^ can't be applied to `Foo` | -help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations +help: mark `Foo` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Foo { | ++++++++++++++ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> const-super-trait.rs:9:17 | LL | const fn foo<T: ~const Bar>(x: &T) { | ^^^^^^ can't be applied to `Bar` | -help: mark `Bar` as `#[const_trait]` to allow it to have `const` implementations +help: mark `Bar` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Bar: ~const Foo {} | ++++++++++++++ diff --git a/tests/run-make/const-trait-stable-toolchain/const-super-trait-stable-disabled.stderr b/tests/run-make/const-trait-stable-toolchain/const-super-trait-stable-disabled.stderr index 3dc147e076f..694e06fb6ea 100644 --- a/tests/run-make/const-trait-stable-toolchain/const-super-trait-stable-disabled.stderr +++ b/tests/run-make/const-trait-stable-toolchain/const-super-trait-stable-disabled.stderr @@ -4,7 +4,7 @@ error: `[const]` is not allowed here 7 | trait Bar: ~const Foo {} | ^^^^^^ | -note: this trait is not a `#[const_trait]`, so it cannot have `[const]` trait bounds +note: this trait is not `const`, so it cannot have `[const]` trait bounds --> const-super-trait.rs:7:1 | 7 | trait Bar: ~const Foo {} @@ -26,25 +26,25 @@ error[E0658]: const trait impls are experimental | = note: see issue #143874 <https://github.com/rust-lang/rust/issues/143874> for more information -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> const-super-trait.rs:7:12 | 7 | trait Bar: ~const Foo {} | ^^^^^^ can't be applied to `Foo` | -note: `Foo` can't be used with `[const]` because it isn't annotated with `#[const_trait]` +note: `Foo` can't be used with `[const]` because it isn't `const` --> const-super-trait.rs:3:1 | 3 | trait Foo { | ^^^^^^^^^ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> const-super-trait.rs:9:17 | 9 | const fn foo<T: ~const Bar>(x: &T) { | ^^^^^^ can't be applied to `Bar` | -note: `Bar` can't be used with `[const]` because it isn't annotated with `#[const_trait]` +note: `Bar` can't be used with `[const]` because it isn't `const` --> const-super-trait.rs:7:1 | 7 | trait Bar: ~const Foo {} diff --git a/tests/run-make/const-trait-stable-toolchain/const-super-trait-stable-enabled.stderr b/tests/run-make/const-trait-stable-toolchain/const-super-trait-stable-enabled.stderr index 2cdeb277ca4..2109f0deb72 100644 --- a/tests/run-make/const-trait-stable-toolchain/const-super-trait-stable-enabled.stderr +++ b/tests/run-make/const-trait-stable-toolchain/const-super-trait-stable-enabled.stderr @@ -4,7 +4,7 @@ error: `[const]` is not allowed here 7 | trait Bar: ~const Foo {} | ^^^^^^ | -note: this trait is not a `#[const_trait]`, so it cannot have `[const]` trait bounds +note: this trait is not `const`, so it cannot have `[const]` trait bounds --> const-super-trait.rs:7:1 | 7 | trait Bar: ~const Foo {} @@ -16,25 +16,25 @@ error[E0554]: `#![feature]` may not be used on the NIGHTLY release channel 1 | #![cfg_attr(feature_enabled, feature(const_trait_impl))] | ^^^^^^^^^^^^^^^^^^^^^^^^^ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> const-super-trait.rs:7:12 | 7 | trait Bar: ~const Foo {} | ^^^^^^ can't be applied to `Foo` | -note: `Foo` can't be used with `[const]` because it isn't annotated with `#[const_trait]` +note: `Foo` can't be used with `[const]` because it isn't `const` --> const-super-trait.rs:3:1 | 3 | trait Foo { | ^^^^^^^^^ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> const-super-trait.rs:9:17 | 9 | const fn foo<T: ~const Bar>(x: &T) { | ^^^^^^ can't be applied to `Bar` | -note: `Bar` can't be used with `[const]` because it isn't annotated with `#[const_trait]` +note: `Bar` can't be used with `[const]` because it isn't `const` --> const-super-trait.rs:7:1 | 7 | trait Bar: ~const Foo {} diff --git a/tests/run-make/const-trait-stable-toolchain/rmake.rs b/tests/run-make/const-trait-stable-toolchain/rmake.rs index 09a7c27a106..729b71457e9 100644 --- a/tests/run-make/const-trait-stable-toolchain/rmake.rs +++ b/tests/run-make/const-trait-stable-toolchain/rmake.rs @@ -11,9 +11,7 @@ fn main() { .env("RUSTC_BOOTSTRAP", "-1") .cfg("feature_enabled") .run_fail() - .assert_stderr_not_contains( - "as `#[const_trait]` to allow it to have `const` implementations", - ) + .assert_stderr_not_contains("as `const` to allow it to have `const` implementations") .stderr_utf8(); diff() .expected_file("const-super-trait-stable-enabled.stderr") @@ -29,7 +27,7 @@ fn main() { .ui_testing() .run_fail() .assert_stderr_not_contains("enable `#![feature(const_trait_impl)]` in your crate and mark") - .assert_stderr_contains("as `#[const_trait]` to allow it to have `const` implementations") + .assert_stderr_contains("as `const` to allow it to have `const` implementations") .stderr_utf8(); diff() .expected_file("const-super-trait-nightly-enabled.stderr") @@ -40,9 +38,7 @@ fn main() { .env("RUSTC_BOOTSTRAP", "-1") .run_fail() .assert_stderr_not_contains("enable `#![feature(const_trait_impl)]` in your crate and mark") - .assert_stderr_not_contains( - "as `#[const_trait]` to allow it to have `const` implementations", - ) + .assert_stderr_not_contains("as `const` to allow it to have `const` implementations") .stderr_utf8(); diff() .expected_file("const-super-trait-stable-disabled.stderr") diff --git a/tests/ui/asm/naked-invalid-attr.stderr b/tests/ui/asm/naked-invalid-attr.stderr index 915b54b3fc2..2571c8fa989 100644 --- a/tests/ui/asm/naked-invalid-attr.stderr +++ b/tests/ui/asm/naked-invalid-attr.stderr @@ -8,7 +8,7 @@ error[E0736]: attribute incompatible with `#[unsafe(naked)]` --> $DIR/naked-invalid-attr.rs:56:3 | LL | #[::a] - | ^^^ the `{{root}}::a` attribute is incompatible with `#[unsafe(naked)]` + | ^^^ the `::a` attribute is incompatible with `#[unsafe(naked)]` ... LL | #[unsafe(naked)] | ---------------- function marked with `#[unsafe(naked)]` here diff --git a/tests/ui/cast/cast-char.rs b/tests/ui/cast/cast-char.rs index 9634ed56f7b..5bf05072253 100644 --- a/tests/ui/cast/cast-char.rs +++ b/tests/ui/cast/cast-char.rs @@ -1,10 +1,58 @@ #![deny(overflowing_literals)] fn main() { - const XYZ: char = 0x1F888 as char; + // Valid cases - should suggest char literal + + // u8 range (0-255) + const VALID_U8_1: char = 0x41 as char; // 'A' + const VALID_U8_2: char = 0xFF as char; // maximum u8 + const VALID_U8_3: char = 0x00 as char; // minimum u8 + + // Valid Unicode in lower range [0x0, 0xD7FF] + const VALID_LOW_1: char = 0x1000 as char; // 4096 + //~^ ERROR: only `u8` can be cast into `char` + const VALID_LOW_2: char = 0xD7FF as char; // last valid in lower range + //~^ ERROR: only `u8` can be cast into `char` + const VALID_LOW_3: char = 0x0500 as char; // cyrillic range + //~^ ERROR: only `u8` can be cast into `char` + + // Valid Unicode in upper range [0xE000, 0x10FFFF] + const VALID_HIGH_1: char = 0xE000 as char; // first valid in upper range + //~^ ERROR only `u8` can be cast into `char` + const VALID_HIGH_2: char = 0x1F888 as char; // 129160 - example from issue + //~^ ERROR only `u8` can be cast into `char` + const VALID_HIGH_3: char = 0x10FFFF as char; // maximum valid Unicode + //~^ ERROR only `u8` can be cast into `char` + const VALID_HIGH_4: char = 0xFFFD as char; // replacement character + //~^ ERROR only `u8` can be cast into `char` + const VALID_HIGH_5: char = 0x1F600 as char; // emoji + //~^ ERROR only `u8` can be cast into `char` + + // Invalid cases - should show InvalidCharCast + + // Surrogate range [0xD800, 0xDFFF] - reserved for UTF-16 + const INVALID_SURROGATE_1: char = 0xD800 as char; // first surrogate + //~^ ERROR: surrogate values are not valid + const INVALID_SURROGATE_2: char = 0xDFFF as char; // last surrogate + //~^ ERROR: surrogate values are not valid + const INVALID_SURROGATE_3: char = 0xDB00 as char; // middle of surrogate range + //~^ ERROR: surrogate values are not valid + + // Too large values (> 0x10FFFF) + const INVALID_TOO_BIG_1: char = 0x110000 as char; // one more than maximum + //~^ ERROR: value exceeds maximum `char` value + const INVALID_TOO_BIG_2: char = 0xEF8888 as char; // example from issue + //~^ ERROR: value exceeds maximum `char` value + const INVALID_TOO_BIG_3: char = 0x1FFFFF as char; // much larger + //~^ ERROR: value exceeds maximum `char` value + const INVALID_TOO_BIG_4: char = 0xFFFFFF as char; // 24-bit maximum + //~^ ERROR: value exceeds maximum `char` value + + // Boundary cases + const BOUNDARY_1: char = 0xD7FE as char; // valid, before surrogate + //~^ ERROR only `u8` can be cast into `char` + const BOUNDARY_2: char = 0xE001 as char; // valid, after surrogate //~^ ERROR only `u8` can be cast into `char` - const XY: char = 129160 as char; + const BOUNDARY_3: char = 0x10FFFE as char; // valid, near maximum //~^ ERROR only `u8` can be cast into `char` - const ZYX: char = '\u{01F888}'; - println!("{}", XYZ); } diff --git a/tests/ui/cast/cast-char.stderr b/tests/ui/cast/cast-char.stderr index 211937c9d6f..a8d0b3b04b0 100644 --- a/tests/ui/cast/cast-char.stderr +++ b/tests/ui/cast/cast-char.stderr @@ -1,8 +1,8 @@ error: only `u8` can be cast into `char` - --> $DIR/cast-char.rs:4:23 + --> $DIR/cast-char.rs:12:31 | -LL | const XYZ: char = 0x1F888 as char; - | ^^^^^^^^^^^^^^^ help: use a `char` literal instead: `'\u{1F888}'` +LL | const VALID_LOW_1: char = 0x1000 as char; // 4096 + | ^^^^^^^^^^^^^^ help: use a `char` literal instead: `'\u{1000}'` | note: the lint level is defined here --> $DIR/cast-char.rs:1:9 @@ -11,10 +11,120 @@ LL | #![deny(overflowing_literals)] | ^^^^^^^^^^^^^^^^^^^^ error: only `u8` can be cast into `char` - --> $DIR/cast-char.rs:6:22 + --> $DIR/cast-char.rs:14:31 | -LL | const XY: char = 129160 as char; - | ^^^^^^^^^^^^^^ help: use a `char` literal instead: `'\u{1F888}'` +LL | const VALID_LOW_2: char = 0xD7FF as char; // last valid in lower range + | ^^^^^^^^^^^^^^ help: use a `char` literal instead: `'\u{D7FF}'` -error: aborting due to 2 previous errors +error: only `u8` can be cast into `char` + --> $DIR/cast-char.rs:16:31 + | +LL | const VALID_LOW_3: char = 0x0500 as char; // cyrillic range + | ^^^^^^^^^^^^^^ help: use a `char` literal instead: `'\u{500}'` + +error: only `u8` can be cast into `char` + --> $DIR/cast-char.rs:20:32 + | +LL | const VALID_HIGH_1: char = 0xE000 as char; // first valid in upper range + | ^^^^^^^^^^^^^^ help: use a `char` literal instead: `'\u{E000}'` + +error: only `u8` can be cast into `char` + --> $DIR/cast-char.rs:22:32 + | +LL | const VALID_HIGH_2: char = 0x1F888 as char; // 129160 - example from issue + | ^^^^^^^^^^^^^^^ help: use a `char` literal instead: `'\u{1F888}'` + +error: only `u8` can be cast into `char` + --> $DIR/cast-char.rs:24:32 + | +LL | const VALID_HIGH_3: char = 0x10FFFF as char; // maximum valid Unicode + | ^^^^^^^^^^^^^^^^ help: use a `char` literal instead: `'\u{10FFFF}'` + +error: only `u8` can be cast into `char` + --> $DIR/cast-char.rs:26:32 + | +LL | const VALID_HIGH_4: char = 0xFFFD as char; // replacement character + | ^^^^^^^^^^^^^^ help: use a `char` literal instead: `'\u{FFFD}'` + +error: only `u8` can be cast into `char` + --> $DIR/cast-char.rs:28:32 + | +LL | const VALID_HIGH_5: char = 0x1F600 as char; // emoji + | ^^^^^^^^^^^^^^^ help: use a `char` literal instead: `'\u{1F600}'` + +error: surrogate values are not valid for `char` + --> $DIR/cast-char.rs:34:39 + | +LL | const INVALID_SURROGATE_1: char = 0xD800 as char; // first surrogate + | ^^^^^^^^^^^^^^ + | + = note: `0xD800..=0xDFFF` are reserved for Unicode surrogates and are not valid `char` values + +error: surrogate values are not valid for `char` + --> $DIR/cast-char.rs:36:39 + | +LL | const INVALID_SURROGATE_2: char = 0xDFFF as char; // last surrogate + | ^^^^^^^^^^^^^^ + | + = note: `0xD800..=0xDFFF` are reserved for Unicode surrogates and are not valid `char` values + +error: surrogate values are not valid for `char` + --> $DIR/cast-char.rs:38:39 + | +LL | const INVALID_SURROGATE_3: char = 0xDB00 as char; // middle of surrogate range + | ^^^^^^^^^^^^^^ + | + = note: `0xD800..=0xDFFF` are reserved for Unicode surrogates and are not valid `char` values + +error: value exceeds maximum `char` value + --> $DIR/cast-char.rs:42:37 + | +LL | const INVALID_TOO_BIG_1: char = 0x110000 as char; // one more than maximum + | ^^^^^^^^^^^^^^^^ + | + = note: maximum valid `char` value is `0x10FFFF` + +error: value exceeds maximum `char` value + --> $DIR/cast-char.rs:44:37 + | +LL | const INVALID_TOO_BIG_2: char = 0xEF8888 as char; // example from issue + | ^^^^^^^^^^^^^^^^ + | + = note: maximum valid `char` value is `0x10FFFF` + +error: value exceeds maximum `char` value + --> $DIR/cast-char.rs:46:37 + | +LL | const INVALID_TOO_BIG_3: char = 0x1FFFFF as char; // much larger + | ^^^^^^^^^^^^^^^^ + | + = note: maximum valid `char` value is `0x10FFFF` + +error: value exceeds maximum `char` value + --> $DIR/cast-char.rs:48:37 + | +LL | const INVALID_TOO_BIG_4: char = 0xFFFFFF as char; // 24-bit maximum + | ^^^^^^^^^^^^^^^^ + | + = note: maximum valid `char` value is `0x10FFFF` + +error: only `u8` can be cast into `char` + --> $DIR/cast-char.rs:52:30 + | +LL | const BOUNDARY_1: char = 0xD7FE as char; // valid, before surrogate + | ^^^^^^^^^^^^^^ help: use a `char` literal instead: `'\u{D7FE}'` + +error: only `u8` can be cast into `char` + --> $DIR/cast-char.rs:54:30 + | +LL | const BOUNDARY_2: char = 0xE001 as char; // valid, after surrogate + | ^^^^^^^^^^^^^^ help: use a `char` literal instead: `'\u{E001}'` + +error: only `u8` can be cast into `char` + --> $DIR/cast-char.rs:56:30 + | +LL | const BOUNDARY_3: char = 0x10FFFE as char; // valid, near maximum + | ^^^^^^^^^^^^^^^^ help: use a `char` literal instead: `'\u{10FFFE}'` + +error: aborting due to 18 previous errors diff --git a/tests/ui/check-cfg/cfg-crate-features.rs b/tests/ui/check-cfg/cfg-crate-features.rs new file mode 100644 index 00000000000..16be8aaeeaa --- /dev/null +++ b/tests/ui/check-cfg/cfg-crate-features.rs @@ -0,0 +1,13 @@ +// https://github.com/rust-lang/rust/issues/143977 +// Check that features are available when an attribute is applied to a crate + +#![cfg(version("1.0"))] +//~^ ERROR `cfg(version)` is experimental and subject to change + +// Using invalid value `does_not_exist`, +// so we don't accidentally configure out the crate for any certain OS +#![cfg(not(target(os = "does_not_exist")))] +//~^ ERROR compact `cfg(target(..))` is experimental and subject to change +//~| WARN unexpected `cfg` condition value: `does_not_exist` + +fn main() {} diff --git a/tests/ui/check-cfg/cfg-crate-features.stderr b/tests/ui/check-cfg/cfg-crate-features.stderr new file mode 100644 index 00000000000..60a5404c073 --- /dev/null +++ b/tests/ui/check-cfg/cfg-crate-features.stderr @@ -0,0 +1,33 @@ +error[E0658]: `cfg(version)` is experimental and subject to change + --> $DIR/cfg-crate-features.rs:4:8 + | +LL | #![cfg(version("1.0"))] + | ^^^^^^^^^^^^^^ + | + = note: see issue #64796 <https://github.com/rust-lang/rust/issues/64796> for more information + = help: add `#![feature(cfg_version)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: compact `cfg(target(..))` is experimental and subject to change + --> $DIR/cfg-crate-features.rs:9:12 + | +LL | #![cfg(not(target(os = "does_not_exist")))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #96901 <https://github.com/rust-lang/rust/issues/96901> for more information + = help: add `#![feature(cfg_target_compact)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +warning: unexpected `cfg` condition value: `does_not_exist` + --> $DIR/cfg-crate-features.rs:9:19 + | +LL | #![cfg(not(target(os = "does_not_exist")))] + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: expected values for `target_os` are: `aix`, `amdhsa`, `android`, `cuda`, `cygwin`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `lynxos178`, `macos`, `netbsd`, `none`, `nto`, `nuttx`, `openbsd`, `psp`, `psx`, `redox`, `rtems`, `solaris`, `solid_asp3`, `teeos`, `trusty`, `tvos`, and `uefi` and 9 more + = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration + = note: `#[warn(unexpected_cfgs)]` on by default + +error: aborting due to 2 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/const-generics/type-dependent/issue-71348.full.stderr b/tests/ui/const-generics/type-dependent/issue-71348.full.stderr index f68fdb3b651..32fa46b92b3 100644 --- a/tests/ui/const-generics/type-dependent/issue-71348.full.stderr +++ b/tests/ui/const-generics/type-dependent/issue-71348.full.stderr @@ -1,14 +1,15 @@ -warning: lifetime flowing from input to output with different syntax can be confusing +warning: hiding a lifetime that's named elsewhere is confusing --> $DIR/issue-71348.rs:18:40 | LL | fn ask<'a, const N: &'static str>(&'a self) -> &'a <Self as Get<N>>::Target - | ^^ -- ------------------------ the lifetimes get resolved as `'a` + | ^^ -- ------------------------ the same lifetime is hidden here | | | - | | the lifetimes get resolved as `'a` - | this lifetime flows to the output + | | the same lifetime is named here + | the lifetime is named here | + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing = note: `#[warn(mismatched_lifetime_syntaxes)]` on by default -help: one option is to consistently use `'a` +help: consistently use `'a` | LL | fn ask<'a, const N: &'static str>(&'a self) -> &'a <Self as Get<'a, N>>::Target | +++ diff --git a/tests/ui/const-generics/type-dependent/issue-71348.rs b/tests/ui/const-generics/type-dependent/issue-71348.rs index c6563c80305..9053f362ce4 100644 --- a/tests/ui/const-generics/type-dependent/issue-71348.rs +++ b/tests/ui/const-generics/type-dependent/issue-71348.rs @@ -17,7 +17,7 @@ trait Get<'a, const N: &'static str> { impl Foo { fn ask<'a, const N: &'static str>(&'a self) -> &'a <Self as Get<N>>::Target //[min]~^ ERROR `&'static str` is forbidden as the type of a const generic parameter - //[full]~^^ WARNING lifetime flowing from input to output with different syntax + //[full]~^^ WARNING hiding a lifetime that's named elsewhere is confusing where Self: Get<'a, N>, { diff --git a/tests/ui/consts/const-eval/heap/alloc_intrinsic_nontransient.rs b/tests/ui/consts/const-eval/heap/alloc_intrinsic_nontransient.rs index 83ed496ac2c..af24e463b50 100644 --- a/tests/ui/consts/const-eval/heap/alloc_intrinsic_nontransient.rs +++ b/tests/ui/consts/const-eval/heap/alloc_intrinsic_nontransient.rs @@ -8,11 +8,11 @@ const FOO_RAW: *const i32 = foo(); const fn foo() -> &'static i32 { let t = unsafe { - let i = intrinsics::const_allocate(4, 4) as * mut i32; + let i = intrinsics::const_allocate(4, 4) as *mut i32; *i = 20; i }; - unsafe { &*t } + unsafe { &*(intrinsics::const_make_global(t as *mut u8) as *const i32) } } fn main() { assert_eq!(*FOO, 20); diff --git a/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.32bit.stderr b/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.32bit.stderr index 11ed0841a00..a8c7ee93971 100644 --- a/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.32bit.stderr +++ b/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.32bit.stderr @@ -1,7 +1,7 @@ error[E0080]: constructing invalid value at .<deref>: encountered uninitialized memory, but expected an integer --> $DIR/alloc_intrinsic_uninit.rs:7:1 | -LL | const BAR: &i32 = unsafe { &*(intrinsics::const_allocate(4, 4) as *mut i32) }; +LL | const BAR: &i32 = unsafe { | ^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. diff --git a/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.64bit.stderr b/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.64bit.stderr index 691bde87d2f..47e1c22cc2c 100644 --- a/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.64bit.stderr +++ b/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.64bit.stderr @@ -1,7 +1,7 @@ error[E0080]: constructing invalid value at .<deref>: encountered uninitialized memory, but expected an integer --> $DIR/alloc_intrinsic_uninit.rs:7:1 | -LL | const BAR: &i32 = unsafe { &*(intrinsics::const_allocate(4, 4) as *mut i32) }; +LL | const BAR: &i32 = unsafe { | ^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. diff --git a/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.rs b/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.rs index ffc35ca1ddc..c54115de204 100644 --- a/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.rs +++ b/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.rs @@ -4,6 +4,8 @@ #![feature(const_heap)] use std::intrinsics; -const BAR: &i32 = unsafe { &*(intrinsics::const_allocate(4, 4) as *mut i32) }; -//~^ ERROR: uninitialized memory +const BAR: &i32 = unsafe { //~ ERROR: uninitialized memory + // Make the pointer immutable to avoid errors related to mutable pointers in constants. + &*(intrinsics::const_make_global(intrinsics::const_allocate(4, 4)) as *const i32) +}; fn main() {} diff --git a/tests/ui/consts/const-eval/heap/alloc_intrinsic_untyped.rs b/tests/ui/consts/const-eval/heap/alloc_intrinsic_untyped.rs deleted file mode 100644 index 26cb69e458b..00000000000 --- a/tests/ui/consts/const-eval/heap/alloc_intrinsic_untyped.rs +++ /dev/null @@ -1,11 +0,0 @@ -// We unleash Miri here since this test demonstrates code that bypasses the checks against interning -// mutable pointers, which currently ICEs. Unleashing Miri silences the ICE. -//@ compile-flags: -Zunleash-the-miri-inside-of-you -#![feature(core_intrinsics)] -#![feature(const_heap)] -use std::intrinsics; - -const BAR: *mut i32 = unsafe { intrinsics::const_allocate(4, 4) as *mut i32 }; -//~^ error: mutable pointer in final value of constant - -fn main() {} diff --git a/tests/ui/consts/const-eval/heap/alloc_intrinsic_untyped.stderr b/tests/ui/consts/const-eval/heap/alloc_intrinsic_untyped.stderr deleted file mode 100644 index 0dc49dc3cd8..00000000000 --- a/tests/ui/consts/const-eval/heap/alloc_intrinsic_untyped.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: encountered mutable pointer in final value of constant - --> $DIR/alloc_intrinsic_untyped.rs:8:1 - | -LL | const BAR: *mut i32 = unsafe { intrinsics::const_allocate(4, 4) as *mut i32 }; - | ^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 1 previous error - diff --git a/tests/ui/consts/const-eval/heap/dealloc_intrinsic.rs b/tests/ui/consts/const-eval/heap/dealloc_intrinsic.rs index 3cc035c66d3..515e12d2b77 100644 --- a/tests/ui/consts/const-eval/heap/dealloc_intrinsic.rs +++ b/tests/ui/consts/const-eval/heap/dealloc_intrinsic.rs @@ -12,7 +12,7 @@ const _X: () = unsafe { const Y: &u32 = unsafe { let ptr = intrinsics::const_allocate(4, 4) as *mut u32; *ptr = 42; - &*ptr + &*(intrinsics::const_make_global(ptr as *mut u8) as *const u32) }; const Z: &u32 = &42; diff --git a/tests/ui/consts/const-eval/heap/make-global-dangling.rs b/tests/ui/consts/const-eval/heap/make-global-dangling.rs new file mode 100644 index 00000000000..f4c5929bc41 --- /dev/null +++ b/tests/ui/consts/const-eval/heap/make-global-dangling.rs @@ -0,0 +1,18 @@ +// Ensure that we can't call `const_make_global` on dangling pointers. + +#![feature(core_intrinsics)] +#![feature(const_heap)] + +use std::intrinsics; + +const Y: &u32 = unsafe { + &*(intrinsics::const_make_global(std::ptr::null_mut()) as *const u32) + //~^ error: pointer not dereferenceable +}; + +const Z: &u32 = unsafe { + &*(intrinsics::const_make_global(std::ptr::dangling_mut()) as *const u32) + //~^ error: pointer not dereferenceable +}; + +fn main() {} diff --git a/tests/ui/consts/const-eval/heap/make-global-dangling.stderr b/tests/ui/consts/const-eval/heap/make-global-dangling.stderr new file mode 100644 index 00000000000..48c2796d0bf --- /dev/null +++ b/tests/ui/consts/const-eval/heap/make-global-dangling.stderr @@ -0,0 +1,15 @@ +error[E0080]: pointer not dereferenceable: pointer must point to some allocation, but got null pointer + --> $DIR/make-global-dangling.rs:9:8 + | +LL | &*(intrinsics::const_make_global(std::ptr::null_mut()) as *const u32) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `Y` failed here + +error[E0080]: pointer not dereferenceable: pointer must point to some allocation, but got 0x1[noalloc] which is a dangling pointer (it has no provenance) + --> $DIR/make-global-dangling.rs:14:8 + | +LL | &*(intrinsics::const_make_global(std::ptr::dangling_mut()) as *const u32) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `Z` failed here + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/heap/make-global-other.rs b/tests/ui/consts/const-eval/heap/make-global-other.rs new file mode 100644 index 00000000000..4e2a59de13e --- /dev/null +++ b/tests/ui/consts/const-eval/heap/make-global-other.rs @@ -0,0 +1,15 @@ +// Ensure that we can't call `const_make_global` on pointers not in the current interpreter. + +#![feature(core_intrinsics)] +#![feature(const_heap)] + +use std::intrinsics; + +const X: &i32 = &0; + +const Y: &i32 = unsafe { + &*(intrinsics::const_make_global(X as *const i32 as *mut u8) as *const i32) + //~^ error: pointer passed to `const_make_global` does not point to a heap allocation: ALLOC0<imm> +}; + +fn main() {} diff --git a/tests/ui/consts/const-eval/heap/make-global-other.stderr b/tests/ui/consts/const-eval/heap/make-global-other.stderr new file mode 100644 index 00000000000..ed0d768cf37 --- /dev/null +++ b/tests/ui/consts/const-eval/heap/make-global-other.stderr @@ -0,0 +1,9 @@ +error[E0080]: pointer passed to `const_make_global` does not point to a heap allocation: ALLOC0<imm> + --> $DIR/make-global-other.rs:11:8 + | +LL | &*(intrinsics::const_make_global(X as *const i32 as *mut u8) as *const i32) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `Y` failed here + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/heap/make-global-twice.rs b/tests/ui/consts/const-eval/heap/make-global-twice.rs new file mode 100644 index 00000000000..0cd617cea3e --- /dev/null +++ b/tests/ui/consts/const-eval/heap/make-global-twice.rs @@ -0,0 +1,18 @@ +// Ensure that we can't call `const_make_global` twice. + +#![feature(core_intrinsics)] +#![feature(const_heap)] + +use std::intrinsics; + +const Y: &i32 = unsafe { + let ptr = intrinsics::const_allocate(4, 4); + let i = ptr as *mut i32; + *i = 20; + intrinsics::const_make_global(ptr); + intrinsics::const_make_global(ptr); + //~^ error: attempting to call `const_make_global` twice on the same allocation ALLOC0 + &*i +}; + +fn main() {} diff --git a/tests/ui/consts/const-eval/heap/make-global-twice.stderr b/tests/ui/consts/const-eval/heap/make-global-twice.stderr new file mode 100644 index 00000000000..95cdb9694d8 --- /dev/null +++ b/tests/ui/consts/const-eval/heap/make-global-twice.stderr @@ -0,0 +1,9 @@ +error[E0080]: attempting to call `const_make_global` twice on the same allocation ALLOC0 + --> $DIR/make-global-twice.rs:13:5 + | +LL | intrinsics::const_make_global(ptr); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `Y` failed here + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/heap/make-global.rs b/tests/ui/consts/const-eval/heap/make-global.rs new file mode 100644 index 00000000000..b26fe2434ab --- /dev/null +++ b/tests/ui/consts/const-eval/heap/make-global.rs @@ -0,0 +1,21 @@ +//@ run-pass +#![feature(core_intrinsics)] +#![feature(const_heap)] +use std::intrinsics; + +const FOO: &i32 = foo(); +const FOO_RAW: *const i32 = foo(); + +const fn foo() -> &'static i32 { + unsafe { + let ptr = intrinsics::const_allocate(4, 4); + let t = ptr as *mut i32; + *t = 20; + intrinsics::const_make_global(ptr); + &*t + } +} +fn main() { + assert_eq!(*FOO, 20); + assert_eq!(unsafe { *FOO_RAW }, 20); +} diff --git a/tests/ui/consts/const-eval/heap/ptr_made_global_mutated.rs b/tests/ui/consts/const-eval/heap/ptr_made_global_mutated.rs new file mode 100644 index 00000000000..bea2a5949c2 --- /dev/null +++ b/tests/ui/consts/const-eval/heap/ptr_made_global_mutated.rs @@ -0,0 +1,15 @@ +// Ensure that once an allocation is "made global", we can no longer mutate it. +#![feature(core_intrinsics)] +#![feature(const_heap)] +use std::intrinsics; + +const A: &u8 = unsafe { + let ptr = intrinsics::const_allocate(1, 1); + *ptr = 1; + let ptr: *const u8 = intrinsics::const_make_global(ptr); + *(ptr as *mut u8) = 2; + //~^ error: writing to ALLOC0 which is read-only + &*ptr +}; + +fn main() {} diff --git a/tests/ui/consts/const-eval/heap/ptr_made_global_mutated.stderr b/tests/ui/consts/const-eval/heap/ptr_made_global_mutated.stderr new file mode 100644 index 00000000000..0e88ea77d1c --- /dev/null +++ b/tests/ui/consts/const-eval/heap/ptr_made_global_mutated.stderr @@ -0,0 +1,9 @@ +error[E0080]: writing to ALLOC0 which is read-only + --> $DIR/ptr_made_global_mutated.rs:10:5 + | +LL | *(ptr as *mut u8) = 2; + | ^^^^^^^^^^^^^^^^^^^^^ evaluation of `A` failed here + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/heap/ptr_not_made_global.rs b/tests/ui/consts/const-eval/heap/ptr_not_made_global.rs new file mode 100644 index 00000000000..6980e92c218 --- /dev/null +++ b/tests/ui/consts/const-eval/heap/ptr_not_made_global.rs @@ -0,0 +1,24 @@ +// Ensure that we reject interning `const_allocate`d allocations in the final value of constants +// if they have not been made global through `const_make_global`. The pointers are made *immutable* +// to focus the test on the missing `make_global`; `ptr_not_made_global_mut.rs` covers the case +// where the pointer remains mutable. + +#![feature(core_intrinsics)] +#![feature(const_heap)] +use std::intrinsics; + +const FOO: &i32 = foo(); +//~^ error: encountered `const_allocate` pointer in final value that was not made global +const FOO_RAW: *const i32 = foo(); +//~^ error: encountered `const_allocate` pointer in final value that was not made global + +const fn foo() -> &'static i32 { + let t = unsafe { + let i = intrinsics::const_allocate(4, 4) as *mut i32; + *i = 20; + i + }; + unsafe { &*t } +} + +fn main() {} diff --git a/tests/ui/consts/const-eval/heap/ptr_not_made_global.stderr b/tests/ui/consts/const-eval/heap/ptr_not_made_global.stderr new file mode 100644 index 00000000000..cb2bb1e8cd8 --- /dev/null +++ b/tests/ui/consts/const-eval/heap/ptr_not_made_global.stderr @@ -0,0 +1,18 @@ +error: encountered `const_allocate` pointer in final value that was not made global + --> $DIR/ptr_not_made_global.rs:10:1 + | +LL | const FOO: &i32 = foo(); + | ^^^^^^^^^^^^^^^ + | + = note: use `const_make_global` to make allocated pointers immutable before returning + +error: encountered `const_allocate` pointer in final value that was not made global + --> $DIR/ptr_not_made_global.rs:12:1 + | +LL | const FOO_RAW: *const i32 = foo(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: use `const_make_global` to make allocated pointers immutable before returning + +error: aborting due to 2 previous errors + diff --git a/tests/ui/consts/const-eval/heap/ptr_not_made_global_mut.rs b/tests/ui/consts/const-eval/heap/ptr_not_made_global_mut.rs new file mode 100644 index 00000000000..e44a3f7a23c --- /dev/null +++ b/tests/ui/consts/const-eval/heap/ptr_not_made_global_mut.rs @@ -0,0 +1,11 @@ +// Ensure that we reject interning `const_allocate`d allocations in the final value of constants +// if they have not been made global through `const_make_global`. This covers the case where the +// pointer is even still mutable, which used to ICE. +#![feature(core_intrinsics)] +#![feature(const_heap)] +use std::intrinsics; + +const BAR: *mut i32 = unsafe { intrinsics::const_allocate(4, 4) as *mut i32 }; +//~^ error: encountered `const_allocate` pointer in final value that was not made global + +fn main() {} diff --git a/tests/ui/consts/const-eval/heap/ptr_not_made_global_mut.stderr b/tests/ui/consts/const-eval/heap/ptr_not_made_global_mut.stderr new file mode 100644 index 00000000000..2445ce633d6 --- /dev/null +++ b/tests/ui/consts/const-eval/heap/ptr_not_made_global_mut.stderr @@ -0,0 +1,10 @@ +error: encountered `const_allocate` pointer in final value that was not made global + --> $DIR/ptr_not_made_global_mut.rs:8:1 + | +LL | const BAR: *mut i32 = unsafe { intrinsics::const_allocate(4, 4) as *mut i32 }; + | ^^^^^^^^^^^^^^^^^^^ + | + = note: use `const_make_global` to make allocated pointers immutable before returning + +error: aborting due to 1 previous error + diff --git a/tests/ui/consts/const-size_of_val-align_of_val-extern-type.rs b/tests/ui/consts/const-size_of_val-align_of_val-extern-type.rs index 2372d1c3e3d..fd3ed8f1826 100644 --- a/tests/ui/consts/const-size_of_val-align_of_val-extern-type.rs +++ b/tests/ui/consts/const-size_of_val-align_of_val-extern-type.rs @@ -8,8 +8,8 @@ extern "C" { } const _SIZE: usize = unsafe { size_of_val(&4 as *const i32 as *const Opaque) }; -//~^ ERROR the size for values of type `Opaque` cannot be known +//~^ ERROR `extern type` does not have known layout const _ALIGN: usize = unsafe { align_of_val(&4 as *const i32 as *const Opaque) }; -//~^ ERROR the size for values of type `Opaque` cannot be known +//~^ ERROR `extern type` does not have known layout fn main() {} diff --git a/tests/ui/consts/const-size_of_val-align_of_val-extern-type.stderr b/tests/ui/consts/const-size_of_val-align_of_val-extern-type.stderr index 825b9e94158..23f7aaf538e 100644 --- a/tests/ui/consts/const-size_of_val-align_of_val-extern-type.stderr +++ b/tests/ui/consts/const-size_of_val-align_of_val-extern-type.stderr @@ -1,39 +1,15 @@ -error[E0277]: the size for values of type `Opaque` cannot be known - --> $DIR/const-size_of_val-align_of_val-extern-type.rs:10:43 +error[E0080]: `extern type` does not have known layout + --> $DIR/const-size_of_val-align_of_val-extern-type.rs:10:31 | LL | const _SIZE: usize = unsafe { size_of_val(&4 as *const i32 as *const Opaque) }; - | ----------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `MetaSized` is not implemented for `Opaque` - | | - | required by a bound introduced by this call - | - = note: the trait bound `Opaque: MetaSized` is not satisfied -note: required by a bound in `std::intrinsics::size_of_val` - --> $SRC_DIR/core/src/intrinsics/mod.rs:LL:COL -help: consider borrowing here - | -LL | const _SIZE: usize = unsafe { size_of_val(&(&4 as *const i32 as *const Opaque)) }; - | ++ + -LL | const _SIZE: usize = unsafe { size_of_val(&mut (&4 as *const i32 as *const Opaque)) }; - | ++++++ + + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `_SIZE` failed here -error[E0277]: the size for values of type `Opaque` cannot be known - --> $DIR/const-size_of_val-align_of_val-extern-type.rs:12:45 +error[E0080]: `extern type` does not have known layout + --> $DIR/const-size_of_val-align_of_val-extern-type.rs:12:32 | LL | const _ALIGN: usize = unsafe { align_of_val(&4 as *const i32 as *const Opaque) }; - | ------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `MetaSized` is not implemented for `Opaque` - | | - | required by a bound introduced by this call - | - = note: the trait bound `Opaque: MetaSized` is not satisfied -note: required by a bound in `std::intrinsics::align_of_val` - --> $SRC_DIR/core/src/intrinsics/mod.rs:LL:COL -help: consider borrowing here - | -LL | const _ALIGN: usize = unsafe { align_of_val(&(&4 as *const i32 as *const Opaque)) }; - | ++ + -LL | const _ALIGN: usize = unsafe { align_of_val(&mut (&4 as *const i32 as *const Opaque)) }; - | ++++++ + + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `_ALIGN` failed here error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0277`. +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-try.rs b/tests/ui/consts/const-try.rs index 26aa9230a39..e13fad78441 100644 --- a/tests/ui/consts/const-try.rs +++ b/tests/ui/consts/const-try.rs @@ -13,14 +13,14 @@ struct TryMe; struct Error; impl const FromResidual<Error> for TryMe { - //~^ ERROR const `impl` for trait `FromResidual` which is not marked with `#[const_trait]` + //~^ ERROR const `impl` for trait `FromResidual` which is not `const` fn from_residual(residual: Error) -> Self { TryMe } } impl const Try for TryMe { - //~^ ERROR const `impl` for trait `Try` which is not marked with `#[const_trait]` + //~^ ERROR const `impl` for trait `Try` which is not `const` type Output = (); type Residual = Error; fn from_output(output: Self::Output) -> Self { diff --git a/tests/ui/consts/const-try.stderr b/tests/ui/consts/const-try.stderr index 4209ca1d526..7004ea3e6db 100644 --- a/tests/ui/consts/const-try.stderr +++ b/tests/ui/consts/const-try.stderr @@ -1,19 +1,19 @@ -error: const `impl` for trait `FromResidual` which is not marked with `#[const_trait]` +error: const `impl` for trait `FromResidual` which is not `const` --> $DIR/const-try.rs:15:12 | LL | impl const FromResidual<Error> for TryMe { | ^^^^^^^^^^^^^^^^^^^ this trait is not `const` | - = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: marking a trait with `const` ensures all default method bodies are `const` = note: adding a non-const method body in the future would be a breaking change -error: const `impl` for trait `Try` which is not marked with `#[const_trait]` +error: const `impl` for trait `Try` which is not `const` --> $DIR/const-try.rs:22:12 | LL | impl const Try for TryMe { | ^^^ this trait is not `const` | - = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: marking a trait with `const` ensures all default method bodies are `const` = note: adding a non-const method body in the future would be a breaking change error[E0015]: `?` is not allowed on `TryMe` in constant functions diff --git a/tests/ui/consts/const_transmute_type_id4.rs b/tests/ui/consts/const_transmute_type_id4.rs index 22a607e9e0e..0ea75f2a2f4 100644 --- a/tests/ui/consts/const_transmute_type_id4.rs +++ b/tests/ui/consts/const_transmute_type_id4.rs @@ -10,7 +10,7 @@ const _: () = { std::ptr::write(ptr.offset(0), main as fn() as *const ()); } assert!(a == b); - //~^ ERROR: type_id_eq: `TypeId` provenance is not a type id + //~^ ERROR: invalid `TypeId` value }; fn main() {} diff --git a/tests/ui/consts/const_transmute_type_id4.stderr b/tests/ui/consts/const_transmute_type_id4.stderr index b418a79d7f0..b224227cf35 100644 --- a/tests/ui/consts/const_transmute_type_id4.stderr +++ b/tests/ui/consts/const_transmute_type_id4.stderr @@ -1,4 +1,4 @@ -error[E0080]: type_id_eq: `TypeId` provenance is not a type id +error[E0080]: invalid `TypeId` value: not all bytes carry type id metadata --> $DIR/const_transmute_type_id4.rs:12:13 | LL | assert!(a == b); diff --git a/tests/ui/consts/const_transmute_type_id5.rs b/tests/ui/consts/const_transmute_type_id5.rs index 0a9ba01e0dd..ae0429f8dbb 100644 --- a/tests/ui/consts/const_transmute_type_id5.rs +++ b/tests/ui/consts/const_transmute_type_id5.rs @@ -1,12 +1,11 @@ -//! Test that we require an equal TypeId to have the same integer -//! part, even if the provenance matches. +//! Test that we require an equal TypeId to have an integer part that properly +//! reflects the type id hash. #![feature(const_type_id, const_trait_impl, const_cmp)] use std::any::TypeId; const _: () = { - let a = TypeId::of::<()>(); let mut b = TypeId::of::<()>(); unsafe { let ptr = &mut b as *mut TypeId as *mut *const (); @@ -14,8 +13,8 @@ const _: () = { let val = std::ptr::read(ptr); std::ptr::write(ptr.offset(1), val); } - assert!(a == b); - //~^ ERROR: type_id_eq: one of the TypeId arguments is invalid, chunk 1 of the hash does not match the type it represents + assert!(b == b); + //~^ ERROR: invalid `TypeId` value }; fn main() {} diff --git a/tests/ui/consts/const_transmute_type_id5.stderr b/tests/ui/consts/const_transmute_type_id5.stderr index 59823fcc1c9..6205679ebb6 100644 --- a/tests/ui/consts/const_transmute_type_id5.stderr +++ b/tests/ui/consts/const_transmute_type_id5.stderr @@ -1,7 +1,7 @@ -error[E0080]: type_id_eq: one of the TypeId arguments is invalid, chunk 1 of the hash does not match the type it represents - --> $DIR/const_transmute_type_id5.rs:17:13 +error[E0080]: invalid `TypeId` value: the hash does not match the type id metadata + --> $DIR/const_transmute_type_id5.rs:16:13 | -LL | assert!(a == b); +LL | assert!(b == b); | ^^^^^^ evaluation of `_` failed inside this call | note: inside `<TypeId as PartialEq>::eq` diff --git a/tests/ui/consts/rustc-impl-const-stability.stderr b/tests/ui/consts/rustc-impl-const-stability.stderr index a3ef4031a13..55c08539688 100644 --- a/tests/ui/consts/rustc-impl-const-stability.stderr +++ b/tests/ui/consts/rustc-impl-const-stability.stderr @@ -1,10 +1,10 @@ -error: const `impl` for trait `Debug` which is not marked with `#[const_trait]` +error: const `impl` for trait `Debug` which is not `const` --> $DIR/rustc-impl-const-stability.rs:15:12 | LL | impl const std::fmt::Debug for Data { | ^^^^^^^^^^^^^^^ this trait is not `const` | - = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: marking a trait with `const` ensures all default method bodies are `const` = note: adding a non-const method body in the future would be a breaking change error: aborting due to 1 previous error diff --git a/tests/ui/extern/extern-types-size_of_val.rs b/tests/ui/extern/extern-types-size_of_val.rs index 3ff51b9b6b0..875ae9a535a 100644 --- a/tests/ui/extern/extern-types-size_of_val.rs +++ b/tests/ui/extern/extern-types-size_of_val.rs @@ -1,4 +1,4 @@ -//@ check-fail +//@ check-pass #![feature(extern_types)] use std::mem::{align_of_val, size_of_val}; @@ -11,7 +11,5 @@ fn main() { let x: &A = unsafe { &*(1usize as *const A) }; size_of_val(x); - //~^ ERROR the size for values of type `A` cannot be known align_of_val(x); - //~^ ERROR the size for values of type `A` cannot be known } diff --git a/tests/ui/extern/extern-types-size_of_val.stderr b/tests/ui/extern/extern-types-size_of_val.stderr deleted file mode 100644 index 8678c6c3d60..00000000000 --- a/tests/ui/extern/extern-types-size_of_val.stderr +++ /dev/null @@ -1,39 +0,0 @@ -error[E0277]: the size for values of type `A` cannot be known - --> $DIR/extern-types-size_of_val.rs:13:17 - | -LL | size_of_val(x); - | ----------- ^ the trait `MetaSized` is not implemented for `A` - | | - | required by a bound introduced by this call - | - = note: the trait bound `A: MetaSized` is not satisfied -note: required by a bound in `std::mem::size_of_val` - --> $SRC_DIR/core/src/mem/mod.rs:LL:COL -help: consider borrowing here - | -LL | size_of_val(&x); - | + -LL | size_of_val(&mut x); - | ++++ - -error[E0277]: the size for values of type `A` cannot be known - --> $DIR/extern-types-size_of_val.rs:15:18 - | -LL | align_of_val(x); - | ------------ ^ the trait `MetaSized` is not implemented for `A` - | | - | required by a bound introduced by this call - | - = note: the trait bound `A: MetaSized` is not satisfied -note: required by a bound in `std::mem::align_of_val` - --> $SRC_DIR/core/src/mem/mod.rs:LL:COL -help: consider borrowing here - | -LL | align_of_val(&x); - | + -LL | align_of_val(&mut x); - | ++++ - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/extern/extern-types-unsized.rs b/tests/ui/extern/extern-types-unsized.rs index 46cdc24e083..94a222a7e7e 100644 --- a/tests/ui/extern/extern-types-unsized.rs +++ b/tests/ui/extern/extern-types-unsized.rs @@ -27,9 +27,7 @@ fn main() { assert_sized::<Bar<A>>(); //~^ ERROR the size for values of type - //~| ERROR the size for values of type assert_sized::<Bar<Bar<A>>>(); //~^ ERROR the size for values of type - //~| ERROR the size for values of type } diff --git a/tests/ui/extern/extern-types-unsized.stderr b/tests/ui/extern/extern-types-unsized.stderr index 43dd9800d6d..a587d4dda55 100644 --- a/tests/ui/extern/extern-types-unsized.stderr +++ b/tests/ui/extern/extern-types-unsized.stderr @@ -59,21 +59,8 @@ help: consider relaxing the implicit `Sized` restriction LL | fn assert_sized<T: ?Sized>() {} | ++++++++ -error[E0277]: the size for values of type `A` cannot be known - --> $DIR/extern-types-unsized.rs:28:20 - | -LL | assert_sized::<Bar<A>>(); - | ^^^^^^ doesn't have a known size - | - = help: the trait `MetaSized` is not implemented for `A` -note: required by a bound in `Bar` - --> $DIR/extern-types-unsized.rs:14:12 - | -LL | struct Bar<T: ?Sized> { - | ^ required by this bound in `Bar` - error[E0277]: the size for values of type `A` cannot be known at compilation time - --> $DIR/extern-types-unsized.rs:32:20 + --> $DIR/extern-types-unsized.rs:31:20 | LL | assert_sized::<Bar<Bar<A>>>(); | ^^^^^^^^^^^ doesn't have a size known at compile-time @@ -94,19 +81,6 @@ help: consider relaxing the implicit `Sized` restriction LL | fn assert_sized<T: ?Sized>() {} | ++++++++ -error[E0277]: the size for values of type `A` cannot be known - --> $DIR/extern-types-unsized.rs:32:20 - | -LL | assert_sized::<Bar<Bar<A>>>(); - | ^^^^^^^^^^^ doesn't have a known size - | - = help: the trait `MetaSized` is not implemented for `A` -note: required by a bound in `Bar` - --> $DIR/extern-types-unsized.rs:14:12 - | -LL | struct Bar<T: ?Sized> { - | ^ required by this bound in `Bar` - -error: aborting due to 6 previous errors +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/extern/unsized-extern-derefmove.rs b/tests/ui/extern/unsized-extern-derefmove.rs index c02375266ab..39597a12fe1 100644 --- a/tests/ui/extern/unsized-extern-derefmove.rs +++ b/tests/ui/extern/unsized-extern-derefmove.rs @@ -7,14 +7,10 @@ extern "C" { } unsafe fn make_device() -> Box<Device> { -//~^ ERROR the size for values of type `Device` cannot be known Box::from_raw(0 as *mut _) -//~^ ERROR the size for values of type `Device` cannot be known -//~| ERROR the size for values of type `Device` cannot be known } fn main() { let d: Device = unsafe { *make_device() }; //~^ ERROR the size for values of type `Device` cannot be known -//~| ERROR the size for values of type `Device` cannot be known } diff --git a/tests/ui/extern/unsized-extern-derefmove.stderr b/tests/ui/extern/unsized-extern-derefmove.stderr index a9efc2e66e3..c43184d94e1 100644 --- a/tests/ui/extern/unsized-extern-derefmove.stderr +++ b/tests/ui/extern/unsized-extern-derefmove.stderr @@ -1,43 +1,5 @@ -error[E0277]: the size for values of type `Device` cannot be known - --> $DIR/unsized-extern-derefmove.rs:9:28 - | -LL | unsafe fn make_device() -> Box<Device> { - | ^^^^^^^^^^^ doesn't have a known size - | - = help: the trait `MetaSized` is not implemented for `Device` -note: required by a bound in `Box` - --> $SRC_DIR/alloc/src/boxed.rs:LL:COL - -error[E0277]: the size for values of type `Device` cannot be known - --> $DIR/unsized-extern-derefmove.rs:11:19 - | -LL | Box::from_raw(0 as *mut _) - | ------------- ^^^^^^^^^^^ the trait `MetaSized` is not implemented for `Device` - | | - | required by a bound introduced by this call - | - = note: the trait bound `Device: MetaSized` is not satisfied -note: required by a bound in `Box::<T>::from_raw` - --> $SRC_DIR/alloc/src/boxed.rs:LL:COL -help: consider borrowing here - | -LL | Box::from_raw(&(0 as *mut _)) - | ++ + -LL | Box::from_raw(&mut (0 as *mut _)) - | ++++++ + - -error[E0277]: the size for values of type `Device` cannot be known - --> $DIR/unsized-extern-derefmove.rs:11:5 - | -LL | Box::from_raw(0 as *mut _) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a known size - | - = help: the trait `MetaSized` is not implemented for `Device` -note: required by a bound in `Box` - --> $SRC_DIR/alloc/src/boxed.rs:LL:COL - error[E0277]: the size for values of type `Device` cannot be known at compilation time - --> $DIR/unsized-extern-derefmove.rs:17:9 + --> $DIR/unsized-extern-derefmove.rs:14:9 | LL | let d: Device = unsafe { *make_device() }; | ^ doesn't have a size known at compile-time @@ -49,16 +11,6 @@ help: consider borrowing here LL | let d: &Device = unsafe { *make_device() }; | + -error[E0277]: the size for values of type `Device` cannot be known - --> $DIR/unsized-extern-derefmove.rs:17:31 - | -LL | let d: Device = unsafe { *make_device() }; - | ^^^^^^^^^^^^^ doesn't have a known size - | - = help: the trait `MetaSized` is not implemented for `Device` -note: required by a bound in `Box` - --> $SRC_DIR/alloc/src/boxed.rs:LL:COL - -error: aborting due to 5 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.rs b/tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.rs index 1ac3c593dbe..1b8a5d4ca99 100644 --- a/tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.rs +++ b/tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.rs @@ -1,7 +1,7 @@ //@ check-pass pub fn iter<'a>(v: Vec<(u32, &'a u32)>) -> impl DoubleEndedIterator<Item = (u32, &u32)> { - //~^ WARNING lifetime flowing from input to output with different syntax + //~^ WARNING eliding a lifetime that's named elsewhere is confusing v.into_iter() } diff --git a/tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.stderr b/tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.stderr index b9d8674992c..3651226e0c3 100644 --- a/tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.stderr +++ b/tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.stderr @@ -1,11 +1,12 @@ -warning: lifetime flowing from input to output with different syntax can be confusing +warning: eliding a lifetime that's named elsewhere is confusing --> $DIR/rpit-assoc-pair-with-lifetime.rs:3:31 | LL | pub fn iter<'a>(v: Vec<(u32, &'a u32)>) -> impl DoubleEndedIterator<Item = (u32, &u32)> { - | ^^ this lifetime flows to the output ---- the lifetime gets resolved as `'a` + | ^^ the lifetime is named here ---- the same lifetime is elided here | + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing = note: `#[warn(mismatched_lifetime_syntaxes)]` on by default -help: one option is to consistently use `'a` +help: consistently use `'a` | LL | pub fn iter<'a>(v: Vec<(u32, &'a u32)>) -> impl DoubleEndedIterator<Item = (u32, &'a u32)> { | ++ diff --git a/tests/ui/layout/unconstrained-param-ice-137308.rs b/tests/ui/layout/unconstrained-param-ice-137308.rs index 03b7e759960..d05e6e1fd3f 100644 --- a/tests/ui/layout/unconstrained-param-ice-137308.rs +++ b/tests/ui/layout/unconstrained-param-ice-137308.rs @@ -17,4 +17,3 @@ impl<C: ?Sized> A for u8 { //~ ERROR: the type parameter `C` is not constrained #[rustc_layout(debug)] struct S([u8; <u8 as A>::B]); //~^ ERROR: the type has an unknown layout -//~| ERROR: type annotations needed diff --git a/tests/ui/layout/unconstrained-param-ice-137308.stderr b/tests/ui/layout/unconstrained-param-ice-137308.stderr index 82cd1217c49..615c131eb90 100644 --- a/tests/ui/layout/unconstrained-param-ice-137308.stderr +++ b/tests/ui/layout/unconstrained-param-ice-137308.stderr @@ -4,19 +4,12 @@ error[E0207]: the type parameter `C` is not constrained by the impl trait, self LL | impl<C: ?Sized> A for u8 { | ^ unconstrained type parameter -error[E0282]: type annotations needed - --> $DIR/unconstrained-param-ice-137308.rs:18:16 - | -LL | struct S([u8; <u8 as A>::B]); - | ^^ cannot infer type for type parameter `C` - error: the type has an unknown layout --> $DIR/unconstrained-param-ice-137308.rs:18:1 | LL | struct S([u8; <u8 as A>::B]); | ^^^^^^^^ -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors -Some errors have detailed explanations: E0207, E0282. -For more information about an error, try `rustc --explain E0207`. +For more information about this error, try `rustc --explain E0207`. diff --git a/tests/ui/lazy-type-alias/opaq-ty-collection-infinite-recur.rs b/tests/ui/lazy-type-alias/opaq-ty-collection-infinite-recur.rs new file mode 100644 index 00000000000..34803c8c103 --- /dev/null +++ b/tests/ui/lazy-type-alias/opaq-ty-collection-infinite-recur.rs @@ -0,0 +1,18 @@ +// The opaque type collector used to expand free alias types (in situ) without guarding against +// endlessly recursing aliases which lead to the compiler overflowing its stack in certain +// situations. +// +// In most situations we wouldn't even reach the collector when there's an overflow because we +// would've already bailed out early during the item's wfcheck due to the normalization failure. +// +// In the case below however, while collecting the opaque types defined by the AnonConst, we +// descend into its nested items (here: type alias `Recur`) to acquire their opaque types -- +// meaning we get there before we wfcheck `Recur`. +// +// issue: <https://github.com/rust-lang/rust/issues/131994> +#![feature(lazy_type_alias)] +#![expect(incomplete_features)] + +struct Hold([(); { type Recur = Recur; 0 }]); //~ ERROR overflow normalizing the type alias `Recur` + +fn main() {} diff --git a/tests/ui/lazy-type-alias/opaq-ty-collection-infinite-recur.stderr b/tests/ui/lazy-type-alias/opaq-ty-collection-infinite-recur.stderr new file mode 100644 index 00000000000..e93fcd03a96 --- /dev/null +++ b/tests/ui/lazy-type-alias/opaq-ty-collection-infinite-recur.stderr @@ -0,0 +1,11 @@ +error[E0275]: overflow normalizing the type alias `Recur` + --> $DIR/opaq-ty-collection-infinite-recur.rs:16:20 + | +LL | struct Hold([(); { type Recur = Recur; 0 }]); + | ^^^^^^^^^^ + | + = note: in case this is a recursive type alias, consider using a struct, enum, or union instead + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/example-from-issue48686.rs b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/example-from-issue48686.rs index 1804003d367..9162a38f510 100644 --- a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/example-from-issue48686.rs +++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/example-from-issue48686.rs @@ -4,7 +4,7 @@ struct Foo; impl Foo { pub fn get_mut(&'static self, x: &mut u8) -> &mut u8 { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR eliding a lifetime that's named elsewhere is confusing unsafe { &mut *(x as *mut _) } } } diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/example-from-issue48686.stderr b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/example-from-issue48686.stderr index 7c7411651d0..5a7a5a6ebf9 100644 --- a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/example-from-issue48686.stderr +++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/example-from-issue48686.stderr @@ -1,17 +1,18 @@ -error: lifetime flowing from input to output with different syntax can be confusing +error: eliding a lifetime that's named elsewhere is confusing --> $DIR/example-from-issue48686.rs:6:21 | LL | pub fn get_mut(&'static self, x: &mut u8) -> &mut u8 { - | ^^^^^^^ ------- the lifetime gets resolved as `'static` + | ^^^^^^^ ------- the same lifetime is elided here | | - | this lifetime flows to the output + | the lifetime is named here | + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing note: the lint level is defined here --> $DIR/example-from-issue48686.rs:1:9 | LL | #![deny(mismatched_lifetime_syntaxes)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: one option is to consistently use `'static` +help: consistently use `'static` | LL | pub fn get_mut(&'static self, x: &mut u8) -> &'static mut u8 { | +++++++ diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/missing-lifetime-kind.rs b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/missing-lifetime-kind.rs index 3d5aab5c829..ecc790be5a0 100644 --- a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/missing-lifetime-kind.rs +++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/missing-lifetime-kind.rs @@ -1,26 +1,26 @@ #![deny(mismatched_lifetime_syntaxes)] fn ampersand<'a>(x: &'a u8) -> &u8 { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR eliding a lifetime that's named elsewhere is confusing x } struct Brackets<'a>(&'a u8); fn brackets<'a>(x: &'a u8) -> Brackets { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR hiding a lifetime that's named elsewhere is confusing Brackets(x) } struct Comma<'a, T>(&'a T); fn comma<'a>(x: &'a u8) -> Comma<u8> { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR hiding a lifetime that's named elsewhere is confusing Comma(x) } fn underscore<'a>(x: &'a u8) -> &'_ u8 { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR eliding a lifetime that's named elsewhere is confusing x } diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/missing-lifetime-kind.stderr b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/missing-lifetime-kind.stderr index 681b3c97052..af56a0a0ea5 100644 --- a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/missing-lifetime-kind.stderr +++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/missing-lifetime-kind.stderr @@ -1,56 +1,60 @@ -error: lifetime flowing from input to output with different syntax can be confusing +error: eliding a lifetime that's named elsewhere is confusing --> $DIR/missing-lifetime-kind.rs:3:22 | LL | fn ampersand<'a>(x: &'a u8) -> &u8 { - | ^^ --- the lifetime gets resolved as `'a` + | ^^ --- the same lifetime is elided here | | - | this lifetime flows to the output + | the lifetime is named here | + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing note: the lint level is defined here --> $DIR/missing-lifetime-kind.rs:1:9 | LL | #![deny(mismatched_lifetime_syntaxes)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: one option is to consistently use `'a` +help: consistently use `'a` | LL | fn ampersand<'a>(x: &'a u8) -> &'a u8 { | ++ -error: lifetime flowing from input to output with different syntax can be confusing +error: hiding a lifetime that's named elsewhere is confusing --> $DIR/missing-lifetime-kind.rs:10:21 | LL | fn brackets<'a>(x: &'a u8) -> Brackets { - | ^^ -------- the lifetime gets resolved as `'a` + | ^^ -------- the same lifetime is hidden here | | - | this lifetime flows to the output + | the lifetime is named here | -help: one option is to consistently use `'a` + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'a` | LL | fn brackets<'a>(x: &'a u8) -> Brackets<'a> { | ++++ -error: lifetime flowing from input to output with different syntax can be confusing +error: hiding a lifetime that's named elsewhere is confusing --> $DIR/missing-lifetime-kind.rs:17:18 | LL | fn comma<'a>(x: &'a u8) -> Comma<u8> { - | ^^ --------- the lifetime gets resolved as `'a` + | ^^ --------- the same lifetime is hidden here | | - | this lifetime flows to the output + | the lifetime is named here | -help: one option is to consistently use `'a` + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'a` | LL | fn comma<'a>(x: &'a u8) -> Comma<'a, u8> { | +++ -error: lifetime flowing from input to output with different syntax can be confusing +error: eliding a lifetime that's named elsewhere is confusing --> $DIR/missing-lifetime-kind.rs:22:23 | LL | fn underscore<'a>(x: &'a u8) -> &'_ u8 { - | ^^ -- the lifetime gets resolved as `'a` + | ^^ -- the same lifetime is elided here | | - | this lifetime flows to the output + | the lifetime is named here | -help: one option is to consistently use `'a` + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'a` | LL - fn underscore<'a>(x: &'a u8) -> &'_ u8 { LL + fn underscore<'a>(x: &'a u8) -> &'a u8 { diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/not-tied-to-crate.rs b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/not-tied-to-crate.rs index cc398ab7888..449b2a3c0a8 100644 --- a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/not-tied-to-crate.rs +++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/not-tied-to-crate.rs @@ -6,13 +6,13 @@ #[warn(mismatched_lifetime_syntaxes)] mod foo { fn bar(x: &'static u8) -> &u8 { - //~^ WARNING lifetime flowing from input to output with different syntax + //~^ WARNING eliding a lifetime that's named elsewhere is confusing x } #[deny(mismatched_lifetime_syntaxes)] fn baz(x: &'static u8) -> &u8 { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR eliding a lifetime that's named elsewhere is confusing x } } diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/not-tied-to-crate.stderr b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/not-tied-to-crate.stderr index da691225c17..cf0a29678fa 100644 --- a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/not-tied-to-crate.stderr +++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/not-tied-to-crate.stderr @@ -1,35 +1,37 @@ -warning: lifetime flowing from input to output with different syntax can be confusing +warning: eliding a lifetime that's named elsewhere is confusing --> $DIR/not-tied-to-crate.rs:8:16 | LL | fn bar(x: &'static u8) -> &u8 { - | ^^^^^^^ --- the lifetime gets resolved as `'static` + | ^^^^^^^ --- the same lifetime is elided here | | - | this lifetime flows to the output + | the lifetime is named here | + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing note: the lint level is defined here --> $DIR/not-tied-to-crate.rs:6:8 | LL | #[warn(mismatched_lifetime_syntaxes)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: one option is to consistently use `'static` +help: consistently use `'static` | LL | fn bar(x: &'static u8) -> &'static u8 { | +++++++ -error: lifetime flowing from input to output with different syntax can be confusing +error: eliding a lifetime that's named elsewhere is confusing --> $DIR/not-tied-to-crate.rs:14:16 | LL | fn baz(x: &'static u8) -> &u8 { - | ^^^^^^^ --- the lifetime gets resolved as `'static` + | ^^^^^^^ --- the same lifetime is elided here | | - | this lifetime flows to the output + | the lifetime is named here | + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing note: the lint level is defined here --> $DIR/not-tied-to-crate.rs:13:12 | LL | #[deny(mismatched_lifetime_syntaxes)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: one option is to consistently use `'static` +help: consistently use `'static` | LL | fn baz(x: &'static u8) -> &'static u8 { | +++++++ diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/static.rs b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/static.rs index 47ae258f138..c41cf44e1c5 100644 --- a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/static.rs +++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/static.rs @@ -14,26 +14,26 @@ impl Trait for () { } fn ampersand(x: &'static u8) -> &u8 { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR eliding a lifetime that's named elsewhere is confusing x } struct Brackets<'a>(&'a u8); fn brackets(x: &'static u8) -> Brackets { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR hiding a lifetime that's named elsewhere is confusing Brackets(x) } struct Comma<'a, T>(&'a T); fn comma(x: &'static u8) -> Comma<u8> { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR hiding a lifetime that's named elsewhere is confusing Comma(x) } fn underscore(x: &'static u8) -> &'_ u8 { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR eliding a lifetime that's named elsewhere is confusing x } diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/static.stderr b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/static.stderr index 5b9a986bcbe..d60bec6f7e4 100644 --- a/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/static.stderr +++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes-details/static.stderr @@ -1,56 +1,60 @@ -error: lifetime flowing from input to output with different syntax can be confusing +error: eliding a lifetime that's named elsewhere is confusing --> $DIR/static.rs:16:18 | LL | fn ampersand(x: &'static u8) -> &u8 { - | ^^^^^^^ --- the lifetime gets resolved as `'static` + | ^^^^^^^ --- the same lifetime is elided here | | - | this lifetime flows to the output + | the lifetime is named here | + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing note: the lint level is defined here --> $DIR/static.rs:1:9 | LL | #![deny(mismatched_lifetime_syntaxes)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: one option is to consistently use `'static` +help: consistently use `'static` | LL | fn ampersand(x: &'static u8) -> &'static u8 { | +++++++ -error: lifetime flowing from input to output with different syntax can be confusing +error: hiding a lifetime that's named elsewhere is confusing --> $DIR/static.rs:23:17 | LL | fn brackets(x: &'static u8) -> Brackets { - | ^^^^^^^ -------- the lifetime gets resolved as `'static` + | ^^^^^^^ -------- the same lifetime is hidden here | | - | this lifetime flows to the output + | the lifetime is named here | -help: one option is to consistently use `'static` + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'static` | LL | fn brackets(x: &'static u8) -> Brackets<'static> { | +++++++++ -error: lifetime flowing from input to output with different syntax can be confusing +error: hiding a lifetime that's named elsewhere is confusing --> $DIR/static.rs:30:14 | LL | fn comma(x: &'static u8) -> Comma<u8> { - | ^^^^^^^ --------- the lifetime gets resolved as `'static` + | ^^^^^^^ --------- the same lifetime is hidden here | | - | this lifetime flows to the output + | the lifetime is named here | -help: one option is to consistently use `'static` + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'static` | LL | fn comma(x: &'static u8) -> Comma<'static, u8> { | ++++++++ -error: lifetime flowing from input to output with different syntax can be confusing +error: eliding a lifetime that's named elsewhere is confusing --> $DIR/static.rs:35:19 | LL | fn underscore(x: &'static u8) -> &'_ u8 { - | ^^^^^^^ -- the lifetime gets resolved as `'static` + | ^^^^^^^ -- the same lifetime is elided here | | - | this lifetime flows to the output + | the lifetime is named here | -help: one option is to consistently use `'static` + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'static` | LL - fn underscore(x: &'static u8) -> &'_ u8 { LL + fn underscore(x: &'static u8) -> &'static u8 { diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes.rs b/tests/ui/lifetimes/mismatched-lifetime-syntaxes.rs index b98423afb17..f6260c47202 100644 --- a/tests/ui/lifetimes/mismatched-lifetime-syntaxes.rs +++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes.rs @@ -5,109 +5,111 @@ struct ContainsLifetime<'a>(&'a u8); struct S(u8); +// ref to ref + fn explicit_bound_ref_to_implicit_ref<'a>(v: &'a u8) -> &u8 { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR eliding a lifetime that's named elsewhere is confusing v } fn explicit_bound_ref_to_explicit_anonymous_ref<'a>(v: &'a u8) -> &'_ u8 { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR eliding a lifetime that's named elsewhere is confusing v } -// --- +// path to path fn implicit_path_to_explicit_anonymous_path(v: ContainsLifetime) -> ContainsLifetime<'_> { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR hiding a lifetime that's elided elsewhere is confusing v } fn explicit_anonymous_path_to_implicit_path(v: ContainsLifetime<'_>) -> ContainsLifetime { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR hiding a lifetime that's elided elsewhere is confusing v } fn explicit_bound_path_to_implicit_path<'a>(v: ContainsLifetime<'a>) -> ContainsLifetime { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR hiding a lifetime that's named elsewhere is confusing v } fn explicit_bound_path_to_explicit_anonymous_path<'a>( v: ContainsLifetime<'a>, - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR eliding a lifetime that's named elsewhere is confusing ) -> ContainsLifetime<'_> { v } -// --- +// ref to path fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR hiding a lifetime that's elided elsewhere is confusing ContainsLifetime(v) } fn explicit_anonymous_ref_to_implicit_path(v: &'_ u8) -> ContainsLifetime { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR hiding a lifetime that's elided elsewhere is confusing ContainsLifetime(v) } fn explicit_bound_ref_to_implicit_path<'a>(v: &'a u8) -> ContainsLifetime { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR hiding a lifetime that's named elsewhere is confusing ContainsLifetime(v) } fn explicit_bound_ref_to_explicit_anonymous_path<'a>(v: &'a u8) -> ContainsLifetime<'_> { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR eliding a lifetime that's named elsewhere is confusing ContainsLifetime(v) } -// --- +// path to ref fn implicit_path_to_implicit_ref(v: ContainsLifetime) -> &u8 { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR hiding a lifetime that's elided elsewhere is confusing v.0 } fn implicit_path_to_explicit_anonymous_ref(v: ContainsLifetime) -> &'_ u8 { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR hiding a lifetime that's elided elsewhere is confusing v.0 } fn explicit_bound_path_to_implicit_ref<'a>(v: ContainsLifetime<'a>) -> &u8 { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR eliding a lifetime that's named elsewhere is confusing v.0 } fn explicit_bound_path_to_explicit_anonymous_ref<'a>(v: ContainsLifetime<'a>) -> &'_ u8 { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR eliding a lifetime that's named elsewhere is confusing v.0 } impl S { fn method_explicit_bound_ref_to_implicit_ref<'a>(&'a self) -> &u8 { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR eliding a lifetime that's named elsewhere is confusing &self.0 } fn method_explicit_bound_ref_to_explicit_anonymous_ref<'a>(&'a self) -> &'_ u8 { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR eliding a lifetime that's named elsewhere is confusing &self.0 } // --- fn method_explicit_anonymous_ref_to_implicit_path(&'_ self) -> ContainsLifetime { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR hiding a lifetime that's elided elsewhere is confusing ContainsLifetime(&self.0) } fn method_explicit_bound_ref_to_implicit_path<'a>(&'a self) -> ContainsLifetime { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR hiding a lifetime that's named elsewhere is confusing ContainsLifetime(&self.0) } fn method_explicit_bound_ref_to_explicit_anonymous_path<'a>(&'a self) -> ContainsLifetime<'_> { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR eliding a lifetime that's named elsewhere is confusing ContainsLifetime(&self.0) } } @@ -122,43 +124,43 @@ mod static_suggestions { struct S(u8); fn static_ref_to_implicit_ref(v: &'static u8) -> &u8 { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR eliding a lifetime that's named elsewhere is confusing v } fn static_ref_to_explicit_anonymous_ref(v: &'static u8) -> &'_ u8 { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR eliding a lifetime that's named elsewhere is confusing v } fn static_ref_to_implicit_path(v: &'static u8) -> ContainsLifetime { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR hiding a lifetime that's named elsewhere is confusing ContainsLifetime(v) } fn static_ref_to_explicit_anonymous_path(v: &'static u8) -> ContainsLifetime<'_> { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR eliding a lifetime that's named elsewhere is confusing ContainsLifetime(v) } impl S { fn static_ref_to_implicit_ref(&'static self) -> &u8 { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR eliding a lifetime that's named elsewhere is confusing &self.0 } fn static_ref_to_explicit_anonymous_ref(&'static self) -> &'_ u8 { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR eliding a lifetime that's named elsewhere is confusing &self.0 } fn static_ref_to_implicit_path(&'static self) -> ContainsLifetime { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR hiding a lifetime that's named elsewhere is confusing ContainsLifetime(&self.0) } fn static_ref_to_explicit_anonymous_path(&'static self) -> ContainsLifetime<'_> { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR eliding a lifetime that's named elsewhere is confusing ContainsLifetime(&self.0) } } @@ -170,23 +172,23 @@ mod impl_trait { struct ContainsLifetime<'a>(&'a u8); fn explicit_bound_ref_to_impl_trait_bound<'a>(v: &'a u8) -> impl FnOnce() + '_ { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR eliding a lifetime that's named elsewhere is confusing move || _ = v } fn explicit_bound_ref_to_impl_trait_precise_capture<'a>(v: &'a u8) -> impl FnOnce() + use<'_> { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR eliding a lifetime that's named elsewhere is confusing move || _ = v } fn explicit_bound_path_to_impl_trait_bound<'a>(v: ContainsLifetime<'a>) -> impl FnOnce() + '_ { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR eliding a lifetime that's named elsewhere is confusing move || _ = v } fn explicit_bound_path_to_impl_trait_precise_capture<'a>( v: ContainsLifetime<'a>, - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR eliding a lifetime that's named elsewhere is confusing ) -> impl FnOnce() + use<'_> { move || _ = v } @@ -200,13 +202,13 @@ mod dyn_trait { struct ContainsLifetime<'a>(&'a u8); fn explicit_bound_ref_to_dyn_trait_bound<'a>(v: &'a u8) -> Box<dyn Iterator<Item = &u8> + '_> { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR eliding a lifetime that's named elsewhere is confusing Box::new(iter::once(v)) } fn explicit_bound_path_to_dyn_trait_bound<'a>( v: ContainsLifetime<'a>, - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR hiding a lifetime that's named elsewhere is confusing ) -> Box<dyn Iterator<Item = ContainsLifetime> + '_> { Box::new(iter::once(v)) } @@ -214,10 +216,28 @@ mod dyn_trait { /// These tests serve to exercise edge cases of the lint formatting mod diagnostic_output { + #[derive(Copy, Clone)] + struct ContainsLifetime<'a>(&'a u8); + + fn multiple_inputs<'a>(v: (&'a u8, &'a u8)) -> &u8 { + //~^ ERROR eliding a lifetime that's named elsewhere is confusing + v.0 + } + fn multiple_outputs<'a>(v: &'a u8) -> (&u8, &u8) { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR eliding a lifetime that's named elsewhere is confusing (v, v) } + + fn all_three_categories<'a>(v: ContainsLifetime<'a>) -> (&u8, ContainsLifetime) { + //~^ ERROR hiding or eliding a lifetime that's named elsewhere is confusing + (v.0, v) + } + + fn explicit_bound_output<'a>(v: &'a u8) -> (&u8, &'a u8, ContainsLifetime<'a>) { + //~^ ERROR eliding a lifetime that's named elsewhere is confusing + (v, v, ContainsLifetime(v)) + } } /// Trait functions are represented differently in the HIR. Make sure @@ -228,20 +248,20 @@ mod trait_functions { trait TheTrait { fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime; - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR hiding a lifetime that's elided elsewhere is confusing fn method_implicit_ref_to_implicit_path(&self) -> ContainsLifetime; - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR hiding a lifetime that's elided elsewhere is confusing } impl TheTrait for &u8 { fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR hiding a lifetime that's elided elsewhere is confusing ContainsLifetime(v) } fn method_implicit_ref_to_implicit_path(&self) -> ContainsLifetime { - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR hiding a lifetime that's elided elsewhere is confusing ContainsLifetime(self) } } @@ -255,7 +275,7 @@ mod foreign_functions { extern "Rust" { fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime; - //~^ ERROR lifetime flowing from input to output with different syntax + //~^ ERROR hiding a lifetime that's elided elsewhere is confusing } } diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes.stderr b/tests/ui/lifetimes/mismatched-lifetime-syntaxes.stderr index 108b3f14169..20b7561c594 100644 --- a/tests/ui/lifetimes/mismatched-lifetime-syntaxes.stderr +++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes.stderr @@ -1,538 +1,613 @@ -error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:8:47 +error: eliding a lifetime that's named elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:10:47 | LL | fn explicit_bound_ref_to_implicit_ref<'a>(v: &'a u8) -> &u8 { - | ^^ --- the lifetime gets resolved as `'a` + | ^^ --- the same lifetime is elided here | | - | this lifetime flows to the output + | the lifetime is named here | + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing note: the lint level is defined here --> $DIR/mismatched-lifetime-syntaxes.rs:1:9 | LL | #![deny(mismatched_lifetime_syntaxes)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: one option is to consistently use `'a` +help: consistently use `'a` | LL | fn explicit_bound_ref_to_implicit_ref<'a>(v: &'a u8) -> &'a u8 { | ++ -error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:13:57 +error: eliding a lifetime that's named elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:15:57 | LL | fn explicit_bound_ref_to_explicit_anonymous_ref<'a>(v: &'a u8) -> &'_ u8 { - | ^^ -- the lifetime gets resolved as `'a` + | ^^ -- the same lifetime is elided here | | - | this lifetime flows to the output + | the lifetime is named here | -help: one option is to consistently use `'a` + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'a` | LL - fn explicit_bound_ref_to_explicit_anonymous_ref<'a>(v: &'a u8) -> &'_ u8 { LL + fn explicit_bound_ref_to_explicit_anonymous_ref<'a>(v: &'a u8) -> &'a u8 { | -error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:20:48 +error: hiding a lifetime that's elided elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:22:48 | LL | fn implicit_path_to_explicit_anonymous_path(v: ContainsLifetime) -> ContainsLifetime<'_> { - | ^^^^^^^^^^^^^^^^ -- the lifetime gets resolved as `'_` + | ^^^^^^^^^^^^^^^^ -- the same lifetime is elided here | | - | this lifetime flows to the output + | the lifetime is hidden here | -help: one option is to consistently use `'_` + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'_` | LL | fn implicit_path_to_explicit_anonymous_path(v: ContainsLifetime<'_>) -> ContainsLifetime<'_> { | ++++ -error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:25:65 +error: hiding a lifetime that's elided elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:27:65 | LL | fn explicit_anonymous_path_to_implicit_path(v: ContainsLifetime<'_>) -> ContainsLifetime { - | ^^ ---------------- the lifetime gets resolved as `'_` + | ^^ ---------------- the same lifetime is hidden here | | - | this lifetime flows to the output + | the lifetime is elided here | -help: one option is to consistently use `'_` + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'_` | LL | fn explicit_anonymous_path_to_implicit_path(v: ContainsLifetime<'_>) -> ContainsLifetime<'_> { | ++++ -error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:30:65 +error: hiding a lifetime that's named elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:32:65 | LL | fn explicit_bound_path_to_implicit_path<'a>(v: ContainsLifetime<'a>) -> ContainsLifetime { - | ^^ ---------------- the lifetime gets resolved as `'a` + | ^^ ---------------- the same lifetime is hidden here | | - | this lifetime flows to the output + | the lifetime is named here | -help: one option is to consistently use `'a` + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'a` | LL | fn explicit_bound_path_to_implicit_path<'a>(v: ContainsLifetime<'a>) -> ContainsLifetime<'a> { | ++++ -error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:36:25 +error: eliding a lifetime that's named elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:38:25 | LL | v: ContainsLifetime<'a>, - | ^^ this lifetime flows to the output + | ^^ the lifetime is named here LL | LL | ) -> ContainsLifetime<'_> { - | -- the lifetime gets resolved as `'a` + | -- the same lifetime is elided here | -help: one option is to consistently use `'a` + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'a` | LL - ) -> ContainsLifetime<'_> { LL + ) -> ContainsLifetime<'a> { | -error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:44:37 +error: hiding a lifetime that's elided elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:46:37 | LL | fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime { - | ^^^ ---------------- the lifetime gets resolved as `'_` + | ^^^ ---------------- the same lifetime is hidden here | | - | this lifetime flows to the output + | the lifetime is elided here | -help: one option is to remove the lifetime for references and use the anonymous lifetime for paths + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: use `'_` for type paths | LL | fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime<'_> { | ++++ -error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:49:48 +error: hiding a lifetime that's elided elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:51:48 | LL | fn explicit_anonymous_ref_to_implicit_path(v: &'_ u8) -> ContainsLifetime { - | ^^ ---------------- the lifetime gets resolved as `'_` + | ^^ ---------------- the same lifetime is hidden here | | - | this lifetime flows to the output + | the lifetime is elided here | -help: one option is to remove the lifetime for references and use the anonymous lifetime for paths - | -LL - fn explicit_anonymous_ref_to_implicit_path(v: &'_ u8) -> ContainsLifetime { -LL + fn explicit_anonymous_ref_to_implicit_path(v: &u8) -> ContainsLifetime<'_> { + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: use `'_` for type paths | +LL | fn explicit_anonymous_ref_to_implicit_path(v: &'_ u8) -> ContainsLifetime<'_> { + | ++++ -error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:54:48 +error: hiding a lifetime that's named elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:56:48 | LL | fn explicit_bound_ref_to_implicit_path<'a>(v: &'a u8) -> ContainsLifetime { - | ^^ ---------------- the lifetime gets resolved as `'a` + | ^^ ---------------- the same lifetime is hidden here | | - | this lifetime flows to the output + | the lifetime is named here | -help: one option is to consistently use `'a` + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'a` | LL | fn explicit_bound_ref_to_implicit_path<'a>(v: &'a u8) -> ContainsLifetime<'a> { | ++++ -error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:59:58 +error: eliding a lifetime that's named elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:61:58 | LL | fn explicit_bound_ref_to_explicit_anonymous_path<'a>(v: &'a u8) -> ContainsLifetime<'_> { - | ^^ -- the lifetime gets resolved as `'a` + | ^^ -- the same lifetime is elided here | | - | this lifetime flows to the output + | the lifetime is named here | -help: one option is to consistently use `'a` + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'a` | LL - fn explicit_bound_ref_to_explicit_anonymous_path<'a>(v: &'a u8) -> ContainsLifetime<'_> { LL + fn explicit_bound_ref_to_explicit_anonymous_path<'a>(v: &'a u8) -> ContainsLifetime<'a> { | -error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:66:37 +error: hiding a lifetime that's elided elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:68:37 | LL | fn implicit_path_to_implicit_ref(v: ContainsLifetime) -> &u8 { - | ^^^^^^^^^^^^^^^^ --- the lifetime gets resolved as `'_` + | ^^^^^^^^^^^^^^^^ --- the same lifetime is elided here | | - | this lifetime flows to the output + | the lifetime is hidden here | -help: one option is to remove the lifetime for references and use the anonymous lifetime for paths + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: use `'_` for type paths | LL | fn implicit_path_to_implicit_ref(v: ContainsLifetime<'_>) -> &u8 { | ++++ -error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:71:47 +error: hiding a lifetime that's elided elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:73:47 | LL | fn implicit_path_to_explicit_anonymous_ref(v: ContainsLifetime) -> &'_ u8 { - | ^^^^^^^^^^^^^^^^ -- the lifetime gets resolved as `'_` + | ^^^^^^^^^^^^^^^^ -- the same lifetime is elided here | | - | this lifetime flows to the output - | -help: one option is to remove the lifetime for references and use the anonymous lifetime for paths + | the lifetime is hidden here | -LL - fn implicit_path_to_explicit_anonymous_ref(v: ContainsLifetime) -> &'_ u8 { -LL + fn implicit_path_to_explicit_anonymous_ref(v: ContainsLifetime<'_>) -> &u8 { + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: use `'_` for type paths | +LL | fn implicit_path_to_explicit_anonymous_ref(v: ContainsLifetime<'_>) -> &'_ u8 { + | ++++ -error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:76:64 +error: eliding a lifetime that's named elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:78:64 | LL | fn explicit_bound_path_to_implicit_ref<'a>(v: ContainsLifetime<'a>) -> &u8 { - | ^^ --- the lifetime gets resolved as `'a` + | ^^ --- the same lifetime is elided here | | - | this lifetime flows to the output + | the lifetime is named here | -help: one option is to consistently use `'a` + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'a` | LL | fn explicit_bound_path_to_implicit_ref<'a>(v: ContainsLifetime<'a>) -> &'a u8 { | ++ -error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:81:74 +error: eliding a lifetime that's named elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:83:74 | LL | fn explicit_bound_path_to_explicit_anonymous_ref<'a>(v: ContainsLifetime<'a>) -> &'_ u8 { - | ^^ -- the lifetime gets resolved as `'a` + | ^^ -- the same lifetime is elided here | | - | this lifetime flows to the output + | the lifetime is named here | -help: one option is to consistently use `'a` + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'a` | LL - fn explicit_bound_path_to_explicit_anonymous_ref<'a>(v: ContainsLifetime<'a>) -> &'_ u8 { LL + fn explicit_bound_path_to_explicit_anonymous_ref<'a>(v: ContainsLifetime<'a>) -> &'a u8 { | -error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:87:55 +error: eliding a lifetime that's named elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:89:55 | LL | fn method_explicit_bound_ref_to_implicit_ref<'a>(&'a self) -> &u8 { - | ^^ --- the lifetime gets resolved as `'a` + | ^^ --- the same lifetime is elided here | | - | this lifetime flows to the output + | the lifetime is named here | -help: one option is to consistently use `'a` + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'a` | LL | fn method_explicit_bound_ref_to_implicit_ref<'a>(&'a self) -> &'a u8 { | ++ -error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:92:65 +error: eliding a lifetime that's named elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:94:65 | LL | fn method_explicit_bound_ref_to_explicit_anonymous_ref<'a>(&'a self) -> &'_ u8 { - | ^^ -- the lifetime gets resolved as `'a` + | ^^ -- the same lifetime is elided here | | - | this lifetime flows to the output + | the lifetime is named here | -help: one option is to consistently use `'a` + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'a` | LL - fn method_explicit_bound_ref_to_explicit_anonymous_ref<'a>(&'a self) -> &'_ u8 { LL + fn method_explicit_bound_ref_to_explicit_anonymous_ref<'a>(&'a self) -> &'a u8 { | -error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:99:56 +error: hiding a lifetime that's elided elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:101:56 | LL | fn method_explicit_anonymous_ref_to_implicit_path(&'_ self) -> ContainsLifetime { - | ^^ ---------------- the lifetime gets resolved as `'_` + | ^^ ---------------- the same lifetime is hidden here | | - | this lifetime flows to the output + | the lifetime is elided here | -help: one option is to remove the lifetime for references and use the anonymous lifetime for paths - | -LL - fn method_explicit_anonymous_ref_to_implicit_path(&'_ self) -> ContainsLifetime { -LL + fn method_explicit_anonymous_ref_to_implicit_path(&self) -> ContainsLifetime<'_> { + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: use `'_` for type paths | +LL | fn method_explicit_anonymous_ref_to_implicit_path(&'_ self) -> ContainsLifetime<'_> { + | ++++ -error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:104:56 +error: hiding a lifetime that's named elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:106:56 | LL | fn method_explicit_bound_ref_to_implicit_path<'a>(&'a self) -> ContainsLifetime { - | ^^ ---------------- the lifetime gets resolved as `'a` + | ^^ ---------------- the same lifetime is hidden here | | - | this lifetime flows to the output + | the lifetime is named here | -help: one option is to consistently use `'a` + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'a` | LL | fn method_explicit_bound_ref_to_implicit_path<'a>(&'a self) -> ContainsLifetime<'a> { | ++++ -error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:109:66 +error: eliding a lifetime that's named elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:111:66 | LL | fn method_explicit_bound_ref_to_explicit_anonymous_path<'a>(&'a self) -> ContainsLifetime<'_> { - | ^^ -- the lifetime gets resolved as `'a` + | ^^ -- the same lifetime is elided here | | - | this lifetime flows to the output + | the lifetime is named here | -help: one option is to consistently use `'a` + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'a` | LL - fn method_explicit_bound_ref_to_explicit_anonymous_path<'a>(&'a self) -> ContainsLifetime<'_> { LL + fn method_explicit_bound_ref_to_explicit_anonymous_path<'a>(&'a self) -> ContainsLifetime<'a> { | -error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:124:39 +error: eliding a lifetime that's named elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:126:39 | LL | fn static_ref_to_implicit_ref(v: &'static u8) -> &u8 { - | ^^^^^^^ --- the lifetime gets resolved as `'static` + | ^^^^^^^ --- the same lifetime is elided here | | - | this lifetime flows to the output + | the lifetime is named here | -help: one option is to consistently use `'static` + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'static` | LL | fn static_ref_to_implicit_ref(v: &'static u8) -> &'static u8 { | +++++++ -error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:129:49 +error: eliding a lifetime that's named elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:131:49 | LL | fn static_ref_to_explicit_anonymous_ref(v: &'static u8) -> &'_ u8 { - | ^^^^^^^ -- the lifetime gets resolved as `'static` + | ^^^^^^^ -- the same lifetime is elided here | | - | this lifetime flows to the output + | the lifetime is named here | -help: one option is to consistently use `'static` + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'static` | LL - fn static_ref_to_explicit_anonymous_ref(v: &'static u8) -> &'_ u8 { LL + fn static_ref_to_explicit_anonymous_ref(v: &'static u8) -> &'static u8 { | -error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:134:40 +error: hiding a lifetime that's named elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:136:40 | LL | fn static_ref_to_implicit_path(v: &'static u8) -> ContainsLifetime { - | ^^^^^^^ ---------------- the lifetime gets resolved as `'static` + | ^^^^^^^ ---------------- the same lifetime is hidden here | | - | this lifetime flows to the output + | the lifetime is named here | -help: one option is to consistently use `'static` + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'static` | LL | fn static_ref_to_implicit_path(v: &'static u8) -> ContainsLifetime<'static> { | +++++++++ -error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:139:50 +error: eliding a lifetime that's named elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:141:50 | LL | fn static_ref_to_explicit_anonymous_path(v: &'static u8) -> ContainsLifetime<'_> { - | ^^^^^^^ -- the lifetime gets resolved as `'static` + | ^^^^^^^ -- the same lifetime is elided here | | - | this lifetime flows to the output + | the lifetime is named here | -help: one option is to consistently use `'static` + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'static` | LL - fn static_ref_to_explicit_anonymous_path(v: &'static u8) -> ContainsLifetime<'_> { LL + fn static_ref_to_explicit_anonymous_path(v: &'static u8) -> ContainsLifetime<'static> { | -error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:145:40 +error: eliding a lifetime that's named elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:147:40 | LL | fn static_ref_to_implicit_ref(&'static self) -> &u8 { - | ^^^^^^^ --- the lifetime gets resolved as `'static` + | ^^^^^^^ --- the same lifetime is elided here | | - | this lifetime flows to the output + | the lifetime is named here | -help: one option is to consistently use `'static` + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'static` | LL | fn static_ref_to_implicit_ref(&'static self) -> &'static u8 { | +++++++ -error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:150:50 +error: eliding a lifetime that's named elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:152:50 | LL | fn static_ref_to_explicit_anonymous_ref(&'static self) -> &'_ u8 { - | ^^^^^^^ -- the lifetime gets resolved as `'static` + | ^^^^^^^ -- the same lifetime is elided here | | - | this lifetime flows to the output + | the lifetime is named here | -help: one option is to consistently use `'static` + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'static` | LL - fn static_ref_to_explicit_anonymous_ref(&'static self) -> &'_ u8 { LL + fn static_ref_to_explicit_anonymous_ref(&'static self) -> &'static u8 { | -error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:155:41 +error: hiding a lifetime that's named elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:157:41 | LL | fn static_ref_to_implicit_path(&'static self) -> ContainsLifetime { - | ^^^^^^^ ---------------- the lifetime gets resolved as `'static` + | ^^^^^^^ ---------------- the same lifetime is hidden here | | - | this lifetime flows to the output + | the lifetime is named here | -help: one option is to consistently use `'static` + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'static` | LL | fn static_ref_to_implicit_path(&'static self) -> ContainsLifetime<'static> { | +++++++++ -error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:160:51 +error: eliding a lifetime that's named elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:162:51 | LL | fn static_ref_to_explicit_anonymous_path(&'static self) -> ContainsLifetime<'_> { - | ^^^^^^^ -- the lifetime gets resolved as `'static` + | ^^^^^^^ -- the same lifetime is elided here | | - | this lifetime flows to the output + | the lifetime is named here | -help: one option is to consistently use `'static` + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'static` | LL - fn static_ref_to_explicit_anonymous_path(&'static self) -> ContainsLifetime<'_> { LL + fn static_ref_to_explicit_anonymous_path(&'static self) -> ContainsLifetime<'static> { | -error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:172:55 +error: eliding a lifetime that's named elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:174:55 | LL | fn explicit_bound_ref_to_impl_trait_bound<'a>(v: &'a u8) -> impl FnOnce() + '_ { - | ^^ -- the lifetime gets resolved as `'a` + | ^^ -- the same lifetime is elided here | | - | this lifetime flows to the output + | the lifetime is named here | -help: one option is to consistently use `'a` + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'a` | LL - fn explicit_bound_ref_to_impl_trait_bound<'a>(v: &'a u8) -> impl FnOnce() + '_ { LL + fn explicit_bound_ref_to_impl_trait_bound<'a>(v: &'a u8) -> impl FnOnce() + 'a { | -error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:177:65 +error: eliding a lifetime that's named elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:179:65 | LL | fn explicit_bound_ref_to_impl_trait_precise_capture<'a>(v: &'a u8) -> impl FnOnce() + use<'_> { - | ^^ -- the lifetime gets resolved as `'a` - | | - | this lifetime flows to the output + | ^^ the lifetime is named here -- the same lifetime is elided here | -help: one option is to consistently use `'a` + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'a` | LL - fn explicit_bound_ref_to_impl_trait_precise_capture<'a>(v: &'a u8) -> impl FnOnce() + use<'_> { LL + fn explicit_bound_ref_to_impl_trait_precise_capture<'a>(v: &'a u8) -> impl FnOnce() + use<'a> { | -error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:182:72 +error: eliding a lifetime that's named elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:184:72 | LL | fn explicit_bound_path_to_impl_trait_bound<'a>(v: ContainsLifetime<'a>) -> impl FnOnce() + '_ { - | ^^ -- the lifetime gets resolved as `'a` + | ^^ -- the same lifetime is elided here | | - | this lifetime flows to the output + | the lifetime is named here | -help: one option is to consistently use `'a` + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'a` | LL - fn explicit_bound_path_to_impl_trait_bound<'a>(v: ContainsLifetime<'a>) -> impl FnOnce() + '_ { LL + fn explicit_bound_path_to_impl_trait_bound<'a>(v: ContainsLifetime<'a>) -> impl FnOnce() + 'a { | -error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:188:29 +error: eliding a lifetime that's named elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:190:29 | LL | v: ContainsLifetime<'a>, - | ^^ this lifetime flows to the output + | ^^ the lifetime is named here LL | LL | ) -> impl FnOnce() + use<'_> { - | -- the lifetime gets resolved as `'a` + | -- the same lifetime is elided here | -help: one option is to consistently use `'a` + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'a` | LL - ) -> impl FnOnce() + use<'_> { LL + ) -> impl FnOnce() + use<'a> { | -error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:202:54 +error: eliding a lifetime that's named elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:204:54 | LL | fn explicit_bound_ref_to_dyn_trait_bound<'a>(v: &'a u8) -> Box<dyn Iterator<Item = &u8> + '_> { - | ^^ --- -- the lifetimes get resolved as `'a` - | | | - | | the lifetimes get resolved as `'a` - | this lifetime flows to the output + | ^^ the lifetime is named here --- the same lifetime is elided here | -help: one option is to consistently use `'a` + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'a` | LL | fn explicit_bound_ref_to_dyn_trait_bound<'a>(v: &'a u8) -> Box<dyn Iterator<Item = &'a u8> + '_> { | ++ -error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:208:29 +error: hiding a lifetime that's named elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:210:29 | LL | v: ContainsLifetime<'a>, - | ^^ this lifetime flows to the output + | ^^ the lifetime is named here LL | LL | ) -> Box<dyn Iterator<Item = ContainsLifetime> + '_> { - | ---------------- -- the lifetimes get resolved as `'a` - | | - | the lifetimes get resolved as `'a` + | ---------------- the same lifetime is hidden here | -help: one option is to consistently use `'a` + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'a` | LL | ) -> Box<dyn Iterator<Item = ContainsLifetime<'a>> + '_> { | ++++ -error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:217:33 +error: eliding a lifetime that's named elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:222:33 + | +LL | fn multiple_inputs<'a>(v: (&'a u8, &'a u8)) -> &u8 { + | ^^ ^^ --- the same lifetime is elided here + | | | + | | the lifetime is named here + | the lifetime is named here + | + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'a` + | +LL | fn multiple_inputs<'a>(v: (&'a u8, &'a u8)) -> &'a u8 { + | ++ + +error: eliding a lifetime that's named elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:227:33 | LL | fn multiple_outputs<'a>(v: &'a u8) -> (&u8, &u8) { - | ^^ --- --- the lifetimes get resolved as `'a` + | ^^ --- --- the same lifetime is elided here | | | - | | the lifetimes get resolved as `'a` - | this lifetime flows to the output + | | the same lifetime is elided here + | the lifetime is named here | -help: one option is to consistently use `'a` + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'a` | LL | fn multiple_outputs<'a>(v: &'a u8) -> (&'a u8, &'a u8) { | ++ ++ -error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:230:45 +error: hiding or eliding a lifetime that's named elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:232:53 + | +LL | fn all_three_categories<'a>(v: ContainsLifetime<'a>) -> (&u8, ContainsLifetime) { + | ^^ --- ---------------- the same lifetime is hidden here + | | | + | | the same lifetime is elided here + | the lifetime is named here + | + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'a` + | +LL | fn all_three_categories<'a>(v: ContainsLifetime<'a>) -> (&'a u8, ContainsLifetime<'a>) { + | ++ ++++ + +error: eliding a lifetime that's named elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:237:38 + | +LL | fn explicit_bound_output<'a>(v: &'a u8) -> (&u8, &'a u8, ContainsLifetime<'a>) { + | ^^ --- -- -- the same lifetime is named here + | | | | + | | | the same lifetime is named here + | | the same lifetime is elided here + | the lifetime is named here + | + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'a` + | +LL | fn explicit_bound_output<'a>(v: &'a u8) -> (&'a u8, &'a u8, ContainsLifetime<'a>) { + | ++ + +error: hiding a lifetime that's elided elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:250:45 | LL | fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime; - | ^^^ ---------------- the lifetime gets resolved as `'_` + | ^^^ ---------------- the same lifetime is hidden here | | - | this lifetime flows to the output + | the lifetime is elided here | -help: one option is to remove the lifetime for references and use the anonymous lifetime for paths + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: use `'_` for type paths | LL | fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime<'_>; | ++++ -error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:233:49 +error: hiding a lifetime that's elided elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:253:49 | LL | fn method_implicit_ref_to_implicit_path(&self) -> ContainsLifetime; - | ^^^^^ ---------------- the lifetime gets resolved as `'_` + | ^^^^^ ---------------- the same lifetime is hidden here | | - | this lifetime flows to the output + | the lifetime is elided here | -help: one option is to remove the lifetime for references and use the anonymous lifetime for paths + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: use `'_` for type paths | LL | fn method_implicit_ref_to_implicit_path(&self) -> ContainsLifetime<'_>; | ++++ -error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:238:45 +error: hiding a lifetime that's elided elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:258:45 | LL | fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime { - | ^^^ ---------------- the lifetime gets resolved as `'_` + | ^^^ ---------------- the same lifetime is hidden here | | - | this lifetime flows to the output + | the lifetime is elided here | -help: one option is to remove the lifetime for references and use the anonymous lifetime for paths + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: use `'_` for type paths | LL | fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime<'_> { | ++++ -error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:243:49 +error: hiding a lifetime that's elided elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:263:49 | LL | fn method_implicit_ref_to_implicit_path(&self) -> ContainsLifetime { - | ^^^^^ ---------------- the lifetime gets resolved as `'_` + | ^^^^^ ---------------- the same lifetime is hidden here | | - | this lifetime flows to the output + | the lifetime is elided here | -help: one option is to remove the lifetime for references and use the anonymous lifetime for paths + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: use `'_` for type paths | LL | fn method_implicit_ref_to_implicit_path(&self) -> ContainsLifetime<'_> { | ++++ -error: lifetime flowing from input to output with different syntax can be confusing - --> $DIR/mismatched-lifetime-syntaxes.rs:257:45 +error: hiding a lifetime that's elided elsewhere is confusing + --> $DIR/mismatched-lifetime-syntaxes.rs:277:45 | LL | fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime; - | ^^^ ---------------- the lifetime gets resolved as `'_` + | ^^^ ---------------- the same lifetime is hidden here | | - | this lifetime flows to the output + | the lifetime is elided here | -help: one option is to remove the lifetime for references and use the anonymous lifetime for paths + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: use `'_` for type paths | LL | fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime<'_>; | ++++ -error: aborting due to 39 previous errors +error: aborting due to 42 previous errors diff --git a/tests/ui/nll/issue-50716.rs b/tests/ui/nll/issue-50716.rs index 76c6fc5e7b9..96168ebeaa1 100644 --- a/tests/ui/nll/issue-50716.rs +++ b/tests/ui/nll/issue-50716.rs @@ -5,7 +5,7 @@ trait A { type X: ?Sized; } -fn foo<'a, T: 'static>(s: Box<<&'a T as A>::X>) //~ ERROR +fn foo<'a, T: 'static>(s: Box<<&'a T as A>::X>) where for<'b> &'b T: A, <&'static T as A>::X: Sized diff --git a/tests/ui/nll/issue-50716.stderr b/tests/ui/nll/issue-50716.stderr index edd7fd765da..536f88085de 100644 --- a/tests/ui/nll/issue-50716.stderr +++ b/tests/ui/nll/issue-50716.stderr @@ -1,18 +1,3 @@ -error[E0308]: mismatched types - --> $DIR/issue-50716.rs:8:27 - | -LL | fn foo<'a, T: 'static>(s: Box<<&'a T as A>::X>) - | ^^^^^^^^^^^^^^^^^^^^ lifetime mismatch - | - = note: expected trait `<<&'a T as A>::X as MetaSized>` - found trait `<<&'static T as A>::X as MetaSized>` -note: the lifetime `'a` as defined here... - --> $DIR/issue-50716.rs:8:8 - | -LL | fn foo<'a, T: 'static>(s: Box<<&'a T as A>::X>) - | ^^ - = note: ...does not necessarily outlive the static lifetime - error: lifetime may not live long enough --> $DIR/issue-50716.rs:13:14 | @@ -22,6 +7,5 @@ LL | fn foo<'a, T: 'static>(s: Box<<&'a T as A>::X>) LL | let _x = *s; | ^^ proving this value is `Sized` requires that `'a` must outlive `'static` -error: aborting due to 2 previous errors +error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/panics/panic-main.rs b/tests/ui/panics/panic-main.rs index 3876dbb37c3..bf79de78a57 100644 --- a/tests/ui/panics/panic-main.rs +++ b/tests/ui/panics/panic-main.rs @@ -1,3 +1,26 @@ +//@ revisions: default abort-zero abort-one abort-full unwind-zero unwind-one unwind-full + +//@[abort-zero] compile-flags: -Cpanic=abort +//@[abort-zero] no-prefer-dynamic +//@[abort-zero] exec-env:RUST_BACKTRACE=0 + +//@[abort-one] compile-flags: -Cpanic=abort +//@[abort-one] no-prefer-dynamic +//@[abort-one] exec-env:RUST_BACKTRACE=1 + +//@[abort-full] compile-flags: -Cpanic=abort +//@[abort-full] no-prefer-dynamic +//@[abort-full] exec-env:RUST_BACKTRACE=full + +//@[unwind-zero] compile-flags: -Cpanic=unwind +//@[unwind-zero] exec-env:RUST_BACKTRACE=0 + +//@[unwind-one] compile-flags: -Cpanic=unwind +//@[unwind-one] exec-env:RUST_BACKTRACE=1 + +//@[unwind-full] compile-flags: -Cpanic=unwind +//@[unwind-full] exec-env:RUST_BACKTRACE=full + //@ run-fail //@ error-pattern:moop //@ needs-subprocess diff --git a/tests/ui/privacy/private-in-public-warn.rs b/tests/ui/privacy/private-in-public-warn.rs index 746b98fbd07..f79e4641312 100644 --- a/tests/ui/privacy/private-in-public-warn.rs +++ b/tests/ui/privacy/private-in-public-warn.rs @@ -35,6 +35,7 @@ mod types { mod traits { trait PrivTr {} + impl PrivTr for () {} pub struct Pub<T>(T); pub trait PubTr {} @@ -45,7 +46,10 @@ mod traits { pub trait Tr3 { type Alias: PrivTr; //~^ ERROR trait `traits::PrivTr` is more private than the item `traits::Tr3::Alias` - fn f<T: PrivTr>(arg: T) {} //~ ERROR trait `traits::PrivTr` is more private than the item `traits::Tr3::f` + fn f<T: PrivTr>(arg: T) {} + //~^ ERROR trait `traits::PrivTr` is more private than the item `traits::Tr3::f` + fn g() -> impl PrivTr; + fn h() -> impl PrivTr {} } impl<T: PrivTr> Pub<T> {} //~ ERROR trait `traits::PrivTr` is more private than the item `traits::Pub<T>` impl<T: PrivTr> PubTr for Pub<T> {} // OK, trait impl predicates @@ -75,12 +79,18 @@ mod generics { pub struct Pub<T = u8>(T); trait PrivTr<T> {} pub trait PubTr<T> {} + impl PrivTr<Priv<()>> for () {} pub trait Tr1: PrivTr<Pub> {} //~^ ERROR trait `generics::PrivTr<generics::Pub>` is more private than the item `generics::Tr1` pub trait Tr2: PubTr<Priv> {} //~ ERROR type `generics::Priv` is more private than the item `generics::Tr2` pub trait Tr3: PubTr<[Priv; 1]> {} //~ ERROR type `generics::Priv` is more private than the item `generics::Tr3` pub trait Tr4: PubTr<Pub<Priv>> {} //~ ERROR type `generics::Priv` is more private than the item `Tr4` + + pub trait Tr5 { + fn required() -> impl PrivTr<Priv<()>>; + fn provided() -> impl PrivTr<Priv<()>> {} + } } mod impls { diff --git a/tests/ui/privacy/private-in-public-warn.stderr b/tests/ui/privacy/private-in-public-warn.stderr index 3743879ffa6..c2a57e3b82c 100644 --- a/tests/ui/privacy/private-in-public-warn.stderr +++ b/tests/ui/privacy/private-in-public-warn.stderr @@ -130,7 +130,7 @@ LL | type Alias = Priv; | ^^^^^^^^^^ can't leak private type error: trait `traits::PrivTr` is more private than the item `traits::Alias` - --> $DIR/private-in-public-warn.rs:41:5 + --> $DIR/private-in-public-warn.rs:42:5 | LL | pub type Alias<T: PrivTr> = T; | ^^^^^^^^^^^^^^^^^^^^^^^^^ type alias `traits::Alias` is reachable at visibility `pub(crate)` @@ -147,7 +147,7 @@ LL | #![deny(private_interfaces, private_bounds)] | ^^^^^^^^^^^^^^ error: trait `traits::PrivTr` is more private than the item `traits::Tr1` - --> $DIR/private-in-public-warn.rs:43:5 + --> $DIR/private-in-public-warn.rs:44:5 | LL | pub trait Tr1: PrivTr {} | ^^^^^^^^^^^^^^^^^^^^^ trait `traits::Tr1` is reachable at visibility `pub(crate)` @@ -159,7 +159,7 @@ LL | trait PrivTr {} | ^^^^^^^^^^^^ error: trait `traits::PrivTr` is more private than the item `traits::Tr2` - --> $DIR/private-in-public-warn.rs:44:5 + --> $DIR/private-in-public-warn.rs:45:5 | LL | pub trait Tr2<T: PrivTr> {} | ^^^^^^^^^^^^^^^^^^^^^^^^ trait `traits::Tr2` is reachable at visibility `pub(crate)` @@ -171,7 +171,7 @@ LL | trait PrivTr {} | ^^^^^^^^^^^^ error: trait `traits::PrivTr` is more private than the item `traits::Tr3::Alias` - --> $DIR/private-in-public-warn.rs:46:9 + --> $DIR/private-in-public-warn.rs:47:9 | LL | type Alias: PrivTr; | ^^^^^^^^^^^^^^^^^^ associated type `traits::Tr3::Alias` is reachable at visibility `pub(crate)` @@ -183,7 +183,7 @@ LL | trait PrivTr {} | ^^^^^^^^^^^^ error: trait `traits::PrivTr` is more private than the item `traits::Tr3::f` - --> $DIR/private-in-public-warn.rs:48:9 + --> $DIR/private-in-public-warn.rs:49:9 | LL | fn f<T: PrivTr>(arg: T) {} | ^^^^^^^^^^^^^^^^^^^^^^^ associated function `traits::Tr3::f` is reachable at visibility `pub(crate)` @@ -195,7 +195,7 @@ LL | trait PrivTr {} | ^^^^^^^^^^^^ error: trait `traits::PrivTr` is more private than the item `traits::Pub<T>` - --> $DIR/private-in-public-warn.rs:50:5 + --> $DIR/private-in-public-warn.rs:54:5 | LL | impl<T: PrivTr> Pub<T> {} | ^^^^^^^^^^^^^^^^^^^^^^ implementation `traits::Pub<T>` is reachable at visibility `pub(crate)` @@ -207,103 +207,103 @@ LL | trait PrivTr {} | ^^^^^^^^^^^^ error: trait `traits_where::PrivTr` is more private than the item `traits_where::Alias` - --> $DIR/private-in-public-warn.rs:59:5 + --> $DIR/private-in-public-warn.rs:63:5 | LL | pub type Alias<T> where T: PrivTr = T; | ^^^^^^^^^^^^^^^^^ type alias `traits_where::Alias` is reachable at visibility `pub(crate)` | note: but trait `traits_where::PrivTr` is only usable at visibility `pub(self)` - --> $DIR/private-in-public-warn.rs:55:5 + --> $DIR/private-in-public-warn.rs:59:5 | LL | trait PrivTr {} | ^^^^^^^^^^^^ error: trait `traits_where::PrivTr` is more private than the item `traits_where::Tr2` - --> $DIR/private-in-public-warn.rs:62:5 + --> $DIR/private-in-public-warn.rs:66:5 | LL | pub trait Tr2<T> where T: PrivTr {} | ^^^^^^^^^^^^^^^^ trait `traits_where::Tr2` is reachable at visibility `pub(crate)` | note: but trait `traits_where::PrivTr` is only usable at visibility `pub(self)` - --> $DIR/private-in-public-warn.rs:55:5 + --> $DIR/private-in-public-warn.rs:59:5 | LL | trait PrivTr {} | ^^^^^^^^^^^^ error: trait `traits_where::PrivTr` is more private than the item `traits_where::Tr3::f` - --> $DIR/private-in-public-warn.rs:65:9 + --> $DIR/private-in-public-warn.rs:69:9 | LL | fn f<T>(arg: T) where T: PrivTr {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ associated function `traits_where::Tr3::f` is reachable at visibility `pub(crate)` | note: but trait `traits_where::PrivTr` is only usable at visibility `pub(self)` - --> $DIR/private-in-public-warn.rs:55:5 + --> $DIR/private-in-public-warn.rs:59:5 | LL | trait PrivTr {} | ^^^^^^^^^^^^ error: trait `traits_where::PrivTr` is more private than the item `traits_where::Pub<T>` - --> $DIR/private-in-public-warn.rs:68:5 + --> $DIR/private-in-public-warn.rs:72:5 | LL | impl<T> Pub<T> where T: PrivTr {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation `traits_where::Pub<T>` is reachable at visibility `pub(crate)` | note: but trait `traits_where::PrivTr` is only usable at visibility `pub(self)` - --> $DIR/private-in-public-warn.rs:55:5 + --> $DIR/private-in-public-warn.rs:59:5 | LL | trait PrivTr {} | ^^^^^^^^^^^^ error: trait `generics::PrivTr<generics::Pub>` is more private than the item `generics::Tr1` - --> $DIR/private-in-public-warn.rs:79:5 + --> $DIR/private-in-public-warn.rs:84:5 | LL | pub trait Tr1: PrivTr<Pub> {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ trait `generics::Tr1` is reachable at visibility `pub(crate)` | note: but trait `generics::PrivTr<generics::Pub>` is only usable at visibility `pub(self)` - --> $DIR/private-in-public-warn.rs:76:5 + --> $DIR/private-in-public-warn.rs:80:5 | LL | trait PrivTr<T> {} | ^^^^^^^^^^^^^^^ error: type `generics::Priv` is more private than the item `generics::Tr2` - --> $DIR/private-in-public-warn.rs:81:5 + --> $DIR/private-in-public-warn.rs:86:5 | LL | pub trait Tr2: PubTr<Priv> {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ trait `generics::Tr2` is reachable at visibility `pub(crate)` | note: but type `generics::Priv` is only usable at visibility `pub(self)` - --> $DIR/private-in-public-warn.rs:74:5 + --> $DIR/private-in-public-warn.rs:78:5 | LL | struct Priv<T = u8>(T); | ^^^^^^^^^^^^^^^^^^^ error: type `generics::Priv` is more private than the item `generics::Tr3` - --> $DIR/private-in-public-warn.rs:82:5 + --> $DIR/private-in-public-warn.rs:87:5 | LL | pub trait Tr3: PubTr<[Priv; 1]> {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait `generics::Tr3` is reachable at visibility `pub(crate)` | note: but type `generics::Priv` is only usable at visibility `pub(self)` - --> $DIR/private-in-public-warn.rs:74:5 + --> $DIR/private-in-public-warn.rs:78:5 | LL | struct Priv<T = u8>(T); | ^^^^^^^^^^^^^^^^^^^ error: type `generics::Priv` is more private than the item `Tr4` - --> $DIR/private-in-public-warn.rs:83:5 + --> $DIR/private-in-public-warn.rs:88:5 | LL | pub trait Tr4: PubTr<Pub<Priv>> {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait `Tr4` is reachable at visibility `pub(crate)` | note: but type `generics::Priv` is only usable at visibility `pub(self)` - --> $DIR/private-in-public-warn.rs:74:5 + --> $DIR/private-in-public-warn.rs:78:5 | LL | struct Priv<T = u8>(T); | ^^^^^^^^^^^^^^^^^^^ error[E0446]: private type `impls::Priv` in public interface - --> $DIR/private-in-public-warn.rs:109:9 + --> $DIR/private-in-public-warn.rs:119:9 | LL | struct Priv; | ----------- `impls::Priv` declared as private @@ -312,19 +312,19 @@ LL | type Alias = Priv; | ^^^^^^^^^^ can't leak private type error: type `aliases_pub::Priv` is more private than the item `aliases_pub::<impl Pub2>::f` - --> $DIR/private-in-public-warn.rs:180:9 + --> $DIR/private-in-public-warn.rs:190:9 | LL | pub fn f(arg: Priv) {} | ^^^^^^^^^^^^^^^^^^^ associated function `aliases_pub::<impl Pub2>::f` is reachable at visibility `pub(crate)` | note: but type `aliases_pub::Priv` is only usable at visibility `pub(self)` - --> $DIR/private-in-public-warn.rs:153:5 + --> $DIR/private-in-public-warn.rs:163:5 | LL | struct Priv; | ^^^^^^^^^^^ error[E0446]: private type `aliases_pub::Priv` in public interface - --> $DIR/private-in-public-warn.rs:183:9 + --> $DIR/private-in-public-warn.rs:193:9 | LL | struct Priv; | ----------- `aliases_pub::Priv` declared as private @@ -333,7 +333,7 @@ LL | type Check = Priv; | ^^^^^^^^^^ can't leak private type error[E0446]: private type `aliases_pub::Priv` in public interface - --> $DIR/private-in-public-warn.rs:186:9 + --> $DIR/private-in-public-warn.rs:196:9 | LL | struct Priv; | ----------- `aliases_pub::Priv` declared as private @@ -342,7 +342,7 @@ LL | type Check = Priv; | ^^^^^^^^^^ can't leak private type error[E0446]: private type `aliases_pub::Priv` in public interface - --> $DIR/private-in-public-warn.rs:189:9 + --> $DIR/private-in-public-warn.rs:199:9 | LL | struct Priv; | ----------- `aliases_pub::Priv` declared as private @@ -351,7 +351,7 @@ LL | type Check = Priv; | ^^^^^^^^^^ can't leak private type error[E0446]: private type `aliases_pub::Priv` in public interface - --> $DIR/private-in-public-warn.rs:192:9 + --> $DIR/private-in-public-warn.rs:202:9 | LL | struct Priv; | ----------- `aliases_pub::Priv` declared as private @@ -360,43 +360,43 @@ LL | type Check = Priv; | ^^^^^^^^^^ can't leak private type error: trait `PrivTr1` is more private than the item `aliases_priv::Tr1` - --> $DIR/private-in-public-warn.rs:222:5 + --> $DIR/private-in-public-warn.rs:232:5 | LL | pub trait Tr1: PrivUseAliasTr {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait `aliases_priv::Tr1` is reachable at visibility `pub(crate)` | note: but trait `PrivTr1` is only usable at visibility `pub(self)` - --> $DIR/private-in-public-warn.rs:208:5 + --> $DIR/private-in-public-warn.rs:218:5 | LL | trait PrivTr1<T = u8> { | ^^^^^^^^^^^^^^^^^^^^^ error: trait `PrivTr1<Priv2>` is more private than the item `aliases_priv::Tr2` - --> $DIR/private-in-public-warn.rs:224:5 + --> $DIR/private-in-public-warn.rs:234:5 | LL | pub trait Tr2: PrivUseAliasTr<PrivAlias> {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait `aliases_priv::Tr2` is reachable at visibility `pub(crate)` | note: but trait `PrivTr1<Priv2>` is only usable at visibility `pub(self)` - --> $DIR/private-in-public-warn.rs:208:5 + --> $DIR/private-in-public-warn.rs:218:5 | LL | trait PrivTr1<T = u8> { | ^^^^^^^^^^^^^^^^^^^^^ error: type `Priv2` is more private than the item `aliases_priv::Tr2` - --> $DIR/private-in-public-warn.rs:224:5 + --> $DIR/private-in-public-warn.rs:234:5 | LL | pub trait Tr2: PrivUseAliasTr<PrivAlias> {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait `aliases_priv::Tr2` is reachable at visibility `pub(crate)` | note: but type `Priv2` is only usable at visibility `pub(self)` - --> $DIR/private-in-public-warn.rs:206:5 + --> $DIR/private-in-public-warn.rs:216:5 | LL | struct Priv2; | ^^^^^^^^^^^^ warning: bounds on generic parameters in type aliases are not enforced - --> $DIR/private-in-public-warn.rs:41:23 + --> $DIR/private-in-public-warn.rs:42:23 | LL | pub type Alias<T: PrivTr> = T; | --^^^^^^ @@ -410,7 +410,7 @@ LL | pub type Alias<T: PrivTr> = T; = note: `#[warn(type_alias_bounds)]` on by default warning: where clauses on type aliases are not enforced - --> $DIR/private-in-public-warn.rs:59:29 + --> $DIR/private-in-public-warn.rs:63:29 | LL | pub type Alias<T> where T: PrivTr = T; | ------^^^^^^^^^ diff --git a/tests/ui/privacy/pub-priv-dep/auxiliary/priv_dep.rs b/tests/ui/privacy/pub-priv-dep/auxiliary/priv_dep.rs index 4eeecdc0569..75640147026 100644 --- a/tests/ui/privacy/pub-priv-dep/auxiliary/priv_dep.rs +++ b/tests/ui/privacy/pub-priv-dep/auxiliary/priv_dep.rs @@ -1,5 +1,6 @@ pub struct OtherType; pub trait OtherTrait {} +impl OtherTrait for OtherType {} #[macro_export] macro_rules! m { diff --git a/tests/ui/privacy/pub-priv-dep/pub-priv1.rs b/tests/ui/privacy/pub-priv-dep/pub-priv1.rs index 877029f3de3..b85f2754fb1 100644 --- a/tests/ui/privacy/pub-priv-dep/pub-priv1.rs +++ b/tests/ui/privacy/pub-priv-dep/pub-priv1.rs @@ -9,10 +9,10 @@ #![deny(exported_private_dependencies)] // This crate is a private dependency -// FIXME: This should trigger. pub extern crate priv_dep; +//~^ ERROR crate `priv_dep` from private dependency 'priv_dep' is re-exported // This crate is a public dependency -extern crate pub_dep; +pub extern crate pub_dep; // This crate is a private dependency extern crate pm; @@ -44,8 +44,12 @@ impl PublicType { pub trait MyPubTrait { type Foo: OtherTrait; + //~^ ERROR trait `OtherTrait` from private dependency 'priv_dep' in public interface + + fn required() -> impl OtherTrait; + + fn provided() -> impl OtherTrait { OtherType } } -//~^^ ERROR trait `OtherTrait` from private dependency 'priv_dep' in public interface pub trait WithSuperTrait: OtherTrait {} //~^ ERROR trait `OtherTrait` from private dependency 'priv_dep' in public interface @@ -91,16 +95,16 @@ pub struct AllowedPrivType { pub allowed: OtherType, } -// FIXME: This should trigger. pub use priv_dep::m; -// FIXME: This should trigger. +//~^ ERROR macro `m` from private dependency 'priv_dep' is re-exported pub use pm::fn_like; -// FIXME: This should trigger. +//~^ ERROR macro `fn_like` from private dependency 'pm' is re-exported pub use pm::PmDerive; -// FIXME: This should trigger. +//~^ ERROR macro `PmDerive` from private dependency 'pm' is re-exported pub use pm::pm_attr; +//~^ ERROR macro `pm_attr` from private dependency 'pm' is re-exported -// FIXME: This should trigger. pub use priv_dep::E::V1; +//~^ ERROR variant `V1` from private dependency 'priv_dep' is re-exported fn main() {} diff --git a/tests/ui/privacy/pub-priv-dep/pub-priv1.stderr b/tests/ui/privacy/pub-priv-dep/pub-priv1.stderr index adfe13424cd..24bd071567f 100644 --- a/tests/ui/privacy/pub-priv-dep/pub-priv1.stderr +++ b/tests/ui/privacy/pub-priv-dep/pub-priv1.stderr @@ -1,8 +1,8 @@ -error: type `OtherType` from private dependency 'priv_dep' in public interface - --> $DIR/pub-priv1.rs:29:5 +error: crate `priv_dep` from private dependency 'priv_dep' is re-exported + --> $DIR/pub-priv1.rs:12:1 | -LL | pub field: OtherType, - | ^^^^^^^^^^^^^^^^^^^^ +LL | pub extern crate priv_dep; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: the lint level is defined here --> $DIR/pub-priv1.rs:9:9 @@ -10,6 +10,42 @@ note: the lint level is defined here LL | #![deny(exported_private_dependencies)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +error: macro `m` from private dependency 'priv_dep' is re-exported + --> $DIR/pub-priv1.rs:98:9 + | +LL | pub use priv_dep::m; + | ^^^^^^^^^^^ + +error: macro `fn_like` from private dependency 'pm' is re-exported + --> $DIR/pub-priv1.rs:100:9 + | +LL | pub use pm::fn_like; + | ^^^^^^^^^^^ + +error: derive macro `PmDerive` from private dependency 'pm' is re-exported + --> $DIR/pub-priv1.rs:102:9 + | +LL | pub use pm::PmDerive; + | ^^^^^^^^^^^^ + +error: attribute macro `pm_attr` from private dependency 'pm' is re-exported + --> $DIR/pub-priv1.rs:104:9 + | +LL | pub use pm::pm_attr; + | ^^^^^^^^^^^ + +error: variant `V1` from private dependency 'priv_dep' is re-exported + --> $DIR/pub-priv1.rs:107:9 + | +LL | pub use priv_dep::E::V1; + | ^^^^^^^^^^^^^^^ + +error: type `OtherType` from private dependency 'priv_dep' in public interface + --> $DIR/pub-priv1.rs:29:5 + | +LL | pub field: OtherType, + | ^^^^^^^^^^^^^^^^^^^^ + error: type `OtherType` from private dependency 'priv_dep' in public interface --> $DIR/pub-priv1.rs:36:5 | @@ -29,66 +65,66 @@ LL | type Foo: OtherTrait; | ^^^^^^^^^^^^^^^^^^^^ error: trait `OtherTrait` from private dependency 'priv_dep' in public interface - --> $DIR/pub-priv1.rs:50:1 + --> $DIR/pub-priv1.rs:54:1 | LL | pub trait WithSuperTrait: OtherTrait {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: type `OtherType` from private dependency 'priv_dep' in public interface - --> $DIR/pub-priv1.rs:59:5 + --> $DIR/pub-priv1.rs:63:5 | LL | type X = OtherType; | ^^^^^^ error: trait `OtherTrait` from private dependency 'priv_dep' in public interface - --> $DIR/pub-priv1.rs:63:1 + --> $DIR/pub-priv1.rs:67:1 | LL | pub fn in_bounds<T: OtherTrait>(x: T) { unimplemented!() } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: type `OtherType` from private dependency 'priv_dep' in public interface - --> $DIR/pub-priv1.rs:66:1 + --> $DIR/pub-priv1.rs:70:1 | LL | pub fn private_in_generic() -> std::num::Saturating<OtherType> { unimplemented!() } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: type `OtherType` from private dependency 'priv_dep' in public interface - --> $DIR/pub-priv1.rs:69:1 + --> $DIR/pub-priv1.rs:73:1 | LL | pub static STATIC: OtherType = OtherType; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: type `OtherType` from private dependency 'priv_dep' in public interface - --> $DIR/pub-priv1.rs:72:1 + --> $DIR/pub-priv1.rs:76:1 | LL | pub const CONST: OtherType = OtherType; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: type `OtherType` from private dependency 'priv_dep' in public interface - --> $DIR/pub-priv1.rs:75:1 + --> $DIR/pub-priv1.rs:79:1 | LL | pub type Alias = OtherType; | ^^^^^^^^^^^^^^ error: trait `OtherTrait` from private dependency 'priv_dep' in public interface - --> $DIR/pub-priv1.rs:80:1 + --> $DIR/pub-priv1.rs:84:1 | LL | impl OtherTrait for PublicWithPrivateImpl {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: type `OtherType` from private dependency 'priv_dep' in public interface - --> $DIR/pub-priv1.rs:85:1 + --> $DIR/pub-priv1.rs:89:1 | LL | impl PubTraitOnPrivate for OtherType {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: type `OtherType` from private dependency 'priv_dep' in public interface - --> $DIR/pub-priv1.rs:85:1 + --> $DIR/pub-priv1.rs:89:1 | LL | impl PubTraitOnPrivate for OtherType {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: aborting due to 14 previous errors +error: aborting due to 20 previous errors diff --git a/tests/ui/privacy/sealed-traits/false-sealed-traits-note.rs b/tests/ui/privacy/sealed-traits/false-sealed-traits-note.rs new file mode 100644 index 00000000000..13f3065e442 --- /dev/null +++ b/tests/ui/privacy/sealed-traits/false-sealed-traits-note.rs @@ -0,0 +1,13 @@ +// We should not emit sealed traits note, see issue #143392 + +mod inner { + pub trait TraitA {} + + pub trait TraitB: TraitA {} +} + +struct Struct; + +impl inner::TraitB for Struct {} //~ ERROR the trait bound `Struct: TraitA` is not satisfied [E0277] + +fn main(){} diff --git a/tests/ui/privacy/sealed-traits/false-sealed-traits-note.stderr b/tests/ui/privacy/sealed-traits/false-sealed-traits-note.stderr new file mode 100644 index 00000000000..f80d985ad6e --- /dev/null +++ b/tests/ui/privacy/sealed-traits/false-sealed-traits-note.stderr @@ -0,0 +1,20 @@ +error[E0277]: the trait bound `Struct: TraitA` is not satisfied + --> $DIR/false-sealed-traits-note.rs:11:24 + | +LL | impl inner::TraitB for Struct {} + | ^^^^^^ the trait `TraitA` is not implemented for `Struct` + | +help: this trait has no implementations, consider adding one + --> $DIR/false-sealed-traits-note.rs:4:5 + | +LL | pub trait TraitA {} + | ^^^^^^^^^^^^^^^^ +note: required by a bound in `TraitB` + --> $DIR/false-sealed-traits-note.rs:6:23 + | +LL | pub trait TraitB: TraitA {} + | ^^^^^^ required by this bound in `TraitB` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/self/elision/ignore-non-reference-lifetimes.rs b/tests/ui/self/elision/ignore-non-reference-lifetimes.rs index ecd669059ed..ce2fb8235cc 100644 --- a/tests/ui/self/elision/ignore-non-reference-lifetimes.rs +++ b/tests/ui/self/elision/ignore-non-reference-lifetimes.rs @@ -4,11 +4,11 @@ struct Foo<'a>(&'a str); impl<'b> Foo<'b> { fn a<'a>(self: Self, a: &'a str) -> &str { - //~^ WARNING lifetime flowing from input to output with different syntax + //~^ WARNING eliding a lifetime that's named elsewhere is confusing a } fn b<'a>(self: Foo<'b>, a: &'a str) -> &str { - //~^ WARNING lifetime flowing from input to output with different syntax + //~^ WARNING eliding a lifetime that's named elsewhere is confusing a } } diff --git a/tests/ui/self/elision/ignore-non-reference-lifetimes.stderr b/tests/ui/self/elision/ignore-non-reference-lifetimes.stderr index 5351bf3c94c..7108fa1a290 100644 --- a/tests/ui/self/elision/ignore-non-reference-lifetimes.stderr +++ b/tests/ui/self/elision/ignore-non-reference-lifetimes.stderr @@ -1,26 +1,28 @@ -warning: lifetime flowing from input to output with different syntax can be confusing +warning: eliding a lifetime that's named elsewhere is confusing --> $DIR/ignore-non-reference-lifetimes.rs:6:30 | LL | fn a<'a>(self: Self, a: &'a str) -> &str { - | ^^ ---- the lifetime gets resolved as `'a` + | ^^ ---- the same lifetime is elided here | | - | this lifetime flows to the output + | the lifetime is named here | + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing = note: `#[warn(mismatched_lifetime_syntaxes)]` on by default -help: one option is to consistently use `'a` +help: consistently use `'a` | LL | fn a<'a>(self: Self, a: &'a str) -> &'a str { | ++ -warning: lifetime flowing from input to output with different syntax can be confusing +warning: eliding a lifetime that's named elsewhere is confusing --> $DIR/ignore-non-reference-lifetimes.rs:10:33 | LL | fn b<'a>(self: Foo<'b>, a: &'a str) -> &str { - | ^^ ---- the lifetime gets resolved as `'a` + | ^^ ---- the same lifetime is elided here | | - | this lifetime flows to the output + | the lifetime is named here | -help: one option is to consistently use `'a` + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'a` | LL | fn b<'a>(self: Foo<'b>, a: &'a str) -> &'a str { | ++ diff --git a/tests/ui/self/self_lifetime-async.rs b/tests/ui/self/self_lifetime-async.rs index f839ab03a60..0093971fee4 100644 --- a/tests/ui/self/self_lifetime-async.rs +++ b/tests/ui/self/self_lifetime-async.rs @@ -4,13 +4,13 @@ struct Foo<'a>(&'a ()); impl<'a> Foo<'a> { async fn foo<'b>(self: &'b Foo<'a>) -> &() { self.0 } - //~^ WARNING lifetime flowing from input to output with different syntax + //~^ WARNING eliding a lifetime that's named elsewhere is confusing } type Alias = Foo<'static>; impl Alias { async fn bar<'a>(self: &Alias, arg: &'a ()) -> &() { arg } - //~^ WARNING lifetime flowing from input to output with different syntax + //~^ WARNING eliding a lifetime that's named elsewhere is confusing } fn main() {} diff --git a/tests/ui/self/self_lifetime-async.stderr b/tests/ui/self/self_lifetime-async.stderr index a9c1be2e808..43dc96abdc2 100644 --- a/tests/ui/self/self_lifetime-async.stderr +++ b/tests/ui/self/self_lifetime-async.stderr @@ -1,26 +1,28 @@ -warning: lifetime flowing from input to output with different syntax can be confusing +warning: eliding a lifetime that's named elsewhere is confusing --> $DIR/self_lifetime-async.rs:6:29 | LL | async fn foo<'b>(self: &'b Foo<'a>) -> &() { self.0 } - | ^^ --- the lifetime gets resolved as `'b` + | ^^ --- the same lifetime is elided here | | - | this lifetime flows to the output + | the lifetime is named here | + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing = note: `#[warn(mismatched_lifetime_syntaxes)]` on by default -help: one option is to consistently use `'b` +help: consistently use `'b` | LL | async fn foo<'b>(self: &'b Foo<'a>) -> &'b () { self.0 } | ++ -warning: lifetime flowing from input to output with different syntax can be confusing +warning: eliding a lifetime that's named elsewhere is confusing --> $DIR/self_lifetime-async.rs:12:42 | LL | async fn bar<'a>(self: &Alias, arg: &'a ()) -> &() { arg } - | ^^ --- the lifetime gets resolved as `'a` + | ^^ --- the same lifetime is elided here | | - | this lifetime flows to the output + | the lifetime is named here | -help: one option is to consistently use `'a` + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'a` | LL | async fn bar<'a>(self: &Alias, arg: &'a ()) -> &'a () { arg } | ++ diff --git a/tests/ui/self/self_lifetime.rs b/tests/ui/self/self_lifetime.rs index aaa31f85ad5..190809af22f 100644 --- a/tests/ui/self/self_lifetime.rs +++ b/tests/ui/self/self_lifetime.rs @@ -5,13 +5,13 @@ struct Foo<'a>(&'a ()); impl<'a> Foo<'a> { fn foo<'b>(self: &'b Foo<'a>) -> &() { self.0 } - //~^ WARNING lifetime flowing from input to output with different syntax + //~^ WARNING eliding a lifetime that's named elsewhere is confusing } type Alias = Foo<'static>; impl Alias { fn bar<'a>(self: &Alias, arg: &'a ()) -> &() { arg } - //~^ WARNING lifetime flowing from input to output with different syntax + //~^ WARNING eliding a lifetime that's named elsewhere is confusing } fn main() {} diff --git a/tests/ui/self/self_lifetime.stderr b/tests/ui/self/self_lifetime.stderr index ec676e69cf6..4f9b2fcd2ad 100644 --- a/tests/ui/self/self_lifetime.stderr +++ b/tests/ui/self/self_lifetime.stderr @@ -1,26 +1,28 @@ -warning: lifetime flowing from input to output with different syntax can be confusing +warning: eliding a lifetime that's named elsewhere is confusing --> $DIR/self_lifetime.rs:7:23 | LL | fn foo<'b>(self: &'b Foo<'a>) -> &() { self.0 } - | ^^ --- the lifetime gets resolved as `'b` + | ^^ --- the same lifetime is elided here | | - | this lifetime flows to the output + | the lifetime is named here | + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing = note: `#[warn(mismatched_lifetime_syntaxes)]` on by default -help: one option is to consistently use `'b` +help: consistently use `'b` | LL | fn foo<'b>(self: &'b Foo<'a>) -> &'b () { self.0 } | ++ -warning: lifetime flowing from input to output with different syntax can be confusing +warning: eliding a lifetime that's named elsewhere is confusing --> $DIR/self_lifetime.rs:13:36 | LL | fn bar<'a>(self: &Alias, arg: &'a ()) -> &() { arg } - | ^^ --- the lifetime gets resolved as `'a` + | ^^ --- the same lifetime is elided here | | - | this lifetime flows to the output + | the lifetime is named here | -help: one option is to consistently use `'a` + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing +help: consistently use `'a` | LL | fn bar<'a>(self: &Alias, arg: &'a ()) -> &'a () { arg } | ++ diff --git a/tests/ui/sized-hierarchy/incomplete-inference-issue-143992.next.stderr b/tests/ui/sized-hierarchy/incomplete-inference-issue-143992.next.stderr new file mode 100644 index 00000000000..cf56f42afc8 --- /dev/null +++ b/tests/ui/sized-hierarchy/incomplete-inference-issue-143992.next.stderr @@ -0,0 +1,17 @@ +error[E0308]: mismatched types + --> $DIR/incomplete-inference-issue-143992.rs:27:28 + | +LL | let _x = T::Assoc::new(()); + | ------------- ^^ expected `[u32; 1]`, found `()` + | | + | arguments to this function are incorrect + | +note: associated function defined here + --> $DIR/incomplete-inference-issue-143992.rs:18:8 + | +LL | fn new(r: R) -> R { + | ^^^ ---- + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/sized-hierarchy/incomplete-inference-issue-143992.rs b/tests/ui/sized-hierarchy/incomplete-inference-issue-143992.rs new file mode 100644 index 00000000000..3e3e1dc50e5 --- /dev/null +++ b/tests/ui/sized-hierarchy/incomplete-inference-issue-143992.rs @@ -0,0 +1,29 @@ +//@ compile-flags: --crate-type=lib +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[current] check-pass +//@[next] compile-flags: -Znext-solver +//@[next] check-fail + +// Test that we avoid incomplete inference when normalizing. Without this, +// `Trait`'s implicit `MetaSized` supertrait requires proving `T::Assoc<_>: MetaSized` +// before checking the `new` arguments, resulting in eagerly constraining the inference +// var to `u32`. This is undesirable and would breaking code. + +pub trait Trait { + type Assoc<G>: OtherTrait<G>; +} + +pub trait OtherTrait<R> { + fn new(r: R) -> R { + r + } +} + +pub fn function<T: Trait>() +where + T::Assoc<[u32; 1]>: Clone, +{ + let _x = T::Assoc::new(()); +//[next]~^ ERROR mismatched types +} diff --git a/tests/ui/sized-hierarchy/overflow.current.stderr b/tests/ui/sized-hierarchy/overflow.current.stderr deleted file mode 100644 index e90548aa78c..00000000000 --- a/tests/ui/sized-hierarchy/overflow.current.stderr +++ /dev/null @@ -1,45 +0,0 @@ -error[E0275]: overflow evaluating the requirement `Element: MetaSized` - --> $DIR/overflow.rs:16:16 - | -LL | struct Element(<Box<Box<Element>> as ParseTokens>::Output); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: required for `Box<Element>` to implement `ParseTokens` - --> $DIR/overflow.rs:12:31 - | -LL | impl<T: ParseTokens + ?Sized> ParseTokens for Box<T> { - | - ^^^^^^^^^^^ ^^^^^^ - | | - | unsatisfied trait bound introduced here - = note: 1 redundant requirement hidden - = note: required for `Box<Box<Element>>` to implement `ParseTokens` - -error[E0275]: overflow evaluating the requirement `Box<Element>: ParseTokens` - --> $DIR/overflow.rs:18:22 - | -LL | impl ParseTokens for Element { - | ^^^^^^^ - | -note: required for `Box<Box<Element>>` to implement `ParseTokens` - --> $DIR/overflow.rs:12:31 - | -LL | impl<T: ParseTokens + ?Sized> ParseTokens for Box<T> { - | ----------- ^^^^^^^^^^^ ^^^^^^ - | | - | unsatisfied trait bound introduced here -note: required because it appears within the type `Element` - --> $DIR/overflow.rs:16:8 - | -LL | struct Element(<Box<Box<Element>> as ParseTokens>::Output); - | ^^^^^^^ -note: required by a bound in `ParseTokens` - --> $DIR/overflow.rs:9:1 - | -LL | / trait ParseTokens { -LL | | type Output; -LL | | } - | |_^ required by this bound in `ParseTokens` - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/sized-hierarchy/overflow.rs b/tests/ui/sized-hierarchy/overflow.rs index e1af4885e53..f8e5dd5d402 100644 --- a/tests/ui/sized-hierarchy/overflow.rs +++ b/tests/ui/sized-hierarchy/overflow.rs @@ -1,9 +1,13 @@ //@ compile-flags: --crate-type=lib //@ revisions: current next //@ ignore-compare-mode-next-solver (explicit revisions) +//@[current] check-pass //@[next] check-pass //@[next] compile-flags: -Znext-solver +// FIXME(sized_hierarchy): this is expected to fail in the old solver when there +// isn't a temporary revert of the `sized_hierarchy` feature + use std::marker::PhantomData; trait ParseTokens { @@ -14,8 +18,6 @@ impl<T: ParseTokens + ?Sized> ParseTokens for Box<T> { } struct Element(<Box<Box<Element>> as ParseTokens>::Output); -//[current]~^ ERROR overflow evaluating impl ParseTokens for Element { -//[current]~^ ERROR overflow evaluating type Output = (); } diff --git a/tests/ui/specialization/const_trait_impl.stderr b/tests/ui/specialization/const_trait_impl.stderr index b9c768812c8..a21a48997ee 100644 --- a/tests/ui/specialization/const_trait_impl.stderr +++ b/tests/ui/specialization/const_trait_impl.stderr @@ -1,57 +1,57 @@ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/const_trait_impl.rs:36:9 | LL | impl<T: [const] Debug> const A for T { | ^^^^^^^ can't be applied to `Debug` | -note: `Debug` can't be used with `[const]` because it isn't annotated with `#[const_trait]` +note: `Debug` can't be used with `[const]` because it isn't `const` --> $SRC_DIR/core/src/fmt/mod.rs:LL:COL -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/const_trait_impl.rs:42:9 | LL | impl<T: [const] Debug + [const] Sup> const A for T { | ^^^^^^^ can't be applied to `Debug` | -note: `Debug` can't be used with `[const]` because it isn't annotated with `#[const_trait]` +note: `Debug` can't be used with `[const]` because it isn't `const` --> $SRC_DIR/core/src/fmt/mod.rs:LL:COL -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/const_trait_impl.rs:48:9 | LL | impl<T: [const] Debug + [const] Sub> const A for T { | ^^^^^^^ can't be applied to `Debug` | -note: `Debug` can't be used with `[const]` because it isn't annotated with `#[const_trait]` +note: `Debug` can't be used with `[const]` because it isn't `const` --> $SRC_DIR/core/src/fmt/mod.rs:LL:COL -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/const_trait_impl.rs:42:9 | LL | impl<T: [const] Debug + [const] Sup> const A for T { | ^^^^^^^ can't be applied to `Debug` | -note: `Debug` can't be used with `[const]` because it isn't annotated with `#[const_trait]` +note: `Debug` can't be used with `[const]` because it isn't `const` --> $SRC_DIR/core/src/fmt/mod.rs:LL:COL = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/const_trait_impl.rs:36:9 | LL | impl<T: [const] Debug> const A for T { | ^^^^^^^ can't be applied to `Debug` | -note: `Debug` can't be used with `[const]` because it isn't annotated with `#[const_trait]` +note: `Debug` can't be used with `[const]` because it isn't `const` --> $SRC_DIR/core/src/fmt/mod.rs:LL:COL = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/const_trait_impl.rs:48:9 | LL | impl<T: [const] Debug + [const] Sub> const A for T { | ^^^^^^^ can't be applied to `Debug` | -note: `Debug` can't be used with `[const]` because it isn't annotated with `#[const_trait]` +note: `Debug` can't be used with `[const]` because it isn't `const` --> $SRC_DIR/core/src/fmt/mod.rs:LL:COL = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` diff --git a/tests/ui/stability-attribute/missing-const-stability.rs b/tests/ui/stability-attribute/missing-const-stability.rs index c3e72e83948..8a37f19ffb0 100644 --- a/tests/ui/stability-attribute/missing-const-stability.rs +++ b/tests/ui/stability-attribute/missing-const-stability.rs @@ -20,8 +20,7 @@ impl Foo { } #[stable(feature = "stable", since = "1.0.0")] -#[const_trait] -pub trait Bar { +pub const trait Bar { //~^ ERROR trait has missing const stability attribute #[stable(feature = "stable", since = "1.0.0")] fn fun(); diff --git a/tests/ui/stability-attribute/missing-const-stability.stderr b/tests/ui/stability-attribute/missing-const-stability.stderr index 09461e6fb54..70a2450c53a 100644 --- a/tests/ui/stability-attribute/missing-const-stability.stderr +++ b/tests/ui/stability-attribute/missing-const-stability.stderr @@ -5,9 +5,9 @@ LL | pub const fn foo() {} | ^^^^^^^^^^^^^^^^^^^^^ error: trait has missing const stability attribute - --> $DIR/missing-const-stability.rs:24:1 + --> $DIR/missing-const-stability.rs:23:1 | -LL | / pub trait Bar { +LL | / pub const trait Bar { LL | | LL | | #[stable(feature = "stable", since = "1.0.0")] LL | | fn fun(); @@ -15,7 +15,7 @@ LL | | } | |_^ error: function has missing const stability attribute - --> $DIR/missing-const-stability.rs:37:1 + --> $DIR/missing-const-stability.rs:36:1 | LL | pub const unsafe fn size_of_val<T>(x: *const T) -> usize { 42 } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/symbol-names/basic.legacy.stderr b/tests/ui/symbol-names/basic.legacy.stderr index 167262dcf06..a028f433172 100644 --- a/tests/ui/symbol-names/basic.legacy.stderr +++ b/tests/ui/symbol-names/basic.legacy.stderr @@ -1,10 +1,10 @@ -error: symbol-name(_ZN5basic4main17hc88b9d80a69d119aE) +error: symbol-name(_ZN5basic4main17h1dddcfd03744167fE) --> $DIR/basic.rs:8:1 | LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ -error: demangling(basic::main::hc88b9d80a69d119a) +error: demangling(basic::main::h1dddcfd03744167f) --> $DIR/basic.rs:8:1 | LL | #[rustc_symbol_name] diff --git a/tests/ui/symbol-names/issue-60925.legacy.stderr b/tests/ui/symbol-names/issue-60925.legacy.stderr index 4e17bdc4577..14cbd877d9f 100644 --- a/tests/ui/symbol-names/issue-60925.legacy.stderr +++ b/tests/ui/symbol-names/issue-60925.legacy.stderr @@ -1,10 +1,10 @@ -error: symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3foo17hbddb77d6f71afb32E) +error: symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3foo17h4b3099ec5dc5d306E) --> $DIR/issue-60925.rs:21:9 | LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ -error: demangling(issue_60925::foo::Foo<issue_60925::llvm::Foo>::foo::hbddb77d6f71afb32) +error: demangling(issue_60925::foo::Foo<issue_60925::llvm::Foo>::foo::h4b3099ec5dc5d306) --> $DIR/issue-60925.rs:21:9 | LL | #[rustc_symbol_name] diff --git a/tests/ui/thir-print/thir-tree-match.stdout b/tests/ui/thir-print/thir-tree-match.stdout index 910582ae4d9..2049c531abd 100644 --- a/tests/ui/thir-print/thir-tree-match.stdout +++ b/tests/ui/thir-print/thir-tree-match.stdout @@ -94,7 +94,7 @@ body: did: DefId(0:10 ~ thir_tree_match[fcf8]::Foo) variants: [VariantDef { def_id: DefId(0:11 ~ thir_tree_match[fcf8]::Foo::FooOne), ctor: Some((Fn, DefId(0:12 ~ thir_tree_match[fcf8]::Foo::FooOne::{constructor#0}))), name: "FooOne", discr: Relative(0), fields: [FieldDef { did: DefId(0:13 ~ thir_tree_match[fcf8]::Foo::FooOne::0), name: "0", vis: Restricted(DefId(0:0 ~ thir_tree_match[fcf8])), safety: Safe, value: None }], tainted: None, flags: }, VariantDef { def_id: DefId(0:14 ~ thir_tree_match[fcf8]::Foo::FooTwo), ctor: Some((Const, DefId(0:15 ~ thir_tree_match[fcf8]::Foo::FooTwo::{constructor#0}))), name: "FooTwo", discr: Relative(1), fields: [], tainted: None, flags: }] flags: IS_ENUM - repr: ReprOptions { int: None, align: None, pack: None, flags: , field_shuffle_seed: 3477539199540094892 } + repr: ReprOptions { int: None, align: None, pack: None, flags: , field_shuffle_seed: 13397682652773712997 } args: [] variant_index: 0 subpatterns: [ @@ -108,7 +108,7 @@ body: did: DefId(0:3 ~ thir_tree_match[fcf8]::Bar) variants: [VariantDef { def_id: DefId(0:4 ~ thir_tree_match[fcf8]::Bar::First), ctor: Some((Const, DefId(0:5 ~ thir_tree_match[fcf8]::Bar::First::{constructor#0}))), name: "First", discr: Relative(0), fields: [], tainted: None, flags: }, VariantDef { def_id: DefId(0:6 ~ thir_tree_match[fcf8]::Bar::Second), ctor: Some((Const, DefId(0:7 ~ thir_tree_match[fcf8]::Bar::Second::{constructor#0}))), name: "Second", discr: Relative(1), fields: [], tainted: None, flags: }, VariantDef { def_id: DefId(0:8 ~ thir_tree_match[fcf8]::Bar::Third), ctor: Some((Const, DefId(0:9 ~ thir_tree_match[fcf8]::Bar::Third::{constructor#0}))), name: "Third", discr: Relative(2), fields: [], tainted: None, flags: }] flags: IS_ENUM - repr: ReprOptions { int: None, align: None, pack: None, flags: , field_shuffle_seed: 10333377570083945360 } + repr: ReprOptions { int: None, align: None, pack: None, flags: , field_shuffle_seed: 7908585036048874241 } args: [] variant_index: 0 subpatterns: [] @@ -156,7 +156,7 @@ body: did: DefId(0:10 ~ thir_tree_match[fcf8]::Foo) variants: [VariantDef { def_id: DefId(0:11 ~ thir_tree_match[fcf8]::Foo::FooOne), ctor: Some((Fn, DefId(0:12 ~ thir_tree_match[fcf8]::Foo::FooOne::{constructor#0}))), name: "FooOne", discr: Relative(0), fields: [FieldDef { did: DefId(0:13 ~ thir_tree_match[fcf8]::Foo::FooOne::0), name: "0", vis: Restricted(DefId(0:0 ~ thir_tree_match[fcf8])), safety: Safe, value: None }], tainted: None, flags: }, VariantDef { def_id: DefId(0:14 ~ thir_tree_match[fcf8]::Foo::FooTwo), ctor: Some((Const, DefId(0:15 ~ thir_tree_match[fcf8]::Foo::FooTwo::{constructor#0}))), name: "FooTwo", discr: Relative(1), fields: [], tainted: None, flags: }] flags: IS_ENUM - repr: ReprOptions { int: None, align: None, pack: None, flags: , field_shuffle_seed: 3477539199540094892 } + repr: ReprOptions { int: None, align: None, pack: None, flags: , field_shuffle_seed: 13397682652773712997 } args: [] variant_index: 0 subpatterns: [ @@ -208,7 +208,7 @@ body: did: DefId(0:10 ~ thir_tree_match[fcf8]::Foo) variants: [VariantDef { def_id: DefId(0:11 ~ thir_tree_match[fcf8]::Foo::FooOne), ctor: Some((Fn, DefId(0:12 ~ thir_tree_match[fcf8]::Foo::FooOne::{constructor#0}))), name: "FooOne", discr: Relative(0), fields: [FieldDef { did: DefId(0:13 ~ thir_tree_match[fcf8]::Foo::FooOne::0), name: "0", vis: Restricted(DefId(0:0 ~ thir_tree_match[fcf8])), safety: Safe, value: None }], tainted: None, flags: }, VariantDef { def_id: DefId(0:14 ~ thir_tree_match[fcf8]::Foo::FooTwo), ctor: Some((Const, DefId(0:15 ~ thir_tree_match[fcf8]::Foo::FooTwo::{constructor#0}))), name: "FooTwo", discr: Relative(1), fields: [], tainted: None, flags: }] flags: IS_ENUM - repr: ReprOptions { int: None, align: None, pack: None, flags: , field_shuffle_seed: 3477539199540094892 } + repr: ReprOptions { int: None, align: None, pack: None, flags: , field_shuffle_seed: 13397682652773712997 } args: [] variant_index: 1 subpatterns: [] diff --git a/tests/ui/traits/const-traits/conditionally-const-invalid-places.stderr b/tests/ui/traits/const-traits/conditionally-const-invalid-places.stderr index d0dd9502915..010b1584643 100644 --- a/tests/ui/traits/const-traits/conditionally-const-invalid-places.stderr +++ b/tests/ui/traits/const-traits/conditionally-const-invalid-places.stderr @@ -72,7 +72,7 @@ error: `[const]` is not allowed here LL | type Type<T: [const] Trait>: [const] Trait; | ^^^^^^^ | -note: associated types in non-`#[const_trait]` traits cannot have `[const]` trait bounds +note: associated types in non-`const` traits cannot have `[const]` trait bounds --> $DIR/conditionally-const-invalid-places.rs:25:5 | LL | type Type<T: [const] Trait>: [const] Trait; @@ -84,7 +84,7 @@ error: `[const]` is not allowed here LL | type Type<T: [const] Trait>: [const] Trait; | ^^^^^^^ | -note: associated types in non-`#[const_trait]` traits cannot have `[const]` trait bounds +note: associated types in non-`const` traits cannot have `[const]` trait bounds --> $DIR/conditionally-const-invalid-places.rs:25:5 | LL | type Type<T: [const] Trait>: [const] Trait; @@ -180,7 +180,7 @@ error: `[const]` is not allowed here LL | trait Child0: [const] Trait {} | ^^^^^^^ | -note: this trait is not a `#[const_trait]`, so it cannot have `[const]` trait bounds +note: this trait is not `const`, so it cannot have `[const]` trait bounds --> $DIR/conditionally-const-invalid-places.rs:52:1 | LL | trait Child0: [const] Trait {} @@ -192,7 +192,7 @@ error: `[const]` is not allowed here LL | trait Child1 where Self: [const] Trait {} | ^^^^^^^ | -note: this trait is not a `#[const_trait]`, so it cannot have `[const]` trait bounds +note: this trait is not `const`, so it cannot have `[const]` trait bounds --> $DIR/conditionally-const-invalid-places.rs:53:1 | LL | trait Child1 where Self: [const] Trait {} diff --git a/tests/ui/traits/const-traits/const-assoc-bound-in-trait-wc.rs b/tests/ui/traits/const-traits/const-assoc-bound-in-trait-wc.rs new file mode 100644 index 00000000000..81acce65f2a --- /dev/null +++ b/tests/ui/traits/const-traits/const-assoc-bound-in-trait-wc.rs @@ -0,0 +1,13 @@ +//@ check-pass + +#![feature(const_clone)] +#![feature(const_trait_impl)] + +#[const_trait] +trait A where Self::Target: [const] Clone { + type Target; +} + +const fn foo<T>() where T: [const] A {} + +fn main() {} diff --git a/tests/ui/traits/const-traits/const-bounds-non-const-trait.rs b/tests/ui/traits/const-traits/const-bounds-non-const-trait.rs index ae31d9ae0ac..baded179201 100644 --- a/tests/ui/traits/const-traits/const-bounds-non-const-trait.rs +++ b/tests/ui/traits/const-traits/const-bounds-non-const-trait.rs @@ -4,10 +4,10 @@ trait NonConst {} const fn perform<T: [const] NonConst>() {} -//~^ ERROR `[const]` can only be applied to `#[const_trait]` traits -//~| ERROR `[const]` can only be applied to `#[const_trait]` traits +//~^ ERROR `[const]` can only be applied to `const` traits +//~| ERROR `[const]` can only be applied to `const` traits fn operate<T: const NonConst>() {} -//~^ ERROR `const` can only be applied to `#[const_trait]` traits +//~^ ERROR `const` can only be applied to `const` traits fn main() {} diff --git a/tests/ui/traits/const-traits/const-bounds-non-const-trait.stderr b/tests/ui/traits/const-traits/const-bounds-non-const-trait.stderr index 6c68e4ec3ac..304d81bb917 100644 --- a/tests/ui/traits/const-traits/const-bounds-non-const-trait.stderr +++ b/tests/ui/traits/const-traits/const-bounds-non-const-trait.stderr @@ -1,33 +1,33 @@ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/const-bounds-non-const-trait.rs:6:21 | LL | const fn perform<T: [const] NonConst>() {} | ^^^^^^^ can't be applied to `NonConst` | -help: mark `NonConst` as `#[const_trait]` to allow it to have `const` implementations +help: mark `NonConst` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait NonConst {} | ++++++++++++++ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/const-bounds-non-const-trait.rs:6:21 | LL | const fn perform<T: [const] NonConst>() {} | ^^^^^^^ can't be applied to `NonConst` | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: mark `NonConst` as `#[const_trait]` to allow it to have `const` implementations +help: mark `NonConst` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait NonConst {} | ++++++++++++++ -error: `const` can only be applied to `#[const_trait]` traits +error: `const` can only be applied to `const` traits --> $DIR/const-bounds-non-const-trait.rs:10:15 | LL | fn operate<T: const NonConst>() {} | ^^^^^ can't be applied to `NonConst` | -help: mark `NonConst` as `#[const_trait]` to allow it to have `const` implementations +help: mark `NonConst` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait NonConst {} | ++++++++++++++ diff --git a/tests/ui/traits/const-traits/const-impl-requires-const-trait.rs b/tests/ui/traits/const-traits/const-impl-requires-const-trait.rs index 6bea664b65f..176ae091a41 100644 --- a/tests/ui/traits/const-traits/const-impl-requires-const-trait.rs +++ b/tests/ui/traits/const-traits/const-impl-requires-const-trait.rs @@ -4,6 +4,6 @@ pub trait A {} impl const A for () {} -//~^ ERROR: const `impl` for trait `A` which is not marked with `#[const_trait]` +//~^ ERROR: const `impl` for trait `A` which is not `const` fn main() {} diff --git a/tests/ui/traits/const-traits/const-impl-requires-const-trait.stderr b/tests/ui/traits/const-traits/const-impl-requires-const-trait.stderr index c728eda069e..bf73436b78d 100644 --- a/tests/ui/traits/const-traits/const-impl-requires-const-trait.stderr +++ b/tests/ui/traits/const-traits/const-impl-requires-const-trait.stderr @@ -1,12 +1,12 @@ -error: const `impl` for trait `A` which is not marked with `#[const_trait]` +error: const `impl` for trait `A` which is not `const` --> $DIR/const-impl-requires-const-trait.rs:6:12 | LL | impl const A for () {} | ^ this trait is not `const` | - = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: marking a trait with `const` ensures all default method bodies are `const` = note: adding a non-const method body in the future would be a breaking change -help: mark `A` as `#[const_trait]` to allow it to have `const` implementations +help: mark `A` as `const` to allow it to have `const` implementations | LL | #[const_trait] pub trait A {} | ++++++++++++++ diff --git a/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.rs b/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.rs index 1d1da9b0e3d..658132441c2 100644 --- a/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.rs +++ b/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.rs @@ -1,9 +1,7 @@ #![feature(const_trait_impl)] -// FIXME(const_trait_impl) add effects //@ edition: 2021 -#[const_trait] -trait Trait {} +const trait Trait {} fn main() { let _: &dyn const Trait; //~ ERROR const trait bounds are not allowed in trait object types @@ -14,7 +12,7 @@ fn main() { trait NonConst {} const fn handle(_: &dyn const NonConst) {} //~^ ERROR const trait bounds are not allowed in trait object types -//~| ERROR `const` can only be applied to `#[const_trait]` traits +//~| ERROR `const` can only be applied to `const` traits const fn take(_: &dyn [const] NonConst) {} //~^ ERROR `[const]` is not allowed here -//~| ERROR `[const]` can only be applied to `#[const_trait]` traits +//~| ERROR `[const]` can only be applied to `const` traits diff --git a/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.stderr b/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.stderr index 06e0493024c..3ba5da39106 100644 --- a/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.stderr +++ b/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.stderr @@ -1,11 +1,11 @@ error: const trait bounds are not allowed in trait object types - --> $DIR/const-trait-bounds-trait-objects.rs:9:17 + --> $DIR/const-trait-bounds-trait-objects.rs:7:17 | LL | let _: &dyn const Trait; | ^^^^^^^^^^^ error: `[const]` is not allowed here - --> $DIR/const-trait-bounds-trait-objects.rs:10:17 + --> $DIR/const-trait-bounds-trait-objects.rs:8:17 | LL | let _: &dyn [const] Trait; | ^^^^^^^ @@ -13,37 +13,37 @@ LL | let _: &dyn [const] Trait; = note: trait objects cannot have `[const]` trait bounds error: const trait bounds are not allowed in trait object types - --> $DIR/const-trait-bounds-trait-objects.rs:15:25 + --> $DIR/const-trait-bounds-trait-objects.rs:13:25 | LL | const fn handle(_: &dyn const NonConst) {} | ^^^^^^^^^^^^^^ error: `[const]` is not allowed here - --> $DIR/const-trait-bounds-trait-objects.rs:18:23 + --> $DIR/const-trait-bounds-trait-objects.rs:16:23 | LL | const fn take(_: &dyn [const] NonConst) {} | ^^^^^^^ | = note: trait objects cannot have `[const]` trait bounds -error: `const` can only be applied to `#[const_trait]` traits - --> $DIR/const-trait-bounds-trait-objects.rs:15:25 +error: `const` can only be applied to `const` traits + --> $DIR/const-trait-bounds-trait-objects.rs:13:25 | LL | const fn handle(_: &dyn const NonConst) {} | ^^^^^ can't be applied to `NonConst` | -help: mark `NonConst` as `#[const_trait]` to allow it to have `const` implementations +help: mark `NonConst` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait NonConst {} | ++++++++++++++ -error: `[const]` can only be applied to `#[const_trait]` traits - --> $DIR/const-trait-bounds-trait-objects.rs:18:23 +error: `[const]` can only be applied to `const` traits + --> $DIR/const-trait-bounds-trait-objects.rs:16:23 | LL | const fn take(_: &dyn [const] NonConst) {} | ^^^^^^^ can't be applied to `NonConst` | -help: mark `NonConst` as `#[const_trait]` to allow it to have `const` implementations +help: mark `NonConst` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait NonConst {} | ++++++++++++++ diff --git a/tests/ui/traits/const-traits/const_derives/derive-const-gate.rs b/tests/ui/traits/const-traits/const_derives/derive-const-gate.rs index 04fea1189ae..c0796907855 100644 --- a/tests/ui/traits/const-traits/const_derives/derive-const-gate.rs +++ b/tests/ui/traits/const-traits/const_derives/derive-const-gate.rs @@ -1,5 +1,5 @@ #[derive_const(Debug)] //~ ERROR use of unstable library feature -//~^ ERROR const `impl` for trait `Debug` which is not marked with `#[const_trait]` +//~^ ERROR const `impl` for trait `Debug` which is not `const` //~| ERROR cannot call non-const method pub struct S; diff --git a/tests/ui/traits/const-traits/const_derives/derive-const-gate.stderr b/tests/ui/traits/const-traits/const_derives/derive-const-gate.stderr index 5bde358001c..5ed12b37052 100644 --- a/tests/ui/traits/const-traits/const_derives/derive-const-gate.stderr +++ b/tests/ui/traits/const-traits/const_derives/derive-const-gate.stderr @@ -7,13 +7,13 @@ LL | #[derive_const(Debug)] = help: add `#![feature(derive_const)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: const `impl` for trait `Debug` which is not marked with `#[const_trait]` +error: const `impl` for trait `Debug` which is not `const` --> $DIR/derive-const-gate.rs:1:16 | LL | #[derive_const(Debug)] | ^^^^^ this trait is not `const` | - = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: marking a trait with `const` ensures all default method bodies are `const` = note: adding a non-const method body in the future would be a breaking change error[E0015]: cannot call non-const method `Formatter::<'_>::write_str` in constant functions diff --git a/tests/ui/traits/const-traits/const_derives/derive-const-non-const-type.stderr b/tests/ui/traits/const-traits/const_derives/derive-const-non-const-type.stderr index c0bd360ebe5..93638801895 100644 --- a/tests/ui/traits/const-traits/const_derives/derive-const-non-const-type.stderr +++ b/tests/ui/traits/const-traits/const_derives/derive-const-non-const-type.stderr @@ -1,10 +1,10 @@ -error: const `impl` for trait `Debug` which is not marked with `#[const_trait]` +error: const `impl` for trait `Debug` which is not `const` --> $DIR/derive-const-non-const-type.rs:12:16 | LL | #[derive_const(Debug)] | ^^^^^ this trait is not `const` | - = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: marking a trait with `const` ensures all default method bodies are `const` = note: adding a non-const method body in the future would be a breaking change error[E0015]: cannot call non-const method `Formatter::<'_>::debug_tuple_field1_finish` in constant functions diff --git a/tests/ui/traits/const-traits/ice-119717-constant-lifetime.rs b/tests/ui/traits/const-traits/ice-119717-constant-lifetime.rs index e53b87274d3..47c85980aca 100644 --- a/tests/ui/traits/const-traits/ice-119717-constant-lifetime.rs +++ b/tests/ui/traits/const-traits/ice-119717-constant-lifetime.rs @@ -4,7 +4,7 @@ use std::ops::FromResidual; impl<T> const FromResidual for T { - //~^ ERROR const `impl` for trait `FromResidual` which is not marked with `#[const_trait]` + //~^ ERROR const `impl` for trait `FromResidual` which is not `const` //~| ERROR type parameter `T` must be used as the type parameter for some local type fn from_residual(t: T) -> _ { //~^ ERROR the placeholder `_` is not allowed diff --git a/tests/ui/traits/const-traits/ice-119717-constant-lifetime.stderr b/tests/ui/traits/const-traits/ice-119717-constant-lifetime.stderr index a165ef12060..5c5fba95f02 100644 --- a/tests/ui/traits/const-traits/ice-119717-constant-lifetime.stderr +++ b/tests/ui/traits/const-traits/ice-119717-constant-lifetime.stderr @@ -1,10 +1,10 @@ -error: const `impl` for trait `FromResidual` which is not marked with `#[const_trait]` +error: const `impl` for trait `FromResidual` which is not `const` --> $DIR/ice-119717-constant-lifetime.rs:6:15 | LL | impl<T> const FromResidual for T { | ^^^^^^^^^^^^ this trait is not `const` | - = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: marking a trait with `const` ensures all default method bodies are `const` = note: adding a non-const method body in the future would be a breaking change error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct<T>`) diff --git a/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.rs b/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.rs index 3473be565c1..5e368b9e6a9 100644 --- a/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.rs +++ b/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.rs @@ -6,11 +6,11 @@ struct TryMe; struct Error; impl const FromResidual<Error> for TryMe {} -//~^ ERROR const `impl` for trait `FromResidual` which is not marked with `#[const_trait]` +//~^ ERROR const `impl` for trait `FromResidual` which is not `const` //~| ERROR not all trait items implemented impl const Try for TryMe { - //~^ ERROR const `impl` for trait `Try` which is not marked with `#[const_trait]` + //~^ ERROR const `impl` for trait `Try` which is not `const` //~| ERROR not all trait items implemented type Output = (); type Residual = Error; diff --git a/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.stderr b/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.stderr index 41f99c2d375..849d6522cd6 100644 --- a/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.stderr +++ b/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.stderr @@ -1,10 +1,10 @@ -error: const `impl` for trait `FromResidual` which is not marked with `#[const_trait]` +error: const `impl` for trait `FromResidual` which is not `const` --> $DIR/ice-126148-failed-to-normalize.rs:8:12 | LL | impl const FromResidual<Error> for TryMe {} | ^^^^^^^^^^^^^^^^^^^ this trait is not `const` | - = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: marking a trait with `const` ensures all default method bodies are `const` = note: adding a non-const method body in the future would be a breaking change error[E0046]: not all trait items implemented, missing: `from_residual` @@ -15,13 +15,13 @@ LL | impl const FromResidual<Error> for TryMe {} | = help: implement the missing item: `fn from_residual(_: Error) -> Self { todo!() }` -error: const `impl` for trait `Try` which is not marked with `#[const_trait]` +error: const `impl` for trait `Try` which is not `const` --> $DIR/ice-126148-failed-to-normalize.rs:12:12 | LL | impl const Try for TryMe { | ^^^ this trait is not `const` | - = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: marking a trait with `const` ensures all default method bodies are `const` = note: adding a non-const method body in the future would be a breaking change error[E0046]: not all trait items implemented, missing: `from_output`, `branch` diff --git a/tests/ui/traits/const-traits/imply-always-const.rs b/tests/ui/traits/const-traits/imply-always-const.rs new file mode 100644 index 00000000000..f6cab0681ec --- /dev/null +++ b/tests/ui/traits/const-traits/imply-always-const.rs @@ -0,0 +1,19 @@ +//@ check-pass + +#![feature(const_trait_impl)] + +#[const_trait] +trait A where Self::Assoc: const B { + type Assoc; +} + +#[const_trait] +trait B {} + +fn needs_b<T: const B>() {} + +fn test<T: A>() { + needs_b::<T::Assoc>(); +} + +fn main() {} diff --git a/tests/ui/traits/const-traits/spec-effectvar-ice.rs b/tests/ui/traits/const-traits/spec-effectvar-ice.rs index c85b1746967..46f71b114a3 100644 --- a/tests/ui/traits/const-traits/spec-effectvar-ice.rs +++ b/tests/ui/traits/const-traits/spec-effectvar-ice.rs @@ -8,11 +8,11 @@ trait Specialize {} trait Foo {} impl<T> const Foo for T {} -//~^ error: const `impl` for trait `Foo` which is not marked with `#[const_trait]` +//~^ error: const `impl` for trait `Foo` which is not `const` impl<T> const Foo for T where T: const Specialize {} -//~^ error: const `impl` for trait `Foo` which is not marked with `#[const_trait]` -//~| error: `const` can only be applied to `#[const_trait]` traits +//~^ error: const `impl` for trait `Foo` which is not `const` +//~| error: `const` can only be applied to `const` traits //~| error: specialization impl does not specialize any associated items //~| error: cannot specialize on trait `Specialize` diff --git a/tests/ui/traits/const-traits/spec-effectvar-ice.stderr b/tests/ui/traits/const-traits/spec-effectvar-ice.stderr index 474d96698d5..ef5e58e1c3d 100644 --- a/tests/ui/traits/const-traits/spec-effectvar-ice.stderr +++ b/tests/ui/traits/const-traits/spec-effectvar-ice.stderr @@ -1,36 +1,36 @@ -error: const `impl` for trait `Foo` which is not marked with `#[const_trait]` +error: const `impl` for trait `Foo` which is not `const` --> $DIR/spec-effectvar-ice.rs:10:15 | LL | impl<T> const Foo for T {} | ^^^ this trait is not `const` | - = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: marking a trait with `const` ensures all default method bodies are `const` = note: adding a non-const method body in the future would be a breaking change -help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations +help: mark `Foo` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Foo {} | ++++++++++++++ -error: const `impl` for trait `Foo` which is not marked with `#[const_trait]` +error: const `impl` for trait `Foo` which is not `const` --> $DIR/spec-effectvar-ice.rs:13:15 | LL | impl<T> const Foo for T where T: const Specialize {} | ^^^ this trait is not `const` | - = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: marking a trait with `const` ensures all default method bodies are `const` = note: adding a non-const method body in the future would be a breaking change -help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations +help: mark `Foo` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Foo {} | ++++++++++++++ -error: `const` can only be applied to `#[const_trait]` traits +error: `const` can only be applied to `const` traits --> $DIR/spec-effectvar-ice.rs:13:34 | LL | impl<T> const Foo for T where T: const Specialize {} | ^^^^^ can't be applied to `Specialize` | -help: mark `Specialize` as `#[const_trait]` to allow it to have `const` implementations +help: mark `Specialize` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Specialize {} | ++++++++++++++ diff --git a/tests/ui/traits/const-traits/super-traits-fail-2.nn.stderr b/tests/ui/traits/const-traits/super-traits-fail-2.nn.stderr index 19f072b289e..0ecbad64bc8 100644 --- a/tests/ui/traits/const-traits/super-traits-fail-2.nn.stderr +++ b/tests/ui/traits/const-traits/super-traits-fail-2.nn.stderr @@ -4,43 +4,43 @@ error: `[const]` is not allowed here LL | trait Bar: [const] Foo {} | ^^^^^^^ | -note: this trait is not a `#[const_trait]`, so it cannot have `[const]` trait bounds +note: this trait is not `const`, so it cannot have `[const]` trait bounds --> $DIR/super-traits-fail-2.rs:11:1 | LL | trait Bar: [const] Foo {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-2.rs:11:12 | LL | trait Bar: [const] Foo {} | ^^^^^^^ can't be applied to `Foo` | -help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations +help: mark `Foo` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Foo { | ++++++++++++++ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-2.rs:11:12 | LL | trait Bar: [const] Foo {} | ^^^^^^^ can't be applied to `Foo` | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations +help: mark `Foo` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Foo { | ++++++++++++++ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-2.rs:11:12 | LL | trait Bar: [const] Foo {} | ^^^^^^^ can't be applied to `Foo` | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations +help: mark `Foo` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Foo { | ++++++++++++++ diff --git a/tests/ui/traits/const-traits/super-traits-fail-2.ny.stderr b/tests/ui/traits/const-traits/super-traits-fail-2.ny.stderr index 4921f78d3ac..0e5b697d1dd 100644 --- a/tests/ui/traits/const-traits/super-traits-fail-2.ny.stderr +++ b/tests/ui/traits/const-traits/super-traits-fail-2.ny.stderr @@ -1,58 +1,58 @@ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-2.rs:11:12 | LL | trait Bar: [const] Foo {} | ^^^^^^^ can't be applied to `Foo` | -help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations +help: mark `Foo` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Foo { | ++++++++++++++ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-2.rs:11:12 | LL | trait Bar: [const] Foo {} | ^^^^^^^ can't be applied to `Foo` | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations +help: mark `Foo` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Foo { | ++++++++++++++ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-2.rs:11:12 | LL | trait Bar: [const] Foo {} | ^^^^^^^ can't be applied to `Foo` | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations +help: mark `Foo` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Foo { | ++++++++++++++ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-2.rs:11:12 | LL | trait Bar: [const] Foo {} | ^^^^^^^ can't be applied to `Foo` | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations +help: mark `Foo` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Foo { | ++++++++++++++ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-2.rs:11:12 | LL | trait Bar: [const] Foo {} | ^^^^^^^ can't be applied to `Foo` | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations +help: mark `Foo` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Foo { | ++++++++++++++ diff --git a/tests/ui/traits/const-traits/super-traits-fail-2.rs b/tests/ui/traits/const-traits/super-traits-fail-2.rs index 781dacb81a1..36e7c1c4e4a 100644 --- a/tests/ui/traits/const-traits/super-traits-fail-2.rs +++ b/tests/ui/traits/const-traits/super-traits-fail-2.rs @@ -9,11 +9,11 @@ trait Foo { #[cfg_attr(any(yy, ny), const_trait)] trait Bar: [const] Foo {} -//[ny,nn]~^ ERROR: `[const]` can only be applied to `#[const_trait]` -//[ny,nn]~| ERROR: `[const]` can only be applied to `#[const_trait]` -//[ny,nn]~| ERROR: `[const]` can only be applied to `#[const_trait]` -//[ny]~| ERROR: `[const]` can only be applied to `#[const_trait]` -//[ny]~| ERROR: `[const]` can only be applied to `#[const_trait]` +//[ny,nn]~^ ERROR: `[const]` can only be applied to `const` traits +//[ny,nn]~| ERROR: `[const]` can only be applied to `const` traits +//[ny,nn]~| ERROR: `[const]` can only be applied to `const` traits +//[ny]~| ERROR: `[const]` can only be applied to `const` traits +//[ny]~| ERROR: `[const]` can only be applied to `const` traits //[yn,nn]~^^^^^^ ERROR: `[const]` is not allowed here const fn foo<T: Bar>(x: &T) { diff --git a/tests/ui/traits/const-traits/super-traits-fail-2.yn.stderr b/tests/ui/traits/const-traits/super-traits-fail-2.yn.stderr index a151349822e..657e8ee82e3 100644 --- a/tests/ui/traits/const-traits/super-traits-fail-2.yn.stderr +++ b/tests/ui/traits/const-traits/super-traits-fail-2.yn.stderr @@ -4,7 +4,7 @@ error: `[const]` is not allowed here LL | trait Bar: [const] Foo {} | ^^^^^^^ | -note: this trait is not a `#[const_trait]`, so it cannot have `[const]` trait bounds +note: this trait is not `const`, so it cannot have `[const]` trait bounds --> $DIR/super-traits-fail-2.rs:11:1 | LL | trait Bar: [const] Foo {} diff --git a/tests/ui/traits/const-traits/super-traits-fail-3.nnn.stderr b/tests/ui/traits/const-traits/super-traits-fail-3.nnn.stderr index 3f48375dd04..a0ae60526ef 100644 --- a/tests/ui/traits/const-traits/super-traits-fail-3.nnn.stderr +++ b/tests/ui/traits/const-traits/super-traits-fail-3.nnn.stderr @@ -4,7 +4,7 @@ error: `[const]` is not allowed here LL | trait Bar: [const] Foo {} | ^^^^^^^ | -note: this trait is not a `#[const_trait]`, so it cannot have `[const]` trait bounds +note: this trait is not `const`, so it cannot have `[const]` trait bounds --> $DIR/super-traits-fail-3.rs:23:1 | LL | trait Bar: [const] Foo {} @@ -30,60 +30,60 @@ LL | const fn foo<T: [const] Bar>(x: &T) { = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-3.rs:23:12 | LL | trait Bar: [const] Foo {} | ^^^^^^^ can't be applied to `Foo` | -help: enable `#![feature(const_trait_impl)]` in your crate and mark `Foo` as `#[const_trait]` to allow it to have `const` implementations +help: enable `#![feature(const_trait_impl)]` in your crate and mark `Foo` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Foo { | ++++++++++++++ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-3.rs:23:12 | LL | trait Bar: [const] Foo {} | ^^^^^^^ can't be applied to `Foo` | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: enable `#![feature(const_trait_impl)]` in your crate and mark `Foo` as `#[const_trait]` to allow it to have `const` implementations +help: enable `#![feature(const_trait_impl)]` in your crate and mark `Foo` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Foo { | ++++++++++++++ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-3.rs:23:12 | LL | trait Bar: [const] Foo {} | ^^^^^^^ can't be applied to `Foo` | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: enable `#![feature(const_trait_impl)]` in your crate and mark `Foo` as `#[const_trait]` to allow it to have `const` implementations +help: enable `#![feature(const_trait_impl)]` in your crate and mark `Foo` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Foo { | ++++++++++++++ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-3.rs:32:17 | LL | const fn foo<T: [const] Bar>(x: &T) { | ^^^^^^^ can't be applied to `Bar` | -help: enable `#![feature(const_trait_impl)]` in your crate and mark `Bar` as `#[const_trait]` to allow it to have `const` implementations +help: enable `#![feature(const_trait_impl)]` in your crate and mark `Bar` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Bar: [const] Foo {} | ++++++++++++++ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-3.rs:32:17 | LL | const fn foo<T: [const] Bar>(x: &T) { | ^^^^^^^ can't be applied to `Bar` | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: enable `#![feature(const_trait_impl)]` in your crate and mark `Bar` as `#[const_trait]` to allow it to have `const` implementations +help: enable `#![feature(const_trait_impl)]` in your crate and mark `Bar` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Bar: [const] Foo {} | ++++++++++++++ diff --git a/tests/ui/traits/const-traits/super-traits-fail-3.nny.stderr b/tests/ui/traits/const-traits/super-traits-fail-3.nny.stderr index 3f48375dd04..a0ae60526ef 100644 --- a/tests/ui/traits/const-traits/super-traits-fail-3.nny.stderr +++ b/tests/ui/traits/const-traits/super-traits-fail-3.nny.stderr @@ -4,7 +4,7 @@ error: `[const]` is not allowed here LL | trait Bar: [const] Foo {} | ^^^^^^^ | -note: this trait is not a `#[const_trait]`, so it cannot have `[const]` trait bounds +note: this trait is not `const`, so it cannot have `[const]` trait bounds --> $DIR/super-traits-fail-3.rs:23:1 | LL | trait Bar: [const] Foo {} @@ -30,60 +30,60 @@ LL | const fn foo<T: [const] Bar>(x: &T) { = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-3.rs:23:12 | LL | trait Bar: [const] Foo {} | ^^^^^^^ can't be applied to `Foo` | -help: enable `#![feature(const_trait_impl)]` in your crate and mark `Foo` as `#[const_trait]` to allow it to have `const` implementations +help: enable `#![feature(const_trait_impl)]` in your crate and mark `Foo` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Foo { | ++++++++++++++ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-3.rs:23:12 | LL | trait Bar: [const] Foo {} | ^^^^^^^ can't be applied to `Foo` | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: enable `#![feature(const_trait_impl)]` in your crate and mark `Foo` as `#[const_trait]` to allow it to have `const` implementations +help: enable `#![feature(const_trait_impl)]` in your crate and mark `Foo` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Foo { | ++++++++++++++ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-3.rs:23:12 | LL | trait Bar: [const] Foo {} | ^^^^^^^ can't be applied to `Foo` | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: enable `#![feature(const_trait_impl)]` in your crate and mark `Foo` as `#[const_trait]` to allow it to have `const` implementations +help: enable `#![feature(const_trait_impl)]` in your crate and mark `Foo` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Foo { | ++++++++++++++ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-3.rs:32:17 | LL | const fn foo<T: [const] Bar>(x: &T) { | ^^^^^^^ can't be applied to `Bar` | -help: enable `#![feature(const_trait_impl)]` in your crate and mark `Bar` as `#[const_trait]` to allow it to have `const` implementations +help: enable `#![feature(const_trait_impl)]` in your crate and mark `Bar` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Bar: [const] Foo {} | ++++++++++++++ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-3.rs:32:17 | LL | const fn foo<T: [const] Bar>(x: &T) { | ^^^^^^^ can't be applied to `Bar` | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: enable `#![feature(const_trait_impl)]` in your crate and mark `Bar` as `#[const_trait]` to allow it to have `const` implementations +help: enable `#![feature(const_trait_impl)]` in your crate and mark `Bar` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Bar: [const] Foo {} | ++++++++++++++ diff --git a/tests/ui/traits/const-traits/super-traits-fail-3.rs b/tests/ui/traits/const-traits/super-traits-fail-3.rs index 5370f607dec..d74bd346784 100644 --- a/tests/ui/traits/const-traits/super-traits-fail-3.rs +++ b/tests/ui/traits/const-traits/super-traits-fail-3.rs @@ -21,17 +21,17 @@ trait Foo { #[cfg_attr(any(yyy, yny, nyy, nyn), const_trait)] //[nyy,nyn]~^ ERROR: `const_trait` is a temporary placeholder for marking a trait that is suitable for `const` `impls` and all default bodies as `const`, which may be removed or renamed in the future trait Bar: [const] Foo {} -//[yny,ynn,nny,nnn]~^ ERROR: `[const]` can only be applied to `#[const_trait]` -//[yny,ynn,nny,nnn]~| ERROR: `[const]` can only be applied to `#[const_trait]` -//[yny,ynn,nny,nnn]~| ERROR: `[const]` can only be applied to `#[const_trait]` -//[yny]~^^^^ ERROR: `[const]` can only be applied to `#[const_trait]` -//[yny]~| ERROR: `[const]` can only be applied to `#[const_trait]` +//[yny,ynn,nny,nnn]~^ ERROR: `[const]` can only be applied to `const` traits +//[yny,ynn,nny,nnn]~| ERROR: `[const]` can only be applied to `const` traits +//[yny,ynn,nny,nnn]~| ERROR: `[const]` can only be applied to `const` traits +//[yny]~^^^^ ERROR: `[const]` can only be applied to `const` traits +//[yny]~| ERROR: `[const]` can only be applied to `const` traits //[yyn,ynn,nny,nnn]~^^^^^^ ERROR: `[const]` is not allowed here //[nyy,nyn,nny,nnn]~^^^^^^^ ERROR: const trait impls are experimental const fn foo<T: [const] Bar>(x: &T) { - //[yyn,ynn,nny,nnn]~^ ERROR: `[const]` can only be applied to `#[const_trait]` - //[yyn,ynn,nny,nnn]~| ERROR: `[const]` can only be applied to `#[const_trait]` + //[yyn,ynn,nny,nnn]~^ ERROR: `[const]` can only be applied to `const` traits + //[yyn,ynn,nny,nnn]~| ERROR: `[const]` can only be applied to `const` traits //[nyy,nyn,nny,nnn]~^^^ ERROR: const trait impls are experimental x.a(); //[yyn]~^ ERROR: the trait bound `T: [const] Foo` is not satisfied diff --git a/tests/ui/traits/const-traits/super-traits-fail-3.ynn.stderr b/tests/ui/traits/const-traits/super-traits-fail-3.ynn.stderr index 89e090b7d1c..c8ec77c2f09 100644 --- a/tests/ui/traits/const-traits/super-traits-fail-3.ynn.stderr +++ b/tests/ui/traits/const-traits/super-traits-fail-3.ynn.stderr @@ -4,66 +4,66 @@ error: `[const]` is not allowed here LL | trait Bar: [const] Foo {} | ^^^^^^^ | -note: this trait is not a `#[const_trait]`, so it cannot have `[const]` trait bounds +note: this trait is not `const`, so it cannot have `[const]` trait bounds --> $DIR/super-traits-fail-3.rs:23:1 | LL | trait Bar: [const] Foo {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-3.rs:23:12 | LL | trait Bar: [const] Foo {} | ^^^^^^^ can't be applied to `Foo` | -help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations +help: mark `Foo` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Foo { | ++++++++++++++ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-3.rs:23:12 | LL | trait Bar: [const] Foo {} | ^^^^^^^ can't be applied to `Foo` | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations +help: mark `Foo` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Foo { | ++++++++++++++ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-3.rs:23:12 | LL | trait Bar: [const] Foo {} | ^^^^^^^ can't be applied to `Foo` | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations +help: mark `Foo` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Foo { | ++++++++++++++ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-3.rs:32:17 | LL | const fn foo<T: [const] Bar>(x: &T) { | ^^^^^^^ can't be applied to `Bar` | -help: mark `Bar` as `#[const_trait]` to allow it to have `const` implementations +help: mark `Bar` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Bar: [const] Foo {} | ++++++++++++++ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-3.rs:32:17 | LL | const fn foo<T: [const] Bar>(x: &T) { | ^^^^^^^ can't be applied to `Bar` | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: mark `Bar` as `#[const_trait]` to allow it to have `const` implementations +help: mark `Bar` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Bar: [const] Foo {} | ++++++++++++++ diff --git a/tests/ui/traits/const-traits/super-traits-fail-3.yny.stderr b/tests/ui/traits/const-traits/super-traits-fail-3.yny.stderr index 683eeb73850..a820239cde0 100644 --- a/tests/ui/traits/const-traits/super-traits-fail-3.yny.stderr +++ b/tests/ui/traits/const-traits/super-traits-fail-3.yny.stderr @@ -1,58 +1,58 @@ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-3.rs:23:12 | LL | trait Bar: [const] Foo {} | ^^^^^^^ can't be applied to `Foo` | -help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations +help: mark `Foo` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Foo { | ++++++++++++++ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-3.rs:23:12 | LL | trait Bar: [const] Foo {} | ^^^^^^^ can't be applied to `Foo` | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations +help: mark `Foo` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Foo { | ++++++++++++++ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-3.rs:23:12 | LL | trait Bar: [const] Foo {} | ^^^^^^^ can't be applied to `Foo` | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations +help: mark `Foo` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Foo { | ++++++++++++++ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-3.rs:23:12 | LL | trait Bar: [const] Foo {} | ^^^^^^^ can't be applied to `Foo` | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations +help: mark `Foo` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Foo { | ++++++++++++++ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-3.rs:23:12 | LL | trait Bar: [const] Foo {} | ^^^^^^^ can't be applied to `Foo` | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations +help: mark `Foo` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Foo { | ++++++++++++++ diff --git a/tests/ui/traits/const-traits/super-traits-fail-3.yyn.stderr b/tests/ui/traits/const-traits/super-traits-fail-3.yyn.stderr index 39cfdfe2030..de3664dae84 100644 --- a/tests/ui/traits/const-traits/super-traits-fail-3.yyn.stderr +++ b/tests/ui/traits/const-traits/super-traits-fail-3.yyn.stderr @@ -4,31 +4,31 @@ error: `[const]` is not allowed here LL | trait Bar: [const] Foo {} | ^^^^^^^ | -note: this trait is not a `#[const_trait]`, so it cannot have `[const]` trait bounds +note: this trait is not `const`, so it cannot have `[const]` trait bounds --> $DIR/super-traits-fail-3.rs:23:1 | LL | trait Bar: [const] Foo {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-3.rs:32:17 | LL | const fn foo<T: [const] Bar>(x: &T) { | ^^^^^^^ can't be applied to `Bar` | -help: mark `Bar` as `#[const_trait]` to allow it to have `const` implementations +help: mark `Bar` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Bar: [const] Foo {} | ++++++++++++++ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-3.rs:32:17 | LL | const fn foo<T: [const] Bar>(x: &T) { | ^^^^^^^ can't be applied to `Bar` | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: mark `Bar` as `#[const_trait]` to allow it to have `const` implementations +help: mark `Bar` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Bar: [const] Foo {} | ++++++++++++++ diff --git a/tests/ui/traits/const-traits/trait-default-body-stability.stderr b/tests/ui/traits/const-traits/trait-default-body-stability.stderr index a13d9a1e075..b995d6f4f3d 100644 --- a/tests/ui/traits/const-traits/trait-default-body-stability.stderr +++ b/tests/ui/traits/const-traits/trait-default-body-stability.stderr @@ -1,19 +1,19 @@ -error: const `impl` for trait `Try` which is not marked with `#[const_trait]` +error: const `impl` for trait `Try` which is not `const` --> $DIR/trait-default-body-stability.rs:19:12 | LL | impl const Try for T { | ^^^ this trait is not `const` | - = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: marking a trait with `const` ensures all default method bodies are `const` = note: adding a non-const method body in the future would be a breaking change -error: const `impl` for trait `FromResidual` which is not marked with `#[const_trait]` +error: const `impl` for trait `FromResidual` which is not `const` --> $DIR/trait-default-body-stability.rs:34:12 | LL | impl const FromResidual for T { | ^^^^^^^^^^^^ this trait is not `const` | - = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: marking a trait with `const` ensures all default method bodies are `const` = note: adding a non-const method body in the future would be a breaking change error[E0015]: `?` is not allowed on `T` in constant functions diff --git a/tests/ui/traits/resolve-impl-before-constrain-check.rs b/tests/ui/traits/resolve-impl-before-constrain-check.rs index 50d1a874551..87f9c241e40 100644 --- a/tests/ui/traits/resolve-impl-before-constrain-check.rs +++ b/tests/ui/traits/resolve-impl-before-constrain-check.rs @@ -15,7 +15,6 @@ use foo::*; fn test() -> impl Sized { <() as Callable>::call() -//~^ ERROR: type annotations needed } fn main() {} diff --git a/tests/ui/traits/resolve-impl-before-constrain-check.stderr b/tests/ui/traits/resolve-impl-before-constrain-check.stderr index 13fbfdb855c..e8e569ba625 100644 --- a/tests/ui/traits/resolve-impl-before-constrain-check.stderr +++ b/tests/ui/traits/resolve-impl-before-constrain-check.stderr @@ -4,13 +4,6 @@ error[E0207]: the type parameter `V` is not constrained by the impl trait, self LL | impl<V: ?Sized> Callable for () { | ^ unconstrained type parameter -error[E0282]: type annotations needed - --> $DIR/resolve-impl-before-constrain-check.rs:17:6 - | -LL | <() as Callable>::call() - | ^^ cannot infer type for type parameter `V` - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error -Some errors have detailed explanations: E0207, E0282. -For more information about an error, try `rustc --explain E0207`. +For more information about this error, try `rustc --explain E0207`. diff --git a/tests/ui/unstable-feature-bound/auxiliary/unstable_feature.rs b/tests/ui/unstable-feature-bound/auxiliary/unstable_feature.rs new file mode 100644 index 00000000000..3749deb7627 --- /dev/null +++ b/tests/ui/unstable-feature-bound/auxiliary/unstable_feature.rs @@ -0,0 +1,25 @@ +#![allow(internal_features)] +#![feature(staged_api)] +#![stable(feature = "a", since = "1.1.1" )] + +#[stable(feature = "a", since = "1.1.1" )] +pub trait Foo { + #[stable(feature = "a", since = "1.1.1" )] + fn foo(); +} +#[stable(feature = "a", since = "1.1.1" )] +pub struct Bar; +#[stable(feature = "a", since = "1.1.1" )] +pub struct Moo; + +#[unstable_feature_bound(feat_bar)] +#[unstable(feature = "feat_bar", issue = "none" )] +impl Foo for Bar { + fn foo() {} +} + +#[unstable_feature_bound(feat_moo)] +#[unstable(feature = "feat_moo", issue = "none" )] +impl Foo for Moo { + fn foo() {} +} diff --git a/tests/ui/unstable-feature-bound/auxiliary/unstable_impl_codegen_aux1.rs b/tests/ui/unstable-feature-bound/auxiliary/unstable_impl_codegen_aux1.rs new file mode 100644 index 00000000000..8c0d14a1bab --- /dev/null +++ b/tests/ui/unstable-feature-bound/auxiliary/unstable_impl_codegen_aux1.rs @@ -0,0 +1,19 @@ +#![allow(internal_features)] +#![feature(staged_api)] +#![stable(feature = "a", since = "1.1.1" )] + +/// Aux crate for unstable impl codegen test. + +#[stable(feature = "a", since = "1.1.1" )] +pub trait Trait { + #[stable(feature = "a", since = "1.1.1" )] + fn method(&self); +} + +#[unstable_feature_bound(foo)] +#[unstable(feature = "foo", issue = "none" )] +impl<T> Trait for T { + fn method(&self) { + println!("hi"); + } +} diff --git a/tests/ui/unstable-feature-bound/auxiliary/unstable_impl_codegen_aux2.rs b/tests/ui/unstable-feature-bound/auxiliary/unstable_impl_codegen_aux2.rs new file mode 100644 index 00000000000..1b0e2b2eec3 --- /dev/null +++ b/tests/ui/unstable-feature-bound/auxiliary/unstable_impl_codegen_aux2.rs @@ -0,0 +1,13 @@ +//@ aux-build:unstable_impl_codegen_aux1.rs +#![feature(foo)] + +extern crate unstable_impl_codegen_aux1 as aux; +use aux::Trait; + +/// Upstream crate for unstable impl codegen test +/// that depends on aux crate in +/// unstable_impl_codegen_aux1.rs + +pub fn foo<T>(a: T) { + a.method(); +} diff --git a/tests/ui/unstable-feature-bound/auxiliary/unstable_impl_coherence_aux.rs b/tests/ui/unstable-feature-bound/auxiliary/unstable_impl_coherence_aux.rs new file mode 100644 index 00000000000..2e055101216 --- /dev/null +++ b/tests/ui/unstable-feature-bound/auxiliary/unstable_impl_coherence_aux.rs @@ -0,0 +1,11 @@ +#![allow(internal_features)] +#![feature(staged_api)] +#![allow(dead_code)] +#![stable(feature = "a", since = "1.1.1" )] + +#[stable(feature = "a", since = "1.1.1" )] +pub trait Trait {} + +#[unstable_feature_bound(foo)] +#[unstable(feature = "foo", issue = "none" )] +impl <T> Trait for T {} diff --git a/tests/ui/unstable-feature-bound/auxiliary/unstable_impl_method_selection_aux.rs b/tests/ui/unstable-feature-bound/auxiliary/unstable_impl_method_selection_aux.rs new file mode 100644 index 00000000000..3a433007b5d --- /dev/null +++ b/tests/ui/unstable-feature-bound/auxiliary/unstable_impl_method_selection_aux.rs @@ -0,0 +1,20 @@ +#![allow(internal_features)] +#![feature(staged_api)] +#![stable(feature = "a", since = "1.1.1" )] + +#[stable(feature = "a", since = "1.1.1" )] +pub trait Trait { + #[stable(feature = "a", since = "1.1.1" )] + fn foo(&self) {} +} + +#[stable(feature = "a", since = "1.1.1" )] +impl Trait for Vec<u32> { + fn foo(&self) {} +} + +#[unstable_feature_bound(bar)] +#[unstable(feature = "bar", issue = "none" )] +impl Trait for Vec<u64> { + fn foo(&self) {} +} diff --git a/tests/ui/unstable-feature-bound/unstable-feature-bound-no-effect.rs b/tests/ui/unstable-feature-bound/unstable-feature-bound-no-effect.rs new file mode 100644 index 00000000000..99501893ae0 --- /dev/null +++ b/tests/ui/unstable-feature-bound/unstable-feature-bound-no-effect.rs @@ -0,0 +1,35 @@ +#![allow(internal_features)] +#![feature(staged_api)] +#![allow(dead_code)] +#![stable(feature = "a", since = "1.1.1" )] + +/// If #[unstable(..)] and #[unstable_feature_name(..)] have the same feature name, +/// the error should not be thrown as it can effectively mark an impl as unstable. +/// +/// If the feature name in #[feature] does not exist in #[unstable_feature_bound(..)] +/// an error should still be thrown because that feature will not be unstable. + +#[stable(feature = "a", since = "1.1.1")] +trait Moo {} +#[stable(feature = "a", since = "1.1.1")] +trait Foo {} +#[stable(feature = "a", since = "1.1.1")] +trait Boo {} +#[stable(feature = "a", since = "1.1.1")] +pub struct Bar; + + +#[unstable(feature = "feat_moo", issue = "none")] +#[unstable_feature_bound(feat_foo)] //~^ ERROR: an `#[unstable]` annotation here has no effect +impl Moo for Bar {} + +#[unstable(feature = "feat_foo", issue = "none")] +#[unstable_feature_bound(feat_foo)] +impl Foo for Bar {} + + +#[unstable(feature = "feat_foo", issue = "none")] +#[unstable_feature_bound(feat_foo, feat_bar)] +impl Boo for Bar {} + +fn main() {} diff --git a/tests/ui/unstable-feature-bound/unstable-feature-bound-no-effect.stderr b/tests/ui/unstable-feature-bound/unstable-feature-bound-no-effect.stderr new file mode 100644 index 00000000000..4c8af2bbe56 --- /dev/null +++ b/tests/ui/unstable-feature-bound/unstable-feature-bound-no-effect.stderr @@ -0,0 +1,11 @@ +error: an `#[unstable]` annotation here has no effect + --> $DIR/unstable-feature-bound-no-effect.rs:22:1 + | +LL | #[unstable(feature = "feat_moo", issue = "none")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #55436 <https://github.com/rust-lang/rust/issues/55436> for more information + = note: `#[deny(ineffective_unstable_trait_impl)]` on by default + +error: aborting due to 1 previous error + diff --git a/tests/ui/unstable-feature-bound/unstable-feature-bound-two-error.rs b/tests/ui/unstable-feature-bound/unstable-feature-bound-two-error.rs new file mode 100644 index 00000000000..798c2d8562c --- /dev/null +++ b/tests/ui/unstable-feature-bound/unstable-feature-bound-two-error.rs @@ -0,0 +1,12 @@ +//@ aux-build:unstable_feature.rs +extern crate unstable_feature; +use unstable_feature::{Foo, Bar, Moo}; + +// FIXME: both `feat_bar` and `feat_moo` are needed to pass this test, +// but the diagnostic only will point out `feat_bar`. + +fn main() { + Bar::foo(); + //~^ ERROR: use of unstable library feature `feat_bar` [E0658] + Moo::foo(); +} diff --git a/tests/ui/unstable-feature-bound/unstable-feature-bound-two-error.stderr b/tests/ui/unstable-feature-bound/unstable-feature-bound-two-error.stderr new file mode 100644 index 00000000000..673d10ce2ad --- /dev/null +++ b/tests/ui/unstable-feature-bound/unstable-feature-bound-two-error.stderr @@ -0,0 +1,13 @@ +error[E0658]: use of unstable library feature `feat_bar` + --> $DIR/unstable-feature-bound-two-error.rs:9:5 + | +LL | Bar::foo(); + | ^^^ + | + = help: add `#![feature(feat_bar)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = note: required for `Bar` to implement `Foo` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/unstable-feature-bound/unstable-feature-cross-crate-exact-symbol.fail.stderr b/tests/ui/unstable-feature-bound/unstable-feature-cross-crate-exact-symbol.fail.stderr new file mode 100644 index 00000000000..ce8d7358cfc --- /dev/null +++ b/tests/ui/unstable-feature-bound/unstable-feature-cross-crate-exact-symbol.fail.stderr @@ -0,0 +1,13 @@ +error[E0658]: use of unstable library feature `feat_moo` + --> $DIR/unstable-feature-cross-crate-exact-symbol.rs:16:5 + | +LL | Moo::foo(); + | ^^^ + | + = help: add `#![feature(feat_moo)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = note: required for `Moo` to implement `Foo` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/unstable-feature-bound/unstable-feature-cross-crate-exact-symbol.rs b/tests/ui/unstable-feature-bound/unstable-feature-cross-crate-exact-symbol.rs new file mode 100644 index 00000000000..a427bb8eb7e --- /dev/null +++ b/tests/ui/unstable-feature-bound/unstable-feature-cross-crate-exact-symbol.rs @@ -0,0 +1,18 @@ +//@ aux-build:unstable_feature.rs +//@ revisions: pass fail +//@[pass] check-pass + +#![cfg_attr(pass, feature(feat_bar, feat_moo))] +#![cfg_attr(fail, feature(feat_bar))] + +extern crate unstable_feature; +use unstable_feature::{Foo, Bar, Moo}; + +/// To use impls gated by both `feat_foo` and `feat_moo`, +/// both features must be enabled. + +fn main() { + Bar::foo(); + Moo::foo(); + //[fail]~^ ERROR:use of unstable library feature `feat_moo` [E0658] +} diff --git a/tests/ui/unstable-feature-bound/unstable-feature-cross-crate-multiple-symbol.rs b/tests/ui/unstable-feature-bound/unstable-feature-cross-crate-multiple-symbol.rs new file mode 100644 index 00000000000..5b09c898a08 --- /dev/null +++ b/tests/ui/unstable-feature-bound/unstable-feature-cross-crate-multiple-symbol.rs @@ -0,0 +1,11 @@ +//@ aux-build:unstable_feature.rs +//@ check-pass +#![feature(feat_bar, feat_moo)] +extern crate unstable_feature; +use unstable_feature::{Foo, Bar}; + +/// Bar::foo() should still be usable even if we enable multiple feature. + +fn main() { + Bar::foo(); +} diff --git a/tests/ui/unstable-feature-bound/unstable-feature-cross-crate-require-bound.fail.stderr b/tests/ui/unstable-feature-bound/unstable-feature-cross-crate-require-bound.fail.stderr new file mode 100644 index 00000000000..87a2ad41fc1 --- /dev/null +++ b/tests/ui/unstable-feature-bound/unstable-feature-cross-crate-require-bound.fail.stderr @@ -0,0 +1,13 @@ +error[E0658]: use of unstable library feature `feat_bar` + --> $DIR/unstable-feature-cross-crate-require-bound.rs:12:5 + | +LL | Bar::foo(); + | ^^^ + | + = help: add `#![feature(feat_bar)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = note: required for `Bar` to implement `Foo` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/unstable-feature-bound/unstable-feature-cross-crate-require-bound.rs b/tests/ui/unstable-feature-bound/unstable-feature-cross-crate-require-bound.rs new file mode 100644 index 00000000000..8be214b5324 --- /dev/null +++ b/tests/ui/unstable-feature-bound/unstable-feature-cross-crate-require-bound.rs @@ -0,0 +1,14 @@ +//@ aux-build:unstable_feature.rs +//@ revisions: pass fail +//@[pass] check-pass + +#![cfg_attr(pass, feature(feat_bar))] +extern crate unstable_feature; +use unstable_feature::{Foo, Bar}; + +/// #[feature(..)] is required to use unstable impl. + +fn main() { + Bar::foo(); + //[fail]~^ ERROR: use of unstable library feature `feat_bar` [E0658] +} diff --git a/tests/ui/unstable-feature-bound/unstable-feature-exact-symbol.fail.stderr b/tests/ui/unstable-feature-bound/unstable-feature-exact-symbol.fail.stderr new file mode 100644 index 00000000000..b8cb63ec65f --- /dev/null +++ b/tests/ui/unstable-feature-bound/unstable-feature-exact-symbol.fail.stderr @@ -0,0 +1,17 @@ +error: unstable feature `feat_moo` is used without being enabled. + --> $DIR/unstable-feature-exact-symbol.rs:37:5 + | +LL | Bar::moo(); + | ^^^ + | + = help: The feature can be enabled by marking the current item with `#[unstable_feature_bound(feat_moo)]` +note: required for `Bar` to implement `Moo` + --> $DIR/unstable-feature-exact-symbol.rs:29:6 + | +LL | #[unstable_feature_bound(feat_moo)] + | ----------------------------------- unsatisfied trait bound introduced here +LL | impl Moo for Bar { + | ^^^ ^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/unstable-feature-bound/unstable-feature-exact-symbol.rs b/tests/ui/unstable-feature-bound/unstable-feature-exact-symbol.rs new file mode 100644 index 00000000000..2de9e6a857e --- /dev/null +++ b/tests/ui/unstable-feature-bound/unstable-feature-exact-symbol.rs @@ -0,0 +1,42 @@ +//@ revisions: pass fail +//@[pass] check-pass + +#![allow(internal_features)] +#![feature(staged_api)] +#![allow(dead_code)] +#![unstable(feature = "feat_foo", issue = "none" )] + +/// In staged-api crate, impl that is marked as unstable with +/// feature name `feat_moo` should not be accessible +/// if only `feat_foo` is enabled. + +pub trait Foo { + fn foo(); +} + +pub trait Moo { + fn moo(); +} + +pub struct Bar; + +#[unstable_feature_bound(feat_foo)] +impl Foo for Bar { + fn foo() {} +} + +#[unstable_feature_bound(feat_moo)] +impl Moo for Bar { + fn moo() {} +} + +#[cfg_attr(fail, unstable_feature_bound(feat_foo))] +#[cfg_attr(pass, unstable_feature_bound(feat_foo, feat_moo))] +fn bar() { + Bar::foo(); + Bar::moo(); + //[fail]~^ ERROR unstable feature `feat_moo` is used without being enabled. + +} + +fn main() {} diff --git a/tests/ui/unstable-feature-bound/unstable-impl-assoc-type.fail.stderr b/tests/ui/unstable-feature-bound/unstable-impl-assoc-type.fail.stderr new file mode 100644 index 00000000000..db9759b4cc3 --- /dev/null +++ b/tests/ui/unstable-feature-bound/unstable-impl-assoc-type.fail.stderr @@ -0,0 +1,22 @@ +error: unstable feature `feat_foo` is used without being enabled. + --> $DIR/unstable-impl-assoc-type.rs:23:16 + | +LL | type Assoc = Self; + | ^^^^ + | + = help: The feature can be enabled by marking the current item with `#[unstable_feature_bound(feat_foo)]` +note: required for `Foo` to implement `Bar` + --> $DIR/unstable-impl-assoc-type.rs:19:6 + | +LL | #[unstable_feature_bound(feat_foo)] + | ----------------------------------- unsatisfied trait bound introduced here +LL | impl Bar for Foo {} + | ^^^ ^^^ +note: required by a bound in `Trait::Assoc` + --> $DIR/unstable-impl-assoc-type.rs:13:17 + | +LL | type Assoc: Bar; + | ^^^ required by this bound in `Trait::Assoc` + +error: aborting due to 1 previous error + diff --git a/tests/ui/unstable-feature-bound/unstable-impl-assoc-type.rs b/tests/ui/unstable-feature-bound/unstable-impl-assoc-type.rs new file mode 100644 index 00000000000..e31dc688dfa --- /dev/null +++ b/tests/ui/unstable-feature-bound/unstable-impl-assoc-type.rs @@ -0,0 +1,28 @@ +//@ revisions: pass fail +//@[pass] check-pass + +#![allow(internal_features)] +#![feature(staged_api)] +#![unstable(feature = "feat_foo", issue = "none" )] + +/// Test that you can't leak unstable impls through item bounds on associated types. + +trait Bar {} + +trait Trait { + type Assoc: Bar; +} + +struct Foo; + +#[unstable_feature_bound(feat_foo)] +impl Bar for Foo {} + +#[cfg_attr(pass, unstable_feature_bound(feat_foo))] +impl Trait for Foo { + type Assoc = Self; + //[fail]~^ ERROR: unstable feature `feat_foo` is used without being enabled. + +} + +fn main(){} diff --git a/tests/ui/unstable-feature-bound/unstable-impl-cannot-use-feature.fail.stderr b/tests/ui/unstable-feature-bound/unstable-impl-cannot-use-feature.fail.stderr new file mode 100644 index 00000000000..d56072362fe --- /dev/null +++ b/tests/ui/unstable-feature-bound/unstable-impl-cannot-use-feature.fail.stderr @@ -0,0 +1,17 @@ +error: unstable feature `feat_foo` is used without being enabled. + --> $DIR/unstable-impl-cannot-use-feature.rs:26:5 + | +LL | Bar::foo(); + | ^^^ + | + = help: The feature can be enabled by marking the current item with `#[unstable_feature_bound(feat_foo)]` +note: required for `Bar` to implement `Foo` + --> $DIR/unstable-impl-cannot-use-feature.rs:20:6 + | +LL | #[unstable_feature_bound(feat_foo)] + | ----------------------------------- unsatisfied trait bound introduced here +LL | impl Foo for Bar { + | ^^^ ^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/unstable-feature-bound/unstable-impl-cannot-use-feature.rs b/tests/ui/unstable-feature-bound/unstable-impl-cannot-use-feature.rs new file mode 100644 index 00000000000..0da618445fd --- /dev/null +++ b/tests/ui/unstable-feature-bound/unstable-impl-cannot-use-feature.rs @@ -0,0 +1,30 @@ +//@ revisions: pass fail +//@[pass] check-pass + +#![allow(internal_features)] +#![feature(staged_api)] +#![allow(dead_code)] +#![unstable(feature = "feat_foo", issue = "none" )] + +#![cfg_attr(fail, feature(feat_foo))] + +/// In staged-api crate, using an unstable impl requires +/// #[unstable_feature_bound(..)], not #[feature(..)]. + +pub trait Foo { + fn foo(); +} +pub struct Bar; + +#[unstable_feature_bound(feat_foo)] +impl Foo for Bar { + fn foo() {} +} + +#[cfg_attr(pass, unstable_feature_bound(feat_foo))] +fn bar() { + Bar::foo(); + //[fail]~^ ERROR: unstable feature `feat_foo` is used without being enabled. +} + +fn main() {} diff --git a/tests/ui/unstable-feature-bound/unstable-impl-multiple-symbol.rs b/tests/ui/unstable-feature-bound/unstable-impl-multiple-symbol.rs new file mode 100644 index 00000000000..c9a9029b0a0 --- /dev/null +++ b/tests/ui/unstable-feature-bound/unstable-impl-multiple-symbol.rs @@ -0,0 +1,27 @@ +//@ check-pass + +#![allow(internal_features)] +#![feature(staged_api)] +#![allow(dead_code)] +#![unstable(feature = "feat_foo", issue = "none" )] + +/// In staged-api crate, if feat_foo is only needed to use an impl, +/// having both `feat_foo` and `feat_bar` will still make it pass. + +pub trait Foo { + fn foo(); +} +pub struct Bar; + +// Annotate the impl as unstable. +#[unstable_feature_bound(feat_foo)] +impl Foo for Bar { + fn foo() {} +} + +#[unstable_feature_bound(feat_foo, feat_bar)] +fn bar() { + Bar::foo(); +} + +fn main() {} diff --git a/tests/ui/unstable-feature-bound/unstable_feature_bound_free_fn.fail.stderr b/tests/ui/unstable-feature-bound/unstable_feature_bound_free_fn.fail.stderr new file mode 100644 index 00000000000..f8354256828 --- /dev/null +++ b/tests/ui/unstable-feature-bound/unstable_feature_bound_free_fn.fail.stderr @@ -0,0 +1,17 @@ +error: unstable feature `feat_bar` is used without being enabled. + --> $DIR/unstable_feature_bound_free_fn.rs:36:5 + | +LL | bar(); + | ^^^^^ + | + = help: The feature can be enabled by marking the current item with `#[unstable_feature_bound(feat_bar)]` +note: required by a bound in `bar` + --> $DIR/unstable_feature_bound_free_fn.rs:29:1 + | +LL | #[unstable_feature_bound(feat_bar)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `bar` +LL | fn bar() { + | --- required by a bound in this function + +error: aborting due to 1 previous error + diff --git a/tests/ui/unstable-feature-bound/unstable_feature_bound_free_fn.rs b/tests/ui/unstable-feature-bound/unstable_feature_bound_free_fn.rs new file mode 100644 index 00000000000..30e2ab3d65e --- /dev/null +++ b/tests/ui/unstable-feature-bound/unstable_feature_bound_free_fn.rs @@ -0,0 +1,40 @@ +//@ revisions: pass fail +//@[pass] check-pass + +#![allow(internal_features)] +#![feature(staged_api)] +#![allow(dead_code)] +#![stable(feature = "a", since = "1.1.1" )] + +/// When a free function with #[unstable_feature_bound(feat_bar)] is called by another +/// free function, that function should be annotated with +/// #[unstable_feature_bound(feat_bar)] too. + +#[stable(feature = "a", since = "1.1.1")] +trait Foo { + #[stable(feature = "a", since = "1.1.1")] + fn foo() { + } +} +#[stable(feature = "a", since = "1.1.1")] +pub struct Bar; + +#[unstable_feature_bound(feat_bar)] +#[unstable(feature = "feat_bar", issue = "none" )] +impl Foo for Bar { + fn foo() {} +} + + +#[unstable_feature_bound(feat_bar)] +fn bar() { + Bar::foo(); +} + +#[cfg_attr(pass, unstable_feature_bound(feat_bar))] +fn bar2() { + bar(); + //[fail]~^ERROR unstable feature `feat_bar` is used without being enabled. +} + +fn main() {} diff --git a/tests/ui/unstable-feature-bound/unstable_feature_bound_incompatible_stability.rs b/tests/ui/unstable-feature-bound/unstable_feature_bound_incompatible_stability.rs new file mode 100644 index 00000000000..1a9652c1023 --- /dev/null +++ b/tests/ui/unstable-feature-bound/unstable_feature_bound_incompatible_stability.rs @@ -0,0 +1,14 @@ +#![allow(internal_features)] +#![feature(staged_api)] +#![allow(dead_code)] +#![stable(feature = "a", since = "1.1.1" )] + +// Lint against the usage of both #[unstable_feature_bound] and #[stable] on the +// same item. + +#[stable(feature = "a", since = "1.1.1")] +#[unstable_feature_bound(feat_bar)] +fn bar() {} +//~^ ERROR Item annotated with `#[unstable_feature_bound]` should not be stable + +fn main() {} diff --git a/tests/ui/unstable-feature-bound/unstable_feature_bound_incompatible_stability.stderr b/tests/ui/unstable-feature-bound/unstable_feature_bound_incompatible_stability.stderr new file mode 100644 index 00000000000..9cb6a181bef --- /dev/null +++ b/tests/ui/unstable-feature-bound/unstable_feature_bound_incompatible_stability.stderr @@ -0,0 +1,10 @@ +error: Item annotated with `#[unstable_feature_bound]` should not be stable + --> $DIR/unstable_feature_bound_incompatible_stability.rs:11:1 + | +LL | fn bar() {} + | ^^^^^^^^^^^ + | + = help: If this item is meant to be stable, do not use any functions annotated with `#[unstable_feature_bound]`. Otherwise, mark this item as unstable with `#[unstable]` + +error: aborting due to 1 previous error + diff --git a/tests/ui/unstable-feature-bound/unstable_feature_bound_multi_attr.rs b/tests/ui/unstable-feature-bound/unstable_feature_bound_multi_attr.rs new file mode 100644 index 00000000000..3d6b52ba517 --- /dev/null +++ b/tests/ui/unstable-feature-bound/unstable_feature_bound_multi_attr.rs @@ -0,0 +1,36 @@ +#![allow(internal_features)] +#![feature(staged_api)] +#![allow(dead_code)] +#![unstable(feature = "feat_bar", issue = "none" )] + +/// Test the behaviour of multiple unstable_feature_bound attribute. + +trait Foo { + fn foo(); +} +struct Bar; + +#[unstable_feature_bound(feat_bar, feat_koo)] +#[unstable_feature_bound(feat_foo, feat_moo)] +impl Foo for Bar { + fn foo(){} +} + +#[unstable_feature_bound(feat_bar, feat_koo)] +#[unstable_feature_bound(feat_foo, feat_moo)] +fn moo() { + Bar::foo(); +} + +#[unstable_feature_bound(feat_bar, feat_koo, feat_foo, feat_moo)] +fn koo() { + Bar::foo(); +} + +#[unstable_feature_bound(feat_koo, feat_foo, feat_moo)] +fn boo() { + Bar::foo(); + //~^ ERROR: unstable feature `feat_bar` is used without being enabled. +} + +fn main() {} diff --git a/tests/ui/unstable-feature-bound/unstable_feature_bound_multi_attr.stderr b/tests/ui/unstable-feature-bound/unstable_feature_bound_multi_attr.stderr new file mode 100644 index 00000000000..936c70c1979 --- /dev/null +++ b/tests/ui/unstable-feature-bound/unstable_feature_bound_multi_attr.stderr @@ -0,0 +1,18 @@ +error: unstable feature `feat_bar` is used without being enabled. + --> $DIR/unstable_feature_bound_multi_attr.rs:32:5 + | +LL | Bar::foo(); + | ^^^ + | + = help: The feature can be enabled by marking the current item with `#[unstable_feature_bound(feat_bar)]` +note: required for `Bar` to implement `Foo` + --> $DIR/unstable_feature_bound_multi_attr.rs:15:6 + | +LL | #[unstable_feature_bound(feat_bar, feat_koo)] + | --------------------------------------------- unsatisfied trait bound introduced here +LL | #[unstable_feature_bound(feat_foo, feat_moo)] +LL | impl Foo for Bar { + | ^^^ ^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/unstable-feature-bound/unstable_feature_bound_staged_api.rs b/tests/ui/unstable-feature-bound/unstable_feature_bound_staged_api.rs new file mode 100644 index 00000000000..51e388f7dd3 --- /dev/null +++ b/tests/ui/unstable-feature-bound/unstable_feature_bound_staged_api.rs @@ -0,0 +1,13 @@ +/// Unstable feature bound can only be used only when +/// #[feature(staged_api)] is enabled. + +pub trait Foo { +} +pub struct Bar; + +#[unstable_feature_bound(feat_bar)] +//~^ ERROR: stability attributes may not be used outside of the standard library +impl Foo for Bar { +} + +fn main(){} diff --git a/tests/ui/unstable-feature-bound/unstable_feature_bound_staged_api.stderr b/tests/ui/unstable-feature-bound/unstable_feature_bound_staged_api.stderr new file mode 100644 index 00000000000..35ab89e6ad9 --- /dev/null +++ b/tests/ui/unstable-feature-bound/unstable_feature_bound_staged_api.stderr @@ -0,0 +1,9 @@ +error[E0734]: stability attributes may not be used outside of the standard library + --> $DIR/unstable_feature_bound_staged_api.rs:8:1 + | +LL | #[unstable_feature_bound(feat_bar)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0734`. diff --git a/tests/ui/unstable-feature-bound/unstable_impl_codegen.rs b/tests/ui/unstable-feature-bound/unstable_impl_codegen.rs new file mode 100644 index 00000000000..285a64d2250 --- /dev/null +++ b/tests/ui/unstable-feature-bound/unstable_impl_codegen.rs @@ -0,0 +1,13 @@ +//@ aux-build:unstable_impl_codegen_aux2.rs +//@ run-pass + +/// Downstream crate for unstable impl codegen test +/// that depends on upstream crate in +/// unstable_impl_codegen_aux2.rs + +extern crate unstable_impl_codegen_aux2 as aux; +use aux::foo; + +fn main() { + foo(1_u8); +} diff --git a/tests/ui/unstable-feature-bound/unstable_impl_coherence.disabled.stderr b/tests/ui/unstable-feature-bound/unstable_impl_coherence.disabled.stderr new file mode 100644 index 00000000000..c3147558b03 --- /dev/null +++ b/tests/ui/unstable-feature-bound/unstable_impl_coherence.disabled.stderr @@ -0,0 +1,13 @@ +error[E0119]: conflicting implementations of trait `Trait` for type `LocalTy` + --> $DIR/unstable_impl_coherence.rs:14:1 + | +LL | impl aux::Trait for LocalTy {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: conflicting implementation in crate `unstable_impl_coherence_aux`: + - impl<T> Trait for T + where unstable feature: `foo`; + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/unstable-feature-bound/unstable_impl_coherence.enabled.stderr b/tests/ui/unstable-feature-bound/unstable_impl_coherence.enabled.stderr new file mode 100644 index 00000000000..c3147558b03 --- /dev/null +++ b/tests/ui/unstable-feature-bound/unstable_impl_coherence.enabled.stderr @@ -0,0 +1,13 @@ +error[E0119]: conflicting implementations of trait `Trait` for type `LocalTy` + --> $DIR/unstable_impl_coherence.rs:14:1 + | +LL | impl aux::Trait for LocalTy {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: conflicting implementation in crate `unstable_impl_coherence_aux`: + - impl<T> Trait for T + where unstable feature: `foo`; + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/unstable-feature-bound/unstable_impl_coherence.rs b/tests/ui/unstable-feature-bound/unstable_impl_coherence.rs new file mode 100644 index 00000000000..22100f85f71 --- /dev/null +++ b/tests/ui/unstable-feature-bound/unstable_impl_coherence.rs @@ -0,0 +1,17 @@ +//@ aux-build:unstable_impl_coherence_aux.rs +//@ revisions: enabled disabled + +#![cfg_attr(enabled, feature(foo))] +extern crate unstable_impl_coherence_aux as aux; +use aux::Trait; + +/// Coherence test for unstable impl. +/// No matter feature `foo` is enabled or not, the impl +/// for aux::Trait will be rejected by coherence checking. + +struct LocalTy; + +impl aux::Trait for LocalTy {} +//~^ ERROR: conflicting implementations of trait `Trait` for type `LocalTy` + +fn main(){} diff --git a/tests/ui/unstable-feature-bound/unstable_impl_method_selection.rs b/tests/ui/unstable-feature-bound/unstable_impl_method_selection.rs new file mode 100644 index 00000000000..acf521d3130 --- /dev/null +++ b/tests/ui/unstable-feature-bound/unstable_impl_method_selection.rs @@ -0,0 +1,15 @@ +//@ aux-build:unstable_impl_method_selection_aux.rs + +extern crate unstable_impl_method_selection_aux as aux; +use aux::Trait; + +// The test below should not infer the type based on the fact +// that `impl Trait for Vec<u64>` is unstable. This would cause breakage +// in downstream crate once `impl Trait for Vec<u64>` is stabilised. + +fn bar() { + vec![].foo(); + //~^ ERROR type annotations needed +} + +fn main() {} diff --git a/tests/ui/unstable-feature-bound/unstable_impl_method_selection.stderr b/tests/ui/unstable-feature-bound/unstable_impl_method_selection.stderr new file mode 100644 index 00000000000..c2bb10f043b --- /dev/null +++ b/tests/ui/unstable-feature-bound/unstable_impl_method_selection.stderr @@ -0,0 +1,14 @@ +error[E0283]: type annotations needed + --> $DIR/unstable_impl_method_selection.rs:11:12 + | +LL | vec![].foo(); + | ^^^ cannot infer type for struct `Vec<_>` + | + = note: multiple `impl`s satisfying `Vec<_>: Trait` found in the `unstable_impl_method_selection_aux` crate: + - impl Trait for Vec<u32>; + - impl Trait for Vec<u64> + where unstable feature: `bar`; + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0283`. diff --git a/tests/ui/unstable-feature-bound/unstable_inherent_method.rs b/tests/ui/unstable-feature-bound/unstable_inherent_method.rs new file mode 100644 index 00000000000..5f3095430a8 --- /dev/null +++ b/tests/ui/unstable-feature-bound/unstable_inherent_method.rs @@ -0,0 +1,23 @@ +#![allow(internal_features)] +#![feature(staged_api)] +#![stable(feature = "a", since = "1.1.1" )] + +/// FIXME(tiif): we haven't allowed marking trait and impl method as +/// unstable yet, but it should be possible. + +#[stable(feature = "a", since = "1.1.1" )] +pub trait Trait { + #[unstable(feature = "feat", issue = "none" )] + #[unstable_feature_bound(foo)] + //~^ ERROR: attribute should be applied to `impl` or free function outside of any `impl` or trait + fn foo(); +} + +#[stable(feature = "a", since = "1.1.1" )] +impl Trait for u8 { + #[unstable_feature_bound(foo)] + //~^ ERROR: attribute should be applied to `impl` or free function outside of any `impl` or trait + fn foo() {} +} + +fn main() {} diff --git a/tests/ui/unstable-feature-bound/unstable_inherent_method.stderr b/tests/ui/unstable-feature-bound/unstable_inherent_method.stderr new file mode 100644 index 00000000000..fa1c39db259 --- /dev/null +++ b/tests/ui/unstable-feature-bound/unstable_inherent_method.stderr @@ -0,0 +1,20 @@ +error: attribute should be applied to `impl` or free function outside of any `impl` or trait + --> $DIR/unstable_inherent_method.rs:11:5 + | +LL | #[unstable_feature_bound(foo)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | fn foo(); + | --------- not an `impl` or free function + +error: attribute should be applied to `impl` or free function outside of any `impl` or trait + --> $DIR/unstable_inherent_method.rs:18:5 + | +LL | #[unstable_feature_bound(foo)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | fn foo() {} + | ----------- not an `impl` or free function + +error: aborting due to 2 previous errors + |
