diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs index 70ec72d73bc6c..ef113b8424d2a 100644 --- a/src/librustc/ich/impls_syntax.rs +++ b/src/librustc/ich/impls_syntax.rs @@ -164,6 +164,7 @@ impl_stable_hash_for!(enum ::syntax::ast::LitIntType { impl_stable_hash_for_spanned!(::syntax::ast::LitKind); impl_stable_hash_for!(enum ::syntax::ast::LitKind { Str(value, style), + Err(value), ByteStr(value), Byte(value), Char(value), @@ -329,6 +330,7 @@ fn hash_token<'a, 'gcx, W: StableHasherResult>( match *lit { token::Lit::Byte(val) | token::Lit::Char(val) | + token::Lit::Err(val) | token::Lit::Integer(val) | token::Lit::Float(val) | token::Lit::Str_(val) | diff --git a/src/librustc_mir/hair/constant.rs b/src/librustc_mir/hair/constant.rs index 37d741d2606d5..f63c3e2ff6142 100644 --- a/src/librustc_mir/hair/constant.rs +++ b/src/librustc_mir/hair/constant.rs @@ -37,6 +37,14 @@ crate fn lit_to_const<'a, 'gcx, 'tcx>( let id = tcx.allocate_bytes(s.as_bytes()); ConstValue::new_slice(Scalar::Ptr(id.into()), s.len() as u64, &tcx) }, + LitKind::Err(ref s) => { + let s = s.as_str(); + let id = tcx.allocate_bytes(s.as_bytes()); + return Ok(ty::Const { + val: ConstValue::new_slice(Scalar::Ptr(id.into()), s.len() as u64, &tcx), + ty: tcx.types.err, + }); + }, LitKind::ByteStr(ref data) => { let id = tcx.allocate_bytes(data); ConstValue::Scalar(Scalar::Ptr(id.into())) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 1b07385d4d1f4..6c228670ff6ab 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3121,7 +3121,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { opt_ty.unwrap_or_else( || tcx.mk_float_var(self.next_float_var_id())) } - ast::LitKind::Bool(_) => tcx.types.bool + ast::LitKind::Bool(_) => tcx.types.bool, + ast::LitKind::Err(_) => tcx.types.err, } } diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index 87e979b93e9ef..558ba1c2e2ef2 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -296,7 +296,7 @@ impl<'a> Classifier<'a> { token::Literal(lit, _suf) => { match lit { // Text literals. - token::Byte(..) | token::Char(..) | + token::Byte(..) | token::Char(..) | token::Err(..) | token::ByteStr(..) | token::ByteStrRaw(..) | token::Str_(..) | token::StrRaw(..) => Class::String, diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 99ab9fbcf5fa0..1180c8c8c1c2b 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1285,6 +1285,8 @@ pub enum LitKind { FloatUnsuffixed(Symbol), /// A boolean literal. Bool(bool), + /// A recovered character literal that contains mutliple `char`s, most likely a typo. + Err(Symbol), } impl LitKind { @@ -1321,6 +1323,7 @@ impl LitKind { | LitKind::ByteStr(..) | LitKind::Byte(..) | LitKind::Char(..) + | LitKind::Err(..) | LitKind::Int(_, LitIntType::Unsuffixed) | LitKind::FloatUnsuffixed(..) | LitKind::Bool(..) => true, diff --git a/src/libsyntax/attr/mod.rs b/src/libsyntax/attr/mod.rs index d03563f8891aa..9c3ee0a3b023a 100644 --- a/src/libsyntax/attr/mod.rs +++ b/src/libsyntax/attr/mod.rs @@ -661,6 +661,7 @@ impl LitKind { } else { "false" })), false), + LitKind::Err(val) => Token::Literal(token::Lit::Err(val), None), } } diff --git a/src/libsyntax/ext/quote.rs b/src/libsyntax/ext/quote.rs index c3124144009ab..01cb1341b9f36 100644 --- a/src/libsyntax/ext/quote.rs +++ b/src/libsyntax/ext/quote.rs @@ -646,6 +646,7 @@ fn expr_mk_token(cx: &ExtCtxt, sp: Span, tok: &token::Token) -> P { token::Literal(token::Byte(i), suf) => return mk_lit!("Byte", suf, i), token::Literal(token::Char(i), suf) => return mk_lit!("Char", suf, i), + token::Literal(token::Err(_i), _suf) => return cx.expr(sp, ast::ExprKind::Err), token::Literal(token::Integer(i), suf) => return mk_lit!("Integer", suf, i), token::Literal(token::Float(i), suf) => return mk_lit!("Float", suf, i), token::Literal(token::Str_(i), suf) => return mk_lit!("Str_", suf, i), diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index 0e1c3b4b61f3a..cf51d3ed58d53 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -1408,9 +1408,10 @@ impl<'a> StringReader<'a> { // lifetimes shouldn't end with a single quote // if we find one, then this is an invalid character literal if self.ch_is('\'') { - self.fatal_span_verbose(start_with_quote, self.next_pos, - String::from("character literal may only contain one codepoint")) - .raise(); + self.err_span_(start_with_quote, self.next_pos, + "character literal may only contain one codepoint"); + self.bump(); + return Ok(token::Literal(token::Err(Symbol::intern("??")), None)) } @@ -1445,7 +1446,7 @@ impl<'a> StringReader<'a> { format!("\"{}\"", &self.src[start..end]), Applicability::MachineApplicable ).emit(); - return Ok(token::Literal(token::Str_(Symbol::intern("??")), None)) + return Ok(token::Literal(token::Err(Symbol::intern("??")), None)) } if self.ch_is('\n') || self.is_eof() || self.ch_is('/') { // Only attempt to infer single line string literals. If we encounter diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index ea205530ca5cc..9e55f359b5ec2 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -466,6 +466,7 @@ crate fn lit_token(lit: token::Lit, suf: Option, diag: Option<(Span, &Ha match lit { token::Byte(i) => (true, Some(LitKind::Byte(byte_lit(&i.as_str()).0))), token::Char(i) => (true, Some(LitKind::Char(char_lit(&i.as_str(), diag).0))), + token::Err(i) => (true, Some(LitKind::Err(i))), // There are some valid suffixes for integer and float literals, // so all the handling is done internally. diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 25a4da38c8c51..f06e975a6d95a 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -60,6 +60,7 @@ impl DelimToken { pub enum Lit { Byte(ast::Name), Char(ast::Name), + Err(ast::Name), Integer(ast::Name), Float(ast::Name), Str_(ast::Name), @@ -73,6 +74,7 @@ impl Lit { match *self { Byte(_) => "byte literal", Char(_) => "char literal", + Err(_) => "invalid literal", Integer(_) => "integer literal", Float(_) => "float literal", Str_(_) | StrRaw(..) => "string literal", @@ -471,8 +473,7 @@ impl Token { Le | EqEq | Ne | Ge | AndAnd | OrOr | Tilde | BinOpEq(..) | At | DotDotDot | DotDotEq | Comma | Semi | ModSep | RArrow | LArrow | FatArrow | Pound | Dollar | - Question | OpenDelim(..) | CloseDelim(..) => return None, - + Question | OpenDelim(..) | CloseDelim(..) | Literal(..) | Ident(..) | Lifetime(..) | Interpolated(..) | DocComment(..) | Whitespace | Comment | Shebang(..) | Eof => return None, }) diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 2ad3d3a6d6487..383baffa266dd 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -224,6 +224,7 @@ pub fn token_to_string(tok: &Token) -> String { let mut out = match lit { token::Byte(b) => format!("b'{}'", b), token::Char(c) => format!("'{}'", c), + token::Err(c) => format!("'{}'", c), token::Float(c) | token::Integer(c) => c.to_string(), token::Str_(s) => format!("\"{}\"", s), @@ -603,6 +604,14 @@ pub trait PrintState<'a> { } match lit.node { ast::LitKind::Str(st, style) => self.print_string(&st.as_str(), style), + ast::LitKind::Err(st) => { + let st = st.as_str().escape_debug(); + let mut res = String::with_capacity(st.len() + 2); + res.push('\''); + res.push_str(&st); + res.push('\''); + self.writer().word(res) + } ast::LitKind::Byte(byte) => { let mut res = String::from("b'"); res.extend(ascii::escape_default(byte).map(|c| c as char)); diff --git a/src/libsyntax_ext/concat.rs b/src/libsyntax_ext/concat.rs index 807f190cb6a1a..f148f8e003df3 100644 --- a/src/libsyntax_ext/concat.rs +++ b/src/libsyntax_ext/concat.rs @@ -23,6 +23,7 @@ pub fn expand_syntax_ext( match e.node { ast::ExprKind::Lit(ref lit) => match lit.node { ast::LitKind::Str(ref s, _) + | ast::LitKind::Err(ref s) | ast::LitKind::Float(ref s, _) | ast::LitKind::FloatUnsuffixed(ref s) => { accumulator.push_str(&s.as_str()); diff --git a/src/test/ui/parser/lex-bad-char-literals-2.rs b/src/test/ui/parser/lex-bad-char-literals-2.rs index 7f859995218d9..1e180f87fc186 100644 --- a/src/test/ui/parser/lex-bad-char-literals-2.rs +++ b/src/test/ui/parser/lex-bad-char-literals-2.rs @@ -1,4 +1,4 @@ // This test needs to the last one appearing in this file as it kills the parser static c: char = - 'nope' //~ ERROR: character literal may only contain one codepoint: 'nope' + 'nope' //~ ERROR: character literal may only contain one codepoint ; diff --git a/src/test/ui/parser/lex-bad-char-literals-2.stderr b/src/test/ui/parser/lex-bad-char-literals-2.stderr index a7075b7187812..7eadb8ebfe06d 100644 --- a/src/test/ui/parser/lex-bad-char-literals-2.stderr +++ b/src/test/ui/parser/lex-bad-char-literals-2.stderr @@ -1,8 +1,13 @@ -error: character literal may only contain one codepoint: 'nope' +error: character literal may only contain one codepoint --> $DIR/lex-bad-char-literals-2.rs:3:5 | -LL | 'nope' //~ ERROR: character literal may only contain one codepoint: 'nope' +LL | 'nope' //~ ERROR: character literal may only contain one codepoint | ^^^^^^ -error: aborting due to previous error +error[E0601]: `main` function not found in crate `lex_bad_char_literals_2` + | + = note: consider adding a `main` function to `$DIR/lex-bad-char-literals-2.rs` + +error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0601`. diff --git a/src/test/ui/parser/lex-bad-char-literals-3.rs b/src/test/ui/parser/lex-bad-char-literals-3.rs index f8749708f7721..5194ff4d9354f 100644 --- a/src/test/ui/parser/lex-bad-char-literals-3.rs +++ b/src/test/ui/parser/lex-bad-char-literals-3.rs @@ -1,7 +1,7 @@ -// This test needs to the last one appearing in this file as it kills the parser -static c: char = - '●●' //~ ERROR: character literal may only contain one codepoint - //~| ERROR: mismatched types -; +static c: char = '●●'; +//~^ ERROR: character literal may only contain one codepoint -fn main() {} +fn main() { + let ch: &str = '●●'; + //~^ ERROR: character literal may only contain one codepoint +} diff --git a/src/test/ui/parser/lex-bad-char-literals-3.stderr b/src/test/ui/parser/lex-bad-char-literals-3.stderr index 89f18e3e2aa4d..6462a3c0e57ba 100644 --- a/src/test/ui/parser/lex-bad-char-literals-3.stderr +++ b/src/test/ui/parser/lex-bad-char-literals-3.stderr @@ -1,22 +1,22 @@ error: character literal may only contain one codepoint - --> $DIR/lex-bad-char-literals-3.rs:3:5 + --> $DIR/lex-bad-char-literals-3.rs:1:18 | -LL | '●●' //~ ERROR: character literal may only contain one codepoint - | ^^^^ +LL | static c: char = '●●'; + | ^^^^ help: if you meant to write a `str` literal, use double quotes | -LL | "●●" //~ ERROR: character literal may only contain one codepoint - | ^^^^ +LL | static c: char = "●●"; + | ^^^^ -error[E0308]: mismatched types - --> $DIR/lex-bad-char-literals-3.rs:3:5 +error: character literal may only contain one codepoint + --> $DIR/lex-bad-char-literals-3.rs:5:20 | -LL | '●●' //~ ERROR: character literal may only contain one codepoint - | ^^^^ expected char, found reference +LL | let ch: &str = '●●'; + | ^^^^ +help: if you meant to write a `str` literal, use double quotes | - = note: expected type `char` - found type `&'static str` +LL | let ch: &str = "●●"; + | ^^^^ error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/parser/lex-bad-char-literals-4.rs b/src/test/ui/parser/lex-bad-char-literals-4.rs index 966e2bb949688..e13f11f36df48 100644 --- a/src/test/ui/parser/lex-bad-char-literals-4.rs +++ b/src/test/ui/parser/lex-bad-char-literals-4.rs @@ -1,5 +1,5 @@ // // This test needs to the last one appearing in this file as it kills the parser static c: char = - '● //~ ERROR: character literal may only contain one codepoint: '● + '● //~ ERROR: character literal may only contain one codepoint ; diff --git a/src/test/ui/parser/lex-bad-char-literals-4.stderr b/src/test/ui/parser/lex-bad-char-literals-4.stderr index 550cb5449df19..881e3d5276bb1 100644 --- a/src/test/ui/parser/lex-bad-char-literals-4.stderr +++ b/src/test/ui/parser/lex-bad-char-literals-4.stderr @@ -1,7 +1,7 @@ error: character literal may only contain one codepoint: '● --> $DIR/lex-bad-char-literals-4.rs:4:5 | -LL | '● //~ ERROR: character literal may only contain one codepoint: '● +LL | '● //~ ERROR: character literal may only contain one codepoint | ^^ error: aborting due to previous error diff --git a/src/test/ui/parser/lex-bad-char-literals-5.rs b/src/test/ui/parser/lex-bad-char-literals-5.rs index 247289ea4d54b..0c4339edc4fa7 100644 --- a/src/test/ui/parser/lex-bad-char-literals-5.rs +++ b/src/test/ui/parser/lex-bad-char-literals-5.rs @@ -1,8 +1,7 @@ -// -// This test needs to the last one appearing in this file as it kills the parser -static c: char = - '\x10\x10' //~ ERROR: character literal may only contain one codepoint - //~| ERROR: mismatched types -; +static c: char = '\x10\x10'; +//~^ ERROR: character literal may only contain one codepoint -fn main() {} +fn main() { + let ch: &str = '\x10\x10'; + //~^ ERROR: character literal may only contain one codepoint +} diff --git a/src/test/ui/parser/lex-bad-char-literals-5.stderr b/src/test/ui/parser/lex-bad-char-literals-5.stderr index 523d71ff49d2b..ef02973310153 100644 --- a/src/test/ui/parser/lex-bad-char-literals-5.stderr +++ b/src/test/ui/parser/lex-bad-char-literals-5.stderr @@ -1,22 +1,22 @@ error: character literal may only contain one codepoint - --> $DIR/lex-bad-char-literals-5.rs:4:5 + --> $DIR/lex-bad-char-literals-5.rs:1:18 | -LL | '/x10/x10' //~ ERROR: character literal may only contain one codepoint - | ^^^^^^^^^^ +LL | static c: char = '/x10/x10'; + | ^^^^^^^^^^ help: if you meant to write a `str` literal, use double quotes | -LL | "/x10/x10" //~ ERROR: character literal may only contain one codepoint - | ^^^^^^^^^^ +LL | static c: char = "/x10/x10"; + | ^^^^^^^^^^ -error[E0308]: mismatched types - --> $DIR/lex-bad-char-literals-5.rs:4:5 +error: character literal may only contain one codepoint + --> $DIR/lex-bad-char-literals-5.rs:5:20 | -LL | '/x10/x10' //~ ERROR: character literal may only contain one codepoint - | ^^^^^^^^^^ expected char, found reference +LL | let ch: &str = '/x10/x10'; + | ^^^^^^^^^^ +help: if you meant to write a `str` literal, use double quotes | - = note: expected type `char` - found type `&'static str` +LL | let ch: &str = "/x10/x10"; + | ^^^^^^^^^^ error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/parser/lex-bad-char-literals-6.rs b/src/test/ui/parser/lex-bad-char-literals-6.rs new file mode 100644 index 0000000000000..4379b4fa6d777 --- /dev/null +++ b/src/test/ui/parser/lex-bad-char-literals-6.rs @@ -0,0 +1,17 @@ +fn main() { + let x: &str = 'ab'; + //~^ ERROR: character literal may only contain one codepoint + let y: char = 'cd'; + //~^ ERROR: character literal may only contain one codepoint + let z = 'ef'; + //~^ ERROR: character literal may only contain one codepoint + + if x == y {} + //~^ ERROR: can't compare `&str` with `char` + if y == z {} // no error here + if x == z {} + //~^ ERROR: can't compare `&str` with `char` + + let a: usize = ""; + //~^ ERROR: mismatched types +} diff --git a/src/test/ui/parser/lex-bad-char-literals-6.stderr b/src/test/ui/parser/lex-bad-char-literals-6.stderr new file mode 100644 index 0000000000000..df99726034878 --- /dev/null +++ b/src/test/ui/parser/lex-bad-char-literals-6.stderr @@ -0,0 +1,47 @@ +error: character literal may only contain one codepoint + --> $DIR/lex-bad-char-literals-6.rs:2:19 + | +LL | let x: &str = 'ab'; + | ^^^^ + +error: character literal may only contain one codepoint + --> $DIR/lex-bad-char-literals-6.rs:4:19 + | +LL | let y: char = 'cd'; + | ^^^^ + +error: character literal may only contain one codepoint + --> $DIR/lex-bad-char-literals-6.rs:6:13 + | +LL | let z = 'ef'; + | ^^^^ + +error[E0277]: can't compare `&str` with `char` + --> $DIR/lex-bad-char-literals-6.rs:9:10 + | +LL | if x == y {} + | ^^ no implementation for `&str == char` + | + = help: the trait `std::cmp::PartialEq` is not implemented for `&str` + +error[E0308]: mismatched types + --> $DIR/lex-bad-char-literals-6.rs:15:20 + | +LL | let a: usize = ""; + | ^^ expected usize, found reference + | + = note: expected type `usize` + found type `&'static str` + +error[E0277]: can't compare `&str` with `char` + --> $DIR/lex-bad-char-literals-6.rs:12:10 + | +LL | if x == z {} + | ^^ no implementation for `&str == char` + | + = help: the trait `std::cmp::PartialEq` is not implemented for `&str` + +error: aborting due to 6 previous errors + +Some errors occurred: E0277, E0308. +For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/str/str-as-char.fixed b/src/test/ui/str/str-as-char.fixed index 9d4297b55c816..accead5c850cc 100644 --- a/src/test/ui/str/str-as-char.fixed +++ b/src/test/ui/str/str-as-char.fixed @@ -1,6 +1,6 @@ // run-rustfix fn main() { - println!("●●"); - //~^ ERROR character literal may only contain one codepoint + println!("{}", "●●"); //~ ERROR character literal may only contain one codepoint + //~^ ERROR format argument must be a string literal } diff --git a/src/test/ui/str/str-as-char.rs b/src/test/ui/str/str-as-char.rs index 710fa74a32a1c..fb179ec7245d2 100644 --- a/src/test/ui/str/str-as-char.rs +++ b/src/test/ui/str/str-as-char.rs @@ -1,6 +1,6 @@ // run-rustfix fn main() { - println!('●●'); - //~^ ERROR character literal may only contain one codepoint + println!('●●'); //~ ERROR character literal may only contain one codepoint + //~^ ERROR format argument must be a string literal } diff --git a/src/test/ui/str/str-as-char.stderr b/src/test/ui/str/str-as-char.stderr index 540a1b55376ff..4ca430a4cde9b 100644 --- a/src/test/ui/str/str-as-char.stderr +++ b/src/test/ui/str/str-as-char.stderr @@ -1,12 +1,22 @@ error: character literal may only contain one codepoint --> $DIR/str-as-char.rs:4:14 | -LL | println!('●●'); +LL | println!('●●'); //~ ERROR character literal may only contain one codepoint | ^^^^ help: if you meant to write a `str` literal, use double quotes | -LL | println!("●●"); +LL | println!("●●"); //~ ERROR character literal may only contain one codepoint | ^^^^ -error: aborting due to previous error +error: format argument must be a string literal + --> $DIR/str-as-char.rs:4:14 + | +LL | println!('●●'); //~ ERROR character literal may only contain one codepoint + | ^^^^ +help: you might be missing a string literal to format with + | +LL | println!("{}", '●●'); //~ ERROR character literal may only contain one codepoint + | ^^^^^ + +error: aborting due to 2 previous errors