diff --git a/Cargo.lock b/Cargo.lock index 2685de2244e..0b545a6347b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3257,6 +3257,7 @@ dependencies = [ "rustc_data_structures", "rustc_errors", "rustc_feature", + "rustc_lexer", "rustc_macros", "rustc_serialize", "rustc_session", diff --git a/src/librustc_attr/Cargo.toml b/src/librustc_attr/Cargo.toml index 496becb8f1b..35bdf747f08 100644 --- a/src/librustc_attr/Cargo.toml +++ b/src/librustc_attr/Cargo.toml @@ -16,6 +16,7 @@ rustc_errors = { path = "../librustc_errors" } rustc_span = { path = "../librustc_span" } rustc_data_structures = { path = "../librustc_data_structures" } rustc_feature = { path = "../librustc_feature" } +rustc_lexer = { path = "../librustc_lexer" } rustc_macros = { path = "../librustc_macros" } rustc_session = { path = "../librustc_session" } rustc_ast = { path = "../librustc_ast" } diff --git a/src/librustc_attr/builtin.rs b/src/librustc_attr/builtin.rs index 552584bb4d0..5f131fae385 100644 --- a/src/librustc_attr/builtin.rs +++ b/src/librustc_attr/builtin.rs @@ -20,6 +20,7 @@ enum AttrError { MultipleItem(String), UnknownMetaItem(String, &'static [&'static str]), MissingSince, + NonIdentFeature, MissingFeature, MultipleStabilityLevels, UnsupportedLiteral(&'static str, /* is_bytestr */ bool), @@ -40,6 +41,9 @@ fn handle_errors(sess: &ParseSess, span: Span, error: AttrError) { AttrError::MissingSince => { struct_span_err!(diag, span, E0542, "missing 'since'").emit(); } + AttrError::NonIdentFeature => { + struct_span_err!(diag, span, E0546, "'feature' is not an identifier").emit(); + } AttrError::MissingFeature => { struct_span_err!(diag, span, E0546, "missing 'feature'").emit(); } @@ -344,6 +348,14 @@ fn find_stability_generic<'a, I>( match (feature, reason, issue) { (Some(feature), reason, Some(_)) => { + if !rustc_lexer::is_ident(&feature.as_str()) { + handle_errors( + &sess.parse_sess, + attr.span, + AttrError::NonIdentFeature, + ); + continue; + } let level = Unstable { reason, issue: issue_num, is_soft }; if sym::unstable == meta_name { stab = Some(Stability { level, feature }); diff --git a/src/librustc_expand/proc_macro_server.rs b/src/librustc_expand/proc_macro_server.rs index dc7ba2d0424..83a650443bc 100644 --- a/src/librustc_expand/proc_macro_server.rs +++ b/src/librustc_expand/proc_macro_server.rs @@ -319,18 +319,10 @@ pub struct Ident { } impl Ident { - fn is_valid(string: &str) -> bool { - let mut chars = string.chars(); - if let Some(start) = chars.next() { - rustc_lexer::is_id_start(start) && chars.all(rustc_lexer::is_id_continue) - } else { - false - } - } 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) { + if !rustc_lexer::is_ident(&string) { panic!("`{:?}` is not a valid identifier", string) } if is_raw && !sym.can_be_raw() { diff --git a/src/librustc_lexer/src/lib.rs b/src/librustc_lexer/src/lib.rs index 862ffd50d38..7949a232b9b 100644 --- a/src/librustc_lexer/src/lib.rs +++ b/src/librustc_lexer/src/lib.rs @@ -274,6 +274,16 @@ pub fn is_id_continue(c: char) -> bool { || (c > '\x7f' && unicode_xid::UnicodeXID::is_xid_continue(c)) } +/// The passed string is lexically an identifier. +pub fn is_ident(string: &str) -> bool { + let mut chars = string.chars(); + if let Some(start) = chars.next() { + is_id_start(start) && chars.all(is_id_continue) + } else { + false + } +} + impl Cursor<'_> { /// Parses a token from the input string. fn advance_token(&mut self) -> Token {