mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-01 15:01:51 +00:00
Support deprecation checking for macros
This commit is contained in:
parent
d9ee97e896
commit
0817fc6c6c
@ -5,10 +5,12 @@
|
||||
//! lints are all available in `rustc_lint::builtin`.
|
||||
|
||||
use crate::lint::{LintPass, LateLintPass, LintArray};
|
||||
use crate::middle::stability;
|
||||
use crate::session::Session;
|
||||
use errors::{Applicability, DiagnosticBuilder};
|
||||
use syntax::ast;
|
||||
use syntax::source_map::Span;
|
||||
use syntax::symbol::Symbol;
|
||||
|
||||
declare_lint! {
|
||||
pub EXCEEDING_BITSHIFTS,
|
||||
@ -461,6 +463,7 @@ pub enum BuiltinLintDiagnostics {
|
||||
UnusedImports(String, Vec<(Span, String)>),
|
||||
NestedImplTrait { outer_impl_trait_span: Span, inner_impl_trait_span: Span },
|
||||
RedundantImport(Vec<(Span, bool)>, ast::Ident),
|
||||
DeprecatedMacro(Option<Symbol>, Span),
|
||||
}
|
||||
|
||||
pub(crate) fn add_elided_lifetime_in_path_suggestion(
|
||||
@ -586,6 +589,8 @@ impl BuiltinLintDiagnostics {
|
||||
);
|
||||
}
|
||||
}
|
||||
BuiltinLintDiagnostics::DeprecatedMacro(suggestion, span) =>
|
||||
stability::deprecation_suggestion(db, suggestion, span),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
pub use self::StabilityLevel::*;
|
||||
|
||||
use crate::lint::{self, Lint, in_derive_expansion};
|
||||
use crate::lint::builtin::BuiltinLintDiagnostics;
|
||||
use crate::hir::{self, Item, Generics, StructField, Variant, HirId};
|
||||
use crate::hir::def::{Res, DefKind};
|
||||
use crate::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId, LOCAL_CRATE};
|
||||
@ -11,12 +12,13 @@ use crate::hir::intravisit::{self, Visitor, NestedVisitorMap};
|
||||
use crate::ty::query::Providers;
|
||||
use crate::middle::privacy::AccessLevels;
|
||||
use crate::session::{DiagnosticMessageId, Session};
|
||||
use errors::DiagnosticBuilder;
|
||||
use syntax::symbol::{Symbol, sym};
|
||||
use syntax_pos::{Span, MultiSpan};
|
||||
use syntax::ast::Attribute;
|
||||
use syntax::ast::{Attribute, CRATE_NODE_ID};
|
||||
use syntax::errors::Applicability;
|
||||
use syntax::feature_gate::{GateIssue, emit_feature_err};
|
||||
use syntax::attr::{self, Stability, Deprecation};
|
||||
use syntax::attr::{self, Stability, Deprecation, RustcDeprecation};
|
||||
use crate::ty::{self, TyCtxt};
|
||||
use crate::util::nodemap::{FxHashSet, FxHashMap};
|
||||
|
||||
@ -531,6 +533,79 @@ pub fn deprecation_in_effect(since: &str) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn deprecation_suggestion(
|
||||
diag: &mut DiagnosticBuilder<'_>, suggestion: Option<Symbol>, span: Span
|
||||
) {
|
||||
if let Some(suggestion) = suggestion {
|
||||
diag.span_suggestion(
|
||||
span,
|
||||
"replace the use of the deprecated item",
|
||||
suggestion.to_string(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn deprecation_message_common(message: String, reason: Option<Symbol>) -> String {
|
||||
match reason {
|
||||
Some(reason) => format!("{}: {}", message, reason),
|
||||
None => message,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn deprecation_message(depr: &Deprecation, path: &str) -> (String, &'static Lint) {
|
||||
let message = format!("use of deprecated item '{}'", path);
|
||||
(deprecation_message_common(message, depr.note), lint::builtin::DEPRECATED)
|
||||
}
|
||||
|
||||
pub fn rustc_deprecation_message(depr: &RustcDeprecation, path: &str) -> (String, &'static Lint) {
|
||||
let (message, lint) = if deprecation_in_effect(&depr.since.as_str()) {
|
||||
(format!("use of deprecated item '{}'", path), lint::builtin::DEPRECATED)
|
||||
} else {
|
||||
(format!("use of item '{}' that will be deprecated in future version {}", path, depr.since),
|
||||
lint::builtin::DEPRECATED_IN_FUTURE)
|
||||
};
|
||||
(deprecation_message_common(message, Some(depr.reason)), lint)
|
||||
}
|
||||
|
||||
pub fn early_report_deprecation(
|
||||
sess: &Session,
|
||||
message: &str,
|
||||
suggestion: Option<Symbol>,
|
||||
lint: &'static Lint,
|
||||
span: Span,
|
||||
) {
|
||||
if in_derive_expansion(span) {
|
||||
return;
|
||||
}
|
||||
|
||||
let diag = BuiltinLintDiagnostics::DeprecatedMacro(suggestion, span);
|
||||
sess.buffer_lint_with_diagnostic(lint, CRATE_NODE_ID, span, message, diag);
|
||||
}
|
||||
|
||||
fn late_report_deprecation(
|
||||
tcx: TyCtxt<'_>,
|
||||
message: &str,
|
||||
suggestion: Option<Symbol>,
|
||||
lint: &'static Lint,
|
||||
span: Span,
|
||||
def_id: DefId,
|
||||
hir_id: HirId,
|
||||
) {
|
||||
if in_derive_expansion(span) {
|
||||
return;
|
||||
}
|
||||
|
||||
let mut diag = tcx.struct_span_lint_hir(lint, hir_id, span, message);
|
||||
if let hir::Node::Expr(_) = tcx.hir().get(hir_id) {
|
||||
deprecation_suggestion(&mut diag, suggestion, span);
|
||||
}
|
||||
diag.emit();
|
||||
if hir_id == hir::DUMMY_HIR_ID {
|
||||
span_bug!(span, "emitted a {} lint with dummy HIR id: {:?}", lint.name, def_id);
|
||||
}
|
||||
}
|
||||
|
||||
struct Checker<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
}
|
||||
@ -593,38 +668,6 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
/// deprecated. If the item is indeed deprecated, we will emit a deprecation lint attached to
|
||||
/// `id`.
|
||||
pub fn eval_stability(self, def_id: DefId, id: Option<HirId>, span: Span) -> EvalResult {
|
||||
let lint_deprecated = |def_id: DefId,
|
||||
id: HirId,
|
||||
note: Option<Symbol>,
|
||||
suggestion: Option<Symbol>,
|
||||
message: &str,
|
||||
lint: &'static Lint| {
|
||||
if in_derive_expansion(span) {
|
||||
return;
|
||||
}
|
||||
let msg = if let Some(note) = note {
|
||||
format!("{}: {}", message, note)
|
||||
} else {
|
||||
format!("{}", message)
|
||||
};
|
||||
|
||||
let mut diag = self.struct_span_lint_hir(lint, id, span, &msg);
|
||||
if let Some(suggestion) = suggestion {
|
||||
if let hir::Node::Expr(_) = self.hir().get(id) {
|
||||
diag.span_suggestion(
|
||||
span,
|
||||
"replace the use of the deprecated item",
|
||||
suggestion.to_string(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
}
|
||||
diag.emit();
|
||||
if id == hir::DUMMY_HIR_ID {
|
||||
span_bug!(span, "emitted a {} lint with dummy HIR id: {:?}", lint.name, def_id);
|
||||
}
|
||||
};
|
||||
|
||||
// Deprecated attributes apply in-crate and cross-crate.
|
||||
if let Some(id) = id {
|
||||
if let Some(depr_entry) = self.lookup_deprecation_entry(def_id) {
|
||||
@ -634,14 +677,9 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
.map_or(false, |parent_depr| parent_depr.same_origin(&depr_entry));
|
||||
|
||||
if !skip {
|
||||
let path = self.def_path_str(def_id);
|
||||
let message = format!("use of deprecated item '{}'", path);
|
||||
lint_deprecated(def_id,
|
||||
id,
|
||||
depr_entry.attr.note,
|
||||
None,
|
||||
&message,
|
||||
lint::builtin::DEPRECATED);
|
||||
let (message, lint) =
|
||||
deprecation_message(&depr_entry.attr, &self.def_path_str(def_id));
|
||||
late_report_deprecation(self, &message, None, lint, span, def_id, id);
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -661,27 +699,11 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
if let Some(id) = id {
|
||||
if let Some(stability) = stability {
|
||||
if let Some(depr) = &stability.rustc_depr {
|
||||
let path = self.def_path_str(def_id);
|
||||
if deprecation_in_effect(&depr.since.as_str()) {
|
||||
let message = format!("use of deprecated item '{}'", path);
|
||||
lint_deprecated(def_id,
|
||||
id,
|
||||
Some(depr.reason),
|
||||
depr.suggestion,
|
||||
&message,
|
||||
lint::builtin::DEPRECATED);
|
||||
} else {
|
||||
let message = format!("use of item '{}' \
|
||||
that will be deprecated in future version {}",
|
||||
path,
|
||||
depr.since);
|
||||
lint_deprecated(def_id,
|
||||
id,
|
||||
Some(depr.reason),
|
||||
depr.suggestion,
|
||||
&message,
|
||||
lint::builtin::DEPRECATED_IN_FUTURE);
|
||||
}
|
||||
let (message, lint) =
|
||||
rustc_deprecation_message(depr, &self.def_path_str(def_id));
|
||||
late_report_deprecation(
|
||||
self, &message, depr.suggestion, lint, span, def_id, id
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -231,21 +231,14 @@ impl<'a> base::Resolver for Resolver<'a> {
|
||||
};
|
||||
|
||||
let span = invoc.span();
|
||||
let path = fast_print_path(path);
|
||||
let format = match kind {
|
||||
MacroKind::Derive => format!("derive({})", fast_print_path(path)),
|
||||
_ => fast_print_path(path),
|
||||
MacroKind::Derive => format!("derive({})", path),
|
||||
_ => path.clone(),
|
||||
};
|
||||
invoc.expansion_data.mark.set_expn_info(ext.expn_info(span, &format));
|
||||
|
||||
if let Some(stability) = ext.stability {
|
||||
if let StabilityLevel::Unstable { reason, issue } = stability.level {
|
||||
let (feature, features) = (stability.feature, self.session.features_untracked());
|
||||
if !span.allows_unstable(feature) &&
|
||||
features.declared_lib_features.iter().all(|(feat, _)| *feat != feature) {
|
||||
stability::report_unstable(self.session, feature, reason, issue, span);
|
||||
}
|
||||
}
|
||||
}
|
||||
self.check_stability_and_deprecation(&ext, &path, span);
|
||||
|
||||
if let Res::Def(_, def_id) = res {
|
||||
if after_derive {
|
||||
@ -1017,6 +1010,28 @@ impl<'a> Resolver<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn check_stability_and_deprecation(&self, ext: &SyntaxExtension, path: &str, span: Span) {
|
||||
if let Some(stability) = &ext.stability {
|
||||
if let StabilityLevel::Unstable { reason, issue } = stability.level {
|
||||
let (feature, features) = (stability.feature, self.session.features_untracked());
|
||||
if !span.allows_unstable(feature) &&
|
||||
features.declared_lib_features.iter().all(|(feat, _)| *feat != feature) {
|
||||
stability::report_unstable(self.session, feature, reason, issue, span);
|
||||
}
|
||||
}
|
||||
if let Some(depr) = &stability.rustc_depr {
|
||||
let (message, lint) = stability::rustc_deprecation_message(depr, path);
|
||||
stability::early_report_deprecation(
|
||||
self.session, &message, depr.suggestion, lint, span
|
||||
);
|
||||
}
|
||||
}
|
||||
if let Some(depr) = &ext.deprecation {
|
||||
let (message, lint) = stability::deprecation_message(depr, path);
|
||||
stability::early_report_deprecation(self.session, &message, None, lint, span);
|
||||
}
|
||||
}
|
||||
|
||||
fn prohibit_imported_non_macro_attrs(&self, binding: Option<&'a NameBinding<'a>>,
|
||||
res: Option<Res>, span: Span) {
|
||||
if let Some(Res::NonMacroAttr(kind)) = res {
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::ast::{self, Attribute, Name, PatKind};
|
||||
use crate::attr::{HasAttrs, Stability};
|
||||
use crate::attr::{HasAttrs, Stability, Deprecation};
|
||||
use crate::source_map::{SourceMap, Spanned, respan};
|
||||
use crate::edition::Edition;
|
||||
use crate::ext::expand::{self, AstFragment, Invocation};
|
||||
@ -616,8 +616,10 @@ pub struct SyntaxExtension {
|
||||
pub allow_internal_unsafe: bool,
|
||||
/// Enables the macro helper hack (`ident!(...)` -> `$crate::ident!(...)`) for this macro.
|
||||
pub local_inner_macros: bool,
|
||||
/// The macro's stability and deprecation info.
|
||||
/// The macro's stability info.
|
||||
pub stability: Option<Stability>,
|
||||
/// The macro's deprecation info.
|
||||
pub deprecation: Option<Deprecation>,
|
||||
/// Names of helper attributes registered by this macro.
|
||||
pub helper_attrs: Vec<Symbol>,
|
||||
/// Edition of the crate in which this macro is defined.
|
||||
@ -663,6 +665,7 @@ impl SyntaxExtension {
|
||||
allow_internal_unsafe: false,
|
||||
local_inner_macros: false,
|
||||
stability: None,
|
||||
deprecation: None,
|
||||
helper_attrs: Vec::new(),
|
||||
edition,
|
||||
kind,
|
||||
|
@ -437,6 +437,7 @@ pub fn compile(
|
||||
allow_internal_unsafe: attr::contains_name(&def.attrs, sym::allow_internal_unsafe),
|
||||
local_inner_macros,
|
||||
stability: attr::find_stability(&sess, &def.attrs, def.span),
|
||||
deprecation: attr::find_deprecation(&sess, &def.attrs, def.span),
|
||||
helper_attrs: Vec::new(),
|
||||
edition,
|
||||
}
|
||||
|
3
src/test/ui/macros/auxiliary/deprecated-macros.rs
Normal file
3
src/test/ui/macros/auxiliary/deprecated-macros.rs
Normal file
@ -0,0 +1,3 @@
|
||||
#[deprecated(since = "1.0.0", note = "deprecation note")]
|
||||
#[macro_export]
|
||||
macro_rules! deprecated_macro{ () => () }
|
@ -1,6 +1,16 @@
|
||||
#![feature(decl_macro)]
|
||||
#![feature(staged_api)]
|
||||
#![stable(feature = "unit_test", since = "1.0.0")]
|
||||
|
||||
#[unstable(feature = "unstable_macros", issue = "0")]
|
||||
#[macro_export]
|
||||
macro_rules! unstable_macro{ () => () }
|
||||
|
||||
#[stable(feature = "deprecated_macros", since = "1.0.0")]
|
||||
#[rustc_deprecated(since = "1.0.0", reason = "deprecation reason")]
|
||||
#[macro_export]
|
||||
macro_rules! deprecated_macro{ () => () }
|
||||
|
||||
// FIXME: Cannot use a `pub` macro 2.0 in a staged API crate due to reachability issues.
|
||||
// #[unstable(feature = "unstable_macros", issue = "0")]
|
||||
// pub macro unstable_macro_modern() {}
|
||||
|
13
src/test/ui/macros/macro-deprecation.rs
Normal file
13
src/test/ui/macros/macro-deprecation.rs
Normal file
@ -0,0 +1,13 @@
|
||||
// compile-pass
|
||||
// aux-build:deprecated-macros.rs
|
||||
|
||||
#[macro_use] extern crate deprecated_macros;
|
||||
|
||||
#[deprecated(since = "1.0.0", note = "local deprecation note")]
|
||||
#[macro_export]
|
||||
macro_rules! local_deprecated{ () => () }
|
||||
|
||||
fn main() {
|
||||
local_deprecated!(); //~ WARN use of deprecated item 'local_deprecated': local deprecation note
|
||||
deprecated_macro!(); //~ WARN use of deprecated item 'deprecated_macro': deprecation note
|
||||
}
|
14
src/test/ui/macros/macro-deprecation.stderr
Normal file
14
src/test/ui/macros/macro-deprecation.stderr
Normal file
@ -0,0 +1,14 @@
|
||||
warning: use of deprecated item 'local_deprecated': local deprecation note
|
||||
--> $DIR/macro-deprecation.rs:11:5
|
||||
|
|
||||
LL | local_deprecated!();
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: #[warn(deprecated)] on by default
|
||||
|
||||
warning: use of deprecated item 'deprecated_macro': deprecation note
|
||||
--> $DIR/macro-deprecation.rs:12:5
|
||||
|
|
||||
LL | deprecated_macro!();
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
@ -1,12 +1,28 @@
|
||||
// aux-build:unstable-macros.rs
|
||||
|
||||
#![feature(decl_macro)]
|
||||
#![feature(staged_api)]
|
||||
#[macro_use] extern crate unstable_macros;
|
||||
|
||||
#[unstable(feature = "local_unstable", issue = "0")]
|
||||
macro_rules! local_unstable { () => () }
|
||||
|
||||
#[unstable(feature = "local_unstable", issue = "0")]
|
||||
macro local_unstable_modern() {}
|
||||
|
||||
#[stable(feature = "deprecated_macros", since = "1.0.0")]
|
||||
#[rustc_deprecated(since = "1.0.0", reason = "local deprecation reason")]
|
||||
#[macro_export]
|
||||
macro_rules! local_deprecated{ () => () }
|
||||
|
||||
fn main() {
|
||||
local_unstable!(); //~ ERROR use of unstable library feature 'local_unstable'
|
||||
local_unstable_modern!(); //~ ERROR use of unstable library feature 'local_unstable'
|
||||
unstable_macro!(); //~ ERROR use of unstable library feature 'unstable_macros'
|
||||
// unstable_macro_modern!(); // ERROR use of unstable library feature 'unstable_macros'
|
||||
|
||||
deprecated_macro!();
|
||||
//~^ WARN use of deprecated item 'deprecated_macro': deprecation reason
|
||||
local_deprecated!();
|
||||
//~^ WARN use of deprecated item 'local_deprecated': local deprecation reason
|
||||
}
|
||||
|
@ -1,19 +1,41 @@
|
||||
error[E0658]: use of unstable library feature 'local_unstable'
|
||||
--> $DIR/macro-stability.rs:10:5
|
||||
--> $DIR/macro-stability.rs:19:5
|
||||
|
|
||||
LL | local_unstable!();
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: add #![feature(local_unstable)] to the crate attributes to enable
|
||||
|
||||
error[E0658]: use of unstable library feature 'local_unstable'
|
||||
--> $DIR/macro-stability.rs:20:5
|
||||
|
|
||||
LL | local_unstable_modern!();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: add #![feature(local_unstable)] to the crate attributes to enable
|
||||
|
||||
error[E0658]: use of unstable library feature 'unstable_macros'
|
||||
--> $DIR/macro-stability.rs:11:5
|
||||
--> $DIR/macro-stability.rs:21:5
|
||||
|
|
||||
LL | unstable_macro!();
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: add #![feature(unstable_macros)] to the crate attributes to enable
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
warning: use of deprecated item 'deprecated_macro': deprecation reason
|
||||
--> $DIR/macro-stability.rs:24:5
|
||||
|
|
||||
LL | deprecated_macro!();
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: #[warn(deprecated)] on by default
|
||||
|
||||
warning: use of deprecated item 'local_deprecated': local deprecation reason
|
||||
--> $DIR/macro-stability.rs:26:5
|
||||
|
|
||||
LL | local_deprecated!();
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
||||
|
Loading…
Reference in New Issue
Block a user