Skip to content

Commit d1f5f1d

Browse files
authored
Rollup merge of #83127 - Aaron1011:time-macros-impl-warn, r=petrochenkov
Introduce `proc_macro_back_compat` lint, and emit for `time-macros-impl` Now that future-incompat-report support has landed in nightly Cargo, we can start to make progress towards removing the various proc-macro back-compat hacks that have accumulated in the compiler. This PR introduces a new lint `proc_macro_back_compat`, which results in a future-incompat-report entry being generated. All proc-macro back-compat warnings will be grouped under this lint. Note that this lint will never actually become a hard error - instead, we will remove the special cases for various macros, which will cause older versions of those crates to emit some other error. I've added code to fire this lint for the `time-macros-impl` case. This is the easiest case out of all of our current back-compat hacks - the crate was renamed to `time-macros`, so seeing a filename with `time-macros-impl` guarantees that an older version of the parent `time` crate is in use. When Cargo's future-incompat-report feature gets stabilized, affected users will start to see future-incompat warnings when they build their crates.
2 parents 8ec9b2a + f190bc4 commit d1f5f1d

File tree

8 files changed

+206
-65
lines changed

8 files changed

+206
-65
lines changed

compiler/rustc_ast/src/token.rs

+1-49
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,9 @@ use crate::tokenstream::TokenTree;
1111
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
1212
use rustc_data_structures::sync::Lrc;
1313
use rustc_macros::HashStable_Generic;
14-
use rustc_span::hygiene::ExpnKind;
15-
use rustc_span::source_map::SourceMap;
1614
use rustc_span::symbol::{kw, sym};
1715
use rustc_span::symbol::{Ident, Symbol};
18-
use rustc_span::{self, edition::Edition, FileName, RealFileName, Span, DUMMY_SP};
16+
use rustc_span::{self, edition::Edition, Span, DUMMY_SP};
1917
use std::borrow::Cow;
2018
use std::{fmt, mem};
2119

@@ -813,52 +811,6 @@ impl Nonterminal {
813811
}
814812
false
815813
}
816-
817-
// See issue #74616 for details
818-
pub fn ident_name_compatibility_hack(
819-
&self,
820-
orig_span: Span,
821-
source_map: &SourceMap,
822-
) -> Option<(Ident, bool)> {
823-
if let NtIdent(ident, is_raw) = self {
824-
if let ExpnKind::Macro(_, macro_name) = orig_span.ctxt().outer_expn_data().kind {
825-
let filename = source_map.span_to_filename(orig_span);
826-
if let FileName::Real(RealFileName::Named(path)) = filename {
827-
let matches_prefix = |prefix, filename| {
828-
// Check for a path that ends with 'prefix*/src/<filename>'
829-
let mut iter = path.components().rev();
830-
iter.next().and_then(|p| p.as_os_str().to_str()) == Some(filename)
831-
&& iter.next().and_then(|p| p.as_os_str().to_str()) == Some("src")
832-
&& iter
833-
.next()
834-
.and_then(|p| p.as_os_str().to_str())
835-
.map_or(false, |p| p.starts_with(prefix))
836-
};
837-
838-
if (macro_name == sym::impl_macros
839-
&& matches_prefix("time-macros-impl", "lib.rs"))
840-
|| (macro_name == sym::arrays && matches_prefix("js-sys", "lib.rs"))
841-
{
842-
let snippet = source_map.span_to_snippet(orig_span);
843-
if snippet.as_deref() == Ok("$name") {
844-
return Some((*ident, *is_raw));
845-
}
846-
}
847-
848-
if macro_name == sym::tuple_from_req
849-
&& (matches_prefix("actix-web", "extract.rs")
850-
|| matches_prefix("actori-web", "extract.rs"))
851-
{
852-
let snippet = source_map.span_to_snippet(orig_span);
853-
if snippet.as_deref() == Ok("$T") {
854-
return Some((*ident, *is_raw));
855-
}
856-
}
857-
}
858-
}
859-
}
860-
None
861-
}
862814
}
863815

