Skip to content

Commit 0817fc6

Browse files
committed
Support deprecation checking for macros
1 parent d9ee97e commit 0817fc6

File tree

11 files changed

+203
-79
lines changed

11 files changed

+203
-79
lines changed

src/librustc/lint/builtin.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@
55
//! lints are all available in `rustc_lint::builtin`.
66
77
use crate::lint::{LintPass, LateLintPass, LintArray};
8+
use crate::middle::stability;
89
use crate::session::Session;
910
use errors::{Applicability, DiagnosticBuilder};
1011
use syntax::ast;
1112
use syntax::source_map::Span;
13+
use syntax::symbol::Symbol;
1214

1315
declare_lint! {
1416
pub EXCEEDING_BITSHIFTS,
@@ -461,6 +463,7 @@ pub enum BuiltinLintDiagnostics {
461463
UnusedImports(String, Vec<(Span, String)>),
462464
NestedImplTrait { outer_impl_trait_span: Span, inner_impl_trait_span: Span },
463465
RedundantImport(Vec<(Span, bool)>, ast::Ident),
466+
DeprecatedMacro(Option<Symbol>, Span),
464467
}
465468

466469
pub(crate) fn add_elided_lifetime_in_path_suggestion(
@@ -586,6 +589,8 @@ impl BuiltinLintDiagnostics {
586589
);
587590
}
588591
}
592+
BuiltinLintDiagnostics::DeprecatedMacro(suggestion, span) =>
593+
stability::deprecation_suggestion(db, suggestion, span),
589594
}
590595
}
591596
}

src/librustc/middle/stability.rs

Lines changed: 85 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,21 @@
44
pub use self::StabilityLevel::*;
55

66
use crate::lint::{self, Lint, in_derive_expansion};
7+
use crate::lint::builtin::BuiltinLintDiagnostics;
78
use crate::hir::{self, Item, Generics, StructField, Variant, HirId};
89
use crate::hir::def::{Res, DefKind};
910
use crate::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId, LOCAL_CRATE};
1011
use crate::hir::intravisit::{self, Visitor, NestedVisitorMap};
1112
use crate::ty::query::Providers;
1213
use crate::middle::privacy::AccessLevels;
1314
use crate::session::{DiagnosticMessageId, Session};
15+
use errors::DiagnosticBuilder;
1416
use syntax::symbol::{Symbol, sym};
1517
use syntax_pos::{Span, MultiSpan};
16-
use syntax::ast::Attribute;
18+
use syntax::ast::{Attribute, CRATE_NODE_ID};
1719
use syntax::errors::Applicability;
1820
use syntax::feature_gate::{GateIssue, emit_feature_err};
19-
use syntax::attr::{self, Stability, Deprecation};
21+
use syntax::attr::{self, Stability, Deprecation, RustcDeprecation};
2022
use crate::ty::{self, TyCtxt};
2123
use crate::util::nodemap::{FxHashSet, FxHashMap};
2224

@@ -531,6 +533,79 @@ pub fn deprecation_in_effect(since: &str) -> bool {
531533
}
532534
}
533535

