Skip to content

Commit

Permalink
Auto merge of #94096 - cjgillot:ensure-stability, r=lcnr
Browse files Browse the repository at this point in the history
Ensure stability directives are checked in all cases

Split off  #93017

Stability and deprecation were not checked in all cases, for instance if a type error happened.
This PR moves the check earlier in the pipeline to ensure the errors are emitted in all cases.

r? `@lcnr`
  • Loading branch information
bors committed Mar 4, 2022
2 parents 8fa5d74 + c680d39 commit 65f6d33
Show file tree
Hide file tree
Showing 133 changed files with 497 additions and 477 deletions.
25 changes: 25 additions & 0 deletions compiler/rustc_ast_passes/src/feature_gate.rs
Expand Up @@ -420,6 +420,31 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
}
}
}

// Emit errors for non-staged-api crates.
if !self.features.staged_api {
if attr.has_name(sym::rustc_deprecated)
|| attr.has_name(sym::unstable)
|| attr.has_name(sym::stable)
|| attr.has_name(sym::rustc_const_unstable)
|| attr.has_name(sym::rustc_const_stable)
{
struct_span_err!(
self.sess,
attr.span,
E0734,
"stability attributes may not be used outside of the standard library",
)
.emit();
}
} else {
if attr.has_name(sym::deprecated) {
self.sess
.struct_span_err(attr.span, "`#[deprecated]` cannot be used in staged API")
.span_label(attr.span, "use `#[rustc_deprecated]` instead")
.emit();
}
}
}

