Skip to content

Commit 04b2344

Browse files
committed
Auto merge of #46653 - estebank:str-as-ch, r=petrochenkov
When attempting to write str with single quote suggest double quotes Fix #26101.
2 parents 84feab3 + c60aab2 commit 04b2344

File tree

9 files changed

+63
-4
lines changed

9 files changed

+63
-4
lines changed

src/Cargo.lock

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/librustc_errors/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,4 @@ crate-type = ["dylib"]
1212
serialize = { path = "../libserialize" }
1313
syntax_pos = { path = "../libsyntax_pos" }
1414
rustc_data_structures = { path = "../librustc_data_structures" }
15+
unicode-width = "0.1.4"

src/librustc_errors/emitter.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ use std::rc::Rc;
2323
use term;
2424
use std::collections::HashMap;
2525
use std::cmp::min;
26+
use unicode_width;
2627

2728
/// Emitter trait for emitting errors.
2829
pub trait Emitter {
@@ -1182,7 +1183,10 @@ impl EmitterWriter {
11821183
if show_underline {
11831184
draw_col_separator(&mut buffer, row_num, max_line_num_len + 1);
11841185
let start = parts[0].snippet.len() - parts[0].snippet.trim_left().len();
1185-
let sub_len = parts[0].snippet.trim().len();
1186+
// account for substitutions containing unicode characters
1187+
let sub_len = parts[0].snippet.trim().chars().fold(0, |acc, ch| {
1188+
acc + unicode_width::UnicodeWidthChar::width(ch).unwrap_or(0)
1189+
});
11861190
let underline_start = span_start_pos.col.0 + start;
11871191
let underline_end = span_start_pos.col.0 + start + sub_len;
11881192
for p in underline_start..underline_end {

src/librustc_errors/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ extern crate libc;
2626
extern crate rustc_data_structures;
2727
extern crate serialize as rustc_serialize;
2828
extern crate syntax_pos;
29+
extern crate unicode_width;
2930

3031
pub use emitter::ColorConfig;
3132

src/libsyntax/parse/lexer/mod.rs

+27-1
Original file line numberDiff line numberDiff line change
@@ -1306,8 +1306,34 @@ impl<'a> StringReader<'a> {
13061306
'\'');
13071307

13081308
if !self.ch_is('\'') {
1309+
let pos = self.pos;
1310+
loop {
1311+
self.bump();
1312+
if self.ch_is('\'') {
1313+
let start = self.byte_offset(start).to_usize();
1314+
let end = self.byte_offset(self.pos).to_usize();
1315+
self.bump();
1316+
let span = self.mk_sp(start_with_quote, self.pos);
1317+
self.sess.span_diagnostic
1318+
.struct_span_err(span,
1319+
"character literal may only contain one codepoint")
1320+
.span_suggestion(span,
1321+
"if you meant to write a `str` literal, \
1322+
use double quotes",
1323+
format!("\"{}\"",
1324+
&self.source_text[start..end]))
1325+
.emit();
1326+
return Ok(token::Literal(token::Str_(Symbol::intern("??")), None))
1327+
}
1328+
if self.ch_is('\n') || self.is_eof() || self.ch_is('/') {
1329+
// Only attempt to infer single line string literals. If we encounter
1330+
// a slash, bail out in order to avoid nonsensical suggestion when
1331+
// involving comments.
1332+
break;
1333+
}
1334+
}
13091335
panic!(self.fatal_span_verbose(
1310-
start_with_quote, self.pos,
1336+
start_with_quote, pos,
13111337
String::from("character literal may only contain one codepoint")));
13121338
}
13131339

src/test/parse-fail/lex-bad-char-literals-3.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,5 @@
1212

1313
// This test needs to the last one appearing in this file as it kills the parser
1414
static c: char =
15-
'●●' //~ ERROR: character literal may only contain one codepoint: '●
15+
'●●' //~ ERROR: character literal may only contain one codepoint
1616
;

src/test/parse-fail/lex-bad-char-literals-5.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,5 @@
1212
//
1313
// This test needs to the last one appearing in this file as it kills the parser
1414
static c: char =
15-
'\x10\x10' //~ ERROR: character literal may only contain one codepoint: '\x10
15+
'\x10\x10' //~ ERROR: character literal may only contain one codepoint
1616
;
+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
fn main() {
12+
println!('●●');
13+
//~^ ERROR character literal may only contain one codepoint
14+
}
+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
error: character literal may only contain one codepoint
2+
--> $DIR/str-as-char.rs:12:14
3+
|
4+
12 | println!('●●');
5+
| ^^^^
6+
help: if you meant to write a `str` literal, use double quotes
7+
|
8+
12 | println!("●●");
9+
| ^^^^
10+
11+
error: aborting due to previous error
12+

0 commit comments

Comments
 (0)