864816
impl PartialEq for Nonterminal {

compiler/rustc_expand/src/proc_macro_server.rs

+66-4
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,21 @@ use crate::base::ExtCtxt;
22

33
use rustc_ast as ast;
44
use rustc_ast::token;
5+
use rustc_ast::token::Nonterminal;
6+
use rustc_ast::token::NtIdent;
57
use rustc_ast::tokenstream::{self, CanSynthesizeMissingTokens};
68
use rustc_ast::tokenstream::{DelimSpan, Spacing::*, TokenStream, TreeAndSpacing};
79
use rustc_ast_pretty::pprust;
810
use rustc_data_structures::sync::Lrc;
911
use rustc_errors::Diagnostic;
12+
use rustc_lint_defs::builtin::PROC_MACRO_BACK_COMPAT;
13+
use rustc_lint_defs::BuiltinLintDiagnostics;
1014
use rustc_parse::lexer::nfc_normalize;
1115
use rustc_parse::{nt_to_tokenstream, parse_stream_from_source_str};
1216
use rustc_session::parse::ParseSess;
17+
use rustc_span::hygiene::ExpnKind;
1318
use rustc_span::symbol::{self, kw, sym, Symbol};
14-
use rustc_span::{BytePos, FileName, MultiSpan, Pos, SourceFile, Span};
19+
use rustc_span::{BytePos, FileName, MultiSpan, Pos, RealFileName, SourceFile, Span};
1520

1621
use pm::bridge::{server, TokenTree};
1722
use pm::{Delimiter, Level, LineColumn, Spacing};
@@ -174,9 +179,7 @@ impl FromInternal<(TreeAndSpacing, &'_ ParseSess, &'_ mut Vec<Self>)>
174179
}
175180

176181
Interpolated(nt) => {
177-
if let Some((name, is_raw)) =
178-
nt.ident_name_compatibility_hack(span, sess.source_map())
179-
{
182+
if let Some((name, is_raw)) = ident_name_compatibility_hack(&nt, span, sess) {
180183
TokenTree::Ident(Ident::new(sess, name.name, is_raw, name.span))
181184
} else {
182185
let stream = nt_to_tokenstream(&nt, sess, CanSynthesizeMissingTokens::No);
@@ -711,3 +714,62 @@ impl server::Span for Rustc<'_> {
711714
self.sess.source_map().span_to_snippet(span).ok()
712715
}
713716
}
717+
718+
// See issue #74616 for details
719+
fn ident_name_compatibility_hack(
720+
nt: &Nonterminal,
721+
orig_span: Span,
722+
sess: &ParseSess,
723+
) -> Option<(rustc_span::symbol::Ident, bool)> {
724+
if let NtIdent(ident, is_raw) = nt {
725+
if let ExpnKind::Macro(_, macro_name) = orig_span.ctxt().outer_expn_data().kind {
726+
let source_map = sess.source_map();
727+
let filename = source_map.span_to_filename(orig_span);
728+
if let FileName::Real(RealFileName::Named(path)) = filename {
729+
let matches_prefix = |prefix, filename| {
730+
// Check for a path that ends with 'prefix*/src/<filename>'
731+
let mut iter = path.components().rev();
732+
iter.next().and_then(|p| p.as_os_str().to_str()) == Some(filename)
733+
&& iter.next().and_then(|p| p.as_os_str().to_str()) == Some("src")
734+
&& iter
735+
.next()
736+
.and_then(|p| p.as_os_str().to_str())
737+
.map_or(false, |p| p.starts_with(prefix))
738+
};
739+
740+
let time_macros_impl =
741+
macro_name == sym::impl_macros && matches_prefix("time-macros-impl", "lib.rs");
742+
if time_macros_impl
743+
|| (macro_name == sym::arrays && matches_prefix("js-sys", "lib.rs"))
744+
{
745+
let snippet = source_map.span_to_snippet(orig_span);
746+
if snippet.as_deref() == Ok("$name") {
747+
if time_macros_impl {
748+
sess.buffer_lint_with_diagnostic(
749+
&PROC_MACRO_BACK_COMPAT,
750+
orig_span,
751+
ast::CRATE_NODE_ID,
752+
"using an old version of `time-macros-impl`",
753+
BuiltinLintDiagnostics::ProcMacroBackCompat(
754+
"the `time-macros-impl` crate will stop compiling in futures version of Rust. \
755+
Please update to the latest version of the `time` crate to avoid breakage".to_string())
756+
);
757+
}
758+
return Some((*ident, *is_raw));
759+
}
760+
}
761+
762+
if macro_name == sym::tuple_from_req
763+
&& (matches_prefix("actix-web", "extract.rs")
764+
|| matches_prefix("actori-web", "extract.rs"))
765+
{
766+
let snippet = source_map.span_to_snippet(orig_span);
767+
if snippet.as_deref() == Ok("$T") {
768+
return Some((*ident, *is_raw));
769+
}
770+
}
771+
}
772+
}
773+
}
774+
None
775+
}

compiler/rustc_lint/src/context.rs

+3
Original file line numberDiff line numberDiff line change
@@ -670,6 +670,9 @@ pub trait LintContext: Sized {
670670
json
671671
);
672672
}
673+
BuiltinLintDiagnostics::ProcMacroBackCompat(note) => {
674+
db.note(&note);
675+
}
673676
}
674677
// Rewrap `db`, and pass control to the user.
675678
decorate(LintDiagnosticBuilder::new(db));