fn visit_item(&mut self, i: &'a ast::Item) {
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_expand/src/config.rs
Expand Up @@ -167,6 +167,7 @@ fn get_features(
if let Some(Feature { since, .. }) = ACCEPTED_FEATURES.iter().find(|f| name == f.name) {
let since = Some(Symbol::intern(since));
features.declared_lang_features.push((name, mi.span(), since));
features.active_features.insert(name);
continue;
}

Expand All @@ -187,10 +188,12 @@ fn get_features(
if let Some(f) = ACTIVE_FEATURES.iter().find(|f| name == f.name) {
f.set(&mut features, mi.span());
features.declared_lang_features.push((name, mi.span(), None));
features.active_features.insert(name);
continue;
}

features.declared_lib_features.push((name, mi.span()));
features.active_features.insert(name);
}
}

Expand Down
8 changes: 8 additions & 0 deletions compiler/rustc_feature/src/active.rs
Expand Up @@ -2,6 +2,7 @@

use super::{to_nonzero, Feature, State};

use rustc_data_structures::fx::FxHashSet;
use rustc_span::edition::Edition;
use rustc_span::symbol::{sym, Symbol};
use rustc_span::Span;
Expand Down Expand Up @@ -47,6 +48,8 @@ macro_rules! declare_features {
pub declared_lang_features: Vec<(Symbol, Span, Option<Symbol>)>,
/// `#![feature]` attrs for non-language (library) features.
pub declared_lib_features: Vec<(Symbol, Span)>,
/// Features enabled for this crate.
pub active_features: FxHashSet<Symbol>,
$(
$(#[doc = $doc])*
pub $feature: bool
Expand All @@ -58,6 +61,11 @@ macro_rules! declare_features {
$(f(stringify!($feature), self.$feature);)+
}

/// Is the given feature active?
pub fn active(&self, feature: Symbol) -> bool {
self.active_features.contains(&feature)
}

/// Is the given feature enabled?
///
/// Panics if the symbol doesn't correspond to a declared feature.
Expand Down
11 changes: 6 additions & 5 deletions compiler/rustc_interface/src/passes.rs
Expand Up @@ -921,12 +921,18 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> {
tcx.ensure().check_mod_const_bodies(module);
});
},
{
sess.time("unused_lib_feature_checking", || {
rustc_passes::stability::check_unused_or_stable_features(tcx)
});
},
{
// We force these querie to run,
// since they might not otherwise get called.
// This marks the corresponding crate-level attributes
// as used, and ensures that their values are valid.
tcx.ensure().limits(());
tcx.ensure().stability_index(());
}
);
});
Expand Down Expand Up @@ -998,11 +1004,6 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> {
tcx.hir()
.par_for_each_module(|module| tcx.ensure().check_mod_deathness(module));
},
{
sess.time("unused_lib_feature_checking", || {
rustc_passes::stability::check_unused_or_stable_features(tcx)
});
},
{
sess.time("lint_checking", || {
rustc_lint::check_crate(tcx, || {
Expand Down
12 changes: 3 additions & 9 deletions compiler/rustc_middle/src/middle/stability.rs
Expand Up @@ -6,12 +6,12 @@ pub use self::StabilityLevel::*;
use crate::ty::{self, DefIdTree, TyCtxt};
use rustc_ast::NodeId;
use rustc_attr::{self as attr, ConstStability, Deprecation, Stability};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{Applicability, Diagnostic};
use rustc_feature::GateIssue;
use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_INDEX};
use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_INDEX};
use rustc_hir::{self, HirId};
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_session::lint::builtin::{DEPRECATED, DEPRECATED_IN_FUTURE, SOFT_UNSTABLE};
Expand Down Expand Up @@ -63,12 +63,6 @@ pub struct Index {
pub stab_map: FxHashMap<LocalDefId, Stability>,
pub const_stab_map: FxHashMap<LocalDefId, ConstStability>,
pub depr_map: FxHashMap<LocalDefId, DeprecationEntry>,

/// Maps for each crate whether it is part of the staged API.
pub staged_api: FxHashMap<CrateNum, bool>,

/// Features enabled for this crate.
pub active_features: FxHashSet<Symbol>,
}

impl Index {
Expand Down Expand Up @@ -423,7 +417,7 @@ impl<'tcx> TyCtxt<'tcx> {
debug!("stability: skipping span={:?} since it is internal", span);
return EvalResult::Allow;
}
if self.stability().active_features.contains(&feature) {
if self.features().active(feature) {
return EvalResult::Allow;
}

Expand Down
5 changes: 0 additions & 5 deletions compiler/rustc_middle/src/ty/context.rs
Expand Up @@ -2999,11 +2999,6 @@ pub fn provide(providers: &mut ty::query::Providers) {
tcx.arena.alloc(tcx.resolutions(()).glob_map.get(&id).cloned().unwrap_or_default())
};

providers.lookup_stability = |tcx, id| tcx.stability().local_stability(id.expect_local());
providers.lookup_const_stability =
|tcx, id| tcx.stability().local_const_stability(id.expect_local());
providers.lookup_deprecation_entry =
|tcx, id| tcx.stability().local_deprecation_entry(id.expect_local());
providers.extern_mod_stmt_cnum =
|tcx, id| tcx.resolutions(()).extern_crate_map.get(&id).cloned();
providers.output_filenames = |tcx, ()| &tcx.output_filenames;
Expand Down
107 changes: 27 additions & 80 deletions compiler/rustc_passes/src/stability.rs
@@ -1,13 +1,12 @@
//! A pass that annotates every item and method with its stability level,
//! propagating default levels lexically from parent to children ast nodes.

use rustc_ast::Attribute;
use rustc_attr::{self as attr, ConstStability, Stability};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
use rustc_errors::struct_span_err;
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, CRATE_DEF_INDEX, LOCAL_CRATE};
use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, CRATE_DEF_INDEX};
use rustc_hir::hir_id::CRATE_HIR_ID;
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{FieldDef, Generics, HirId, Item, TraitRef, Ty, TyKind, Variant};
Expand Down Expand Up @@ -113,12 +112,8 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
{
let attrs = self.tcx.get_attrs(def_id.to_def_id());
debug!("annotate(id = {:?}, attrs = {:?})", def_id, attrs);
let mut did_error = false;
if !self.tcx.features().staged_api {
did_error = self.forbid_staged_api_attrs(def_id, attrs, inherit_deprecation.clone());
}

let depr = if did_error { None } else { attr::find_deprecation(&self.tcx.sess, attrs) };
let depr = attr::find_deprecation(&self.tcx.sess, attrs);
let mut is_deprecated = false;
if let Some((depr, span)) = &depr {
is_deprecated = true;
Expand Down Expand Up @@ -148,16 +143,15 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
}
}

if self.tcx.features().staged_api {
if let Some(a) = attrs.iter().find(|a| a.has_name(sym::deprecated)) {
self.tcx
.sess
.struct_span_err(a.span, "`#[deprecated]` cannot be used in staged API")
.span_label(a.span, "use `#[rustc_deprecated]` instead")
.span_label(item_sp, "")
.emit();
if !self.tcx.features().staged_api {
// Propagate unstability. This can happen even for non-staged-api crates in case
// -Zforce-unstable-if-unmarked is set.
if let Some(stab) = self.parent_stab {
if inherit_deprecation.yes() && stab.level.is_unstable() {
self.index.stab_map.insert(def_id, stab);
}
}
} else {

self.recurse_with_stability_attrs(
depr.map(|(d, _)| DeprecationEntry::local(d, def_id)),
None,
Expand Down Expand Up @@ -329,47 +323,6 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
self.parent_const_stab = orig_parent_const_stab;
}
}

// returns true if an error occurred, used to suppress some spurious errors
fn forbid_staged_api_attrs(
&mut self,
def_id: LocalDefId,
attrs: &[Attribute],
inherit_deprecation: InheritDeprecation,
) -> bool {
// Emit errors for non-staged-api crates.
let unstable_attrs = [
sym::unstable,
sym::stable,
sym::rustc_deprecated,
sym::rustc_const_unstable,
sym::rustc_const_stable,
];
let mut has_error = false;
for attr in attrs {
let name = attr.name_or_empty();
if unstable_attrs.contains(&name) {
struct_span_err!(
self.tcx.sess,
attr.span,
E0734,
"stability attributes may not be used outside of the standard library",
)
.emit();
has_error = true;
}
}

// Propagate unstability. This can happen even for non-staged-api crates in case
// -Zforce-unstable-if-unmarked is set.
if let Some(stab) = self.parent_stab {
if inherit_deprecation.yes() && stab.level.is_unstable() {
self.index.stab_map.insert(def_id, stab);
}
}

has_error
}
}

impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
Expand Down Expand Up @@ -654,28 +607,12 @@ impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> {
}

fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index {
let is_staged_api =
tcx.sess.opts.debugging_opts.force_unstable_if_unmarked || tcx.features().staged_api;
let mut staged_api = FxHashMap::default();
staged_api.insert(LOCAL_CRATE, is_staged_api);
let mut index = Index {
staged_api,
stab_map: Default::default(),
const_stab_map: Default::default(),
depr_map: Default::default(),
active_features: Default::default(),
};

let active_lib_features = &tcx.features().declared_lib_features;
let active_lang_features = &tcx.features().declared_lang_features;

// Put the active features into a map for quick lookup.
index.active_features = active_lib_features
.iter()
.map(|&(s, ..)| s)
.chain(active_lang_features.iter().map(|&(s, ..)| s))
.collect();

{
let mut annotator = Annotator {
tcx,
Expand Down Expand Up @@ -728,7 +665,16 @@ fn check_mod_unstable_api_usage(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
}

pub(crate) fn provide(providers: &mut Providers) {
*providers = Providers { check_mod_unstable_api_usage, stability_index, ..*providers };
*providers = Providers {
check_mod_unstable_api_usage,
stability_index,
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| {
tcx.stability().local_deprecation_entry(id.expect_local())
},
..*providers
};
}

struct Checker<'tcx> {
Expand Down Expand Up @@ -884,9 +830,10 @@ impl<'tcx> Visitor<'tcx> for CheckTraitImplStable<'tcx> {
/// were expected to be library features), and the list of features used from
/// libraries, identify activated features that don't exist and error about them.
pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) {
let access_levels = &tcx.privacy_access_levels(());

if tcx.stability().staged_api[&LOCAL_CRATE] {
let is_staged_api =
tcx.sess.opts.debugging_opts.force_unstable_if_unmarked || tcx.features().staged_api;
if is_staged_api {
let access_levels = &tcx.privacy_access_levels(());
let mut missing = MissingStabilityAnnotations { tcx, access_levels };
missing.check_missing_stability(CRATE_DEF_ID, tcx.hir().span(CRATE_HIR_ID));
tcx.hir().walk_toplevel_module(&mut missing);
Expand All @@ -907,7 +854,7 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) {
}

let declared_lib_features = &tcx.features().declared_lib_features;
let mut remaining_lib_features = FxHashMap::default();
let mut remaining_lib_features = FxIndexMap::default();
for (feature, span) in declared_lib_features {
if !tcx.sess.opts.unstable_features.is_nightly_build() {
struct_span_err!(
Expand All @@ -934,7 +881,7 @@ 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 FxHashMap<_, _>, defined_features: &[_]| {
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) {
Expand Down
@@ -1,6 +1,6 @@
// compile-flags:-C panic=abort

#![feature(alloc_error_handler, panic_handler)]
#![feature(alloc_error_handler)]
#![no_std]
#![no_main]

Expand Down
@@ -1,6 +1,6 @@
// compile-flags:-C panic=abort

#![feature(alloc_error_handler, panic_handler)]
#![feature(alloc_error_handler)]
#![no_std]
#![no_main]

Expand Down
@@ -1,6 +1,6 @@
// compile-flags:-C panic=abort

#![feature(alloc_error_handler, panic_handler)]
#![feature(alloc_error_handler)]
#![no_std]
#![no_main]

Expand Down
1 change: 0 additions & 1 deletion src/test/ui/asm/naked-functions.rs
Expand Up @@ -4,7 +4,6 @@
// ignore-wasm32

#![feature(naked_functions)]
#![feature(or_patterns)]
#![feature(asm_const, asm_sym, asm_unwind)]
#![crate_type = "lib"]

Expand Down

0 comments on commit 65f6d33

Please sign in to comment.