From a6915218672f3a929343df10c3a9e1059c9e8bf1 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Sat, 2 May 2020 18:16:36 +0200 Subject: [PATCH 01/10] typo --- src/librustc_infer/infer/nll_relate/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_infer/infer/nll_relate/mod.rs b/src/librustc_infer/infer/nll_relate/mod.rs index 0fb926d94166a..a2907e6e373b8 100644 --- a/src/librustc_infer/infer/nll_relate/mod.rs +++ b/src/librustc_infer/infer/nll_relate/mod.rs @@ -657,7 +657,7 @@ where // Reset the ambient variance to covariant. This is needed // to correctly handle cases like // - // for<'a> fn(&'a u32, &'a u3) == for<'b, 'c> fn(&'b u32, &'c u32) + // for<'a> fn(&'a u32, &'a u32) == for<'b, 'c> fn(&'b u32, &'c u32) // // Somewhat surprisingly, these two types are actually // **equal**, even though the one on the right looks more From 902aa62d51210403787f54b881918319e51866c2 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Thu, 16 Apr 2020 17:49:41 +0200 Subject: [PATCH 02/10] slice::fill: take T by value. --- src/libcore/slice/mod.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index 7b357bb487a0a..f74c6862006c1 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -23,7 +23,6 @@ // * The `raw` and `bytes` submodules. // * Boilerplate trait implementations. -use crate::borrow::Borrow; use crate::cmp; use crate::cmp::Ordering::{self, Equal, Greater, Less}; use crate::fmt; @@ -2157,14 +2156,16 @@ impl [T] { /// assert_eq!(buf, vec![1; 10]); /// ``` #[unstable(feature = "slice_fill", issue = "70758")] - pub fn fill(&mut self, value: V) + pub fn fill(&mut self, value: T) where - V: Borrow, T: Clone, { - let value = value.borrow(); - for el in self { - el.clone_from(value) + if let Some((last, elems)) = self.split_last_mut() { + for el in elems { + el.clone_from(&value); + } + + *last = value } } From c05961c2db4b02f599c8509031818339e10d592a Mon Sep 17 00:00:00 2001 From: Charles Lew Date: Sat, 25 Apr 2020 09:38:31 +0800 Subject: [PATCH 03/10] Implement `confusable_idents` lint. --- Cargo.lock | 81 ++++++++-------- src/librustc_expand/proc_macro_server.rs | 9 +- src/librustc_lint/Cargo.toml | 2 +- src/librustc_lint/levels.rs | 7 +- src/librustc_lint/non_ascii_idents.rs | 96 ++++++++++++++++++- src/librustc_parse/lexer/mod.rs | 3 +- src/librustc_session/parse.rs | 16 ++++ .../lint-confusable-idents.rs | 9 ++ .../lint-confusable-idents.stderr | 17 ++++ 9 files changed, 192 insertions(+), 48 deletions(-) create mode 100644 src/test/ui/lint/rfc-2457-non-ascii-idents/lint-confusable-idents.rs create mode 100644 src/test/ui/lint/rfc-2457-non-ascii-idents/lint-confusable-idents.stderr diff --git a/Cargo.lock b/Cargo.lock index 8bd1e5f3308b4..32a6f5fce74fe 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -74,7 +74,7 @@ name = "arena" version = "0.0.0" dependencies = [ "rustc_data_structures", - "smallvec 1.0.0", + "smallvec 1.4.0", ] [[package]] @@ -492,7 +492,7 @@ dependencies = [ "regex-syntax", "semver", "serde", - "smallvec 1.0.0", + "smallvec 1.4.0", "toml", "unicode-normalization", "url 2.1.0", @@ -2428,7 +2428,7 @@ dependencies = [ "cloudabi", "libc", "redox_syscall", - "smallvec 1.0.0", + "smallvec 1.4.0", "winapi 0.3.8", ] @@ -3151,7 +3151,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81dfcfbb0ddfd533abf8c076e3b49d1e5042d1962526a12ce2c66d514b24cca3" dependencies = [ "rustc-ap-rustc_data_structures", - "smallvec 1.0.0", + "smallvec 1.4.0", ] [[package]] @@ -3174,7 +3174,7 @@ dependencies = [ "rustc-ap-rustc_span", "rustc-ap-serialize", "scoped-tls", - "smallvec 1.0.0", + "smallvec 1.4.0", ] [[package]] @@ -3223,7 +3223,7 @@ dependencies = [ "rustc-ap-rustc_session", "rustc-ap-rustc_span", "rustc-ap-serialize", - "smallvec 1.0.0", + "smallvec 1.4.0", ] [[package]] @@ -3249,7 +3249,7 @@ dependencies = [ "rustc-hash", "rustc-rayon", "rustc-rayon-core", - "smallvec 1.0.0", + "smallvec 1.4.0", "stable_deref_trait", "winapi 0.3.8", ] @@ -3291,7 +3291,7 @@ dependencies = [ "rustc-ap-rustc_session", "rustc-ap-rustc_span", "rustc-ap-serialize", - "smallvec 1.0.0", + "smallvec 1.4.0", ] [[package]] @@ -3318,7 +3318,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32220c3e6cdf226f38e4474b747dca15f3106bb680c74f10b299af3f6cdb1663" dependencies = [ "rustc-ap-serialize", - "smallvec 1.0.0", + "smallvec 1.4.0", ] [[package]] @@ -3358,7 +3358,7 @@ dependencies = [ "rustc-ap-rustc_lexer", "rustc-ap-rustc_session", "rustc-ap-rustc_span", - "smallvec 1.0.0", + "smallvec 1.4.0", "unicode-normalization", ] @@ -3423,7 +3423,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "756e8f526ec7906e132188bf25e3c10a6ee42ab77294ecb3b3602647f0508eef" dependencies = [ "indexmap", - "smallvec 1.0.0", + "smallvec 1.4.0", ] [[package]] @@ -3507,7 +3507,7 @@ dependencies = [ "serde", "serde_json", "smallvec 0.6.10", - "smallvec 1.0.0", + "smallvec 1.4.0", "syn 0.15.35", "url 2.1.0", "winapi 0.3.8", @@ -3518,7 +3518,7 @@ name = "rustc_apfloat" version = "0.0.0" dependencies = [ "bitflags", - "smallvec 1.0.0", + "smallvec 1.4.0", ] [[package]] @@ -3533,7 +3533,7 @@ dependencies = [ "rustc_span", "scoped-tls", "serialize", - "smallvec 1.0.0", + "smallvec 1.4.0", ] [[package]] @@ -3551,7 +3551,7 @@ dependencies = [ "rustc_session", "rustc_span", "rustc_target", - "smallvec 1.0.0", + "smallvec 1.4.0", ] [[package]] @@ -3612,7 +3612,7 @@ dependencies = [ "rustc_session", "rustc_span", "rustc_target", - "smallvec 1.0.0", + "smallvec 1.4.0", ] [[package]] @@ -3641,7 +3641,7 @@ dependencies = [ "rustc_span", "rustc_target", "serialize", - "smallvec 1.0.0", + "smallvec 1.4.0", ] [[package]] @@ -3694,7 +3694,7 @@ dependencies = [ "rustc-rayon-core", "rustc_index", "serialize", - "smallvec 1.0.0", + "smallvec 1.4.0", "stable_deref_trait", "winapi 0.3.8", ] @@ -3768,7 +3768,7 @@ dependencies = [ "rustc_session", "rustc_span", "serialize", - "smallvec 1.0.0", + "smallvec 1.4.0", ] [[package]] @@ -3797,7 +3797,7 @@ dependencies = [ "rustc_span", "rustc_target", "serialize", - "smallvec 1.0.0", + "smallvec 1.4.0", ] [[package]] @@ -3833,7 +3833,7 @@ name = "rustc_index" version = "0.0.0" dependencies = [ "serialize", - "smallvec 1.0.0", + "smallvec 1.4.0", ] [[package]] @@ -3853,7 +3853,7 @@ dependencies = [ "rustc_span", "rustc_target", "serialize", - "smallvec 1.0.0", + "smallvec 1.4.0", ] [[package]] @@ -3895,7 +3895,7 @@ dependencies = [ "rustc_ty", "rustc_typeck", "serialize", - "smallvec 1.0.0", + "smallvec 1.4.0", "tempfile", "winapi 0.3.8", ] @@ -3968,7 +3968,7 @@ dependencies = [ "rustc_span", "rustc_target", "serialize", - "smallvec 1.0.0", + "smallvec 1.4.0", "stable_deref_trait", "winapi 0.3.8", ] @@ -4000,7 +4000,7 @@ dependencies = [ "rustc_target", "scoped-tls", "serialize", - "smallvec 1.0.0", + "smallvec 1.4.0", ] [[package]] @@ -4029,7 +4029,7 @@ dependencies = [ "rustc_target", "rustc_trait_selection", "serialize", - "smallvec 1.0.0", + "smallvec 1.4.0", ] [[package]] @@ -4053,7 +4053,7 @@ dependencies = [ "rustc_target", "rustc_trait_selection", "serialize", - "smallvec 1.0.0", + "smallvec 1.4.0", ] [[package]] @@ -4134,7 +4134,7 @@ dependencies = [ "rustc_index", "rustc_span", "serialize", - "smallvec 1.0.0", + "smallvec 1.4.0", ] [[package]] @@ -4157,7 +4157,7 @@ dependencies = [ "rustc_middle", "rustc_session", "rustc_span", - "smallvec 1.0.0", + "smallvec 1.4.0", ] [[package]] @@ -4272,7 +4272,7 @@ dependencies = [ "rustc_session", "rustc_span", "rustc_target", - "smallvec 1.0.0", + "smallvec 1.4.0", ] [[package]] @@ -4287,7 +4287,7 @@ dependencies = [ "rustc_middle", "rustc_span", "rustc_trait_selection", - "smallvec 1.0.0", + "smallvec 1.4.0", ] [[package]] @@ -4324,7 +4324,7 @@ dependencies = [ "rustc_span", "rustc_target", "rustc_trait_selection", - "smallvec 1.0.0", + "smallvec 1.4.0", ] [[package]] @@ -4568,7 +4568,7 @@ name = "serialize" version = "0.0.0" dependencies = [ "indexmap", - "smallvec 1.0.0", + "smallvec 1.4.0", ] [[package]] @@ -4635,9 +4635,9 @@ checksum = "ab606a9c5e214920bb66c458cd7be8ef094f813f20fe77a54cc7dbfff220d4b7" [[package]] name = "smallvec" -version = "1.0.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ecf3b85f68e8abaa7555aa5abdb1153079387e60b718283d732f03897fcfc86" +checksum = "c7cb5678e1615754284ec264d9bb5b4c27d2018577fd90ac0ceb578591ed5ee4" [[package]] name = "socket2" @@ -5359,11 +5359,11 @@ dependencies = [ [[package]] name = "unicode-normalization" -version = "0.1.11" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b561e267b2326bb4cebfc0ef9e68355c7abe6c6f522aeac2f5bf95d56c59bdcf" +checksum = "5479532badd04e128284890390c1e876ef7a993d0570b3597ae43dfa1d59afa4" dependencies = [ - "smallvec 1.0.0", + "smallvec 1.4.0", ] [[package]] @@ -5374,10 +5374,11 @@ checksum = "5b2c5c29e805da6817f5af6a627d65adb045cebf05cccd5a3493d6109454391c" [[package]] name = "unicode-security" -version = "0.0.2" +version = "0.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c49d35967fa037b881acc34ef717c38c4b5560eba10e3685271b3f530bb19634" +checksum = "a5f9011bbed9c13372bc8df618b55a38138445199caf3b61d432c6859c36dee0" dependencies = [ + "unicode-normalization", "unicode-script", ] diff --git a/src/librustc_expand/proc_macro_server.rs b/src/librustc_expand/proc_macro_server.rs index 5f21ff503d59e..10baffb28ac2d 100644 --- a/src/librustc_expand/proc_macro_server.rs +++ b/src/librustc_expand/proc_macro_server.rs @@ -141,10 +141,10 @@ impl FromInternal<(TreeAndJoint, &'_ ParseSess, &'_ mut Vec)> SingleQuote => op!('\''), Ident(name, false) if name == kw::DollarCrate => tt!(Ident::dollar_crate()), - Ident(name, is_raw) => tt!(Ident::new(name, is_raw)), + Ident(name, is_raw) => tt!(Ident::new(sess, name, is_raw)), Lifetime(name) => { let ident = ast::Ident::new(name, span).without_first_quote(); - stack.push(tt!(Ident::new(ident.name, false))); + stack.push(tt!(Ident::new(sess, ident.name, false))); tt!(Punct::new('\'', true)) } Literal(lit) => tt!(Literal { lit }), @@ -322,7 +322,7 @@ impl Ident { false } } - fn new(sym: Symbol, is_raw: bool, span: Span) -> Ident { + fn new(sess: &ParseSess, sym: Symbol, is_raw: bool, span: Span) -> Ident { let sym = nfc_normalize(&sym.as_str()); let string = sym.as_str(); if !Self::is_valid(&string) { @@ -331,6 +331,7 @@ impl Ident { if is_raw && !sym.can_be_raw() { panic!("`{}` cannot be a raw identifier", string); } + sess.symbol_gallery.insert(sym, span); Ident { sym, is_raw, span } } fn dollar_crate(span: Span) -> Ident { @@ -495,7 +496,7 @@ impl server::Punct for Rustc<'_> { impl server::Ident for Rustc<'_> { fn new(&mut self, string: &str, span: Self::Span, is_raw: bool) -> Self::Ident { - Ident::new(Symbol::intern(string), is_raw, span) + Ident::new(self.sess, Symbol::intern(string), is_raw, span) } fn span(&mut self, ident: Self::Ident) -> Self::Span { ident.span diff --git a/src/librustc_lint/Cargo.toml b/src/librustc_lint/Cargo.toml index b238a3156fae5..ada6f2a9381dc 100644 --- a/src/librustc_lint/Cargo.toml +++ b/src/librustc_lint/Cargo.toml @@ -10,7 +10,7 @@ path = "lib.rs" [dependencies] log = "0.4" -unicode-security = "0.0.2" +unicode-security = "0.0.3" rustc_middle = { path = "../librustc_middle" } rustc_ast_pretty = { path = "../librustc_ast_pretty" } rustc_attr = { path = "../librustc_attr" } diff --git a/src/librustc_lint/levels.rs b/src/librustc_lint/levels.rs index 7e8e4f59707c1..293dd326d3b08 100644 --- a/src/librustc_lint/levels.rs +++ b/src/librustc_lint/levels.rs @@ -388,6 +388,11 @@ impl<'s> LintLevelsBuilder<'s> { self.cur = push.prev; } + /// Find the lint level for a lint. + pub fn lint_level(&self, lint: &'static Lint) -> (Level, LintSource) { + self.sets.get_lint_level(lint, self.cur, None, self.sess) + } + /// Used to emit a lint-related diagnostic based on the current state of /// this lint context. pub fn struct_lint( @@ -396,7 +401,7 @@ impl<'s> LintLevelsBuilder<'s> { span: Option, decorate: impl for<'a> FnOnce(LintDiagnosticBuilder<'a>), ) { - let (level, src) = self.sets.get_lint_level(lint, self.cur, None, self.sess); + let (level, src) = self.lint_level(lint); struct_lint_level(self.sess, lint, level, src, span, decorate) } diff --git a/src/librustc_lint/non_ascii_idents.rs b/src/librustc_lint/non_ascii_idents.rs index 470fac2675bac..522f292dc949b 100644 --- a/src/librustc_lint/non_ascii_idents.rs +++ b/src/librustc_lint/non_ascii_idents.rs @@ -1,5 +1,7 @@ use crate::{EarlyContext, EarlyLintPass, LintContext}; use rustc_ast::ast; +use rustc_data_structures::fx::FxHashMap; +use rustc_span::symbol::SymbolStr; declare_lint! { pub NON_ASCII_IDENTS, @@ -13,9 +15,101 @@ declare_lint! { "detects uncommon Unicode codepoints in identifiers" } -declare_lint_pass!(NonAsciiIdents => [NON_ASCII_IDENTS, UNCOMMON_CODEPOINTS]); +// FIXME: Change this to warn. +declare_lint! { + pub CONFUSABLE_IDENTS, + Allow, + "detects visually confusable pairs between identifiers" +} + +declare_lint_pass!(NonAsciiIdents => [NON_ASCII_IDENTS, UNCOMMON_CODEPOINTS, CONFUSABLE_IDENTS]); + +use std::hash::{Hash, Hasher}; +use std::ops::Deref; + +enum CowBoxSymStr { + Interned(SymbolStr), + Owned(Box), +} + +impl Deref for CowBoxSymStr { + type Target = str; + + fn deref(&self) -> &str { + match self { + CowBoxSymStr::Interned(interned) => interned, + CowBoxSymStr::Owned(ref owned) => owned, + } + } +} + +impl Hash for CowBoxSymStr { + #[inline] + fn hash(&self, state: &mut H) { + Hash::hash(&**self, state) + } +} + +impl PartialEq for CowBoxSymStr { + #[inline] + fn eq(&self, other: &CowBoxSymStr) -> bool { + PartialEq::eq(&**self, &**other) + } +} + +impl Eq for CowBoxSymStr {} + +fn calc_skeleton(symbol_str: SymbolStr, buffer: &'_ mut String) -> CowBoxSymStr { + use std::mem::swap; + use unicode_security::confusable_detection::skeleton; + buffer.clear(); + buffer.extend(skeleton(&symbol_str)); + if symbol_str == *buffer { + CowBoxSymStr::Interned(symbol_str) + } else { + let mut owned = String::new(); + swap(buffer, &mut owned); + CowBoxSymStr::Owned(owned.into_boxed_str()) + } +} impl EarlyLintPass for NonAsciiIdents { + fn check_crate(&mut self, cx: &EarlyContext<'_>, _: &ast::Crate) { + use rustc_session::lint::Level; + if cx.builder.lint_level(CONFUSABLE_IDENTS).0 == Level::Allow { + return; + } + let symbols = cx.sess.parse_sess.symbol_gallery.symbols.lock(); + let mut symbol_strs_and_spans = Vec::with_capacity(symbols.len()); + for (symbol, sp) in symbols.iter() { + let symbol_str = symbol.as_str(); + symbol_strs_and_spans.push((symbol_str, *sp)); + } + drop(symbols); + symbol_strs_and_spans.sort_by_key(|x| x.0.clone()); + let mut skeleton_map = + FxHashMap::with_capacity_and_hasher(symbol_strs_and_spans.len(), Default::default()); + let mut str_buf = String::new(); + for (symbol_str, sp) in symbol_strs_and_spans { + let skeleton = calc_skeleton(symbol_str.clone(), &mut str_buf); + skeleton_map + .entry(skeleton) + .and_modify(|(existing_symbolstr, existing_span)| { + cx.struct_span_lint(CONFUSABLE_IDENTS, sp, |lint| { + lint.build(&format!( + "identifier pair considered confusable between `{}` and `{}`", + existing_symbolstr, symbol_str + )) + .span_label( + *existing_span, + "this is where the previous identifier occurred", + ) + .emit(); + }); + }) + .or_insert((symbol_str, sp)); + } + } fn check_ident(&mut self, cx: &EarlyContext<'_>, ident: ast::Ident) { use unicode_security::GeneralSecurityProfile; let name_str = ident.name.as_str(); diff --git a/src/librustc_parse/lexer/mod.rs b/src/librustc_parse/lexer/mod.rs index 96321ef2145e5..f676a34a1d12b 100644 --- a/src/librustc_parse/lexer/mod.rs +++ b/src/librustc_parse/lexer/mod.rs @@ -222,8 +222,9 @@ impl<'a> StringReader<'a> { ident_start = ident_start + BytePos(2); } let sym = nfc_normalize(self.str_from(ident_start)); + let span = self.mk_sp(start, self.pos); + self.sess.symbol_gallery.insert(sym, span); if is_raw_ident { - let span = self.mk_sp(start, self.pos); if !sym.can_be_raw() { self.err_span(span, &format!("`{}` cannot be a raw identifier", sym)); } diff --git a/src/librustc_session/parse.rs b/src/librustc_session/parse.rs index 387d35422c43e..69d3e99b7458e 100644 --- a/src/librustc_session/parse.rs +++ b/src/librustc_session/parse.rs @@ -60,6 +60,20 @@ impl GatedSpans { } } +#[derive(Default)] +pub struct SymbolGallery { + /// All symbols occurred and their first occurrance span. + pub symbols: Lock>, +} + +impl SymbolGallery { + /// Insert a symbol and its span into symbol gallery. + /// If the symbol has occurred before, ignore the new occurance. + pub fn insert(&self, symbol: Symbol, span: Span) { + self.symbols.lock().entry(symbol).or_insert(span); + } +} + /// Construct a diagnostic for a language feature error due to the given `span`. /// The `feature`'s `Symbol` is the one you used in `active.rs` and `rustc_span::symbols`. pub fn feature_err<'a>( @@ -118,6 +132,7 @@ pub struct ParseSess { pub ambiguous_block_expr_parse: Lock>, pub injected_crate_name: Once, pub gated_spans: GatedSpans, + pub symbol_gallery: SymbolGallery, /// The parser has reached `Eof` due to an unclosed brace. Used to silence unnecessary errors. pub reached_eof: Lock, } @@ -143,6 +158,7 @@ impl ParseSess { ambiguous_block_expr_parse: Lock::new(FxHashMap::default()), injected_crate_name: Once::new(), gated_spans: GatedSpans::default(), + symbol_gallery: SymbolGallery::default(), reached_eof: Lock::new(false), } } diff --git a/src/test/ui/lint/rfc-2457-non-ascii-idents/lint-confusable-idents.rs b/src/test/ui/lint/rfc-2457-non-ascii-idents/lint-confusable-idents.rs new file mode 100644 index 0000000000000..12093837d2630 --- /dev/null +++ b/src/test/ui/lint/rfc-2457-non-ascii-idents/lint-confusable-idents.rs @@ -0,0 +1,9 @@ +#![feature(non_ascii_idents)] +#![deny(confusable_idents)] +#![allow(uncommon_codepoints, non_upper_case_globals)] + +const s: usize = 42; //~ ERROR identifier pair considered confusable + +fn main() { + let s = "rust"; +} diff --git a/src/test/ui/lint/rfc-2457-non-ascii-idents/lint-confusable-idents.stderr b/src/test/ui/lint/rfc-2457-non-ascii-idents/lint-confusable-idents.stderr new file mode 100644 index 0000000000000..40ee18acb3cd4 --- /dev/null +++ b/src/test/ui/lint/rfc-2457-non-ascii-idents/lint-confusable-idents.stderr @@ -0,0 +1,17 @@ +error: identifier pair considered confusable between `s` and `s` + --> $DIR/lint-confusable-idents.rs:5:7 + | +LL | const s: usize = 42; + | ^^ +... +LL | let s = "rust"; + | - this is where the previous identifier occurred + | +note: the lint level is defined here + --> $DIR/lint-confusable-idents.rs:2:9 + | +LL | #![deny(confusable_idents)] + | ^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + From f3ec00a5fecabe5587bdd2f7edee86a755b1f52b Mon Sep 17 00:00:00 2001 From: Charles Lew Date: Fri, 1 May 2020 12:34:04 +0800 Subject: [PATCH 04/10] Add a fast code path to optimize `confusable_idents` lint for ASCII code base. --- src/librustc_lint/non_ascii_idents.rs | 53 +++++++++++++++++++++++++-- 1 file changed, 49 insertions(+), 4 deletions(-) diff --git a/src/librustc_lint/non_ascii_idents.rs b/src/librustc_lint/non_ascii_idents.rs index 522f292dc949b..94fc1a228df03 100644 --- a/src/librustc_lint/non_ascii_idents.rs +++ b/src/librustc_lint/non_ascii_idents.rs @@ -2,6 +2,8 @@ use crate::{EarlyContext, EarlyLintPass, LintContext}; use rustc_ast::ast; use rustc_data_structures::fx::FxHashMap; use rustc_span::symbol::SymbolStr; +use std::hash::{Hash, Hasher}; +use std::ops::Deref; declare_lint! { pub NON_ASCII_IDENTS, @@ -24,9 +26,6 @@ declare_lint! { declare_lint_pass!(NonAsciiIdents => [NON_ASCII_IDENTS, UNCOMMON_CODEPOINTS, CONFUSABLE_IDENTS]); -use std::hash::{Hash, Hasher}; -use std::ops::Deref; - enum CowBoxSymStr { Interned(SymbolStr), Owned(Box), @@ -73,6 +72,35 @@ fn calc_skeleton(symbol_str: SymbolStr, buffer: &'_ mut String) -> CowBoxSymStr } } +fn is_in_ascii_confusable_closure(c: char) -> bool { + // FIXME: move this table to `unicode_security` crate. + // data here corresponds to Unicode 13. + const ASCII_CONFUSABLE_CLOSURE: &[(u64, u64)] = &[(0x00, 0x7f), (0xba, 0xba), (0x2080, 0x2080)]; + let c = c as u64; + for &(range_start, range_end) in ASCII_CONFUSABLE_CLOSURE { + if c >= range_start && c <= range_end { + return true; + } + } + false +} + +fn is_in_ascii_confusable_closure_relevant_list(c: char) -> bool { + // FIXME: move this table to `unicode_security` crate. + // data here corresponds to Unicode 13. + const ASCII_CONFUSABLE_CLOSURE_RELEVANT_LIST: &[u64] = &[ + 0x22, 0x25, 0x27, 0x2f, 0x30, 0x31, 0x49, 0x4f, 0x60, 0x6c, 0x6d, 0x6e, 0x72, 0x7c, 0xba, + 0x2080, + ]; + let c = c as u64; + for &item in ASCII_CONFUSABLE_CLOSURE_RELEVANT_LIST { + if c == item { + return true; + } + } + false +} + impl EarlyLintPass for NonAsciiIdents { fn check_crate(&mut self, cx: &EarlyContext<'_>, _: &ast::Crate) { use rustc_session::lint::Level; @@ -81,9 +109,26 @@ impl EarlyLintPass for NonAsciiIdents { } let symbols = cx.sess.parse_sess.symbol_gallery.symbols.lock(); let mut symbol_strs_and_spans = Vec::with_capacity(symbols.len()); + let mut in_fast_path = true; for (symbol, sp) in symbols.iter() { + // fast path let symbol_str = symbol.as_str(); - symbol_strs_and_spans.push((symbol_str, *sp)); + if !symbol_str.chars().all(is_in_ascii_confusable_closure) { + // fallback to slow path. + symbol_strs_and_spans.clear(); + in_fast_path = false; + break; + } + if symbol_str.chars().any(is_in_ascii_confusable_closure_relevant_list) { + symbol_strs_and_spans.push((symbol_str, *sp)); + } + } + if !in_fast_path { + // slow path + for (symbol, sp) in symbols.iter() { + let symbol_str = symbol.as_str(); + symbol_strs_and_spans.push((symbol_str, *sp)); + } } drop(symbols); symbol_strs_and_spans.sort_by_key(|x| x.0.clone()); From bcc44b8e025978ae14ff11d484aacbb85aa8eaed Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Sat, 2 May 2020 14:39:12 -0700 Subject: [PATCH 05/10] Test associated const default qualifs cross-crate This also tests for the ICE in #71734 --- .../const_in_pattern/auxiliary/consts.rs | 5 +++++ .../const_in_pattern/cross-crate-fail.rs | 12 ++++++++++++ .../const_in_pattern/cross-crate-fail.stderr | 18 +++++++++++++++--- .../const_in_pattern/cross-crate-pass.rs | 9 +++++++++ 4 files changed, 41 insertions(+), 3 deletions(-) diff --git a/src/test/ui/consts/const_in_pattern/auxiliary/consts.rs b/src/test/ui/consts/const_in_pattern/auxiliary/consts.rs index 303c2f12bbce9..b438bcd9fb5eb 100644 --- a/src/test/ui/consts/const_in_pattern/auxiliary/consts.rs +++ b/src/test/ui/consts/const_in_pattern/auxiliary/consts.rs @@ -9,3 +9,8 @@ impl PartialEq for CustomEq { pub const NONE: Option = None; pub const SOME: Option = Some(CustomEq); + +pub trait AssocConst { + const NONE: Option = None; + const SOME: Option = Some(CustomEq); +} diff --git a/src/test/ui/consts/const_in_pattern/cross-crate-fail.rs b/src/test/ui/consts/const_in_pattern/cross-crate-fail.rs index c9e6050fdc508..05c53e5edccc5 100644 --- a/src/test/ui/consts/const_in_pattern/cross-crate-fail.rs +++ b/src/test/ui/consts/const_in_pattern/cross-crate-fail.rs @@ -4,7 +4,11 @@ extern crate consts; +struct Defaulted; +impl consts::AssocConst for Defaulted {} + fn main() { + let _ = Defaulted; match None { consts::SOME => panic!(), //~^ must be annotated with `#[derive(PartialEq, Eq)]` @@ -12,4 +16,12 @@ fn main() { _ => {} } + + match None { + ::SOME => panic!(), + //~^ must be annotated with `#[derive(PartialEq, Eq)]` + //~| must be annotated with `#[derive(PartialEq, Eq)]` + + _ => {} + } } diff --git a/src/test/ui/consts/const_in_pattern/cross-crate-fail.stderr b/src/test/ui/consts/const_in_pattern/cross-crate-fail.stderr index c97298f66e677..5d147e32f5a86 100644 --- a/src/test/ui/consts/const_in_pattern/cross-crate-fail.stderr +++ b/src/test/ui/consts/const_in_pattern/cross-crate-fail.stderr @@ -1,14 +1,26 @@ error: to use a constant of type `consts::CustomEq` in a pattern, `consts::CustomEq` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/cross-crate-fail.rs:9:9 + --> $DIR/cross-crate-fail.rs:13:9 | LL | consts::SOME => panic!(), | ^^^^^^^^^^^^ error: to use a constant of type `consts::CustomEq` in a pattern, `consts::CustomEq` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/cross-crate-fail.rs:9:9 + --> $DIR/cross-crate-fail.rs:21:9 + | +LL | ::SOME => panic!(), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: to use a constant of type `consts::CustomEq` in a pattern, `consts::CustomEq` must be annotated with `#[derive(PartialEq, Eq)]` + --> $DIR/cross-crate-fail.rs:13:9 | LL | consts::SOME => panic!(), | ^^^^^^^^^^^^ -error: aborting due to 2 previous errors +error: to use a constant of type `consts::CustomEq` in a pattern, `consts::CustomEq` must be annotated with `#[derive(PartialEq, Eq)]` + --> $DIR/cross-crate-fail.rs:21:9 + | +LL | ::SOME => panic!(), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors diff --git a/src/test/ui/consts/const_in_pattern/cross-crate-pass.rs b/src/test/ui/consts/const_in_pattern/cross-crate-pass.rs index ccf655c11cf8a..1d8ecf8ae6640 100644 --- a/src/test/ui/consts/const_in_pattern/cross-crate-pass.rs +++ b/src/test/ui/consts/const_in_pattern/cross-crate-pass.rs @@ -6,9 +6,18 @@ extern crate consts; use consts::CustomEq; +struct Defaulted; +impl consts::AssocConst for Defaulted {} + fn main() { + let _ = Defaulted; match Some(CustomEq) { consts::NONE => panic!(), _ => {} } + + match Some(CustomEq) { + ::NONE => panic!(), + _ => {} + } } From 14a2c8d042e1da811d96b843922e569f2cd5e283 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Sat, 2 May 2020 14:17:04 -0700 Subject: [PATCH 06/10] Decode qualifs from defaulted trait associated consts --- src/librustc_metadata/rmeta/decoder.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/librustc_metadata/rmeta/decoder.rs b/src/librustc_metadata/rmeta/decoder.rs index 6a4b35ed3d7fa..04f17230717d9 100644 --- a/src/librustc_metadata/rmeta/decoder.rs +++ b/src/librustc_metadata/rmeta/decoder.rs @@ -1123,11 +1123,13 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { match self.kind(id) { EntryKind::Const(qualif, _) | EntryKind::AssocConst( - AssocContainer::ImplDefault | AssocContainer::ImplFinal, + AssocContainer::ImplDefault + | AssocContainer::ImplFinal + | AssocContainer::TraitWithDefault, qualif, _, ) => qualif, - _ => bug!(), + _ => bug!("mir_const_qualif: unexpected kind"), } } From 90aa62a1bf00c555abc834a21e84d9e7e20dcf86 Mon Sep 17 00:00:00 2001 From: mibac138 <5672750+mibac138@users.noreply.github.com> Date: Sun, 19 Apr 2020 10:47:55 +0200 Subject: [PATCH 07/10] Implement RFC 2523, `#[cfg(version(..))]` --- Cargo.lock | 1 + .../src/language-features/cfg-version.md | 34 +++++++ src/librustc_attr/Cargo.toml | 1 + src/librustc_attr/builtin.rs | 64 ++++++++++--- src/librustc_attr/lib.rs | 2 + src/librustc_feature/active.rs | 3 + src/librustc_feature/builtin_attrs.rs | 1 + src/librustc_span/symbol.rs | 2 + .../traits/on_unimplemented.rs | 17 ++-- .../feature-gates/feature-gate-cfg-version.rs | 28 ++++++ .../feature-gate-cfg-version.stderr | 93 +++++++++++++++++++ 11 files changed, 227 insertions(+), 19 deletions(-) create mode 100644 src/doc/unstable-book/src/language-features/cfg-version.md create mode 100644 src/test/ui/feature-gates/feature-gate-cfg-version.rs create mode 100644 src/test/ui/feature-gates/feature-gate-cfg-version.stderr diff --git a/Cargo.lock b/Cargo.lock index 8bd1e5f3308b4..0fed32f4a9d04 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3593,6 +3593,7 @@ dependencies = [ "rustc_session", "rustc_span", "serialize", + "version_check", ] [[package]] diff --git a/src/doc/unstable-book/src/language-features/cfg-version.md b/src/doc/unstable-book/src/language-features/cfg-version.md new file mode 100644 index 0000000000000..2b1e50835b767 --- /dev/null +++ b/src/doc/unstable-book/src/language-features/cfg-version.md @@ -0,0 +1,34 @@ +# `cfg_version` + +The tracking issue for this feature is: [#64796] + +[#64796]: https://github.com/rust-lang/rust/issues/64796 + +------------------------ + +The `cfg_version` feature makes it possible to execute different code +depending on the compiler version. + +## Examples + +```rust +#![feature(cfg_version)] + +#[cfg(version("1.42"))] +fn a() { + // ... +} + +#[cfg(not(version("1.42")))] +fn a() { + // ... +} + +fn b() { + if cfg!(version("1.42")) { + // ... + } else { + // ... + } +} +``` diff --git a/src/librustc_attr/Cargo.toml b/src/librustc_attr/Cargo.toml index a7a7e3dcc5f02..ad97ac8ffd3d2 100644 --- a/src/librustc_attr/Cargo.toml +++ b/src/librustc_attr/Cargo.toml @@ -19,3 +19,4 @@ rustc_feature = { path = "../librustc_feature" } rustc_macros = { path = "../librustc_macros" } rustc_session = { path = "../librustc_session" } rustc_ast = { path = "../librustc_ast" } +version_check = "0.9" diff --git a/src/librustc_attr/builtin.rs b/src/librustc_attr/builtin.rs index 0a6a4821e278e..c29d8c0e0feb6 100644 --- a/src/librustc_attr/builtin.rs +++ b/src/librustc_attr/builtin.rs @@ -2,7 +2,7 @@ use super::{find_by_name, mark_used}; -use rustc_ast::ast::{self, Attribute, MetaItem, MetaItemKind, NestedMetaItem}; +use rustc_ast::ast::{self, Attribute, Lit, LitKind, MetaItem, MetaItemKind, NestedMetaItem}; use rustc_ast_pretty::pprust; use rustc_errors::{struct_span_err, Applicability, Handler}; use rustc_feature::{find_gated_cfg, is_builtin_attr_name, Features, GatedCfg}; @@ -11,6 +11,7 @@ use rustc_session::parse::{feature_err, ParseSess}; use rustc_span::hygiene::Transparency; use rustc_span::{symbol::sym, symbol::Symbol, Span}; use std::num::NonZeroU32; +use version_check::Version; pub fn is_builtin_attr(attr: &Attribute) -> bool { attr.is_doc_comment() || attr.ident().filter(|ident| is_builtin_attr_name(ident.name)).is_some() @@ -568,11 +569,8 @@ pub fn find_crate_name(attrs: &[Attribute]) -> Option { /// Tests if a cfg-pattern matches the cfg set pub fn cfg_matches(cfg: &ast::MetaItem, sess: &ParseSess, features: Option<&Features>) -> bool { - eval_condition(cfg, sess, &mut |cfg| { - let gate = find_gated_cfg(|sym| cfg.check_name(sym)); - if let (Some(feats), Some(gated_cfg)) = (features, gate) { - gate_cfg(&gated_cfg, cfg.span, sess, feats); - } + eval_condition(cfg, sess, features, &mut |cfg| { + try_gate_cfg(cfg, sess, features); let error = |span, msg| { sess.span_diagnostic.span_err(span, msg); true @@ -603,6 +601,13 @@ pub fn cfg_matches(cfg: &ast::MetaItem, sess: &ParseSess, features: Option<&Feat }) } +fn try_gate_cfg(cfg: &ast::MetaItem, sess: &ParseSess, features: Option<&Features>) { + let gate = find_gated_cfg(|sym| cfg.check_name(sym)); + if let (Some(feats), Some(gated_cfg)) = (features, gate) { + gate_cfg(&gated_cfg, cfg.span, sess, feats); + } +} + fn gate_cfg(gated_cfg: &GatedCfg, cfg_span: Span, sess: &ParseSess, features: &Features) { let (cfg, feature, has_feature) = gated_cfg; if !has_feature(features) && !cfg_span.allows_unstable(*feature) { @@ -616,9 +621,42 @@ fn gate_cfg(gated_cfg: &GatedCfg, cfg_span: Span, sess: &ParseSess, features: &F pub fn eval_condition( cfg: &ast::MetaItem, sess: &ParseSess, + features: Option<&Features>, eval: &mut impl FnMut(&ast::MetaItem) -> bool, ) -> bool { match cfg.kind { + ast::MetaItemKind::List(ref mis) if cfg.name_or_empty() == sym::version => { + try_gate_cfg(cfg, sess, features); + let (min_version, span) = match &mis[..] { + [NestedMetaItem::Literal(Lit { kind: LitKind::Str(sym, ..), span, .. })] => { + (sym, span) + } + [NestedMetaItem::Literal(Lit { span, .. }) + | NestedMetaItem::MetaItem(MetaItem { span, .. })] => { + sess.span_diagnostic + .struct_span_err(*span, &*format!("expected string literal")) + .emit(); + return false; + } + [..] => { + sess.span_diagnostic + .struct_span_err(cfg.span, "expected single string literal") + .emit(); + return false; + } + }; + let min_version = match Version::parse(&min_version.as_str()) { + Some(ver) => ver, + None => { + sess.span_diagnostic.struct_span_err(*span, "invalid version string").emit(); + return false; + } + }; + let version = option_env!("CFG_VERSION").unwrap_or("unknown rustc version"); + let version = Version::parse(version).unwrap(); + + version >= min_version + } ast::MetaItemKind::List(ref mis) => { for mi in mis.iter() { if !mi.is_meta_item() { @@ -634,12 +672,12 @@ pub fn eval_condition( // The unwraps below may look dangerous, but we've already asserted // that they won't fail with the loop above. match cfg.name_or_empty() { - sym::any => { - mis.iter().any(|mi| eval_condition(mi.meta_item().unwrap(), sess, eval)) - } - sym::all => { - mis.iter().all(|mi| eval_condition(mi.meta_item().unwrap(), sess, eval)) - } + sym::any => mis + .iter() + .any(|mi| eval_condition(mi.meta_item().unwrap(), sess, features, eval)), + sym::all => mis + .iter() + .all(|mi| eval_condition(mi.meta_item().unwrap(), sess, features, eval)), sym::not => { if mis.len() != 1 { struct_span_err!( @@ -652,7 +690,7 @@ pub fn eval_condition( return false; } - !eval_condition(mis[0].meta_item().unwrap(), sess, eval) + !eval_condition(mis[0].meta_item().unwrap(), sess, features, eval) } _ => { struct_span_err!( diff --git a/src/librustc_attr/lib.rs b/src/librustc_attr/lib.rs index 9803501fb96c2..66c4495c5afc8 100644 --- a/src/librustc_attr/lib.rs +++ b/src/librustc_attr/lib.rs @@ -4,6 +4,8 @@ //! The goal is to move the definition of `MetaItem` and things that don't need to be in `syntax` //! to this crate. +#![feature(or_patterns)] + mod builtin; pub use builtin::*; diff --git a/src/librustc_feature/active.rs b/src/librustc_feature/active.rs index cec9e0ce3af71..a1dd7a5ca5225 100644 --- a/src/librustc_feature/active.rs +++ b/src/librustc_feature/active.rs @@ -562,6 +562,9 @@ declare_features! ( /// Allows the use of `#[target_feature]` on safe functions. (active, target_feature_11, "1.45.0", Some(69098), None), + /// Allow conditional compilation depending on rust version + (active, cfg_version, "1.45.0", Some(64796), None), + // ------------------------------------------------------------------------- // feature-group-end: actual feature gates // ------------------------------------------------------------------------- diff --git a/src/librustc_feature/builtin_attrs.rs b/src/librustc_feature/builtin_attrs.rs index e4975aae6b983..466b318bca730 100644 --- a/src/librustc_feature/builtin_attrs.rs +++ b/src/librustc_feature/builtin_attrs.rs @@ -26,6 +26,7 @@ const GATED_CFGS: &[GatedCfg] = &[ (sym::target_has_atomic, sym::cfg_target_has_atomic, cfg_fn!(cfg_target_has_atomic)), (sym::target_has_atomic_load_store, sym::cfg_target_has_atomic, cfg_fn!(cfg_target_has_atomic)), (sym::sanitize, sym::cfg_sanitize, cfg_fn!(cfg_sanitize)), + (sym::version, sym::cfg_version, cfg_fn!(cfg_version)), ]; /// Find a gated cfg determined by the `pred`icate which is given the cfg's name. diff --git a/src/librustc_span/symbol.rs b/src/librustc_span/symbol.rs index 74d73404acd8e..f194506e66069 100644 --- a/src/librustc_span/symbol.rs +++ b/src/librustc_span/symbol.rs @@ -192,6 +192,7 @@ symbols! { cfg_target_has_atomic, cfg_target_thread_local, cfg_target_vendor, + cfg_version, char, clippy, clone, @@ -805,6 +806,7 @@ symbols! { var, vec, Vec, + version, vis, visible_private_types, volatile, diff --git a/src/librustc_trait_selection/traits/on_unimplemented.rs b/src/librustc_trait_selection/traits/on_unimplemented.rs index cf29c4249c019..3fbc0b7f08e5f 100644 --- a/src/librustc_trait_selection/traits/on_unimplemented.rs +++ b/src/librustc_trait_selection/traits/on_unimplemented.rs @@ -81,7 +81,7 @@ impl<'tcx> OnUnimplementedDirective { None, ) })?; - attr::eval_condition(cond, &tcx.sess.parse_sess, &mut |_| true); + attr::eval_condition(cond, &tcx.sess.parse_sess, Some(tcx.features()), &mut |_| true); Some(cond.clone()) }; @@ -208,11 +208,16 @@ impl<'tcx> OnUnimplementedDirective { for command in self.subcommands.iter().chain(Some(self)).rev() { if let Some(ref condition) = command.condition { - if !attr::eval_condition(condition, &tcx.sess.parse_sess, &mut |c| { - c.ident().map_or(false, |ident| { - options.contains(&(ident.name, c.value_str().map(|s| s.to_string()))) - }) - }) { + if !attr::eval_condition( + condition, + &tcx.sess.parse_sess, + Some(tcx.features()), + &mut |c| { + c.ident().map_or(false, |ident| { + options.contains(&(ident.name, c.value_str().map(|s| s.to_string()))) + }) + }, + ) { debug!("evaluate: skipping {:?} due to condition", command); continue; } diff --git a/src/test/ui/feature-gates/feature-gate-cfg-version.rs b/src/test/ui/feature-gates/feature-gate-cfg-version.rs new file mode 100644 index 0000000000000..71b82b7f749e1 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-cfg-version.rs @@ -0,0 +1,28 @@ +#[cfg(version("1.44"))] +//~^ ERROR `cfg(version)` is experimental and subject to change +fn foo() -> bool { true } +#[cfg(not(version("1.44")))] +//~^ ERROR `cfg(version)` is experimental and subject to change +fn foo() -> bool { false } + +#[cfg(version("1.43", "1.44", "1.45"))] //~ ERROR: expected single string literal +//~^ ERROR `cfg(version)` is experimental and subject to change +fn bar() -> bool { false } +#[cfg(version(false))] //~ ERROR: expected string literal +//~^ ERROR `cfg(version)` is experimental and subject to change +fn bar() -> bool { false } +#[cfg(version("foo"))] //~ ERROR: invalid version string +//~^ ERROR `cfg(version)` is experimental and subject to change +fn bar() -> bool { false } +#[cfg(version("999"))] +//~^ ERROR `cfg(version)` is experimental and subject to change +fn bar() -> bool { false } +#[cfg(version("0"))] +//~^ ERROR `cfg(version)` is experimental and subject to change +fn bar() -> bool { true } + +fn main() { + assert!(foo()); + assert!(bar()); + assert!(cfg!(version("1.42"))); //~ ERROR `cfg(version)` is experimental and subject to change +} diff --git a/src/test/ui/feature-gates/feature-gate-cfg-version.stderr b/src/test/ui/feature-gates/feature-gate-cfg-version.stderr new file mode 100644 index 0000000000000..48686dd4aebfe --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-cfg-version.stderr @@ -0,0 +1,93 @@ +error[E0658]: `cfg(version)` is experimental and subject to change + --> $DIR/feature-gate-cfg-version.rs:1:7 + | +LL | #[cfg(version("1.44"))] + | ^^^^^^^^^^^^^^^ + | + = note: see issue #64796 for more information + = help: add `#![feature(cfg_version)]` to the crate attributes to enable + +error[E0658]: `cfg(version)` is experimental and subject to change + --> $DIR/feature-gate-cfg-version.rs:4:11 + | +LL | #[cfg(not(version("1.44")))] + | ^^^^^^^^^^^^^^^ + | + = note: see issue #64796 for more information + = help: add `#![feature(cfg_version)]` to the crate attributes to enable + +error[E0658]: `cfg(version)` is experimental and subject to change + --> $DIR/feature-gate-cfg-version.rs:8:7 + | +LL | #[cfg(version("1.43", "1.44", "1.45"))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #64796 for more information + = help: add `#![feature(cfg_version)]` to the crate attributes to enable + +error: expected single string literal + --> $DIR/feature-gate-cfg-version.rs:8:7 + | +LL | #[cfg(version("1.43", "1.44", "1.45"))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0658]: `cfg(version)` is experimental and subject to change + --> $DIR/feature-gate-cfg-version.rs:11:7 + | +LL | #[cfg(version(false))] + | ^^^^^^^^^^^^^^ + | + = note: see issue #64796 for more information + = help: add `#![feature(cfg_version)]` to the crate attributes to enable + +error: expected string literal + --> $DIR/feature-gate-cfg-version.rs:11:15 + | +LL | #[cfg(version(false))] + | ^^^^^ + +error[E0658]: `cfg(version)` is experimental and subject to change + --> $DIR/feature-gate-cfg-version.rs:14:7 + | +LL | #[cfg(version("foo"))] + | ^^^^^^^^^^^^^^ + | + = note: see issue #64796 for more information + = help: add `#![feature(cfg_version)]` to the crate attributes to enable + +error: invalid version string + --> $DIR/feature-gate-cfg-version.rs:14:15 + | +LL | #[cfg(version("foo"))] + | ^^^^^ + +error[E0658]: `cfg(version)` is experimental and subject to change + --> $DIR/feature-gate-cfg-version.rs:17:7 + | +LL | #[cfg(version("999"))] + | ^^^^^^^^^^^^^^ + | + = note: see issue #64796 for more information + = help: add `#![feature(cfg_version)]` to the crate attributes to enable + +error[E0658]: `cfg(version)` is experimental and subject to change + --> $DIR/feature-gate-cfg-version.rs:20:7 + | +LL | #[cfg(version("0"))] + | ^^^^^^^^^^^^ + | + = note: see issue #64796 for more information + = help: add `#![feature(cfg_version)]` to the crate attributes to enable + +error[E0658]: `cfg(version)` is experimental and subject to change + --> $DIR/feature-gate-cfg-version.rs:27:18 + | +LL | assert!(cfg!(version("1.42"))); + | ^^^^^^^^^^^^^^^ + | + = note: see issue #64796 for more information + = help: add `#![feature(cfg_version)]` to the crate attributes to enable + +error: aborting due to 11 previous errors + +For more information about this error, try `rustc --explain E0658`. From 96f27c73cfb943e11afaff16dbe8415e6a3ae5a5 Mon Sep 17 00:00:00 2001 From: mibac138 <5672750+mibac138@users.noreply.github.com> Date: Tue, 28 Apr 2020 16:07:11 +0200 Subject: [PATCH 08/10] Change cfg(version) error message wording --- src/librustc_attr/builtin.rs | 6 +++--- src/test/ui/feature-gates/feature-gate-cfg-version.rs | 9 ++++++--- .../ui/feature-gates/feature-gate-cfg-version.stderr | 6 +++--- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/librustc_attr/builtin.rs b/src/librustc_attr/builtin.rs index c29d8c0e0feb6..fedc29d268fd0 100644 --- a/src/librustc_attr/builtin.rs +++ b/src/librustc_attr/builtin.rs @@ -634,13 +634,13 @@ pub fn eval_condition( [NestedMetaItem::Literal(Lit { span, .. }) | NestedMetaItem::MetaItem(MetaItem { span, .. })] => { sess.span_diagnostic - .struct_span_err(*span, &*format!("expected string literal")) + .struct_span_err(*span, &*format!("expected a version literal")) .emit(); return false; } [..] => { sess.span_diagnostic - .struct_span_err(cfg.span, "expected single string literal") + .struct_span_err(cfg.span, "expected single version literal") .emit(); return false; } @@ -648,7 +648,7 @@ pub fn eval_condition( let min_version = match Version::parse(&min_version.as_str()) { Some(ver) => ver, None => { - sess.span_diagnostic.struct_span_err(*span, "invalid version string").emit(); + sess.span_diagnostic.struct_span_err(*span, "invalid version literal").emit(); return false; } }; diff --git a/src/test/ui/feature-gates/feature-gate-cfg-version.rs b/src/test/ui/feature-gates/feature-gate-cfg-version.rs index 71b82b7f749e1..ffb08dedc8f54 100644 --- a/src/test/ui/feature-gates/feature-gate-cfg-version.rs +++ b/src/test/ui/feature-gates/feature-gate-cfg-version.rs @@ -5,13 +5,16 @@ fn foo() -> bool { true } //~^ ERROR `cfg(version)` is experimental and subject to change fn foo() -> bool { false } -#[cfg(version("1.43", "1.44", "1.45"))] //~ ERROR: expected single string literal +#[cfg(version("1.43", "1.44", "1.45"))] //~ ERROR: expected single version literal //~^ ERROR `cfg(version)` is experimental and subject to change fn bar() -> bool { false } -#[cfg(version(false))] //~ ERROR: expected string literal +#[cfg(version(false))] //~ ERROR: expected a version literal //~^ ERROR `cfg(version)` is experimental and subject to change fn bar() -> bool { false } -#[cfg(version("foo"))] //~ ERROR: invalid version string +#[cfg(version("foo"))] //~ ERROR: invalid version literal +//~^ ERROR `cfg(version)` is experimental and subject to change +fn bar() -> bool { false } +#[cfg(version("999"))] //~^ ERROR `cfg(version)` is experimental and subject to change fn bar() -> bool { false } #[cfg(version("999"))] diff --git a/src/test/ui/feature-gates/feature-gate-cfg-version.stderr b/src/test/ui/feature-gates/feature-gate-cfg-version.stderr index 48686dd4aebfe..ffc0b4d491422 100644 --- a/src/test/ui/feature-gates/feature-gate-cfg-version.stderr +++ b/src/test/ui/feature-gates/feature-gate-cfg-version.stderr @@ -25,7 +25,7 @@ LL | #[cfg(version("1.43", "1.44", "1.45"))] = note: see issue #64796 for more information = help: add `#![feature(cfg_version)]` to the crate attributes to enable -error: expected single string literal +error: expected single version literal --> $DIR/feature-gate-cfg-version.rs:8:7 | LL | #[cfg(version("1.43", "1.44", "1.45"))] @@ -40,7 +40,7 @@ LL | #[cfg(version(false))] = note: see issue #64796 for more information = help: add `#![feature(cfg_version)]` to the crate attributes to enable -error: expected string literal +error: expected a version literal --> $DIR/feature-gate-cfg-version.rs:11:15 | LL | #[cfg(version(false))] @@ -55,7 +55,7 @@ LL | #[cfg(version("foo"))] = note: see issue #64796 for more information = help: add `#![feature(cfg_version)]` to the crate attributes to enable -error: invalid version string +error: invalid version literal --> $DIR/feature-gate-cfg-version.rs:14:15 | LL | #[cfg(version("foo"))] From a3ee28370fda2f956dc1c1d92858b18ddf55bf79 Mon Sep 17 00:00:00 2001 From: mibac138 <5672750+mibac138@users.noreply.github.com> Date: Tue, 28 Apr 2020 16:07:50 +0200 Subject: [PATCH 09/10] Add more tests for cfg(version) --- src/librustc_attr/builtin.rs | 3 +- .../feature-gates/feature-gate-cfg-version.rs | 12 +++++- .../feature-gate-cfg-version.stderr | 43 ++++++++++++++++++- 3 files changed, 53 insertions(+), 5 deletions(-) diff --git a/src/librustc_attr/builtin.rs b/src/librustc_attr/builtin.rs index fedc29d268fd0..ce38e3f5f4e4e 100644 --- a/src/librustc_attr/builtin.rs +++ b/src/librustc_attr/builtin.rs @@ -652,8 +652,7 @@ pub fn eval_condition( return false; } }; - let version = option_env!("CFG_VERSION").unwrap_or("unknown rustc version"); - let version = Version::parse(version).unwrap(); + let version = Version::parse(env!("CFG_VERSION")).unwrap(); version >= min_version } diff --git a/src/test/ui/feature-gates/feature-gate-cfg-version.rs b/src/test/ui/feature-gates/feature-gate-cfg-version.rs index ffb08dedc8f54..c29ef99945e71 100644 --- a/src/test/ui/feature-gates/feature-gate-cfg-version.rs +++ b/src/test/ui/feature-gates/feature-gate-cfg-version.rs @@ -17,14 +17,24 @@ fn bar() -> bool { false } #[cfg(version("999"))] //~^ ERROR `cfg(version)` is experimental and subject to change fn bar() -> bool { false } -#[cfg(version("999"))] +#[cfg(version("-1"))] //~ ERROR: invalid version literal +//~^ ERROR `cfg(version)` is experimental and subject to change +fn bar() -> bool { false } +#[cfg(version("65536"))] //~ ERROR: invalid version literal //~^ ERROR `cfg(version)` is experimental and subject to change fn bar() -> bool { false } #[cfg(version("0"))] //~^ ERROR `cfg(version)` is experimental and subject to change fn bar() -> bool { true } +#[cfg(version("1.65536.2"))] +//~^ ERROR `cfg(version)` is experimental and subject to change +fn version_check_bug() {} + fn main() { + // This should fail but due to a bug in version_check `1.65536.2` is interpreted as `1.2`. + // See https://github.com/SergioBenitez/version_check/issues/11 + version_check_bug(); assert!(foo()); assert!(bar()); assert!(cfg!(version("1.42"))); //~ ERROR `cfg(version)` is experimental and subject to change diff --git a/src/test/ui/feature-gates/feature-gate-cfg-version.stderr b/src/test/ui/feature-gates/feature-gate-cfg-version.stderr index ffc0b4d491422..bdf160b5a0270 100644 --- a/src/test/ui/feature-gates/feature-gate-cfg-version.stderr +++ b/src/test/ui/feature-gates/feature-gate-cfg-version.stderr @@ -73,6 +73,36 @@ LL | #[cfg(version("999"))] error[E0658]: `cfg(version)` is experimental and subject to change --> $DIR/feature-gate-cfg-version.rs:20:7 | +LL | #[cfg(version("-1"))] + | ^^^^^^^^^^^^^ + | + = note: see issue #64796 for more information + = help: add `#![feature(cfg_version)]` to the crate attributes to enable + +error: invalid version literal + --> $DIR/feature-gate-cfg-version.rs:20:15 + | +LL | #[cfg(version("-1"))] + | ^^^^ + +error[E0658]: `cfg(version)` is experimental and subject to change + --> $DIR/feature-gate-cfg-version.rs:23:7 + | +LL | #[cfg(version("65536"))] + | ^^^^^^^^^^^^^^^^ + | + = note: see issue #64796 for more information + = help: add `#![feature(cfg_version)]` to the crate attributes to enable + +error: invalid version literal + --> $DIR/feature-gate-cfg-version.rs:23:15 + | +LL | #[cfg(version("65536"))] + | ^^^^^^^ + +error[E0658]: `cfg(version)` is experimental and subject to change + --> $DIR/feature-gate-cfg-version.rs:26:7 + | LL | #[cfg(version("0"))] | ^^^^^^^^^^^^ | @@ -80,7 +110,16 @@ LL | #[cfg(version("0"))] = help: add `#![feature(cfg_version)]` to the crate attributes to enable error[E0658]: `cfg(version)` is experimental and subject to change - --> $DIR/feature-gate-cfg-version.rs:27:18 + --> $DIR/feature-gate-cfg-version.rs:30:7 + | +LL | #[cfg(version("1.65536.2"))] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #64796 for more information + = help: add `#![feature(cfg_version)]` to the crate attributes to enable + +error[E0658]: `cfg(version)` is experimental and subject to change + --> $DIR/feature-gate-cfg-version.rs:40:18 | LL | assert!(cfg!(version("1.42"))); | ^^^^^^^^^^^^^^^ @@ -88,6 +127,6 @@ LL | assert!(cfg!(version("1.42"))); = note: see issue #64796 for more information = help: add `#![feature(cfg_version)]` to the crate attributes to enable -error: aborting due to 11 previous errors +error: aborting due to 16 previous errors For more information about this error, try `rustc --explain E0658`. From 8a77d1ca3fc2df789157f7986ddbaf2a377ff0fe Mon Sep 17 00:00:00 2001 From: mibac138 <5672750+mibac138@users.noreply.github.com> Date: Sat, 2 May 2020 18:33:42 +0200 Subject: [PATCH 10/10] Add build script to rustc_attr because of cfg(version) --- src/librustc_attr/Cargo.toml | 1 + src/librustc_attr/build.rs | 4 ++++ 2 files changed, 5 insertions(+) create mode 100644 src/librustc_attr/build.rs diff --git a/src/librustc_attr/Cargo.toml b/src/librustc_attr/Cargo.toml index ad97ac8ffd3d2..d7af7fe6143e5 100644 --- a/src/librustc_attr/Cargo.toml +++ b/src/librustc_attr/Cargo.toml @@ -3,6 +3,7 @@ authors = ["The Rust Project Developers"] name = "rustc_attr" version = "0.0.0" edition = "2018" +build = "build.rs" [lib] name = "rustc_attr" diff --git a/src/librustc_attr/build.rs b/src/librustc_attr/build.rs new file mode 100644 index 0000000000000..d230ba91039ad --- /dev/null +++ b/src/librustc_attr/build.rs @@ -0,0 +1,4 @@ +fn main() { + println!("cargo:rerun-if-changed=build.rs"); + println!("cargo:rerun-if-env-changed=CFG_VERSION"); +}