compiler/rustc_lint_defs/src/builtin.rs

+52-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
//! compiler code, rather than using their own custom pass. Those
77
//! lints are all available in `rustc_lint::builtin`.
88
9-
use crate::{declare_lint, declare_lint_pass};
9+
use crate::{declare_lint, declare_lint_pass, FutureBreakage};
1010
use rustc_span::edition::Edition;
1111

1212
declare_lint! {
@@ -2955,6 +2955,7 @@ declare_lint_pass! {
29552955
SEMICOLON_IN_EXPRESSIONS_FROM_MACROS,
29562956
DISJOINT_CAPTURE_DROP_REORDER,
29572957
LEGACY_DERIVE_HELPERS,
2958+
PROC_MACRO_BACK_COMPAT,
29582959
]
29592960
}
29602961

@@ -3082,3 +3083,53 @@ declare_lint! {
30823083
edition: None,
30833084
};
30843085
}
3086+
3087+
declare_lint! {
3088+
/// The `proc_macro_back_compat` lint detects uses of old versions of certain
3089+
/// proc-macro crates, which have hardcoded workarounds in the compiler.
3090+
///
3091+
/// ### Example
3092+
///
3093+
/// ```rust,ignore (needs-dependency)
3094+
///
3095+
/// use time_macros_impl::impl_macros;
3096+
/// struct Foo;
3097+
/// impl_macros!(Foo);
3098+
/// ```
3099+
///
3100+
/// This will produce:
3101+
///
3102+
/// ```text
3103+
/// warning: using an old version of `time-macros-impl`
3104+
/// ::: $DIR/group-compat-hack.rs:27:5
3105+
/// |
3106+
/// LL | impl_macros!(Foo);
3107+
/// | ------------------ in this macro invocation
3108+
/// |
3109+
/// = note: `#[warn(proc_macro_back_compat)]` on by default
3110+
/// = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
3111+
/// = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
3112+
/// = note: the `time-macros-impl` crate will stop compiling in futures version of Rust. Please update to the latest version of the `time` crate to avoid breakage
3113+
/// = note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
3114+
/// ```
3115+
///
3116+
/// ### Explanation
3117+
///
3118+
/// Eventually, the backwards-compatibility hacks present in the compiler will be removed,
3119+
/// causing older versions of certain crates to stop compiling.
3120+
/// This is a [future-incompatible] lint to ease the transition to an error.
3121+
/// See [issue #83125] for more details.
3122+
///
3123+
/// [issue #83125]: https://github.com/rust-lang/rust/issues/83125
3124+
/// [future-incompatible]: ../index.md#future-incompatible-lints
3125+
pub PROC_MACRO_BACK_COMPAT,
3126+
Warn,
3127+
"detects usage of old versions of certain proc-macro crates",
3128+
@future_incompatible = FutureIncompatibleInfo {
3129+
reference: "issue #83125 <https://github.com/rust-lang/rust/issues/83125>",
3130+
edition: None,
3131+
future_breakage: Some(FutureBreakage {
3132+
date: None
3133+
})
3134+
};
3135+
}

