Auto merge of #56203 - aheart:master, r=varkor

Add lint for items deprecated in future

Resolves #55892
diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs
index b7759a8..82145f6 100644
--- a/src/librustc/lint/builtin.rs
+++ b/src/librustc/lint/builtin.rs
@@ -365,6 +365,13 @@
     }
 }
 
+declare_lint! {
+    pub DEPRECATED_IN_FUTURE,
+    Allow,
+    "detects use of items that will be deprecated in a future version",
+    report_in_external_macro: true
+}
+
 /// Does nothing as a lint pass, but registers some `Lint`s
 /// that are used by other parts of the compiler.
 #[derive(Copy, Clone)]
@@ -427,6 +434,7 @@
             MACRO_USE_EXTERN_CRATE,
             MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS,
             parser::QUESTION_MARK_MACRO_SEP,
+            DEPRECATED_IN_FUTURE,
         )
     }
 }
diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs
index ab379c9..61341cb 100644
--- a/src/librustc/middle/stability.rs
+++ b/src/librustc/middle/stability.rs
@@ -13,7 +13,7 @@
 
 pub use self::StabilityLevel::*;
 
-use lint;
+use lint::{self, Lint};
 use hir::{self, Item, Generics, StructField, Variant, HirId};
 use hir::def::Def;
 use hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId, LOCAL_CRATE};
@@ -562,18 +562,20 @@
             return EvalResult::Allow;
         }
 
-        let lint_deprecated = |def_id: DefId, id: NodeId, note: Option<Symbol>| {
-            let path = self.item_path_str(def_id);
-
+        let lint_deprecated = |def_id: DefId,
+                               id: NodeId,
+                               note: Option<Symbol>,
+                               message: &str,
+                               lint: &'static Lint| {
             let msg = if let Some(note) = note {
-                format!("use of deprecated item '{}': {}", path, note)
+                format!("{}: {}", message, note)
             } else {
-                format!("use of deprecated item '{}'", path)
+                format!("{}", message)
             };
 
-            self.lint_node(lint::builtin::DEPRECATED, id, span, &msg);
+            self.lint_node(lint, id, span, &msg);
             if id == ast::DUMMY_NODE_ID {
-                span_bug!(span, "emitted a deprecated lint with dummy node id: {:?}", def_id);
+                span_bug!(span, "emitted a {} lint with dummy node id: {:?}", lint.name, def_id);
             }
         };
 
@@ -584,17 +586,39 @@
                 // version, then we should display no warning message.
                 let deprecated_in_future_version = if let Some(sym) = depr_entry.attr.since {
                     let since = sym.as_str();
-                    !deprecation_in_effect(&since)
+                    if !deprecation_in_effect(&since) {
+                        Some(since)
+                    } else {
+                        None
+                    }
                 } else {
-                    false
+                    None
                 };
 
                 let parent_def_id = self.hir().local_def_id(self.hir().get_parent(id));
-                let skip = deprecated_in_future_version ||
-                           self.lookup_deprecation_entry(parent_def_id)
+                let skip = self.lookup_deprecation_entry(parent_def_id)
                                .map_or(false, |parent_depr| parent_depr.same_origin(&depr_entry));
-                if !skip {
-                    lint_deprecated(def_id, id, depr_entry.attr.note);
+
+                if let Some(since) = deprecated_in_future_version {
+                    let path = self.item_path_str(def_id);
+                    let message = format!("use of item '{}' \
+                                           that will be deprecated in future version {}",
+                                          path,
+                                          since);
+
+                    lint_deprecated(def_id,
+                                    id,
+                                    depr_entry.attr.note,
+                                    &message,
+                                    lint::builtin::DEPRECATED_IN_FUTURE);
+                } else if !skip {
+                    let path = self.item_path_str(def_id);
+                    let message = format!("use of deprecated item '{}'", path);
+                    lint_deprecated(def_id,
+                                    id,
+                                    depr_entry.attr.note,
+                                    &message,
+                                    lint::builtin::DEPRECATED);
                 }
             };
         }
@@ -614,8 +638,24 @@
         if let Some(&Stability{rustc_depr: Some(attr::RustcDeprecation { reason, since }), ..})
                 = stability {
             if let Some(id) = id {
+                let path = self.item_path_str(def_id);
                 if deprecation_in_effect(&since.as_str()) {
-                    lint_deprecated(def_id, id, Some(reason));
+                    let message = format!("use of deprecated item '{}'", path);
+                    lint_deprecated(def_id,
+                                    id,
+                                    Some(reason),
+                                    &message,
+                                    lint::builtin::DEPRECATED);
+                } else {
+                    let message = format!("use of item '{}' \
+                                           that will be deprecated in future version {}",
+                                          path,
+                                          since);
+                    lint_deprecated(def_id,
+                                    id,
+                                    Some(reason),
+                                    &message,
+                                    lint::builtin::DEPRECATED_IN_FUTURE);
                 }
             }
         }
diff --git a/src/test/ui/deprecation/deprecation-in-future.rs b/src/test/ui/deprecation/deprecation-in-future.rs
new file mode 100644
index 0000000..c6c6017
--- /dev/null
+++ b/src/test/ui/deprecation/deprecation-in-future.rs
@@ -0,0 +1,12 @@
+// ignore-tidy-linelength
+
+#![deny(deprecated_in_future)]
+
+#[deprecated(since = "99.99.99", note = "text")]
+pub fn deprecated_future() {}
+
+fn test() {
+    deprecated_future(); //~ ERROR use of item 'deprecated_future' that will be deprecated in future version 99.99.99: text
+}
+
+fn main() {}
diff --git a/src/test/ui/deprecation/deprecation-in-future.stderr b/src/test/ui/deprecation/deprecation-in-future.stderr
new file mode 100644
index 0000000..38392cf
--- /dev/null
+++ b/src/test/ui/deprecation/deprecation-in-future.stderr
@@ -0,0 +1,14 @@
+error: use of item 'deprecated_future' that will be deprecated in future version 99.99.99: text
+  --> $DIR/deprecation-in-future.rs:9:5
+   |
+LL |     deprecated_future(); //~ ERROR use of item 'deprecated_future' that will be deprecated in future version 99.99.99: text
+   |     ^^^^^^^^^^^^^^^^^
+   |
+note: lint level defined here
+  --> $DIR/deprecation-in-future.rs:3:9
+   |
+LL | #![deny(deprecated_in_future)]
+   |         ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+