From 0a4e187fc685888cf0cfd8787e2e0fb8dab21284 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 6 Sep 2023 16:30:22 -0700 Subject: [PATCH 1/2] Allow library features to be marked internal as well --- compiler/rustc_attr/messages.ftl | 3 + compiler/rustc_attr/src/builtin.rs | 10 +++ .../rustc_attr/src/session_diagnostics.rs | 7 ++ compiler/rustc_lint/src/builtin.rs | 23 ++++- compiler/rustc_lint/src/levels.rs | 4 - compiler/rustc_lint/src/lib.rs | 2 +- compiler/rustc_metadata/src/rmeta/decoder.rs | 16 +++- .../src/rmeta/decoder/cstore_impl.rs | 2 +- compiler/rustc_metadata/src/rmeta/encoder.rs | 5 +- compiler/rustc_metadata/src/rmeta/mod.rs | 3 +- compiler/rustc_middle/src/middle/mod.rs | 21 +++-- compiler/rustc_middle/src/middle/stability.rs | 2 +- compiler/rustc_middle/src/query/mod.rs | 7 +- compiler/rustc_middle/src/ty/parameterized.rs | 1 + compiler/rustc_passes/src/lib_features.rs | 83 ++++++++++++------- compiler/rustc_passes/src/stability.rs | 29 ++++--- compiler/rustc_resolve/src/macros.rs | 3 +- compiler/rustc_span/src/symbol.rs | 1 + tests/ui/lint/auxiliary/lint_stability.rs | 3 + tests/ui/lint/lint-stability-internal.rs | 11 +++ tests/ui/lint/lint-stability-internal.stderr | 15 ++++ 21 files changed, 179 insertions(+), 72 deletions(-) create mode 100644 tests/ui/lint/lint-stability-internal.rs create mode 100644 tests/ui/lint/lint-stability-internal.stderr diff --git a/compiler/rustc_attr/messages.ftl b/compiler/rustc_attr/messages.ftl index e6cbbaf3704bc..4c6f1ee4ecf54 100644 --- a/compiler/rustc_attr/messages.ftl +++ b/compiler/rustc_attr/messages.ftl @@ -88,6 +88,9 @@ attr_rustc_promotable_pairing = attr_soft_no_args = `soft` should not have any arguments +attr_internal_no_args = + `is_internal` should not have any arguments + attr_unknown_meta_item = unknown meta item '{$item}' .label = expected one of {$expected} diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index ca4b3662a089f..3bcaf4ba584b6 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -160,6 +160,8 @@ pub enum StabilityLevel { /// Relevant `rust-lang/rust` issue. issue: Option, is_soft: bool, + /// If the feature is internal + is_internal: 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. @@ -461,6 +463,7 @@ fn parse_unstability(sess: &Session, attr: &Attribute) -> Option<(Symbol, Stabil let mut issue = None; let mut issue_num = None; let mut is_soft = false; + let mut is_internal = false; let mut implied_by = None; for meta in metas { let Some(mi) = meta.meta_item() else { @@ -515,6 +518,12 @@ fn parse_unstability(sess: &Session, attr: &Attribute) -> Option<(Symbol, Stabil } is_soft = true; } + sym::is_internal => { + if !mi.is_word() { + sess.emit_err(session_diagnostics::InternalNoArgs { span: mi.span }); + } + is_internal = true; + } sym::implied_by => { if !insert_or_error(mi, &mut implied_by) { return None; @@ -545,6 +554,7 @@ fn parse_unstability(sess: &Session, attr: &Attribute) -> Option<(Symbol, Stabil issue: issue_num, is_soft, implied_by, + is_internal, }; Some((feature, level)) } diff --git a/compiler/rustc_attr/src/session_diagnostics.rs b/compiler/rustc_attr/src/session_diagnostics.rs index ee79545e304ae..4bfe519d24b89 100644 --- a/compiler/rustc_attr/src/session_diagnostics.rs +++ b/compiler/rustc_attr/src/session_diagnostics.rs @@ -386,6 +386,13 @@ pub(crate) struct SoftNoArgs { pub span: Span, } +#[derive(Diagnostic)] +#[diag(attr_internal_no_args)] +pub(crate) struct InternalNoArgs { + #[primary_span] + pub span: Span, +} + #[derive(Diagnostic)] #[diag(attr_unknown_version_literal)] pub(crate) struct UnknownVersionLiteral { diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index de228bdb85030..7f066a1c9b619 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -51,7 +51,7 @@ use rustc_errors::{Applicability, DecorateLint, MultiSpan}; use rustc_feature::{deprecated_attributes, AttributeGate, BuiltinAttribute, GateIssue, Stability}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID}; +use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE}; use rustc_hir::intravisit::FnKind as HirFnKind; use rustc_hir::{Body, FnDecl, GenericParamKind, Node, PatKind, PredicateOrigin}; use rustc_middle::lint::in_external_macro; @@ -2249,9 +2249,9 @@ declare_lint_pass!( IncompleteInternalFeatures => [INCOMPLETE_FEATURES, INTERNAL_FEATURES] ); -impl EarlyLintPass for IncompleteInternalFeatures { - fn check_crate(&mut self, cx: &EarlyContext<'_>, _: &ast::Crate) { - let features = cx.builder.features(); +impl<'tcx> LateLintPass<'tcx> for IncompleteInternalFeatures { + fn check_crate(&mut self, cx: &LateContext<'tcx>) { + let features = cx.tcx.features(); features .declared_lang_features .iter() @@ -2278,6 +2278,21 @@ impl EarlyLintPass for IncompleteInternalFeatures { ); } }); + + for cnum in [LOCAL_CRATE].into_iter().chain(cx.tcx.crates(()).iter().copied()) { + let crate_features = cx.tcx.lib_features(cnum); + for &(name, span) in &features.declared_lib_features { + if let Some((is_unstable, _)) = crate_features.unstable.get(&name) { + if *is_unstable { + cx.emit_spanned_lint( + INTERNAL_FEATURES, + span, + BuiltinInternalFeatures { name, note: None }, + ); + } + } + } + } } } diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index f58782c0f2244..40c49ba6902d7 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -534,10 +534,6 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { self.sess } - pub(crate) fn features(&self) -> &Features { - self.features - } - pub(crate) fn lint_store(&self) -> &LintStore { self.store } diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 84434d585d3d6..f865d2cb18f59 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -176,7 +176,6 @@ early_lint_methods!( WhileTrue: WhileTrue, NonAsciiIdents: NonAsciiIdents, HiddenUnicodeCodepoints: HiddenUnicodeCodepoints, - IncompleteInternalFeatures: IncompleteInternalFeatures, RedundantSemicolons: RedundantSemicolons, UnusedDocComment: UnusedDocComment, UnexpectedCfgs: UnexpectedCfgs, @@ -200,6 +199,7 @@ late_lint_methods!( BoxPointers: BoxPointers, PathStatements: PathStatements, LetUnderscore: LetUnderscore, + IncompleteInternalFeatures: IncompleteInternalFeatures, InvalidReferenceCasting: InvalidReferenceCasting::default(), // Depends on referenced function signatures in expressions UnusedResults: UnusedResults, diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 7fd3c0f494a11..22a7cbd0f1738 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -21,6 +21,7 @@ use rustc_index::{Idx, IndexVec}; use rustc_middle::metadata::ModChild; use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile; use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo}; +use rustc_middle::middle::lib_features::LibFeatures; use rustc_middle::mir::interpret::{AllocDecodingSession, AllocDecodingState}; use rustc_middle::ty::codec::TyDecoder; use rustc_middle::ty::fast_reject::SimplifiedType; @@ -1007,8 +1008,19 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } /// Iterates over all the stability attributes in the given crate. - fn get_lib_features(self, tcx: TyCtxt<'tcx>) -> &'tcx [(Symbol, Option)] { - tcx.arena.alloc_from_iter(self.root.lib_features.decode(self)) + fn get_lib_features(self, _tcx: TyCtxt<'tcx>) -> LibFeatures { + let mut features = LibFeatures::default(); + for (symbol, stability) in self.root.lib_features.decode(self) { + match stability { + FeatureStability::AcceptedSince(since) => { + features.stable.insert(symbol, (since, DUMMY_SP)); + } + FeatureStability::Unstable(internal) => { + features.unstable.insert(symbol, (internal, DUMMY_SP)); + } + } + } + features } /// Iterates over the stability implications in the given crate (when a `#[unstable]` attribute diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index aeda8af6d2cab..f4b9e4ee34191 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -343,7 +343,7 @@ provide! { tcx, def_id, other, cdata, module_children => { tcx.arena.alloc_from_iter(cdata.get_module_children(def_id.index, tcx.sess)) } - defined_lib_features => { cdata.get_lib_features(tcx) } + lib_features => { cdata.get_lib_features(tcx) } stability_implications => { cdata.get_stability_implications(tcx).iter().copied().collect() } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 4f4351633a2ce..7c6e9654db00a 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -24,6 +24,7 @@ use rustc_middle::middle::dependency_format::Linkage; use rustc_middle::middle::exported_symbols::{ metadata_symbol_name, ExportedSymbol, SymbolExportInfo, }; +use rustc_middle::middle::lib_features::FeatureStability; use rustc_middle::mir::interpret; use rustc_middle::query::LocalCrate; use rustc_middle::query::Providers; @@ -1871,10 +1872,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.lazy_array(deps.iter().map(|(_, dep)| dep)) } - fn encode_lib_features(&mut self) -> LazyArray<(Symbol, Option)> { + fn encode_lib_features(&mut self) -> LazyArray<(Symbol, FeatureStability)> { empty_proc_macro!(self); let tcx = self.tcx; - let lib_features = tcx.lib_features(()); + let lib_features = tcx.lib_features(LOCAL_CRATE); self.lazy_array(lib_features.to_vec()) } diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 71269779d4239..b36dd584bdbf5 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -3,6 +3,7 @@ use decoder::Metadata; use def_path_hash_map::DefPathHashMapRef; use rustc_data_structures::fx::FxHashMap; use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile; +use rustc_middle::middle::lib_features::FeatureStability; use table::TableBuilder; use rustc_ast as ast; @@ -264,7 +265,7 @@ pub(crate) struct CrateRoot { crate_deps: LazyArray, dylib_dependency_formats: LazyArray>, - lib_features: LazyArray<(Symbol, Option)>, + lib_features: LazyArray<(Symbol, FeatureStability)>, stability_implications: LazyArray<(Symbol, Symbol)>, lang_items: LazyArray<(DefIndex, LangItem)>, lang_items_missing: LazyArray, diff --git a/compiler/rustc_middle/src/middle/mod.rs b/compiler/rustc_middle/src/middle/mod.rs index 85c5af9ca13cb..6e14e322be021 100644 --- a/compiler/rustc_middle/src/middle/mod.rs +++ b/compiler/rustc_middle/src/middle/mod.rs @@ -7,20 +7,31 @@ pub mod lib_features { use rustc_data_structures::fx::FxHashMap; use rustc_span::{symbol::Symbol, Span}; - #[derive(HashStable, Debug)] + #[derive(Copy, Clone, Debug, PartialEq, Eq)] + #[derive(HashStable, TyEncodable, TyDecodable)] + pub enum FeatureStability { + AcceptedSince(Symbol), + Unstable(bool), + } + + #[derive(HashStable, Debug, Default)] pub struct LibFeatures { /// A map from feature to stabilisation version. pub stable: FxHashMap, - pub unstable: FxHashMap, + pub unstable: FxHashMap, } impl LibFeatures { - pub fn to_vec(&self) -> Vec<(Symbol, Option)> { + pub fn to_vec(&self) -> Vec<(Symbol, FeatureStability)> { let mut all_features: Vec<_> = self .stable .iter() - .map(|(f, (s, _))| (*f, Some(*s))) - .chain(self.unstable.keys().map(|f| (*f, None))) + .map(|(f, (s, _))| (*f, FeatureStability::AcceptedSince(*s))) + .chain( + self.unstable + .iter() + .map(|(f, (internal, _))| (*f, FeatureStability::Unstable(*internal))), + ) .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 908ab8b613e88..70cdf1b0b6e97 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -440,7 +440,7 @@ impl<'tcx> TyCtxt<'tcx> { match stability { Some(Stability { - level: attr::Unstable { reason, issue, is_soft, implied_by }, + level: attr::Unstable { reason, issue, is_soft, implied_by, is_internal: _ }, feature, .. }) => { diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index bf340846f108c..c6434ef8d2d35 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1744,13 +1744,10 @@ rustc_queries! { desc { |tcx| "computing crate imported by `{}`", tcx.def_path_str(def_id) } } - query lib_features(_: ()) -> &'tcx LibFeatures { - arena_cache - desc { "calculating the lib features map" } - } - query defined_lib_features(_: CrateNum) -> &'tcx [(Symbol, Option)] { + query lib_features(_: CrateNum) -> &'tcx LibFeatures { desc { "calculating the lib features defined in a crate" } separate_provide_extern + arena_cache } query stability_implications(_: CrateNum) -> &'tcx FxHashMap { arena_cache diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs index f1c38984296c7..91e1cad21e1a8 100644 --- a/compiler/rustc_middle/src/ty/parameterized.rs +++ b/compiler/rustc_middle/src/ty/parameterized.rs @@ -59,6 +59,7 @@ trivially_parameterized_over_tcx! { crate::middle::codegen_fn_attrs::CodegenFnAttrs, crate::middle::debugger_visualizer::DebuggerVisualizerFile, crate::middle::exported_symbols::SymbolExportInfo, + crate::middle::lib_features::FeatureStability, crate::middle::resolve_bound_vars::ObjectLifetimeDefault, crate::mir::ConstQualifs, ty::AssocItemContainer, diff --git a/compiler/rustc_passes/src/lib_features.rs b/compiler/rustc_passes/src/lib_features.rs index 44174b1b89d11..64f6498a6deb7 100644 --- a/compiler/rustc_passes/src/lib_features.rs +++ b/compiler/rustc_passes/src/lib_features.rs @@ -8,18 +8,14 @@ use rustc_ast::Attribute; use rustc_attr::{rust_version_symbol, VERSION_PLACEHOLDER}; use rustc_hir::intravisit::Visitor; use rustc_middle::hir::nested_filter; -use rustc_middle::middle::lib_features::LibFeatures; -use rustc_middle::query::Providers; +use rustc_middle::middle::lib_features::{FeatureStability, LibFeatures}; +use rustc_middle::query::{LocalCrate, Providers}; use rustc_middle::ty::TyCtxt; use rustc_span::symbol::Symbol; use rustc_span::{sym, Span}; use crate::errors::{FeaturePreviouslyDeclared, FeatureStableTwice}; -fn new_lib_features() -> LibFeatures { - LibFeatures { stable: Default::default(), unstable: Default::default() } -} - pub struct LibFeatureCollector<'tcx> { tcx: TyCtxt<'tcx>, lib_features: LibFeatures, @@ -27,10 +23,10 @@ pub struct LibFeatureCollector<'tcx> { impl<'tcx> LibFeatureCollector<'tcx> { fn new(tcx: TyCtxt<'tcx>) -> LibFeatureCollector<'tcx> { - LibFeatureCollector { tcx, lib_features: new_lib_features() } + LibFeatureCollector { tcx, lib_features: LibFeatures::default() } } - fn extract(&self, attr: &Attribute) -> Option<(Symbol, Option, Span)> { + fn extract(&self, attr: &Attribute) -> Option<(Symbol, FeatureStability, Span)> { let stab_attrs = [ sym::stable, sym::unstable, @@ -45,12 +41,16 @@ impl<'tcx> LibFeatureCollector<'tcx> { if let Some(metas) = attr.meta_item_list() { let mut feature = None; let mut since = None; + let mut is_internal = false; for meta in metas { if let Some(mi) = meta.meta_item() { // Find the `feature = ".."` meta-item. match (mi.name_or_empty(), mi.value_str()) { (sym::feature, val) => feature = val, (sym::since, val) => since = val, + (sym::is_internal, _val) => { + is_internal = true; + } _ => {} } } @@ -70,8 +70,11 @@ impl<'tcx> LibFeatureCollector<'tcx> { | sym::rustc_const_unstable | sym::rustc_default_body_unstable ); - if since.is_some() || is_unstable { - return Some((feature, since, attr.span)); + if is_unstable { + return Some((feature, FeatureStability::Unstable(is_internal), attr.span)); + } + if let Some(since) = since { + return Some((feature, FeatureStability::AcceptedSince(since), attr.span)); } } // We need to iterate over the other attributes, because @@ -84,37 +87,53 @@ impl<'tcx> LibFeatureCollector<'tcx> { None } - fn collect_feature(&mut self, feature: Symbol, since: Option, span: Span) { + fn collect_feature(&mut self, feature: Symbol, stability: FeatureStability, span: Span) { let already_in_stable = self.lib_features.stable.contains_key(&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 *prev_since != since { - self.tcx.sess.emit_err(FeatureStableTwice { - span, - feature, - since, - prev_since: *prev_since, - }); - return; - } + match (stability, already_in_stable, already_in_unstable) { + (FeatureStability::AcceptedSince(since), _, false) => { + if let Some((prev_since, _)) = self.lib_features.stable.get(&feature) + && *prev_since != since + { + self.tcx.sess.emit_err(FeatureStableTwice { + span, + feature, + since, + prev_since: *prev_since, + }); + return; } self.lib_features.stable.insert(feature, (since, span)); } - (None, false, _) => { - self.lib_features.unstable.insert(feature, span); + (FeatureStability::AcceptedSince(_), _, true) => { + self.tcx.sess.emit_err(FeaturePreviouslyDeclared { + span, + feature, + declared: "stable", + prev_declared: "unstable", + }); + } + (FeatureStability::Unstable(internal), false, _) => { + if let Some(&(prev_internal, _)) = self.lib_features.unstable.get(&feature) + && prev_internal != internal + { + self.tcx.sess.emit_err(FeaturePreviouslyDeclared { + span, + feature, + declared: if internal { "internal" } else { "unstable "}, + prev_declared: if prev_internal { "internal" } else { "unstable "}, + }); + } + self.lib_features.unstable.insert(feature, (internal, span)); } - (Some(_), _, true) | (None, true, _) => { - let declared = if since.is_some() { "stable" } else { "unstable" }; - let prev_declared = if since.is_none() { "stable" } else { "unstable" }; + (FeatureStability::Unstable(_), true, _) => { self.tcx.sess.emit_err(FeaturePreviouslyDeclared { span, feature, - declared, - prev_declared, + declared: "unstable", + prev_declared: "stable", }); } } @@ -135,11 +154,11 @@ impl<'tcx> Visitor<'tcx> for LibFeatureCollector<'tcx> { } } -fn lib_features(tcx: TyCtxt<'_>, (): ()) -> LibFeatures { +fn lib_features(tcx: TyCtxt<'_>, LocalCrate: LocalCrate) -> LibFeatures { // If `staged_api` is not enabled then we aren't allowed to define lib // features; there is no point collecting them. if !tcx.features().staged_api { - return new_lib_features(); + return LibFeatures::default(); } let mut collector = LibFeatureCollector::new(tcx); diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 9c265e8ec11e5..9dfb4bc5f3258 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -14,6 +14,7 @@ use rustc_hir::hir_id::CRATE_HIR_ID; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{FieldDef, Item, ItemKind, TraitRef, Ty, TyKind, Variant}; use rustc_middle::hir::nested_filter; +use rustc_middle::middle::lib_features::{FeatureStability, LibFeatures}; use rustc_middle::middle::privacy::EffectiveVisibilities; use rustc_middle::middle::stability::{AllowUnstable, DeprecationEntry, Index}; use rustc_middle::query::Providers; @@ -660,6 +661,7 @@ fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index { issue: NonZeroU32::new(27812), is_soft: false, implied_by: None, + is_internal: false, }, feature: sym::rustc_private, }; @@ -994,26 +996,27 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) { tcx: TyCtxt<'tcx>, remaining_lib_features: &mut FxIndexMap<&Symbol, Span>, remaining_implications: &mut FxHashMap, - defined_features: &[(Symbol, Option)], + defined_features: &LibFeatures, all_implications: &FxHashMap, ) { - for (feature, since) in defined_features { - if let Some(since) = since && let Some(span) = remaining_lib_features.get(&feature) { + for (feature, stability) in defined_features.to_vec() { + if let FeatureStability::AcceptedSince(since) = stability + && let Some(span) = remaining_lib_features.get(&feature) + { // Warn if the user has enabled an already-stable lib feature. if let Some(implies) = all_implications.get(&feature) { - unnecessary_partially_stable_feature_lint(tcx, *span, *feature, *implies, *since); + unnecessary_partially_stable_feature_lint(tcx, *span, feature, *implies, since); } else { - unnecessary_stable_feature_lint(tcx, *span, *feature, *since); + unnecessary_stable_feature_lint(tcx, *span, feature, since); } - } - remaining_lib_features.remove(feature); + remaining_lib_features.remove(&feature); // `feature` is the feature doing the implying, but `implied_by` is the feature with // the attribute that establishes this relationship. `implied_by` is guaranteed to be a // feature defined in the local crate because `remaining_implications` is only the // implications from this crate. - remaining_implications.remove(feature); + remaining_implications.remove(&feature); if remaining_lib_features.is_empty() && remaining_implications.is_empty() { break; @@ -1027,7 +1030,7 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) { // 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(); + let local_defined_features = tcx.lib_features(rustc_hir::def_id::LOCAL_CRATE); if !remaining_lib_features.is_empty() || !remaining_implications.is_empty() { // Loading the implications of all crates is unavoidable to be able to emit the partial // stabilization diagnostic, but it can be avoided when there are no @@ -1041,7 +1044,7 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) { tcx, &mut remaining_lib_features, &mut remaining_implications, - local_defined_features.as_slice(), + local_defined_features, &all_implications, ); @@ -1053,7 +1056,7 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) { tcx, &mut remaining_lib_features, &mut remaining_implications, - tcx.defined_lib_features(cnum).to_vec().as_slice(), + tcx.lib_features(cnum), &all_implications, ); } @@ -1064,12 +1067,12 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) { } for (implied_by, feature) in remaining_implications { - let local_defined_features = tcx.lib_features(()); + let local_defined_features = tcx.lib_features(rustc_hir::def_id::LOCAL_CRATE); let span = *local_defined_features .stable .get(&feature) .map(|(_, span)| span) - .or_else(|| local_defined_features.unstable.get(&feature)) + .or_else(|| Some(&local_defined_features.unstable.get(&feature)?.1)) .expect("feature that implied another does not exist"); tcx.sess.emit_err(errors::ImpliedFeatureNotExist { span, feature, implied_by }); } diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 1199290a4d1c6..2d1dff8c6b6f3 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -849,7 +849,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { ) { let span = path.span; if let Some(stability) = &ext.stability { - if let StabilityLevel::Unstable { reason, issue, is_soft, implied_by } = stability.level + if let StabilityLevel::Unstable { reason, issue, is_soft, implied_by, is_internal: _ } = + stability.level { let feature = stability.feature; diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 656deebb5d06b..7cf2ecc22cbee 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -865,6 +865,7 @@ symbols! { intra_doc_pointers, intrinsics, irrefutable_let_patterns, + is_internal, isa_attribute, isize, issue, diff --git a/tests/ui/lint/auxiliary/lint_stability.rs b/tests/ui/lint/auxiliary/lint_stability.rs index 99c29dcdda677..988b0e3b7c73d 100644 --- a/tests/ui/lint/auxiliary/lint_stability.rs +++ b/tests/ui/lint/auxiliary/lint_stability.rs @@ -186,3 +186,6 @@ macro_rules! macro_test_arg { macro_rules! macro_test_arg_nested { ($func:ident) => (macro_test_arg!($func())); } + +#[unstable(feature = "unstable_test_feature_internal", issue = "none", is_internal)] +pub struct InternalStruct; diff --git a/tests/ui/lint/lint-stability-internal.rs b/tests/ui/lint/lint-stability-internal.rs new file mode 100644 index 0000000000000..59cf8bfdbdeda --- /dev/null +++ b/tests/ui/lint/lint-stability-internal.rs @@ -0,0 +1,11 @@ +// aux-build:lint_stability.rs + +#![feature(unstable_test_feature_internal)] +//~^ ERROR the feature `unstable_test_feature_internal` is internal to the compiler or standard library +#![forbid(internal_features)] + +extern crate lint_stability; + +fn main() { + let _ = lint_stability::InternalStruct; +} diff --git a/tests/ui/lint/lint-stability-internal.stderr b/tests/ui/lint/lint-stability-internal.stderr new file mode 100644 index 0000000000000..9b09c5d967426 --- /dev/null +++ b/tests/ui/lint/lint-stability-internal.stderr @@ -0,0 +1,15 @@ +error: the feature `unstable_test_feature_internal` is internal to the compiler or standard library + --> $DIR/lint-stability-internal.rs:3:12 + | +LL | #![feature(unstable_test_feature_internal)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: using it is strongly discouraged +note: the lint level is defined here + --> $DIR/lint-stability-internal.rs:5:11 + | +LL | #![forbid(internal_features)] + | ^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + From 1da0c897ea43bc69f303f5fb45803ec0a191b62f Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 6 Sep 2023 17:05:00 -0700 Subject: [PATCH 2/2] Split early and late internal feature lint --- compiler/rustc_attr/messages.ftl | 6 +++--- compiler/rustc_lint/src/builtin.rs | 19 +++++++++++++++---- compiler/rustc_lint/src/levels.rs | 4 ++++ compiler/rustc_lint/src/lib.rs | 3 ++- 4 files changed, 24 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_attr/messages.ftl b/compiler/rustc_attr/messages.ftl index 4c6f1ee4ecf54..2042553b6d6a7 100644 --- a/compiler/rustc_attr/messages.ftl +++ b/compiler/rustc_attr/messages.ftl @@ -34,6 +34,9 @@ attr_incorrect_repr_format_generic = attr_incorrect_repr_format_packed_one_or_zero_arg = incorrect `repr(packed)` attribute format: `packed` takes exactly one parenthesized argument, or no parentheses at all +attr_internal_no_args = + `is_internal` should not have any arguments + attr_invalid_issue_string = `issue` must be a non-zero numeric string or "none" .must_not_be_zero = `issue` must not be "0", use "none" instead @@ -88,9 +91,6 @@ attr_rustc_promotable_pairing = attr_soft_no_args = `soft` should not have any arguments -attr_internal_no_args = - `is_internal` should not have any arguments - attr_unknown_meta_item = unknown meta item '{$item}' .label = expected one of {$expected} diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 7f066a1c9b619..89fbca967ba86 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -2246,12 +2246,17 @@ declare_lint! { declare_lint_pass!( /// Check for used feature gates in `INCOMPLETE_FEATURES` in `rustc_feature/src/active.rs`. - IncompleteInternalFeatures => [INCOMPLETE_FEATURES, INTERNAL_FEATURES] + IncompleteInternalLangFeatures => [INCOMPLETE_FEATURES, INTERNAL_FEATURES] ); -impl<'tcx> LateLintPass<'tcx> for IncompleteInternalFeatures { - fn check_crate(&mut self, cx: &LateContext<'tcx>) { - let features = cx.tcx.features(); +declare_lint_pass!( + /// Check for used library features declared as `unstable(is_internal)`. + InternalLibFeatures => [] +); + +impl EarlyLintPass for IncompleteInternalLangFeatures { + fn check_crate(&mut self, cx: &EarlyContext<'_>, _: &ast::Crate) { + let features = cx.builder.features(); features .declared_lang_features .iter() @@ -2278,7 +2283,13 @@ impl<'tcx> LateLintPass<'tcx> for IncompleteInternalFeatures { ); } }); + } +} +// Needs to be a late pass because we need the list of parent crates +impl<'tcx> LateLintPass<'tcx> for InternalLibFeatures { + fn check_crate(&mut self, cx: &LateContext<'tcx>) { + let features = cx.tcx.features(); for cnum in [LOCAL_CRATE].into_iter().chain(cx.tcx.crates(()).iter().copied()) { let crate_features = cx.tcx.lib_features(cnum); for &(name, span) in &features.declared_lib_features { diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index 40c49ba6902d7..f58782c0f2244 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -534,6 +534,10 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { self.sess } + pub(crate) fn features(&self) -> &Features { + self.features + } + pub(crate) fn lint_store(&self) -> &LintStore { self.store } diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index f865d2cb18f59..45e22ecdcd897 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -171,6 +171,7 @@ early_lint_methods!( SpecialModuleName: SpecialModuleName, AnonymousParameters: AnonymousParameters, EllipsisInclusiveRangePatterns: EllipsisInclusiveRangePatterns::default(), + IncompleteInternalLangFeatures: IncompleteInternalLangFeatures, NonCamelCaseTypes: NonCamelCaseTypes, DeprecatedAttr: DeprecatedAttr::new(), WhileTrue: WhileTrue, @@ -199,7 +200,7 @@ late_lint_methods!( BoxPointers: BoxPointers, PathStatements: PathStatements, LetUnderscore: LetUnderscore, - IncompleteInternalFeatures: IncompleteInternalFeatures, + InternalLibFeatures: InternalLibFeatures, InvalidReferenceCasting: InvalidReferenceCasting::default(), // Depends on referenced function signatures in expressions UnusedResults: UnusedResults,