compiler/rustc_lint_defs/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,7 @@ pub enum BuiltinLintDiagnostics {
266266
PatternsInFnsWithoutBody(Span, Ident),
267267
LegacyDeriveHelpers(Span),
268268
ExternDepSpec(String, ExternDepSpec),
269+
ProcMacroBackCompat(String),
269270
}
270271

271272
/// Lints that are buffered up early on in the `Session` before the

src/test/ui/proc-macro/group-compat-hack/group-compat-hack.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ mod no_version {
2424
}
2525

2626
struct Foo;
27-
impl_macros!(Foo);
27+
impl_macros!(Foo); //~ WARN using an old version
28+
//~| WARN this was previously
2829
arrays!(Foo);
2930
other!(Foo);
3031
}
@@ -40,7 +41,8 @@ mod with_version {
4041
}
4142

4243
struct Foo;
43-
impl_macros!(Foo);
44+
impl_macros!(Foo); //~ WARN using an old version
45+
//~| WARN this was previously
4446
arrays!(Foo);
4547
other!(Foo);
4648
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
warning: using an old version of `time-macros-impl`
2+
--> $DIR/time-macros-impl/src/lib.rs:5:32
3+
|
4+
LL | #[my_macro] struct One($name);
5+
| ^^^^^
6+
|
7+
::: $DIR/group-compat-hack.rs:27:5
8+
|
9+
LL | impl_macros!(Foo);
10+
| ------------------ in this macro invocation
11+
|
12+
= note: `#[warn(proc_macro_back_compat)]` on by default
13+
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
14+
= note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
15+
= note: the `time-macros-impl` crate will stop compiling in futures version of Rust. Please update to the latest version of the `time` crate to avoid breakage
16+
= note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
17+
18+
warning: using an old version of `time-macros-impl`
19+
--> $DIR/time-macros-impl-0.1.0/src/lib.rs:5:32
20+
|
21+
LL | #[my_macro] struct One($name);
22+
| ^^^^^
23+
|
24+
::: $DIR/group-compat-hack.rs:44:5
25+
|
26+
LL | impl_macros!(Foo);
27+
| ------------------ in this macro invocation
28+
|
29+
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
30+
= note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
31+
= note: the `time-macros-impl` crate will stop compiling in futures version of Rust. Please update to the latest version of the `time` crate to avoid breakage
32+
= note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
33+
34+
warning: 2 warnings emitted
35+
36+
Future incompatibility report: Future breakage date: None, diagnostic:
37+
warning: using an old version of `time-macros-impl`
38+
--> $DIR/time-macros-impl/src/lib.rs:5:32
39+
|
40+
LL | #[my_macro] struct One($name);
41+
| ^^^^^
42+
|
43+
::: $DIR/group-compat-hack.rs:27:5
44+
|
45+
LL | impl_macros!(Foo);
46+
| ------------------ in this macro invocation
47+
|
48+
= note: `#[warn(proc_macro_back_compat)]` on by default
49+
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
50+
= note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
51+
= note: the `time-macros-impl` crate will stop compiling in futures version of Rust. Please update to the latest version of the `time` crate to avoid breakage
52+
= note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
53+
54+
Future breakage date: None, diagnostic:
55+
warning: using an old version of `time-macros-impl`
56+
--> $DIR/time-macros-impl-0.1.0/src/lib.rs:5:32
57+
|
58+
LL | #[my_macro] struct One($name);
59+
| ^^^^^
60+
|
61+
::: $DIR/group-compat-hack.rs:44:5
62+
|
63+
LL | impl_macros!(Foo);
64+
| ------------------ in this macro invocation
65+
|
66+
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
67+
= note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
68+
= note: the `time-macros-impl` crate will stop compiling in futures version of Rust. Please update to the latest version of the `time` crate to avoid breakage
69+
= note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
70+

0 commit comments

Comments
 (0)