diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index dcfbecedfe8ff..64a6f91f02206 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -135,9 +135,42 @@ impl ConstStability { #[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, Hash)] #[derive(HashStable_Generic)] pub enum StabilityLevel { - // Reason for the current stability level and the relevant rust-lang issue - Unstable { reason: Option, issue: Option, is_soft: bool }, - Stable { since: Symbol, allowed_through_unstable_modules: bool }, + /// `#[unstable]` + Unstable { + /// Reason for the current stability level. + reason: Option, + /// Relevant `rust-lang/rust` issue. + issue: Option, + is_soft: bool, + /// If part of a feature is stabilized and a new feature is added for the remaining parts, + /// then the `implied_by` attribute is used to indicate which now-stable feature previously + /// contained a item. + /// + /// ```pseudo-Rust + /// #[unstable(feature = "foo", issue = "...")] + /// fn foo() {} + /// #[unstable(feature = "foo", issue = "...")] + /// fn foobar() {} + /// ``` + /// + /// ...becomes... + /// + /// ```pseudo-Rust + /// #[stable(feature = "foo", since = "1.XX.X")] + /// fn foo() {} + /// #[unstable(feature = "foobar", issue = "...", implied_by = "foo")] + /// fn foobar() {} + /// ``` + implied_by: Option, + }, + /// `#[stable]` + Stable { + /// Rust release which stabilized this feature. + since: Symbol, + /// Is this item allowed to be referred to on stable, despite being contained in unstable + /// modules? + allowed_through_unstable_modules: bool, + }, } impl StabilityLevel { @@ -243,6 +276,7 @@ where let mut issue = None; let mut issue_num = None; let mut is_soft = false; + let mut implied_by = None; for meta in metas { let Some(mi) = meta.meta_item() else { handle_errors( @@ -308,6 +342,11 @@ where } is_soft = true; } + sym::implied_by => { + if !get(mi, &mut implied_by) { + continue 'outer; + } + } _ => { handle_errors( &sess.parse_sess, @@ -332,7 +371,7 @@ where ); continue; } - let level = Unstable { reason, issue: issue_num, is_soft }; + let level = Unstable { reason, issue: issue_num, is_soft, implied_by }; if sym::unstable == meta_name { stab = Some((Stability { level, feature }, attr.span)); } else { @@ -391,7 +430,7 @@ where meta.span(), AttrError::UnknownMetaItem( pprust::path_to_string(&mi.path), - &["since", "note"], + &["feature", "since"], ), ); continue 'outer; diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index 3b7e2102ffa9b..ce897abb766e5 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -485,7 +485,7 @@ impl<'a, 'b> Context<'a, 'b> { if let Some(span) = fmt.width_span { let span = self.fmtsp.from_inner(InnerSpan::new(span.start, span.end)); match fmt.width { - parse::CountIsParam(pos) if pos > self.num_args() => { + parse::CountIsParam(pos) if pos >= self.num_args() => { e.span_label( span, &format!( @@ -1004,9 +1004,7 @@ fn lint_named_arguments_used_positionally( node_id: ast::CRATE_NODE_ID, lint_id: LintId::of(&NAMED_ARGUMENTS_USED_POSITIONALLY), diagnostic: BuiltinLintDiagnostics::NamedArgumentUsedPositionally( - arg_span, - span, - symbol.to_string(), + arg_span, span, symbol, ), }); } diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 7d7f3e1833576..ba888d77b15c1 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -390,18 +390,17 @@ impl Diagnostic { expected: DiagnosticStyledString, found: DiagnosticStyledString, ) -> &mut Self { - let mut msg: Vec<_> = - vec![("required when trying to coerce from type `".to_string(), Style::NoStyle)]; + let mut msg: Vec<_> = vec![("required when trying to coerce from type `", Style::NoStyle)]; msg.extend(expected.0.iter().map(|x| match *x { - StringPart::Normal(ref s) => (s.to_owned(), Style::NoStyle), - StringPart::Highlighted(ref s) => (s.to_owned(), Style::Highlight), + StringPart::Normal(ref s) => (s.as_str(), Style::NoStyle), + StringPart::Highlighted(ref s) => (s.as_str(), Style::Highlight), })); - msg.push(("` to type '".to_string(), Style::NoStyle)); + msg.push(("` to type '", Style::NoStyle)); msg.extend(found.0.iter().map(|x| match *x { - StringPart::Normal(ref s) => (s.to_owned(), Style::NoStyle), - StringPart::Highlighted(ref s) => (s.to_owned(), Style::Highlight), + StringPart::Normal(ref s) => (s.as_str(), Style::NoStyle), + StringPart::Highlighted(ref s) => (s.as_str(), Style::Highlight), })); - msg.push(("`".to_string(), Style::NoStyle)); + msg.push(("`", Style::NoStyle)); // For now, just attach these as notes self.highlighted_note(msg); diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs index fdd8dc93fc1a5..3037855ae28a6 100644 --- a/compiler/rustc_expand/src/mbe/transcribe.rs +++ b/compiler/rustc_expand/src/mbe/transcribe.rs @@ -512,7 +512,18 @@ fn out_of_bounds_err<'a>( span: Span, ty: &str, ) -> DiagnosticBuilder<'a, ErrorGuaranteed> { - cx.struct_span_err(span, &format!("{ty} depth must be less than {max}")) + let msg = if max == 0 { + format!( + "meta-variable expression `{ty}` with depth parameter \ + must be called inside of a macro repetition" + ) + } else { + format!( + "depth parameter on meta-variable expression `{ty}` \ + must be less than {max}" + ) + }; + cx.struct_span_err(span, &msg) } fn transcribe_metavar_expr<'a>( diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 4fd57ed853379..3872d866dee86 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -467,7 +467,7 @@ pub enum BuiltinLintDiagnostics { /// If true, the lifetime will be fully elided. use_span: Option<(Span, bool)>, }, - NamedArgumentUsedPositionally(Option, Span, String), + NamedArgumentUsedPositionally(Option, Span, Symbol), } /// Lints that are buffered up early on in the `Session` before the diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index f0874f8f2da00..aa5705d3fcdc3 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -951,6 +951,13 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { tcx.arena.alloc_from_iter(self.root.lib_features.decode(self)) } + /// Iterates over the stability implications in the given crate (when a `#[unstable]` attribute + /// has an `implied_by` meta item, then the mapping from the implied feature to the actual + /// feature is a stability implication). + fn get_stability_implications(self, tcx: TyCtxt<'tcx>) -> &'tcx [(Symbol, Symbol)] { + tcx.arena.alloc_from_iter(self.root.stability_implications.decode(self)) + } + /// Iterates over the language items in the given crate. fn get_lang_items(self, tcx: TyCtxt<'tcx>) -> &'tcx [(DefId, usize)] { tcx.arena.alloc_from_iter( diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 565eec18ea9b8..65cae29c58dcb 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -291,6 +291,9 @@ provide! { <'tcx> tcx, def_id, other, cdata, tcx.arena.alloc_slice(&result) } defined_lib_features => { cdata.get_lib_features(tcx) } + stability_implications => { + cdata.get_stability_implications(tcx).iter().copied().collect() + } is_intrinsic => { cdata.get_is_intrinsic(def_id.index) } defined_lang_items => { cdata.get_lang_items(tcx) } diagnostic_items => { cdata.get_diagnostic_items() } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 8e97300977723..50d983754e89c 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -538,6 +538,11 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let lib_features = self.encode_lib_features(); let lib_feature_bytes = self.position() - i; + // Encode the stability implications. + i = self.position(); + let stability_implications = self.encode_stability_implications(); + let stability_implications_bytes = self.position() - i; + // Encode the language items. i = self.position(); let lang_items = self.encode_lang_items(); @@ -686,6 +691,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { crate_deps, dylib_dependency_formats, lib_features, + stability_implications, lang_items, diagnostic_items, lang_items_missing, @@ -710,6 +716,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let computed_total_bytes = preamble_bytes + dep_bytes + lib_feature_bytes + + stability_implications_bytes + lang_item_bytes + diagnostic_item_bytes + native_lib_bytes @@ -761,6 +768,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { p("preamble", preamble_bytes); p("dep", dep_bytes); p("lib feature", lib_feature_bytes); + p("stability_implications", stability_implications_bytes); p("lang item", lang_item_bytes); p("diagnostic item", diagnostic_item_bytes); p("native lib", native_lib_bytes); @@ -1777,6 +1785,13 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.lazy_array(lib_features.to_vec()) } + fn encode_stability_implications(&mut self) -> LazyArray<(Symbol, Symbol)> { + empty_proc_macro!(self); + let tcx = self.tcx; + let implications = tcx.stability_implications(LOCAL_CRATE); + self.lazy_array(implications.iter().map(|(k, v)| (*k, *v))) + } + fn encode_diagnostic_items(&mut self) -> LazyArray<(Symbol, DefIndex)> { empty_proc_macro!(self); let tcx = self.tcx; diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index af1c09f4ae87a..0f291f9264777 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -226,6 +226,7 @@ pub(crate) struct CrateRoot { crate_deps: LazyArray, dylib_dependency_formats: LazyArray>, lib_features: LazyArray<(Symbol, Option)>, + stability_implications: LazyArray<(Symbol, Symbol)>, lang_items: LazyArray<(DefIndex, usize)>, lang_items_missing: LazyArray, diagnostic_items: LazyArray<(Symbol, DefIndex)>, diff --git a/compiler/rustc_middle/src/middle/mod.rs b/compiler/rustc_middle/src/middle/mod.rs index fc35cafcc77a1..8dc68b1f5a820 100644 --- a/compiler/rustc_middle/src/middle/mod.rs +++ b/compiler/rustc_middle/src/middle/mod.rs @@ -3,14 +3,14 @@ pub mod dependency_format; pub mod exported_symbols; pub mod lang_items; pub mod lib_features { - use rustc_data_structures::fx::{FxHashMap, FxHashSet}; - use rustc_span::symbol::Symbol; + use rustc_data_structures::fx::FxHashMap; + use rustc_span::{symbol::Symbol, Span}; #[derive(HashStable, Debug)] pub struct LibFeatures { - // A map from feature to stabilisation version. - pub stable: FxHashMap, - pub unstable: FxHashSet, + /// A map from feature to stabilisation version. + pub stable: FxHashMap, + pub unstable: FxHashMap, } impl LibFeatures { @@ -18,8 +18,8 @@ pub mod lib_features { let mut all_features: Vec<_> = self .stable .iter() - .map(|(f, s)| (*f, Some(*s))) - .chain(self.unstable.iter().map(|f| (*f, None))) + .map(|(f, (s, _))| (*f, Some(*s))) + .chain(self.unstable.iter().map(|(f, _)| (*f, None))) .collect(); all_features.sort_unstable_by(|a, b| a.0.as_str().partial_cmp(b.0.as_str()).unwrap()); all_features diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index 96e068a36012a..0fbad3f0f0f06 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -62,6 +62,19 @@ pub struct Index { pub stab_map: FxHashMap, pub const_stab_map: FxHashMap, pub depr_map: FxHashMap, + /// Mapping from feature name to feature name based on the `implied_by` field of `#[unstable]` + /// attributes. If a `#[unstable(feature = "implier", implied_by = "impliee")]` attribute + /// exists, then this map will have a `impliee -> implier` entry. + /// + /// This mapping is necessary unless both the `#[stable]` and `#[unstable]` attributes should + /// specify their implications (both `implies` and `implied_by`). If only one of the two + /// attributes do (as in the current implementation, `implied_by` in `#[unstable]`), then this + /// mapping is necessary for diagnostics. When a "unnecessary feature attribute" error is + /// reported, only the `#[stable]` attribute information is available, so the map is necessary + /// to know that the feature implies another feature. If it were reversed, and the `#[stable]` + /// attribute had an `implies` meta item, then a map would be necessary when avoiding a "use of + /// unstable feature" error for a feature that was implied. + pub implications: FxHashMap, } impl Index { @@ -423,7 +436,9 @@ impl<'tcx> TyCtxt<'tcx> { match stability { Some(Stability { - level: attr::Unstable { reason, issue, is_soft }, feature, .. + level: attr::Unstable { reason, issue, is_soft, implied_by }, + feature, + .. }) => { if span.allows_unstable(feature) { debug!("stability: skipping span={:?} since it is internal", span); @@ -433,6 +448,13 @@ impl<'tcx> TyCtxt<'tcx> { return EvalResult::Allow; } + // If this item was previously part of a now-stabilized feature which is still + // active (i.e. the user hasn't removed the attribute for the stabilized feature + // yet) then allow use of this item. + if let Some(implied_by) = implied_by && self.features().active(implied_by) { + return EvalResult::Allow; + } + // When we're compiling the compiler itself we may pull in // crates from crates.io, but those crates may depend on other // crates also pulled in from crates.io. We want to ideally be diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 0581ef41f66c2..466a0fc25f7d1 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1634,11 +1634,15 @@ rustc_queries! { storage(ArenaCacheSelector<'tcx>) desc { "calculating the lib features map" } } - query defined_lib_features(_: CrateNum) - -> &'tcx [(Symbol, Option)] { + query defined_lib_features(_: CrateNum) -> &'tcx [(Symbol, Option)] { desc { "calculating the lib features defined in a crate" } separate_provide_extern } + query stability_implications(_: CrateNum) -> FxHashMap { + storage(ArenaCacheSelector<'tcx>) + desc { "calculating the implications between `#[unstable]` features defined in a crate" } + separate_provide_extern + } /// Whether the function is an intrinsic query is_intrinsic(def_id: DefId) -> bool { desc { |tcx| "is_intrinsic({})", tcx.def_path_str(def_id) } diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs index f6fa19030acb9..6e7553f5e496b 100644 --- a/compiler/rustc_parse_format/src/lib.rs +++ b/compiler/rustc_parse_format/src/lib.rs @@ -572,9 +572,10 @@ impl<'a> Parser<'a> { // '0' flag and then an ill-formatted format string with just a '$' // and no count, but this is better if we instead interpret this as // no '0' flag and '0$' as the width instead. - if self.consume('$') { + if let Some(end) = self.consume_pos('$') { spec.width = CountIsParam(0); havewidth = true; + spec.width_span = Some(self.to_span_index(end - 1).to(self.to_span_index(end + 1))); } else { spec.flags |= 1 << (FlagSignAwareZeroPad as u32); } diff --git a/compiler/rustc_parse_format/src/tests.rs b/compiler/rustc_parse_format/src/tests.rs index c9667922ee7c3..9c305b4996a13 100644 --- a/compiler/rustc_parse_format/src/tests.rs +++ b/compiler/rustc_parse_format/src/tests.rs @@ -178,6 +178,23 @@ fn format_counts() { }, })], ); + same( + "{1:0$.10x}", + &[NextArgument(Argument { + position: ArgumentIs(1), + format: FormatSpec { + fill: None, + align: AlignUnknown, + flags: 0, + precision: CountIs(10), + width: CountIsParam(0), + precision_span: None, + width_span: Some(InnerSpan::new(4, 6)), + ty: "x", + ty_span: None, + }, + })], + ); same( "{:.*x}", &[NextArgument(Argument { diff --git a/compiler/rustc_passes/src/lib_features.rs b/compiler/rustc_passes/src/lib_features.rs index 26bfa4737a752..e05994f13e4d9 100644 --- a/compiler/rustc_passes/src/lib_features.rs +++ b/compiler/rustc_passes/src/lib_features.rs @@ -1,8 +1,8 @@ -// Detecting lib features (i.e., features that are not lang features). -// -// These are declared using stability attributes (e.g., `#[stable (..)]` -// and `#[unstable (..)]`), but are not declared in one single location -// (unlike lang features), which means we need to collect them instead. +//! Detecting lib features (i.e., features that are not lang features). +//! +//! These are declared using stability attributes (e.g., `#[stable (..)]` and `#[unstable (..)]`), +//! but are not declared in one single location (unlike lang features), which means we need to +//! collect them instead. use rustc_ast::{Attribute, MetaItemKind}; use rustc_errors::struct_span_err; @@ -71,11 +71,11 @@ impl<'tcx> LibFeatureCollector<'tcx> { fn collect_feature(&mut self, feature: Symbol, since: Option, span: Span) { let already_in_stable = self.lib_features.stable.contains_key(&feature); - let already_in_unstable = self.lib_features.unstable.contains(&feature); + let already_in_unstable = self.lib_features.unstable.contains_key(&feature); match (since, already_in_stable, already_in_unstable) { (Some(since), _, false) => { - if let Some(prev_since) = self.lib_features.stable.get(&feature) { + if let Some((prev_since, _)) = self.lib_features.stable.get(&feature) { if *prev_since != since { self.span_feature_error( span, @@ -89,10 +89,10 @@ impl<'tcx> LibFeatureCollector<'tcx> { } } - self.lib_features.stable.insert(feature, since); + self.lib_features.stable.insert(feature, (since, span)); } (None, false, _) => { - self.lib_features.unstable.insert(feature); + self.lib_features.unstable.insert(feature, span); } (Some(_), _, true) | (None, true, _) => { self.span_feature_error( diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 4e091c5b70d5c..81b04c414ed9b 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -2,9 +2,9 @@ //! propagating default levels lexically from parent to children ast nodes. use attr::StabilityLevel; -use rustc_attr::{self as attr, ConstStability, Stability}; -use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; -use rustc_errors::struct_span_err; +use rustc_attr::{self as attr, ConstStability, Stability, Unstable}; +use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; +use rustc_errors::{struct_span_err, Applicability}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID}; @@ -29,13 +29,13 @@ use std::num::NonZeroU32; #[derive(PartialEq)] enum AnnotationKind { - // Annotation is required if not inherited from unstable parents + /// Annotation is required if not inherited from unstable parents. Required, - // Annotation is useless, reject it + /// Annotation is useless, reject it. Prohibited, - // Deprecation annotation is useless, reject it. (Stability attribute is still required.) + /// Deprecation annotation is useless, reject it. (Stability attribute is still required.) DeprecationProhibited, - // Annotation itself is useless, but it can be propagated to children + /// Annotation itself is useless, but it can be propagated to children. Container, } @@ -83,7 +83,7 @@ impl InheritStability { } } -// A private tree-walker for producing an Index. +/// A private tree-walker for producing an `Index`. struct Annotator<'a, 'tcx> { tcx: TyCtxt<'tcx>, index: &'a mut Index, @@ -94,9 +94,9 @@ struct Annotator<'a, 'tcx> { } impl<'a, 'tcx> Annotator<'a, 'tcx> { - // Determine the stability for a node based on its attributes and inherited - // stability. The stability is recorded in the index and used as the parent. - // If the node is a function, `fn_sig` is its signature + /// Determine the stability for a node based on its attributes and inherited stability. The + /// stability is recorded in the index and used as the parent. If the node is a function, + /// `fn_sig` is its signature. fn annotate( &mut self, def_id: LocalDefId, @@ -265,6 +265,10 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { } } + if let Stability { level: Unstable { implied_by: Some(implied_by), .. }, feature } = stab { + self.index.implications.insert(implied_by, feature); + } + self.index.stab_map.insert(def_id, stab); stab }); @@ -610,6 +614,7 @@ fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index { stab_map: Default::default(), const_stab_map: Default::default(), depr_map: Default::default(), + implications: Default::default(), }; { @@ -637,6 +642,7 @@ fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index { reason: Some(Symbol::intern(reason)), issue: NonZeroU32::new(27812), is_soft: false, + implied_by: None, }, feature: sym::rustc_private, }; @@ -667,6 +673,7 @@ pub(crate) fn provide(providers: &mut Providers) { *providers = Providers { check_mod_unstable_api_usage, stability_index, + stability_implications: |tcx, _| tcx.stability().implications.clone(), lookup_stability: |tcx, id| tcx.stability().local_stability(id.expect_local()), lookup_const_stability: |tcx, id| tcx.stability().local_const_stability(id.expect_local()), lookup_deprecation_entry: |tcx, id| { @@ -945,32 +952,51 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) { remaining_lib_features.remove(&sym::libc); remaining_lib_features.remove(&sym::test); - let check_features = |remaining_lib_features: &mut FxIndexMap<_, _>, defined_features: &[_]| { - for &(feature, since) in defined_features { - if let Some(since) = since { - if let Some(span) = remaining_lib_features.get(&feature) { - // Warn if the user has enabled an already-stable lib feature. - unnecessary_stable_feature_lint(tcx, *span, feature, since); - } - } - remaining_lib_features.remove(&feature); - if remaining_lib_features.is_empty() { - break; - } - } - }; - // We always collect the lib features declared in the current crate, even if there are // no unknown features, because the collection also does feature attribute validation. - let local_defined_features = tcx.lib_features(()).to_vec(); - if !remaining_lib_features.is_empty() { - check_features(&mut remaining_lib_features, &local_defined_features); + let local_defined_features = tcx.lib_features(()); + let mut all_lib_features: FxHashMap<_, _> = + local_defined_features.to_vec().iter().map(|el| *el).collect(); + let mut implications = tcx.stability_implications(rustc_hir::def_id::LOCAL_CRATE).clone(); + for &cnum in tcx.crates(()) { + implications.extend(tcx.stability_implications(cnum)); + all_lib_features.extend(tcx.defined_lib_features(cnum).iter().map(|el| *el)); + } - for &cnum in tcx.crates(()) { + // Check that every feature referenced by an `implied_by` exists (for features defined in the + // local crate). + for (implied_by, feature) in tcx.stability_implications(rustc_hir::def_id::LOCAL_CRATE) { + // Only `implied_by` needs to be checked, `feature` is guaranteed to exist. + if !all_lib_features.contains_key(implied_by) { + let span = local_defined_features + .stable + .get(feature) + .map(|(_, span)| span) + .or_else(|| local_defined_features.unstable.get(feature)) + .expect("feature that implied another does not exist"); + tcx.sess + .struct_span_err( + *span, + format!("feature `{implied_by}` implying `{feature}` does not exist"), + ) + .emit(); + } + } + + if !remaining_lib_features.is_empty() { + for (feature, since) in all_lib_features.iter() { + if let Some(since) = since && let Some(span) = remaining_lib_features.get(&feature) { + // Warn if the user has enabled an already-stable lib feature. + if let Some(implies) = implications.get(&feature) { + unnecessary_partially_stable_feature_lint(tcx, *span, *feature, *implies, *since); + } else { + unnecessary_stable_feature_lint(tcx, *span, *feature, *since); + } + } + remaining_lib_features.remove(&feature); if remaining_lib_features.is_empty() { break; } - check_features(&mut remaining_lib_features, tcx.defined_lib_features(cnum)); } } @@ -982,12 +1008,41 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) { // don't lint about unused features. We should re-enable this one day! } +fn unnecessary_partially_stable_feature_lint( + tcx: TyCtxt<'_>, + span: Span, + feature: Symbol, + implies: Symbol, + since: Symbol, +) { + tcx.struct_span_lint_hir(lint::builtin::STABLE_FEATURES, hir::CRATE_HIR_ID, span, |lint| { + lint.build(&format!( + "the feature `{feature}` has been partially stabilized since {since} and is succeeded \ + by the feature `{implies}`" + )) + .span_suggestion( + span, + &format!( + "if you are using features which are still unstable, change to using `{implies}`" + ), + implies, + Applicability::MaybeIncorrect, + ) + .span_suggestion( + tcx.sess.source_map().span_extend_to_line(span), + "if you are using features which are now stable, remove this line", + "", + Applicability::MaybeIncorrect, + ) + .emit(); + }); +} + fn unnecessary_stable_feature_lint(tcx: TyCtxt<'_>, span: Span, feature: Symbol, since: Symbol) { tcx.struct_span_lint_hir(lint::builtin::STABLE_FEATURES, hir::CRATE_HIR_ID, span, |lint| { lint.build(&format!( - "the feature `{}` has been stable since {} and no longer requires \ - an attribute to enable", - feature, since + "the feature `{feature}` has been stable since {since} and no longer requires an \ + attribute to enable", )) .emit(); }); diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 7a1695fc862bf..df13136dcce37 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -2603,9 +2603,9 @@ fn show_candidates( .skip(1) .all(|(_, descr, _, _)| descr == descr_first) { - descr_first.to_string() + descr_first } else { - "item".to_string() + "item" }; let plural_descr = if descr.ends_with("s") { format!("{}es", descr) } else { format!("{}s", descr) }; diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 54dd15270a136..2b5eb12a8a890 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -796,9 +796,16 @@ impl<'a> Resolver<'a> { ) { let span = path.span; if let Some(stability) = &ext.stability { - if let StabilityLevel::Unstable { reason, issue, is_soft } = stability.level { + if let StabilityLevel::Unstable { reason, issue, is_soft, implied_by } = stability.level + { let feature = stability.feature; - if !self.active_features.contains(&feature) && !span.allows_unstable(feature) { + + let is_allowed = |feature| { + self.active_features.contains(&feature) || span.allows_unstable(feature) + }; + let allowed_by_implication = + implied_by.map(|feature| is_allowed(feature)).unwrap_or(false); + if !is_allowed(feature) && !allowed_by_implication { let lint_buffer = &mut self.lint_buffer; let soft_handler = |lint, span, msg: &_| lint_buffer.buffer_lint(lint, node_id, span, msg); diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index afbb88e923360..b4a4424e876cd 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -718,6 +718,11 @@ impl SourceMap { sp } + /// Extends the given `Span` to contain the entire line it is on. + pub fn span_extend_to_line(&self, sp: Span) -> Span { + self.span_extend_to_prev_char(self.span_extend_to_next_char(sp, '\n', true), '\n', true) + } + /// Given a `Span`, tries to get a shorter span ending before the first occurrence of `char` /// `c`. pub fn span_until_char(&self, sp: Span, c: char) -> Span { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index ec1d2c39b8092..2ac1ecfe87eb5 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -800,6 +800,7 @@ symbols! { impl_lint_pass, impl_macros, impl_trait_in_bindings, + implied_by, import, import_shadowing, imported_main, diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs index e3db70845ddf1..8aa8ac90b4c56 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs @@ -1757,19 +1757,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .flat_map(|a| a.args.iter()) { if let hir::GenericArg::Type(hir_ty) = &arg { - if let hir::TyKind::Path(hir::QPath::TypeRelative(..)) = - &hir_ty.kind - { - // Avoid ICE with associated types. As this is best - // effort only, it's ok to ignore the case. It - // would trigger in `is_send::();` - // from `typeck-default-trait-impl-assoc-type.rs`. - } else { - let ty = >::ast_ty_to_ty(self, hir_ty); - let ty = self.resolve_vars_if_possible(ty); - if ty == predicate.self_ty() { - error.obligation.cause.span = hir_ty.span; - } + let ty = self.resolve_vars_if_possible( + self.typeck_results.borrow().node_type(hir_ty.hir_id), + ); + if ty == predicate.self_ty() { + error.obligation.cause.span = hir_ty.span; } } } diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs index 5cf16bdd08cdd..08b45ac11a14c 100644 --- a/library/proc_macro/src/lib.rs +++ b/library/proc_macro/src/lib.rs @@ -1484,7 +1484,7 @@ impl fmt::Debug for Literal { } /// Tracked access to environment variables. -#[unstable(feature = "proc_macro_tracked_env", issue = "74690")] +#[unstable(feature = "proc_macro_tracked_env", issue = "99515")] pub mod tracked_env { use std::env::{self, VarError}; use std::ffi::OsStr; @@ -1494,7 +1494,7 @@ pub mod tracked_env { /// compilation, and will be able to rerun the build when the value of that variable changes. /// Besides the dependency tracking this function should be equivalent to `env::var` from the /// standard library, except that the argument must be UTF-8. - #[unstable(feature = "proc_macro_tracked_env", issue = "74690")] + #[unstable(feature = "proc_macro_tracked_env", issue = "99515")] pub fn var + AsRef>(key: K) -> Result { let key: &str = key.as_ref(); let value = env::var(key); @@ -1504,13 +1504,13 @@ pub mod tracked_env { } /// Tracked access to additional files. -#[unstable(feature = "track_path", issue = "73921")] +#[unstable(feature = "track_path", issue = "99515")] pub mod tracked_path { /// Track a file explicitly. /// /// Commonly used for tracking asset preprocessing. - #[unstable(feature = "track_path", issue = "73921")] + #[unstable(feature = "track_path", issue = "99515")] pub fn path>(path: P) { let path: &str = path.as_ref(); crate::bridge::client::FreeFunctions::track_path(path); diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index c6933a8254bc2..69409b77251cb 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -949,7 +949,7 @@ table, #crate-search { min-width: 115px; margin-top: 5px; - padding-left: 0.3125em; + padding-left: 0.15em; padding-right: 23px; border: 1px solid; border-radius: 4px; @@ -958,8 +958,6 @@ table, -moz-appearance: none; -webkit-appearance: none; /* Removes default arrow from firefox */ - text-indent: 0.01px; - text-overflow: ""; background-repeat: no-repeat; background-color: transparent; background-size: 20px; @@ -986,7 +984,6 @@ table, border-radius: 2px; padding: 8px; font-size: 1rem; - transition: border-color 300ms ease; width: 100%; } diff --git a/src/librustdoc/html/static/css/themes/ayu.css b/src/librustdoc/html/static/css/themes/ayu.css index 142ce456c5213..7ff8063904ace 100644 --- a/src/librustdoc/html/static/css/themes/ayu.css +++ b/src/librustdoc/html/static/css/themes/ayu.css @@ -184,7 +184,13 @@ details.rustdoc-toggle > summary::before { #crate-search, .search-input { background-color: #141920; - /* Without the `!important`, the border-color is ignored for ``... + It cannot be in the group above because `.search-input` has a different border color on + hover. */ border-color: #424c57 !important; } diff --git a/src/librustdoc/html/static/css/themes/dark.css b/src/librustdoc/html/static/css/themes/dark.css index aeaca7515f962..8e753f5768206 100644 --- a/src/librustdoc/html/static/css/themes/dark.css +++ b/src/librustdoc/html/static/css/themes/dark.css @@ -159,7 +159,13 @@ details.rustdoc-toggle > summary::before { #crate-search, .search-input { color: #111; background-color: #f0f0f0; - /* Without the `!important`, the border-color is ignored for ``... + It cannot be in the group above because `.search-input` has a different border color on + hover. */ border-color: #f0f0f0 !important; } diff --git a/src/librustdoc/html/static/css/themes/light.css b/src/librustdoc/html/static/css/themes/light.css index 54d1a7b65d665..40d965c39c390 100644 --- a/src/librustdoc/html/static/css/themes/light.css +++ b/src/librustdoc/html/static/css/themes/light.css @@ -146,7 +146,13 @@ details.rustdoc-toggle > summary::before { #crate-search, .search-input { background-color: white; - /* Without the `!important`, the border-color is ignored for ``... + It cannot be in the group above because `.search-input` has a different border color on + hover. */ border-color: #e0e0e0 !important; } diff --git a/src/test/assembly/static-relocation-model.rs b/src/test/assembly/static-relocation-model.rs index 6c41e0b78f137..faa2e3952096d 100644 --- a/src/test/assembly/static-relocation-model.rs +++ b/src/test/assembly/static-relocation-model.rs @@ -36,7 +36,8 @@ extern "C" { } // CHECK-LABEL: banana: -// x64: movb chaenomeles{{(\(%[a-z0-9]+\))?}}, %{{[a-z0-9]+}} +// On the next line LLVM 14 produces a `movb`, whereas LLVM 15+ produces a `movzbl`. +// x64: {{movb|movzbl}} chaenomeles{{(\(%[a-z0-9]+\))?}}, %{{[a-z0-9]+}} // A64: adrp [[REG:[a-z0-9]+]], chaenomeles // A64-NEXT: ldrb {{[a-z0-9]+}}, {{\[}}[[REG]], :lo12:chaenomeles] #[no_mangle] @@ -47,7 +48,7 @@ pub fn banana() -> u8 { } // CHECK-LABEL: peach: -// x64: movb banana{{(\(%[a-z0-9]+\))?}}, %{{[a-z0-9]+}} +// x64: {{movb|movzbl}} banana{{(\(%[a-z0-9]+\))?}}, %{{[a-z0-9]+}} // A64: adrp [[REG2:[a-z0-9]+]], banana // A64-NEXT: ldrb {{[a-z0-9]+}}, {{\[}}[[REG2]], :lo12:banana] #[no_mangle] @@ -59,7 +60,7 @@ pub fn peach() -> u8 { // CHECK-LABEL: mango: // x64: movq EXOCHORDA{{(\(%[a-z0-9]+\))?}}, %[[REG:[a-z0-9]+]] -// x64-NEXT: movb (%[[REG]]), %{{[a-z0-9]+}} +// x64-NEXT: {{movb|movzbl}} (%[[REG]]), %{{[a-z0-9]+}} // A64: adrp [[REG2:[a-z0-9]+]], EXOCHORDA // A64-NEXT: ldr {{[a-z0-9]+}}, {{\[}}[[REG2]], :lo12:EXOCHORDA] #[no_mangle] diff --git a/src/test/debuginfo/basic-types-globals-lto.rs b/src/test/debuginfo/basic-types-globals-lto.rs deleted file mode 100644 index 1adf278ad32de..0000000000000 --- a/src/test/debuginfo/basic-types-globals-lto.rs +++ /dev/null @@ -1,81 +0,0 @@ -// Caveat - gdb doesn't know about UTF-32 character encoding and will print a -// rust char as only its numerical value. - -// min-lldb-version: 310 -// min-gdb-version: 8.0 - -// no-prefer-dynamic -// compile-flags:-g -C lto -// gdb-command:run -// gdbg-command:print 'basic_types_globals::B' -// gdbr-command:print B -// gdb-check:$1 = false -// gdbg-command:print 'basic_types_globals::I' -// gdbr-command:print I -// gdb-check:$2 = -1 -// gdbg-command:print 'basic_types_globals::C' -// gdbr-command:print/d C -// gdbg-check:$3 = 97 -// gdbr-check:$3 = 97 -// gdbg-command:print/d 'basic_types_globals::I8' -// gdbr-command:print I8 -// gdb-check:$4 = 68 -// gdbg-command:print 'basic_types_globals::I16' -// gdbr-command:print I16 -// gdb-check:$5 = -16 -// gdbg-command:print 'basic_types_globals::I32' -// gdbr-command:print I32 -// gdb-check:$6 = -32 -// gdbg-command:print 'basic_types_globals::I64' -// gdbr-command:print I64 -// gdb-check:$7 = -64 -// gdbg-command:print 'basic_types_globals::U' -// gdbr-command:print U -// gdb-check:$8 = 1 -// gdbg-command:print/d 'basic_types_globals::U8' -// gdbr-command:print U8 -// gdb-check:$9 = 100 -// gdbg-command:print 'basic_types_globals::U16' -// gdbr-command:print U16 -// gdb-check:$10 = 16 -// gdbg-command:print 'basic_types_globals::U32' -// gdbr-command:print U32 -// gdb-check:$11 = 32 -// gdbg-command:print 'basic_types_globals::U64' -// gdbr-command:print U64 -// gdb-check:$12 = 64 -// gdbg-command:print 'basic_types_globals::F32' -// gdbr-command:print F32 -// gdb-check:$13 = 2.5 -// gdbg-command:print 'basic_types_globals::F64' -// gdbr-command:print F64 -// gdb-check:$14 = 3.5 -// gdb-command:continue - -#![allow(unused_variables)] -#![feature(omit_gdb_pretty_printer_section)] -#![omit_gdb_pretty_printer_section] - -// N.B. These are `mut` only so they don't constant fold away. -static mut B: bool = false; -static mut I: isize = -1; -static mut C: char = 'a'; -static mut I8: i8 = 68; -static mut I16: i16 = -16; -static mut I32: i32 = -32; -static mut I64: i64 = -64; -static mut U: usize = 1; -static mut U8: u8 = 100; -static mut U16: u16 = 16; -static mut U32: u32 = 32; -static mut U64: u64 = 64; -static mut F32: f32 = 2.5; -static mut F64: f64 = 3.5; - -fn main() { - _zzz(); // #break - - let a = unsafe { (B, I, C, I8, I16, I32, I64, U, U8, U16, U32, U64, F32, F64) }; -} - -fn _zzz() {()} diff --git a/src/test/debuginfo/basic-types-globals.rs b/src/test/debuginfo/basic-types-globals.rs index 3602db39a4ec1..8a3df8ba2d18e 100644 --- a/src/test/debuginfo/basic-types-globals.rs +++ b/src/test/debuginfo/basic-types-globals.rs @@ -4,7 +4,13 @@ // min-lldb-version: 310 // min-gdb-version: 8.0 +// revisions: lto no-lto + // compile-flags:-g + +// [lto] compile-flags:-C lto +// [lto] no-prefer-dynamic + // gdb-command:run // gdbg-command:print 'basic_types_globals::B' // gdbr-command:print B diff --git a/src/test/rustdoc-gui/search-input.goml b/src/test/rustdoc-gui/search-input.goml new file mode 100644 index 0000000000000..44123b702df8a --- /dev/null +++ b/src/test/rustdoc-gui/search-input.goml @@ -0,0 +1,23 @@ +// Ensures that the search input border color changes on focus. +goto: file://|DOC_PATH|/test_docs/index.html +local-storage: {"rustdoc-use-system-theme": "false", "rustdoc-theme": "dark"} +reload: + +assert-css: (".search-input", {"border-color": "rgb(224, 224, 224)"}) +click: ".search-input" +focus: ".search-input" +assert-css: (".search-input", {"border-color": "rgb(0, 141, 253)"}) + +local-storage: {"rustdoc-theme": "light"} +reload: + +assert-css: (".search-input", {"border-color": "rgb(224, 224, 224)"}) +click: ".search-input" +assert-css: (".search-input", {"border-color": "rgb(102, 175, 233)"}) + +local-storage: {"rustdoc-theme": "ayu"} +reload: + +assert-css: (".search-input", {"border-color": "rgb(66, 76, 87)"}) +click: ".search-input" +assert-css: (".search-input", {"border-color": "rgb(66, 76, 87)"}) diff --git a/src/test/rustdoc-gui/search-result-display.goml b/src/test/rustdoc-gui/search-result-display.goml index 6295d7fae8907..8464ba7c23cfe 100644 --- a/src/test/rustdoc-gui/search-result-display.goml +++ b/src/test/rustdoc-gui/search-result-display.goml @@ -18,7 +18,7 @@ assert-css: (".search-results div.desc", {"width": "570px"}) size: (900, 900) // First we check the current width and position. -assert-css: ("#crate-search", {"width": "222px"}) +assert-css: ("#crate-search", {"width": "218px"}) compare-elements-position-near: ( "#crate-search", "#search-settings .search-results-title", diff --git a/src/test/ui/fmt/ifmt-bad-arg.rs b/src/test/ui/fmt/ifmt-bad-arg.rs index b3e54ed32aac7..84f4cc7f4ccd8 100644 --- a/src/test/ui/fmt/ifmt-bad-arg.rs +++ b/src/test/ui/fmt/ifmt-bad-arg.rs @@ -86,6 +86,9 @@ tenth number: {}", println!("{:foo}", 1); //~ ERROR unknown format trait `foo` println!("{5} {:4$} {6:7$}", 1); //~^ ERROR invalid reference to positional arguments 4, 5, 6 and 7 (there is 1 argument) + let foo = 1; + println!("{foo:0$}"); + //~^ ERROR invalid reference to positional argument 0 (no arguments were given) // We used to ICE here because we tried to unconditionally access the first argument, which // doesn't exist. diff --git a/src/test/ui/fmt/ifmt-bad-arg.stderr b/src/test/ui/fmt/ifmt-bad-arg.stderr index d181fe14107e7..5439ee173985b 100644 --- a/src/test/ui/fmt/ifmt-bad-arg.stderr +++ b/src/test/ui/fmt/ifmt-bad-arg.stderr @@ -251,8 +251,19 @@ LL | println!("{5} {:4$} {6:7$}", 1); = note: positional arguments are zero-based = note: for information about formatting flags, visit https://doc.rust-lang.org/std/fmt/index.html +error: invalid reference to positional argument 0 (no arguments were given) + --> $DIR/ifmt-bad-arg.rs:90:15 + | +LL | println!("{foo:0$}"); + | ^^^^^--^ + | | + | this width flag expects an `usize` argument at position 0, but no arguments were given + | + = note: positional arguments are zero-based + = note: for information about formatting flags, visit https://doc.rust-lang.org/std/fmt/index.html + error: 2 positional arguments in format string, but no arguments were given - --> $DIR/ifmt-bad-arg.rs:92:15 + --> $DIR/ifmt-bad-arg.rs:95:15 | LL | println!("{:.*}"); | ^^--^ @@ -328,7 +339,7 @@ LL | pub fn from_usize(x: &usize) -> ArgumentV1<'_> { | ^^^^^^^^^^ = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 36 previous errors +error: aborting due to 37 previous errors Some errors have detailed explanations: E0308, E0425. For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/kindck/kindck-copy.stderr b/src/test/ui/kindck/kindck-copy.stderr index 1c61c85368be9..025a5008d0f11 100644 --- a/src/test/ui/kindck/kindck-copy.stderr +++ b/src/test/ui/kindck/kindck-copy.stderr @@ -91,10 +91,10 @@ LL | fn assert_copy() { } | ^^^^ required by this bound in `assert_copy` error[E0277]: the trait bound `Box: Copy` is not satisfied - --> $DIR/kindck-copy.rs:42:5 + --> $DIR/kindck-copy.rs:42:19 | LL | assert_copy::>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Box` + | ^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Box` | note: required by a bound in `assert_copy` --> $DIR/kindck-copy.rs:5:18 @@ -103,10 +103,10 @@ LL | fn assert_copy() { } | ^^^^ required by this bound in `assert_copy` error[E0277]: the trait bound `Box: Copy` is not satisfied - --> $DIR/kindck-copy.rs:43:5 + --> $DIR/kindck-copy.rs:43:19 | LL | assert_copy::>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Box` + | ^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Box` | note: required by a bound in `assert_copy` --> $DIR/kindck-copy.rs:5:18 diff --git a/src/test/ui/macros/meta-variable-depth-outside-repeat.rs b/src/test/ui/macros/meta-variable-depth-outside-repeat.rs new file mode 100644 index 0000000000000..b7fb947854f04 --- /dev/null +++ b/src/test/ui/macros/meta-variable-depth-outside-repeat.rs @@ -0,0 +1,12 @@ +#![feature(macro_metavar_expr)] + +macro_rules! metavar { + ( $i:expr ) => { + ${length(0)} + //~^ ERROR meta-variable expression `length` with depth parameter must be called inside of a macro repetition + }; +} + +const _: i32 = metavar!(0); + +fn main() {} diff --git a/src/test/ui/macros/meta-variable-depth-outside-repeat.stderr b/src/test/ui/macros/meta-variable-depth-outside-repeat.stderr new file mode 100644 index 0000000000000..fad150cadfca6 --- /dev/null +++ b/src/test/ui/macros/meta-variable-depth-outside-repeat.stderr @@ -0,0 +1,8 @@ +error: meta-variable expression `length` with depth parameter must be called inside of a macro repetition + --> $DIR/meta-variable-depth-outside-repeat.rs:5:10 + | +LL | ${length(0)} + | ^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/macros/rfc-3086-metavar-expr/out-of-bounds-arguments.rs b/src/test/ui/macros/rfc-3086-metavar-expr/out-of-bounds-arguments.rs index d81c8628bab26..6a0d68bd6b16a 100644 --- a/src/test/ui/macros/rfc-3086-metavar-expr/out-of-bounds-arguments.rs +++ b/src/test/ui/macros/rfc-3086-metavar-expr/out-of-bounds-arguments.rs @@ -5,7 +5,7 @@ macro_rules! a { ( ${count(foo, 0)}, ${count(foo, 10)}, - //~^ ERROR count depth must be less than 4 + //~^ ERROR depth parameter on meta-variable expression `count` must be less than 4 ) }; } @@ -17,7 +17,7 @@ macro_rules! b { ${ignore(foo)} ${index(0)}, ${index(10)}, - //~^ ERROR index depth must be less than 3 + //~^ ERROR depth parameter on meta-variable expression `index` must be less than 3 )* )* )* ) }; @@ -30,15 +30,14 @@ macro_rules! c { ${ignore(foo)} ${length(0)} ${length(10)} - //~^ ERROR length depth must be less than 2 + //~^ ERROR depth parameter on meta-variable expression `length` must be less than 2 )* )* ) }; } - fn main() { a!( { [ (a) ] [ (b c) ] } ); b!( { [ a b ] } ); - c!( { a } ); + c!({ a }); } diff --git a/src/test/ui/macros/rfc-3086-metavar-expr/out-of-bounds-arguments.stderr b/src/test/ui/macros/rfc-3086-metavar-expr/out-of-bounds-arguments.stderr index 7474c03c0f98b..236122b6465b2 100644 --- a/src/test/ui/macros/rfc-3086-metavar-expr/out-of-bounds-arguments.stderr +++ b/src/test/ui/macros/rfc-3086-metavar-expr/out-of-bounds-arguments.stderr @@ -1,16 +1,16 @@ -error: count depth must be less than 4 +error: depth parameter on meta-variable expression `count` must be less than 4 --> $DIR/out-of-bounds-arguments.rs:7:14 | LL | ${count(foo, 10)}, | ^^^^^^^^^^^^^^^^ -error: index depth must be less than 3 +error: depth parameter on meta-variable expression `index` must be less than 3 --> $DIR/out-of-bounds-arguments.rs:19:18 | LL | ${index(10)}, | ^^^^^^^^^^^ -error: length depth must be less than 2 +error: depth parameter on meta-variable expression `length` must be less than 2 --> $DIR/out-of-bounds-arguments.rs:32:18 | LL | ${length(10)} diff --git a/src/test/ui/not-panic/not-panic-safe.stderr b/src/test/ui/not-panic/not-panic-safe.stderr index 3e54df12376ba..2cd51a439988d 100644 --- a/src/test/ui/not-panic/not-panic-safe.stderr +++ b/src/test/ui/not-panic/not-panic-safe.stderr @@ -1,8 +1,11 @@ error[E0277]: the type `&mut i32` may not be safely transferred across an unwind boundary - --> $DIR/not-panic-safe.rs:8:5 + --> $DIR/not-panic-safe.rs:8:14 | LL | assert::<&mut i32>(); - | ^^^^^^^^^^^^^^^^^^ `&mut i32` may not be safely transferred across an unwind boundary + | -^^^^^^^ + | | + | `&mut i32` may not be safely transferred across an unwind boundary + | help: consider removing the leading `&`-reference | = help: the trait `UnwindSafe` is not implemented for `&mut i32` = note: `UnwindSafe` is implemented for `&i32`, but not for `&mut i32` diff --git a/src/test/ui/stability-attribute/auxiliary/stability-attribute-implies.rs b/src/test/ui/stability-attribute/auxiliary/stability-attribute-implies.rs new file mode 100644 index 0000000000000..468be1bc14450 --- /dev/null +++ b/src/test/ui/stability-attribute/auxiliary/stability-attribute-implies.rs @@ -0,0 +1,8 @@ +#![feature(staged_api)] +#![stable(feature = "stability_attribute_implies", since = "1.0.0")] + +#[stable(feature = "foo", since = "1.62.0")] +pub fn foo() {} + +#[unstable(feature = "foobar", issue = "1", implied_by = "foo")] +pub fn foobar() {} diff --git a/src/test/ui/stability-attribute/stability-attribute-implies-missing.rs b/src/test/ui/stability-attribute/stability-attribute-implies-missing.rs new file mode 100644 index 0000000000000..613878536721b --- /dev/null +++ b/src/test/ui/stability-attribute/stability-attribute-implies-missing.rs @@ -0,0 +1,10 @@ +#![feature(staged_api)] +#![stable(feature = "stability_attribute_implies", since = "1.0.0")] + +// Tests that `implied_by = "bar"` results in an error being emitted if `bar` does not exist. + +#[unstable(feature = "foobar", issue = "1", implied_by = "bar")] +//~^ ERROR feature `bar` implying `foobar` does not exist +pub fn foobar() {} + +fn main() {} diff --git a/src/test/ui/stability-attribute/stability-attribute-implies-missing.stderr b/src/test/ui/stability-attribute/stability-attribute-implies-missing.stderr new file mode 100644 index 0000000000000..ff1856f1763f9 --- /dev/null +++ b/src/test/ui/stability-attribute/stability-attribute-implies-missing.stderr @@ -0,0 +1,8 @@ +error: feature `bar` implying `foobar` does not exist + --> $DIR/stability-attribute-implies-missing.rs:6:1 + | +LL | #[unstable(feature = "foobar", issue = "1", implied_by = "bar")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/stability-attribute/stability-attribute-implies-no-feature.rs b/src/test/ui/stability-attribute/stability-attribute-implies-no-feature.rs new file mode 100644 index 0000000000000..947f9f73eff11 --- /dev/null +++ b/src/test/ui/stability-attribute/stability-attribute-implies-no-feature.rs @@ -0,0 +1,13 @@ +// aux-build:stability-attribute-implies.rs + +// Tests that despite the `foobar` feature being implied by now-stable feature `foo`, if `foobar` +// isn't allowed in this crate then an error will be emitted. + +extern crate stability_attribute_implies; +use stability_attribute_implies::{foo, foobar}; +//~^ ERROR use of unstable library feature 'foobar' + +fn main() { + foo(); // no error - stable + foobar(); //~ ERROR use of unstable library feature 'foobar' +} diff --git a/src/test/ui/stability-attribute/stability-attribute-implies-no-feature.stderr b/src/test/ui/stability-attribute/stability-attribute-implies-no-feature.stderr new file mode 100644 index 0000000000000..c2331f6766c4f --- /dev/null +++ b/src/test/ui/stability-attribute/stability-attribute-implies-no-feature.stderr @@ -0,0 +1,21 @@ +error[E0658]: use of unstable library feature 'foobar' + --> $DIR/stability-attribute-implies-no-feature.rs:7:40 + | +LL | use stability_attribute_implies::{foo, foobar}; + | ^^^^^^ + | + = note: see issue #1 for more information + = help: add `#![feature(foobar)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'foobar' + --> $DIR/stability-attribute-implies-no-feature.rs:12:5 + | +LL | foobar(); + | ^^^^^^ + | + = note: see issue #1 for more information + = help: add `#![feature(foobar)]` to the crate attributes to enable + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/stability-attribute/stability-attribute-implies-using-stable.rs b/src/test/ui/stability-attribute/stability-attribute-implies-using-stable.rs new file mode 100644 index 0000000000000..1a2d8e271de04 --- /dev/null +++ b/src/test/ui/stability-attribute/stability-attribute-implies-using-stable.rs @@ -0,0 +1,15 @@ +// aux-build:stability-attribute-implies.rs +#![deny(stable_features)] +#![feature(foo)] +//~^ ERROR the feature `foo` has been partially stabilized since 1.62.0 and is succeeded by the feature `foobar` + +// Tests that the use of `implied_by` in the `#[unstable]` attribute results in a diagnostic +// mentioning partial stabilization, and that given the implied unstable feature is unused (there +// is no `foobar` call), that the compiler suggests removing the flag. + +extern crate stability_attribute_implies; +use stability_attribute_implies::foo; + +fn main() { + foo(); +} diff --git a/src/test/ui/stability-attribute/stability-attribute-implies-using-stable.stderr b/src/test/ui/stability-attribute/stability-attribute-implies-using-stable.stderr new file mode 100644 index 0000000000000..c9b3f07cc70b1 --- /dev/null +++ b/src/test/ui/stability-attribute/stability-attribute-implies-using-stable.stderr @@ -0,0 +1,22 @@ +error: the feature `foo` has been partially stabilized since 1.62.0 and is succeeded by the feature `foobar` + --> $DIR/stability-attribute-implies-using-stable.rs:3:12 + | +LL | #![feature(foo)] + | ^^^ + | +note: the lint level is defined here + --> $DIR/stability-attribute-implies-using-stable.rs:2:9 + | +LL | #![deny(stable_features)] + | ^^^^^^^^^^^^^^^ +help: if you are using features which are still unstable, change to using `foobar` + | +LL | #![feature(foobar)] + | ~~~~~~ +help: if you are using features which are now stable, remove this line + | +LL - #![feature(foo)] + | + +error: aborting due to previous error + diff --git a/src/test/ui/stability-attribute/stability-attribute-implies-using-unstable.rs b/src/test/ui/stability-attribute/stability-attribute-implies-using-unstable.rs new file mode 100644 index 0000000000000..3c73c5abf3b54 --- /dev/null +++ b/src/test/ui/stability-attribute/stability-attribute-implies-using-unstable.rs @@ -0,0 +1,17 @@ +// aux-build:stability-attribute-implies.rs +#![deny(stable_features)] +#![feature(foo)] +//~^ ERROR the feature `foo` has been partially stabilized since 1.62.0 and is succeeded by the feature `foobar` + +// Tests that the use of `implied_by` in the `#[unstable]` attribute results in a diagnostic +// mentioning partial stabilization and that given the implied unstable feature is used (there is a +// `foobar` call), that the compiler suggests changing to that feature and doesn't error about its +// use. + +extern crate stability_attribute_implies; +use stability_attribute_implies::{foo, foobar}; + +fn main() { + foo(); + foobar(); // no error! +} diff --git a/src/test/ui/stability-attribute/stability-attribute-implies-using-unstable.stderr b/src/test/ui/stability-attribute/stability-attribute-implies-using-unstable.stderr new file mode 100644 index 0000000000000..9a5c7ef5a4762 --- /dev/null +++ b/src/test/ui/stability-attribute/stability-attribute-implies-using-unstable.stderr @@ -0,0 +1,22 @@ +error: the feature `foo` has been partially stabilized since 1.62.0 and is succeeded by the feature `foobar` + --> $DIR/stability-attribute-implies-using-unstable.rs:3:12 + | +LL | #![feature(foo)] + | ^^^ + | +note: the lint level is defined here + --> $DIR/stability-attribute-implies-using-unstable.rs:2:9 + | +LL | #![deny(stable_features)] + | ^^^^^^^^^^^^^^^ +help: if you are using features which are still unstable, change to using `foobar` + | +LL | #![feature(foobar)] + | ~~~~~~ +help: if you are using features which are now stable, remove this line + | +LL - #![feature(foo)] + | + +error: aborting due to previous error + diff --git a/src/test/ui/stability-attribute/stability-attribute-sanity-2.stderr b/src/test/ui/stability-attribute/stability-attribute-sanity-2.stderr index bd7b88da1584d..8dbcc6c97efd5 100644 --- a/src/test/ui/stability-attribute/stability-attribute-sanity-2.stderr +++ b/src/test/ui/stability-attribute/stability-attribute-sanity-2.stderr @@ -8,7 +8,7 @@ error[E0541]: unknown meta item 'sinse' --> $DIR/stability-attribute-sanity-2.rs:10:25 | LL | #[stable(feature = "a", sinse = "1.0.0")] - | ^^^^^^^^^^^^^^^ expected one of `since`, `note` + | ^^^^^^^^^^^^^^^ expected one of `feature`, `since` error[E0545]: `issue` must be a non-zero numeric string or "none" --> $DIR/stability-attribute-sanity-2.rs:13:27 diff --git a/src/test/ui/stability-attribute/stability-attribute-sanity.stderr b/src/test/ui/stability-attribute/stability-attribute-sanity.stderr index fcb1eefddbcef..079230b2a3160 100644 --- a/src/test/ui/stability-attribute/stability-attribute-sanity.stderr +++ b/src/test/ui/stability-attribute/stability-attribute-sanity.stderr @@ -14,7 +14,7 @@ error[E0541]: unknown meta item 'reason' --> $DIR/stability-attribute-sanity.rs:8:42 | LL | #[stable(feature = "a", since = "b", reason)] - | ^^^^^^ expected one of `since`, `note` + | ^^^^^^ expected one of `feature`, `since` error[E0539]: incorrect meta item --> $DIR/stability-attribute-sanity.rs:11:29 diff --git a/src/test/ui/traits/issue-32963.rs b/src/test/ui/traits/issue-32963.rs index 58055cd54561a..56a68f3a2312c 100644 --- a/src/test/ui/traits/issue-32963.rs +++ b/src/test/ui/traits/issue-32963.rs @@ -7,6 +7,5 @@ fn size_of_copy() -> usize { mem::size_of::() } fn main() { size_of_copy::(); //~^ ERROR only auto traits can be used as additional traits in a trait object - //~| ERROR only auto traits can be used as additional traits in a trait object //~| ERROR the trait bound `dyn Misc: Copy` is not satisfied } diff --git a/src/test/ui/traits/issue-32963.stderr b/src/test/ui/traits/issue-32963.stderr index 5e7762b32200a..bad45e54d6428 100644 --- a/src/test/ui/traits/issue-32963.stderr +++ b/src/test/ui/traits/issue-32963.stderr @@ -9,22 +9,11 @@ LL | size_of_copy::(); = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Misc + Copy {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit -error[E0225]: only auto traits can be used as additional traits in a trait object - --> $DIR/issue-32963.rs:8:31 - | -LL | size_of_copy::(); - | ---- ^^^^ additional non-auto trait - | | - | first non-auto trait - | - = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Misc + Copy {}` - = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit - error[E0277]: the trait bound `dyn Misc: Copy` is not satisfied - --> $DIR/issue-32963.rs:8:5 + --> $DIR/issue-32963.rs:8:20 | LL | size_of_copy::(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `dyn Misc` + | ^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `dyn Misc` | note: required by a bound in `size_of_copy` --> $DIR/issue-32963.rs:5:20 @@ -32,7 +21,7 @@ note: required by a bound in `size_of_copy` LL | fn size_of_copy() -> usize { mem::size_of::() } | ^^^^ required by this bound in `size_of_copy` -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors Some errors have detailed explanations: E0225, E0277. For more information about an error, try `rustc --explain E0225`. diff --git a/src/test/ui/traits/suggest-where-clause.stderr b/src/test/ui/traits/suggest-where-clause.stderr index 21b339d12a8de..d4d9b4967478a 100644 --- a/src/test/ui/traits/suggest-where-clause.stderr +++ b/src/test/ui/traits/suggest-where-clause.stderr @@ -85,10 +85,10 @@ LL | pub const fn size_of() -> usize { | ^ required by this bound in `std::mem::size_of` error[E0277]: the size for values of type `[&U]` cannot be known at compilation time - --> $DIR/suggest-where-clause.rs:31:5 + --> $DIR/suggest-where-clause.rs:31:20 | LL | mem::size_of::<[&U]>(); - | ^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | ^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `[&U]` note: required by a bound in `std::mem::size_of` diff --git a/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.stderr b/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.stderr index 7aefa0646114c..468a14762c0d7 100644 --- a/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.stderr +++ b/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.stderr @@ -1,8 +1,8 @@ error[E0277]: `::AssocType` cannot be sent between threads safely - --> $DIR/typeck-default-trait-impl-assoc-type.rs:11:5 + --> $DIR/typeck-default-trait-impl-assoc-type.rs:11:15 | LL | is_send::(); - | ^^^^^^^^^^^^^^^^^^^^^^^ `::AssocType` cannot be sent between threads safely + | ^^^^^^^^^^^^ `::AssocType` cannot be sent between threads safely | = help: the trait `Send` is not implemented for `::AssocType` note: required by a bound in `is_send` diff --git a/src/test/ui/unboxed-closures/unboxed-closure-sugar-default.stderr b/src/test/ui/unboxed-closures/unboxed-closure-sugar-default.stderr index 09d3eec6b2148..a3b32d2c1c8ce 100644 --- a/src/test/ui/unboxed-closures/unboxed-closure-sugar-default.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closure-sugar-default.stderr @@ -1,8 +1,8 @@ error[E0277]: the trait bound `dyn Foo<(isize,), isize, Output = ()>: Eq>` is not satisfied - --> $DIR/unboxed-closure-sugar-default.rs:21:5 + --> $DIR/unboxed-closure-sugar-default.rs:21:10 | LL | eq::, dyn Foo(isize)>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Eq>` is not implemented for `dyn Foo<(isize,), isize, Output = ()>` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Eq>` is not implemented for `dyn Foo<(isize,), isize, Output = ()>` | note: required by a bound in `eq` --> $DIR/unboxed-closure-sugar-default.rs:14:40 diff --git a/src/test/ui/unboxed-closures/unboxed-closure-sugar-equiv.rs b/src/test/ui/unboxed-closures/unboxed-closure-sugar-equiv.rs index 0fc3e23ec73ef..acf0227a79b8c 100644 --- a/src/test/ui/unboxed-closures/unboxed-closure-sugar-equiv.rs +++ b/src/test/ui/unboxed-closures/unboxed-closure-sugar-equiv.rs @@ -42,7 +42,7 @@ fn test<'a,'b>() { // Errors expected: eq::< dyn Foo<(),Output=()>, dyn Foo(char) >(); - //~^^ ERROR E0277 + //~^ ERROR E0277 } fn main() { } diff --git a/src/test/ui/unboxed-closures/unboxed-closure-sugar-equiv.stderr b/src/test/ui/unboxed-closures/unboxed-closure-sugar-equiv.stderr index a1cbf842a683b..bccbf307ae157 100644 --- a/src/test/ui/unboxed-closures/unboxed-closure-sugar-equiv.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closure-sugar-equiv.stderr @@ -1,9 +1,8 @@ error[E0277]: the trait bound `dyn Foo<(char,), Output = ()>: Eq>` is not satisfied - --> $DIR/unboxed-closure-sugar-equiv.rs:43:5 + --> $DIR/unboxed-closure-sugar-equiv.rs:44:11 | -LL | / eq::< dyn Foo<(),Output=()>, -LL | | dyn Foo(char) >(); - | |_______________________________________________________________________^ the trait `Eq>` is not implemented for `dyn Foo<(char,), Output = ()>` +LL | dyn Foo(char) >(); + | ^^^^^^^^^^^^^ the trait `Eq>` is not implemented for `dyn Foo<(char,), Output = ()>` | note: required by a bound in `eq` --> $DIR/unboxed-closure-sugar-equiv.rs:16:28 diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index 17f2b77dab052..02f4d29a2f05f 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -535,6 +535,29 @@ impl TestProps { } } +pub fn line_directive<'line>( + comment: &str, + ln: &'line str, +) -> Option<(Option<&'line str>, &'line str)> { + if ln.starts_with(comment) { + let ln = ln[comment.len()..].trim_start(); + if ln.starts_with('[') { + // A comment like `//[foo]` is specific to revision `foo` + if let Some(close_brace) = ln.find(']') { + let lncfg = &ln[1..close_brace]; + + Some((Some(lncfg), ln[(close_brace + 1)..].trim_start())) + } else { + panic!("malformed condition directive: expected `{}[foo]`, found `{}`", comment, ln) + } + } else { + Some((None, ln)) + } + } else { + None + } +} + fn iter_header(testfile: &Path, rdr: R, it: &mut dyn FnMut(Option<&str>, &str)) { if testfile.is_dir() { return; @@ -557,17 +580,8 @@ fn iter_header(testfile: &Path, rdr: R, it: &mut dyn FnMut(Option<&str> let ln = ln.trim(); if ln.starts_with("fn") || ln.starts_with("mod") { return; - } else if ln.starts_with(comment) && ln[comment.len()..].trim_start().starts_with('[') { - // A comment like `//[foo]` is specific to revision `foo` - if let Some(close_brace) = ln.find(']') { - let open_brace = ln.find('[').unwrap(); - let lncfg = &ln[open_brace + 1..close_brace]; - it(Some(lncfg), ln[(close_brace + 1)..].trim_start()); - } else { - panic!("malformed condition directive: expected `{}[foo]`, found `{}`", comment, ln) - } - } else if ln.starts_with(comment) { - it(None, ln[comment.len()..].trim_start()); + } else if let Some((lncfg, ln)) = line_directive(comment, ln) { + it(lncfg, ln); } } } diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 5517b5a12c393..26730fcec4cec 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -648,8 +648,6 @@ impl<'test> TestCx<'test> { } fn run_debuginfo_cdb_test(&self) { - assert!(self.revision.is_none(), "revisions not relevant here"); - let config = Config { target_rustcflags: self.cleanup_debug_info_options(&self.config.target_rustcflags), host_rustcflags: self.cleanup_debug_info_options(&self.config.host_rustcflags), @@ -695,7 +693,12 @@ impl<'test> TestCx<'test> { // Parse debugger commands etc from test files let DebuggerCommands { commands, check_lines, breakpoint_lines, .. } = - match DebuggerCommands::parse_from(&self.testpaths.file, self.config, prefixes) { + match DebuggerCommands::parse_from( + &self.testpaths.file, + self.config, + prefixes, + self.revision, + ) { Ok(cmds) => cmds, Err(e) => self.fatal(&e), }; @@ -756,8 +759,6 @@ impl<'test> TestCx<'test> { } fn run_debuginfo_gdb_test(&self) { - assert!(self.revision.is_none(), "revisions not relevant here"); - let config = Config { target_rustcflags: self.cleanup_debug_info_options(&self.config.target_rustcflags), host_rustcflags: self.cleanup_debug_info_options(&self.config.host_rustcflags), @@ -783,7 +784,12 @@ impl<'test> TestCx<'test> { }; let DebuggerCommands { commands, check_lines, breakpoint_lines } = - match DebuggerCommands::parse_from(&self.testpaths.file, self.config, prefixes) { + match DebuggerCommands::parse_from( + &self.testpaths.file, + self.config, + prefixes, + self.revision, + ) { Ok(cmds) => cmds, Err(e) => self.fatal(&e), }; @@ -1005,8 +1011,6 @@ impl<'test> TestCx<'test> { } fn run_debuginfo_lldb_test(&self) { - assert!(self.revision.is_none(), "revisions not relevant here"); - if self.config.lldb_python_dir.is_none() { self.fatal("Can't run LLDB test because LLDB's python path is not set."); } @@ -1059,7 +1063,12 @@ impl<'test> TestCx<'test> { // Parse debugger commands etc from test files let DebuggerCommands { commands, check_lines, breakpoint_lines, .. } = - match DebuggerCommands::parse_from(&self.testpaths.file, self.config, prefixes) { + match DebuggerCommands::parse_from( + &self.testpaths.file, + self.config, + prefixes, + self.revision, + ) { Ok(cmds) => cmds, Err(e) => self.fatal(&e), }; diff --git a/src/tools/compiletest/src/runtest/debugger.rs b/src/tools/compiletest/src/runtest/debugger.rs index cbd5e4c431f56..379ff0bab408a 100644 --- a/src/tools/compiletest/src/runtest/debugger.rs +++ b/src/tools/compiletest/src/runtest/debugger.rs @@ -1,4 +1,5 @@ use crate::common::Config; +use crate::header::line_directive; use crate::runtest::ProcRes; use std::fs::File; @@ -16,6 +17,7 @@ impl DebuggerCommands { file: &Path, config: &Config, debugger_prefixes: &[&str], + rev: Option<&str>, ) -> Result { let directives = debugger_prefixes .iter() @@ -25,13 +27,19 @@ impl DebuggerCommands { let mut breakpoint_lines = vec![]; let mut commands = vec![]; let mut check_lines = vec![]; - let mut counter = 1; + let mut counter = 0; let reader = BufReader::new(File::open(file).unwrap()); for line in reader.lines() { + counter += 1; match line { Ok(line) => { - let line = - if line.starts_with("//") { line[2..].trim_start() } else { line.as_str() }; + let (lnrev, line) = line_directive("//", &line).unwrap_or((None, &line)); + + // Skip any revision specific directive that doesn't match the current + // revision being tested + if lnrev.is_some() && lnrev != rev { + continue; + } if line.contains("#break") { breakpoint_lines.push(counter); @@ -49,7 +57,6 @@ impl DebuggerCommands { } Err(e) => return Err(format!("Error while parsing debugger commands: {}", e)), } - counter += 1; } Ok(Self { commands, check_lines, breakpoint_lines })