536+
pub fn deprecation_suggestion(
537+
diag: &mut DiagnosticBuilder<'_>, suggestion: Option<Symbol>, span: Span
538+
) {
539+
if let Some(suggestion) = suggestion {
540+
diag.span_suggestion(
541+
span,
542+
"replace the use of the deprecated item",
543+
suggestion.to_string(),
544+
Applicability::MachineApplicable,
545+
);
546+
}
547+
}
548+
549+
fn deprecation_message_common(message: String, reason: Option<Symbol>) -> String {
550+
match reason {
551+
Some(reason) => format!("{}: {}", message, reason),
552+
None => message,
553+
}
554+
}
555+
556+
pub fn deprecation_message(depr: &Deprecation, path: &str) -> (String, &'static Lint) {
557+
let message = format!("use of deprecated item '{}'", path);
558+
(deprecation_message_common(message, depr.note), lint::builtin::DEPRECATED)
559+
}
560+
561+
pub fn rustc_deprecation_message(depr: &RustcDeprecation, path: &str) -> (String, &'static Lint) {
562+
let (message, lint) = if deprecation_in_effect(&depr.since.as_str()) {
563+
(format!("use of deprecated item '{}'", path), lint::builtin::DEPRECATED)
564+
} else {
565+
(format!("use of item '{}' that will be deprecated in future version {}", path, depr.since),
566+
lint::builtin::DEPRECATED_IN_FUTURE)
567+
};
568+
(deprecation_message_common(message, Some(depr.reason)), lint)
569+
}
570+
571+
pub fn early_report_deprecation(
572+
sess: &Session,
573+
message: &str,
574+
suggestion: Option<Symbol>,
575+
lint: &'static Lint,
576+
span: Span,
577+
) {
578+
if in_derive_expansion(span) {
579+
return;
580+
}
581+
582+
let diag = BuiltinLintDiagnostics::DeprecatedMacro(suggestion, span);
583+
sess.buffer_lint_with_diagnostic(lint, CRATE_NODE_ID, span, message, diag);
584+
}
585+
586+
fn late_report_deprecation(
587+
tcx: TyCtxt<'_>,
588+
message: &str,
589+
suggestion: Option<Symbol>,
590+
lint: &'static Lint,
591+
span: Span,
592+
def_id: DefId,
593+
hir_id: HirId,
594+
) {
595+
if in_derive_expansion(span) {
596+
return;
597+
}
598+
599+
let mut diag = tcx.struct_span_lint_hir(lint, hir_id, span, message);
600+
if let hir::Node::Expr(_) = tcx.hir().get(hir_id) {
601+
deprecation_suggestion(&mut diag, suggestion, span);
602+
}
603+
diag.emit();
604+
if hir_id == hir::DUMMY_HIR_ID {
605+
span_bug!(span, "emitted a {} lint with dummy HIR id: {:?}", lint.name, def_id);
606+
}
607+
}
608+
534609
struct Checker<'tcx> {
535610
tcx: TyCtxt<'tcx>,
536611
}
@@ -593,38 +668,6 @@ impl<'tcx> TyCtxt<'tcx> {
593668
/// deprecated. If the item is indeed deprecated, we will emit a deprecation lint attached to
594669
/// `id`.
595670
pub fn eval_stability(self, def_id: DefId, id: Option<HirId>, span: Span) -> EvalResult {
596-
let lint_deprecated = |def_id: DefId,
597-
id: HirId,
598-
note: Option<Symbol>,
599-
suggestion: Option<Symbol>,
600-
message: &str,
601-
lint: &'static Lint| {
602-
if in_derive_expansion(span) {
603-
return;
604-
}
605-
let msg = if let Some(note) = note {
606-
format!("{}: {}", message, note)
607-
} else {
608-
format!("{}", message)
609-
};
610-
611-
let mut diag = self.struct_span_lint_hir(lint, id, span, &msg);
612-
if let Some(suggestion) = suggestion {
613-
if let hir::Node::Expr(_) = self.hir().get(id) {
614-
diag.span_suggestion(
615-
span,
616-
"replace the use of the deprecated item",
617-
suggestion.to_string(),
618-
Applicability::MachineApplicable,
619-
);
620-
}
621-
}
622-
diag.emit();
623-
if id == hir::DUMMY_HIR_ID {
624-
span_bug!(span, "emitted a {} lint with dummy HIR id: {:?}", lint.name, def_id);
625-
}
626-
};
627-
628671
// Deprecated attributes apply in-crate and cross-crate.
629672
if let Some(id) = id {
630673
if let Some(depr_entry) = self.lookup_deprecation_entry(def_id) {
@@ -634,14 +677,9 @@ impl<'tcx> TyCtxt<'tcx> {
634677
.map_or(false, |parent_depr| parent_depr.same_origin(&depr_entry));
635678

636679
if !skip {
637-
let path = self.def_path_str(def_id);
638-
let message = format!("use of deprecated item '{}'", path);
639-
lint_deprecated(def_id,
640-
id,
641-
depr_entry.attr.note,
642-
None,
643-
&message,
644-
lint::builtin::DEPRECATED);
680+
let (message, lint) =
681+
deprecation_message(&depr_entry.attr, &self.def_path_str(def_id));
682+
late_report_deprecation(self, &message, None, lint, span, def_id, id);
645683
}
646684
};
647685
}
@@ -661,27 +699,11 @@ impl<'tcx> TyCtxt<'tcx> {
661699
if let Some(id) = id {
662700
if let Some(stability) = stability {
663701
if let Some(depr) = &stability.rustc_depr {
664-
let path = self.def_path_str(def_id);
665-
if deprecation_in_effect(&depr.since.as_str()) {
666-
let message = format!("use of deprecated item '{}'", path);
667-
lint_deprecated(def_id,
668-
id,
669-
Some(depr.reason),
670-
depr.suggestion,
671-
&message,
672-
lint::builtin::DEPRECATED);
673-
} else {
674-
let message = format!("use of item '{}' \
675-
that will be deprecated in future version {}",
676-
path,
677-
depr.since);
678-
lint_deprecated(def_id,
679-
id,
680-
Some(depr.reason),
681-
depr.suggestion,
682-
&message,
683-
lint::builtin::DEPRECATED_IN_FUTURE);
684-
}
702+
let (message, lint) =
703+
rustc_deprecation_message(depr, &self.def_path_str(def_id));
704+
late_report_deprecation(
705+
self, &message, depr.suggestion, lint, span, def_id, id
706+
);
685707
}
686708
}
687709
}

src/librustc_resolve/macros.rs

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -231,21 +231,14 @@ impl<'a> base::Resolver for Resolver<'a> {
231231
};
232232

233233
let span = invoc.span();
234+
let path = fast_print_path(path);
234235
let format = match kind {
235-
MacroKind::Derive => format!("derive({})", fast_print_path(path)),
236-
_ => fast_print_path(path),
236+
MacroKind::Derive => format!("derive({})", path),
237+
_ => path.clone(),
237238
};
238239
invoc.expansion_data.mark.set_expn_info(ext.expn_info(span, &format));
239240

240-
if let Some(stability) = ext.stability {
241-
if let StabilityLevel::Unstable { reason, issue } = stability.level {
242-
let (feature, features) = (stability.feature, self.session.features_untracked());
243-
if !span.allows_unstable(feature) &&
244-
features.declared_lib_features.iter().all(|(feat, _)| *feat != feature) {
245-
stability::report_unstable(self.session, feature, reason, issue, span);
246-
}
247-
}
248-
}
241+
self.check_stability_and_deprecation(&ext, &path, span);
249242

250243
if let Res::Def(_, def_id) = res {
251244
if after_derive {
@@ -1017,6 +1010,28 @@ impl<'a> Resolver<'a> {
10171010
}
10181011
}
10191012

1013+
fn check_stability_and_deprecation(&self, ext: &SyntaxExtension, path: &str, span: Span) {
1014+
if let Some(stability) = &ext.stability {
1015+
if let StabilityLevel::Unstable { reason, issue } = stability.level {
1016+
let (feature, features) = (stability.feature, self.session.features_untracked());
1017+
if !span.allows_unstable(feature) &&
1018+
features.declared_lib_features.iter().all(|(feat, _)| *feat != feature) {
1019+
stability::report_unstable(self.session, feature, reason, issue, span);
1020+
}
1021+
}
1022+
if let Some(depr) = &stability.rustc_depr {
1023+
let (message, lint) = stability::rustc_deprecation_message(depr, path);
1024+
stability::early_report_deprecation(
1025+
self.session, &message, depr.suggestion, lint, span
1026+
);
1027+
}
1028+
}
1029+
if let Some(depr) = &ext.deprecation {
1030+
let (message, lint) = stability::deprecation_message(depr, path);
1031+
stability::early_report_deprecation(self.session, &message, None, lint, span);
1032+
}
1033+
}
1034+
10201035
fn prohibit_imported_non_macro_attrs(&self, binding: Option<&'a NameBinding<'a>>,
10211036
res: Option<Res>, span: Span) {
10221037
if let Some(Res::NonMacroAttr(kind)) = res {

src/libsyntax/ext/base.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::ast::{self, Attribute, Name, PatKind};
2-
use crate::attr::{HasAttrs, Stability};
2+
use crate::attr::{HasAttrs, Stability, Deprecation};
33
use crate::source_map::{SourceMap, Spanned, respan};
44
use crate::edition::Edition;
55
use crate::ext::expand::{self, AstFragment, Invocation};
@@ -616,8 +616,10 @@ pub struct SyntaxExtension {
616616
pub allow_internal_unsafe: bool,
617617
/// Enables the macro helper hack (`ident!(...)` -> `$crate::ident!(...)`) for this macro.
618618
pub local_inner_macros: bool,
619-
/// The macro's stability and deprecation info.
619+
/// The macro's stability info.
620620
pub stability: Option<Stability>,
621+
/// The macro's deprecation info.
622+
pub deprecation: Option<Deprecation>,
621623
/// Names of helper attributes registered by this macro.
622624
pub helper_attrs: Vec<Symbol>,
623625
/// Edition of the crate in which this macro is defined.
@@ -663,6 +665,7 @@ impl SyntaxExtension {
663665
allow_internal_unsafe: false,
664666
local_inner_macros: false,
665667
stability: None,
668+
deprecation: None,
666669
helper_attrs: Vec::new(),
667670
edition,
668671
kind,

src/libsyntax/ext/tt/macro_rules.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -437,6 +437,7 @@ pub fn compile(
437437
allow_internal_unsafe: attr::contains_name(&def.attrs, sym::allow_internal_unsafe),
438438
local_inner_macros,
439439
stability: attr::find_stability(&sess, &def.attrs, def.span),
440+
deprecation: attr::find_deprecation(&sess, &def.attrs, def.span),
440441
helper_attrs: Vec::new(),
441442
edition,
442443
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#[deprecated(since = "1.0.0", note = "deprecation note")]
2+
#[macro_export]
3+
macro_rules! deprecated_macro{ () => () }
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,16 @@
1+
#![feature(decl_macro)]
12
#![feature(staged_api)]
23
#![stable(feature = "unit_test", since = "1.0.0")]
34

45
#[unstable(feature = "unstable_macros", issue = "0")]
56
#[macro_export]
67
macro_rules! unstable_macro{ () => () }
8+
9+
#[stable(feature = "deprecated_macros", since = "1.0.0")]
10+
#[rustc_deprecated(since = "1.0.0", reason = "deprecation reason")]
11+
#[macro_export]
12+
macro_rules! deprecated_macro{ () => () }
13+
14+
// FIXME: Cannot use a `pub` macro 2.0 in a staged API crate due to reachability issues.
15+
// #[unstable(feature = "unstable_macros", issue = "0")]
16+
// pub macro unstable_macro_modern() {}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// compile-pass
2+
// aux-build:deprecated-macros.rs
3+
4+
#[macro_use] extern crate deprecated_macros;
5+
6+
#[deprecated(since = "1.0.0", note = "local deprecation note")]
7+
#[macro_export]
8+
macro_rules! local_deprecated{ () => () }
9+
10+
fn main() {
11+
local_deprecated!(); //~ WARN use of deprecated item 'local_deprecated': local deprecation note
12+
deprecated_macro!(); //~ WARN use of deprecated item 'deprecated_macro': deprecation note
13+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
warning: use of deprecated item 'local_deprecated': local deprecation note
2+
--> $DIR/macro-deprecation.rs:11:5
3+
|
4+
LL | local_deprecated!();
5+
| ^^^^^^^^^^^^^^^^^^^^
6+
|
7+
= note: #[warn(deprecated)] on by default
8+
9+
warning: use of deprecated item 'deprecated_macro': deprecation note
10+
--> $DIR/macro-deprecation.rs:12:5
11+
|
12+
LL | deprecated_macro!();
13+
| ^^^^^^^^^^^^^^^^^^^^
14+

src/test/ui/macros/macro-stability.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,28 @@
11
// aux-build:unstable-macros.rs
22

3+
#![feature(decl_macro)]
34
#![feature(staged_api)]
45
#[macro_use] extern crate unstable_macros;
56

67
#[unstable(feature = "local_unstable", issue = "0")]
78
macro_rules! local_unstable { () => () }
89

10+
#[unstable(feature = "local_unstable", issue = "0")]
11+
macro local_unstable_modern() {}
12+
13+
#[stable(feature = "deprecated_macros", since = "1.0.0")]
14+
#[rustc_deprecated(since = "1.0.0", reason = "local deprecation reason")]
15+
#[macro_export]
16+
macro_rules! local_deprecated{ () => () }
17+
918
fn main() {
1019
local_unstable!(); //~ ERROR use of unstable library feature 'local_unstable'
20+
local_unstable_modern!(); //~ ERROR use of unstable library feature 'local_unstable'
1121
unstable_macro!(); //~ ERROR use of unstable library feature 'unstable_macros'
22+
// unstable_macro_modern!(); // ERROR use of unstable library feature 'unstable_macros'
23+
24+
deprecated_macro!();
25+
//~^ WARN use of deprecated item 'deprecated_macro': deprecation reason
26+
local_deprecated!();
27+
//~^ WARN use of deprecated item 'local_deprecated': local deprecation reason
1228
}

0 commit comments

Comments
 (0)