From 3638f0e4778bc9ecac206811941db9b1df98fe63 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 14 Jan 2019 09:23:49 -0800 Subject: [PATCH 01/22] Remove GCE cloud setting from AppVeyor config AppVeyor has informed us that this may no longer be necessary after some infrastructure upgrades on their side, so let's see how this goes! --- appveyor.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index f043b8bfefca7..d70ad54b1c812 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -5,12 +5,6 @@ environment: # server goes down presumably. See #43333 for more info CARGO_HTTP_CHECK_REVOKE: false - # Recommended by AppVeyor this moves our builds to GCE which incurs a 3-4 - # minute startup overhead, but that's paltry compared to our overall build - # times so we're will to eat the cost. This is intended to give us better - # performance I believe! - appveyor_build_worker_cloud: gce - matrix: # 32/64 bit MSVC tests - MSYS_BITS: 64 From ee10d99b9a44c57f450678310b16e651d08075cd Mon Sep 17 00:00:00 2001 From: Andy Russell Date: Sat, 15 Dec 2018 12:56:45 -0500 Subject: [PATCH 02/22] generalize markdown to source span calculation --- .../passes/collect_intra_doc_links.rs | 63 +------------- src/librustdoc/passes/mod.rs | 83 +++++++++++++++++++ 2 files changed, 87 insertions(+), 59 deletions(-) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index fdc1c0616187a..56d6671266065 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -451,17 +451,9 @@ pub fn span_of_attrs(attrs: &Attributes) -> syntax_pos::Span { /// Reports a resolution failure diagnostic. /// -/// Ideally we can report the diagnostic with the actual span in the source where the link failure -/// occurred. However, there's a mismatch between the span in the source code and the span in the -/// markdown, so we have to do a bit of work to figure out the correspondence. -/// -/// It's not too hard to find the span for sugared doc comments (`///` and `/**`), because the -/// source will match the markdown exactly, excluding the comment markers. However, it's much more -/// difficult to calculate the spans for unsugared docs, because we have to deal with escaping and -/// other source features. So, we attempt to find the exact source span of the resolution failure -/// in sugared docs, but use the span of the documentation attributes themselves for unsugared -/// docs. Because this span might be overly large, we display the markdown line containing the -/// failure as a note. +/// If we cannot find the exact source span of the resolution failure, we use the span of the +/// documentation attributes themselves. This is a little heavy-handed, so we display the markdown +/// line containing the failure as a note as well. fn resolution_failure( cx: &DocContext, attrs: &Attributes, @@ -473,54 +465,7 @@ fn resolution_failure( let msg = format!("`[{}]` cannot be resolved, ignoring it...", path_str); let mut diag = if let Some(link_range) = link_range { - let src = cx.sess().source_map().span_to_snippet(sp); - let is_all_sugared_doc = attrs.doc_strings.iter().all(|frag| match frag { - DocFragment::SugaredDoc(..) => true, - _ => false, - }); - - if let (Ok(src), true) = (src, is_all_sugared_doc) { - // The number of markdown lines up to and including the resolution failure. - let num_lines = dox[..link_range.start].lines().count(); - - // We use `split_terminator('\n')` instead of `lines()` when counting bytes to ensure - // that DOS-style line endings do not cause the spans to be calculated incorrectly. - let mut src_lines = src.split_terminator('\n'); - let mut md_lines = dox.split_terminator('\n').take(num_lines).peekable(); - - // The number of bytes from the start of the source span to the resolution failure that - // are *not* part of the markdown, like comment markers. - let mut extra_src_bytes = 0; - - while let Some(md_line) = md_lines.next() { - loop { - let source_line = src_lines - .next() - .expect("could not find markdown line in source"); - - match source_line.find(md_line) { - Some(offset) => { - extra_src_bytes += if md_lines.peek().is_some() { - source_line.len() - md_line.len() - } else { - offset - }; - break; - } - None => { - // Since this is a source line that doesn't include a markdown line, - // we have to count the newline that we split from earlier. - extra_src_bytes += source_line.len() + 1; - } - } - } - } - - let sp = sp.from_inner_byte_pos( - link_range.start + extra_src_bytes, - link_range.end + extra_src_bytes, - ); - + if let Some(sp) = super::source_span_for_markdown_range(cx, dox, &link_range, attrs) { let mut diag = cx.tcx.struct_span_lint_node( lint::builtin::INTRA_DOC_LINK_RESOLUTION_FAILURE, NodeId::from_u32(0), diff --git a/src/librustdoc/passes/mod.rs b/src/librustdoc/passes/mod.rs index e897b9a7de58e..23581d0051166 100644 --- a/src/librustdoc/passes/mod.rs +++ b/src/librustdoc/passes/mod.rs @@ -8,6 +8,8 @@ use rustc::util::nodemap::DefIdSet; use std::mem; use std::fmt; use syntax::ast::NodeId; +use syntax_pos::Span; +use std::ops::Range; use clean::{self, GetDefId, Item}; use core::{DocContext, DocAccessLevels}; @@ -396,3 +398,84 @@ pub fn look_for_tests<'a, 'tcx: 'a, 'rcx: 'a>( } } } + +/// Attempts to match a range of bytes from parsed markdown to a `Span` in the source code. +/// +/// This method will return `None` if we cannot construct a span from the source map or if the +/// attributes are not all sugared doc comments. It's difficult to calculate the correct span in +/// that case due to escaping and other source features. +crate fn source_span_for_markdown_range( + cx: &DocContext, + markdown: &str, + md_range: &Range, + attrs: &clean::Attributes, +) -> Option { + let is_all_sugared_doc = attrs.doc_strings.iter().all(|frag| match frag { + clean::DocFragment::SugaredDoc(..) => true, + _ => false, + }); + + if !is_all_sugared_doc { + return None; + } + + let snippet = cx + .sess() + .source_map() + .span_to_snippet(span_of_attrs(attrs)) + .ok()?; + + let starting_line = markdown[..md_range.start].lines().count() - 1; + let ending_line = markdown[..md_range.end].lines().count() - 1; + + // We use `split_terminator('\n')` instead of `lines()` when counting bytes so that we only + // we can treat CRLF and LF line endings the same way. + let mut src_lines = snippet.split_terminator('\n'); + let md_lines = markdown.split_terminator('\n'); + + // The number of bytes from the source span to the markdown span that are not part + // of the markdown, like comment markers. + let mut start_bytes = 0; + let mut end_bytes = 0; + + 'outer: for (line_no, md_line) in md_lines.enumerate() { + loop { + let source_line = src_lines.next().expect("could not find markdown in source"); + match source_line.find(md_line) { + Some(offset) => { + if line_no == starting_line { + start_bytes += offset; + + if starting_line == ending_line { + break 'outer; + } + } else if line_no == ending_line { + end_bytes += offset; + break 'outer; + } else if line_no < starting_line { + start_bytes += source_line.len() - md_line.len(); + } else { + end_bytes += source_line.len() - md_line.len(); + } + break; + } + None => { + // Since this is a source line that doesn't include a markdown line, + // we have to count the newline that we split from earlier. + if line_no <= starting_line { + start_bytes += source_line.len() + 1; + } else { + end_bytes += source_line.len() + 1; + } + } + } + } + } + + let sp = span_of_attrs(attrs).from_inner_byte_pos( + md_range.start + start_bytes, + md_range.end + start_bytes + end_bytes, + ); + + Some(sp) +} From 8c93798e9f80d6d6ed9a2ab4b01af06a8fea23b7 Mon Sep 17 00:00:00 2001 From: Andy Russell Date: Sat, 15 Dec 2018 16:25:50 -0500 Subject: [PATCH 03/22] rustdoc: check code block syntax in early pass --- src/librustdoc/html/highlight.rs | 92 +++++++++------ src/librustdoc/html/markdown.rs | 109 ++++++++++++++++++ src/librustdoc/lib.rs | 1 + .../passes/check_code_block_syntax.rs | 109 ++++++++++++++++++ .../passes/collect_intra_doc_links.rs | 12 +- src/librustdoc/passes/mod.rs | 20 +++- src/libsyntax/parse/lexer/mod.rs | 13 --- src/test/rustdoc-ui/invalid-syntax.rs | 61 +++++++++- src/test/rustdoc-ui/invalid-syntax.stderr | 105 +++++++++++++++-- src/test/rustdoc/bad-codeblock-syntax.rs | 27 +++++ 10 files changed, 476 insertions(+), 73 deletions(-) create mode 100644 src/librustdoc/passes/check_code_block_syntax.rs create mode 100644 src/test/rustdoc/bad-codeblock-syntax.rs diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index 87e979b93e9ef..29a41384edcda 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -25,40 +25,51 @@ pub fn render_with_highlighting( tooltip: Option<(&str, &str)>, ) -> String { debug!("highlighting: ================\n{}\n==============", src); - let sess = parse::ParseSess::new(FilePathMapping::empty()); - let fm = sess.source_map().new_source_file(FileName::Custom("stdin".to_string()), - src.to_string()); - let mut out = Vec::new(); if let Some((tooltip, class)) = tooltip { write!(out, "
{}
", class, tooltip).unwrap(); } - write_header(class, &mut out).unwrap(); - - let lexer = match lexer::StringReader::new_without_err(&sess, fm, None, "Output from rustc:") { - Ok(l) => l, - Err(_) => { - let first_line = src.lines().next().unwrap_or_else(|| ""); - let mut err = sess.span_diagnostic - .struct_warn(&format!("Invalid doc comment starting with: `{}`\n\ - (Ignoring this codeblock)", - first_line)); - err.emit(); - return String::new(); + + let sess = parse::ParseSess::new(FilePathMapping::empty()); + let fm = sess.source_map().new_source_file( + FileName::Custom(String::from("rustdoc-highlighting")), + src.to_owned(), + ); + let highlight_result = + lexer::StringReader::new_or_buffered_errs(&sess, fm, None).and_then(|lexer| { + let mut classifier = Classifier::new(lexer, sess.source_map()); + + let mut highlighted_source = vec![]; + if classifier.write_source(&mut highlighted_source).is_err() { + Err(classifier.lexer.buffer_fatal_errors()) + } else { + Ok(String::from_utf8_lossy(&highlighted_source).into_owned()) + } + }); + + match highlight_result { + Ok(highlighted_source) => { + write_header(class, &mut out).unwrap(); + write!(out, "{}", highlighted_source).unwrap(); + if let Some(extension) = extension { + write!(out, "{}", extension).unwrap(); + } + write_footer(&mut out).unwrap(); } - }; - let mut classifier = Classifier::new(lexer, sess.source_map()); - if classifier.write_source(&mut out).is_err() { - classifier.lexer.emit_fatal_errors(); - return format!("
{}
", src); - } + Err(errors) => { + // If errors are encountered while trying to highlight, cancel the errors and just emit + // the unhighlighted source. The errors will have already been reported in the + // `check-code-block-syntax` pass. + for mut error in errors { + error.cancel(); + } - if let Some(extension) = extension { - write!(out, "{}", extension).unwrap(); + write!(out, "
{}
", src).unwrap(); + } } - write_footer(&mut out).unwrap(); + String::from_utf8_lossy(&out[..]).into_owned() } @@ -151,6 +162,17 @@ impl Writer for U { } } +enum HighlightError { + LexError, + IoError(io::Error), +} + +impl From for HighlightError { + fn from(err: io::Error) -> Self { + HighlightError::IoError(err) + } +} + impl<'a> Classifier<'a> { fn new(lexer: lexer::StringReader<'a>, source_map: &'a SourceMap) -> Classifier<'a> { Classifier { @@ -162,17 +184,11 @@ impl<'a> Classifier<'a> { } } - /// Gets the next token out of the lexer, emitting fatal errors if lexing fails. - fn try_next_token(&mut self) -> io::Result { + /// Gets the next token out of the lexer. + fn try_next_token(&mut self) -> Result { match self.lexer.try_next_token() { Ok(tas) => Ok(tas), - Err(_) => { - let mut err = self.lexer.sess.span_diagnostic - .struct_warn("Backing out of syntax highlighting"); - err.note("You probably did not intend to render this as a rust code-block"); - err.emit(); - Err(io::Error::new(io::ErrorKind::Other, "")) - } + Err(_) => Err(HighlightError::LexError), } } @@ -185,7 +201,7 @@ impl<'a> Classifier<'a> { /// source. fn write_source(&mut self, out: &mut W) - -> io::Result<()> { + -> Result<(), HighlightError> { loop { let next = self.try_next_token()?; if next.tok == token::Eof { @@ -202,7 +218,7 @@ impl<'a> Classifier<'a> { fn write_token(&mut self, out: &mut W, tas: TokenAndSpan) - -> io::Result<()> { + -> Result<(), HighlightError> { let klass = match tas.tok { token::Shebang(s) => { out.string(Escape(&s.as_str()), Class::None)?; @@ -341,7 +357,9 @@ impl<'a> Classifier<'a> { // Anything that didn't return above is the simple case where we the // class just spans a single token, so we can use the `string` method. - out.string(Escape(&self.snip(tas.sp)), klass) + out.string(Escape(&self.snip(tas.sp)), klass)?; + + Ok(()) } // Helper function to get a snippet from the source_map. diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 05a9a2d1312ae..6b7f54044ca1d 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -919,6 +919,115 @@ pub fn markdown_links(md: &str) -> Vec<(String, Option>)> { links } +#[derive(Debug)] +crate struct RustCodeBlock { + /// The range in the markdown that the code block occupies. Note that this includes the fences + /// for fenced code blocks. + pub range: Range, + /// The range in the markdown that the code within the code block occupies. + pub code: Range, + pub is_fenced: bool, + pub syntax: Option, +} + +/// Returns a range of bytes for each code block in the markdown that is tagged as `rust` or +/// untagged (and assumed to be rust). +crate fn rust_code_blocks(md: &str) -> Vec { + let mut code_blocks = vec![]; + + if md.is_empty() { + return code_blocks; + } + + let mut opts = Options::empty(); + opts.insert(OPTION_ENABLE_TABLES); + opts.insert(OPTION_ENABLE_FOOTNOTES); + let mut p = Parser::new_ext(md, opts); + + let mut code_block_start = 0; + let mut code_start = 0; + let mut is_fenced = false; + let mut previous_offset = 0; + let mut in_rust_code_block = false; + while let Some(event) = p.next() { + let offset = p.get_offset(); + + match event { + Event::Start(Tag::CodeBlock(syntax)) => { + let lang_string = if syntax.is_empty() { + LangString::all_false() + } else { + LangString::parse(&*syntax, ErrorCodes::Yes) + }; + + if lang_string.rust { + in_rust_code_block = true; + + code_start = offset; + code_block_start = match md[previous_offset..offset].find("```") { + Some(fence_idx) => { + is_fenced = true; + previous_offset + fence_idx + } + None => offset, + }; + } + } + Event::End(Tag::CodeBlock(syntax)) if in_rust_code_block => { + in_rust_code_block = false; + + let code_block_end = if is_fenced { + let fence_str = &md[previous_offset..offset] + .chars() + .rev() + .collect::(); + fence_str + .find("```") + .map(|fence_idx| offset - fence_idx) + .unwrap_or_else(|| offset) + } else if md + .as_bytes() + .get(offset) + .map(|b| *b == b'\n') + .unwrap_or_default() + { + offset - 1 + } else { + offset + }; + + let code_end = if is_fenced { + previous_offset + } else { + code_block_end + }; + + code_blocks.push(RustCodeBlock { + is_fenced, + range: Range { + start: code_block_start, + end: code_block_end, + }, + code: Range { + start: code_start, + end: code_end, + }, + syntax: if !syntax.is_empty() { + Some(syntax.into_owned()) + } else { + None + }, + }); + } + _ => (), + } + + previous_offset = offset; + } + + code_blocks +} + #[derive(Clone, Default, Debug)] pub struct IdMap { map: FxHashMap, diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 1b6d7e87192d6..6e7141f94a776 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -3,6 +3,7 @@ html_root_url = "https://doc.rust-lang.org/nightly/", html_playground_url = "https://play.rust-lang.org/")] +#![feature(bind_by_move_pattern_guards)] #![feature(rustc_private)] #![feature(box_patterns)] #![feature(box_syntax)] diff --git a/src/librustdoc/passes/check_code_block_syntax.rs b/src/librustdoc/passes/check_code_block_syntax.rs new file mode 100644 index 0000000000000..a013cc36c722d --- /dev/null +++ b/src/librustdoc/passes/check_code_block_syntax.rs @@ -0,0 +1,109 @@ +use errors::Applicability; +use syntax::parse::lexer::{TokenAndSpan, StringReader as Lexer}; +use syntax::parse::{ParseSess, token}; +use syntax::source_map::FilePathMapping; +use syntax_pos::FileName; + +use clean; +use core::DocContext; +use fold::DocFolder; +use html::markdown::{self, RustCodeBlock}; +use passes::Pass; + +pub const CHECK_CODE_BLOCK_SYNTAX: Pass = + Pass::early("check-code-block-syntax", check_code_block_syntax, + "validates syntax inside Rust code blocks"); + +pub fn check_code_block_syntax(krate: clean::Crate, cx: &DocContext) -> clean::Crate { + SyntaxChecker { cx }.fold_crate(krate) +} + +struct SyntaxChecker<'a, 'tcx: 'a, 'rcx: 'a> { + cx: &'a DocContext<'a, 'tcx, 'rcx>, +} + +impl<'a, 'tcx, 'rcx> SyntaxChecker<'a, 'tcx, 'rcx> { + fn check_rust_syntax(&self, item: &clean::Item, dox: &str, code_block: RustCodeBlock) { + let sess = ParseSess::new(FilePathMapping::empty()); + let source_file = sess.source_map().new_source_file( + FileName::Custom(String::from("doctest")), + dox[code_block.code].to_owned(), + ); + + let errors = Lexer::new_or_buffered_errs(&sess, source_file, None).and_then(|mut lexer| { + while let Ok(TokenAndSpan { tok, .. }) = lexer.try_next_token() { + if tok == token::Eof { + break; + } + } + + let errors = lexer.buffer_fatal_errors(); + + if !errors.is_empty() { + Err(errors) + } else { + Ok(()) + } + }); + + if let Err(errors) = errors { + let mut diag = if let Some(sp) = + super::source_span_for_markdown_range(self.cx, &dox, &code_block.range, &item.attrs) + { + let mut diag = self + .cx + .sess() + .struct_span_warn(sp, "could not parse code block as Rust code"); + + for mut err in errors { + diag.note(&format!("error from rustc: {}", err.message())); + err.cancel(); + } + + if code_block.syntax.is_none() && code_block.is_fenced { + let sp = sp.from_inner_byte_pos(0, 3); + diag.span_suggestion_with_applicability( + sp, + "mark blocks that do not contain Rust code as text", + String::from("```text"), + Applicability::MachineApplicable, + ); + } + + diag + } else { + // We couldn't calculate the span of the markdown block that had the error, so our + // diagnostics are going to be a bit lacking. + let mut diag = self.cx.sess().struct_span_warn( + super::span_of_attrs(&item.attrs), + "doc comment contains an invalid Rust code block", + ); + + for mut err in errors { + // Don't bother reporting the error, because we can't show where it happened. + err.cancel(); + } + + if code_block.syntax.is_none() && code_block.is_fenced { + diag.help("mark blocks that do not contain Rust code as text: ```text"); + } + + diag + }; + + diag.emit(); + } + } +} + +impl<'a, 'tcx, 'rcx> DocFolder for SyntaxChecker<'a, 'tcx, 'rcx> { + fn fold_item(&mut self, item: clean::Item) -> Option { + if let Some(dox) = &item.attrs.collapsed_doc_value() { + for code_block in markdown::rust_code_blocks(&dox) { + self.check_rust_syntax(&item, &dox, code_block); + } + } + + self.fold_item_recur(item) + } +} diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 56d6671266065..3d6096b07ce43 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -6,7 +6,7 @@ use syntax; use syntax::ast::{self, Ident, NodeId}; use syntax::feature_gate::UnstableFeatures; use syntax::symbol::Symbol; -use syntax_pos::{self, DUMMY_SP}; +use syntax_pos::DUMMY_SP; use std::ops::Range; @@ -16,6 +16,7 @@ use html::markdown::markdown_links; use clean::*; use passes::{look_for_tests, Pass}; +use super::span_of_attrs; pub const COLLECT_INTRA_DOC_LINKS: Pass = Pass::early("collect-intra-doc-links", collect_intra_doc_links, @@ -440,15 +441,6 @@ fn macro_resolve(cx: &DocContext, path_str: &str) -> Option { None } -pub fn span_of_attrs(attrs: &Attributes) -> syntax_pos::Span { - if attrs.doc_strings.is_empty() { - return DUMMY_SP; - } - let start = attrs.doc_strings[0].span(); - let end = attrs.doc_strings.last().expect("No doc strings provided").span(); - start.to(end) -} - /// Reports a resolution failure diagnostic. /// /// If we cannot find the exact source span of the resolution failure, we use the span of the diff --git a/src/librustdoc/passes/mod.rs b/src/librustdoc/passes/mod.rs index 23581d0051166..c9a3a2c003fe0 100644 --- a/src/librustdoc/passes/mod.rs +++ b/src/librustdoc/passes/mod.rs @@ -8,7 +8,7 @@ use rustc::util::nodemap::DefIdSet; use std::mem; use std::fmt; use syntax::ast::NodeId; -use syntax_pos::Span; +use syntax_pos::{DUMMY_SP, Span}; use std::ops::Range; use clean::{self, GetDefId, Item}; @@ -18,8 +18,6 @@ use fold::StripItem; use html::markdown::{find_testable_code, ErrorCodes, LangString}; -use self::collect_intra_doc_links::span_of_attrs; - mod collapse_docs; pub use self::collapse_docs::COLLAPSE_DOCS; @@ -47,6 +45,9 @@ pub use self::private_items_doc_tests::CHECK_PRIVATE_ITEMS_DOC_TESTS; mod collect_trait_impls; pub use self::collect_trait_impls::COLLECT_TRAIT_IMPLS; +mod check_code_block_syntax; +pub use self::check_code_block_syntax::CHECK_CODE_BLOCK_SYNTAX; + /// Represents a single pass. #[derive(Copy, Clone)] pub enum Pass { @@ -137,6 +138,7 @@ pub const PASSES: &'static [Pass] = &[ STRIP_PRIV_IMPORTS, PROPAGATE_DOC_CFG, COLLECT_INTRA_DOC_LINKS, + CHECK_CODE_BLOCK_SYNTAX, COLLECT_TRAIT_IMPLS, ]; @@ -147,6 +149,7 @@ pub const DEFAULT_PASSES: &'static [&'static str] = &[ "strip-hidden", "strip-private", "collect-intra-doc-links", + "check-code-block-syntax", "collapse-docs", "unindent-comments", "propagate-doc-cfg", @@ -158,6 +161,7 @@ pub const DEFAULT_PRIVATE_PASSES: &'static [&'static str] = &[ "check-private-items-doc-tests", "strip-priv-imports", "collect-intra-doc-links", + "check-code-block-syntax", "collapse-docs", "unindent-comments", "propagate-doc-cfg", @@ -399,6 +403,16 @@ pub fn look_for_tests<'a, 'tcx: 'a, 'rcx: 'a>( } } +/// Return a span encompassing all the given attributes. +crate fn span_of_attrs(attrs: &clean::Attributes) -> Span { + if attrs.doc_strings.is_empty() { + return DUMMY_SP; + } + let start = attrs.doc_strings[0].span(); + let end = attrs.doc_strings.last().expect("No doc strings provided").span(); + start.to(end) +} + /// Attempts to match a range of bytes from parsed markdown to a `Span` in the source code. /// /// This method will return `None` if we cannot construct a span from the source map or if the diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index ecb34e43c590c..53650bd55aea3 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -238,19 +238,6 @@ impl<'a> StringReader<'a> { sr } - pub fn new_without_err(sess: &'a ParseSess, - source_file: Lrc, - override_span: Option, - prepend_error_text: &str) -> Result { - let mut sr = StringReader::new_raw(sess, source_file, override_span); - if sr.advance_token().is_err() { - eprintln!("{}", prepend_error_text); - sr.emit_fatal_errors(); - return Err(()); - } - Ok(sr) - } - pub fn new_or_buffered_errs(sess: &'a ParseSess, source_file: Lrc, override_span: Option) -> Result> { diff --git a/src/test/rustdoc-ui/invalid-syntax.rs b/src/test/rustdoc-ui/invalid-syntax.rs index 537816be8d735..924e0386d3191 100644 --- a/src/test/rustdoc-ui/invalid-syntax.rs +++ b/src/test/rustdoc-ui/invalid-syntax.rs @@ -1,7 +1,66 @@ // compile-pass -// compile-flags: --error-format=human /// ``` /// \__________pkt->size___________/ \_result->size_/ \__pkt->size__/ /// ``` pub fn foo() {} + +/// ``` +/// | +/// LL | use foobar::Baz; +/// | ^^^^^^ did you mean `baz::foobar`? +/// ``` +pub fn bar() {} + +/// ``` +/// valid +/// ``` +/// +/// ``` +/// \_ +/// ``` +/// +/// ```text +/// "invalid +/// ``` +pub fn valid_and_invalid() {} + +/// This is a normal doc comment, but... +/// +/// There's a code block with bad syntax in it: +/// +/// ```rust +/// \_ +/// ``` +/// +/// Good thing we tested it! +pub fn baz() {} + +/// Indented block start +/// +/// code with bad syntax +/// \_ +/// +/// Indented block end +pub fn quux() {} + +/// Unclosed fence +/// +/// ``` +/// slkdjf +pub fn xyzzy() {} + +/// Indented code that contains a fence +/// +/// ``` +pub fn blah() {} + +/// ```edition2018 +/// \_ +/// ``` +pub fn blargh() {} + +#[doc = "```"] +/// \_ +#[doc = "```"] +pub fn crazy_attrs() {} diff --git a/src/test/rustdoc-ui/invalid-syntax.stderr b/src/test/rustdoc-ui/invalid-syntax.stderr index b5661332e8d0e..10800380a05d3 100644 --- a/src/test/rustdoc-ui/invalid-syntax.stderr +++ b/src/test/rustdoc-ui/invalid-syntax.stderr @@ -1,10 +1,97 @@ -Output from rustc: -error: unknown start of token: / - --> :1:1 - | -1 | /__________pkt->size___________/ /_result->size_/ /__pkt->size__/ - | ^ - -warning: Invalid doc comment starting with: `/__________pkt->size___________/ /_result->size_/ /__pkt->size__/` -(Ignoring this codeblock) +warning: could not parse code block as Rust code + --> $DIR/invalid-syntax.rs:3:5 + | +LL | /// ``` + | _____^ +LL | | /// /__________pkt->size___________/ /_result->size_/ /__pkt->size__/ +LL | | /// ``` + | |_______^ + | + = note: error from rustc: unknown start of token: / +help: mark blocks that do not contain Rust code as text + | +LL | /// ```text + | ^^^^^^^ + +warning: could not parse code block as Rust code + --> $DIR/invalid-syntax.rs:8:5 + | +LL | /// ``` + | _____^ +LL | | /// | +LL | | /// LL | use foobar::Baz; +LL | | /// | ^^^^^^ did you mean `baz::foobar`? +LL | | /// ``` + | |_______^ + | + = note: error from rustc: unknown start of token: ` +help: mark blocks that do not contain Rust code as text + | +LL | /// ```text + | ^^^^^^^ + +warning: could not parse code block as Rust code + --> $DIR/invalid-syntax.rs:19:5 + | +LL | /// ``` + | _____^ +LL | | /// /_ +LL | | /// ``` + | |_______^ + | + = note: error from rustc: unknown start of token: / +help: mark blocks that do not contain Rust code as text + | +LL | /// ```text + | ^^^^^^^ + +warning: could not parse code block as Rust code + --> $DIR/invalid-syntax.rs:32:5 + | +LL | /// ```rust + | _____^ +LL | | /// /_ +LL | | /// ``` + | |_______^ + | + = note: error from rustc: unknown start of token: / + +warning: could not parse code block as Rust code + --> $DIR/invalid-syntax.rs:41:9 + | +LL | /// code with bad syntax + | _________^ +LL | | /// /_ + | |__________^ + | + = note: error from rustc: unknown start of token: / + +warning: could not parse code block as Rust code + --> $DIR/invalid-syntax.rs:55:9 + | +LL | /// ``` + | ^^^ + | + = note: error from rustc: unknown start of token: ` + +warning: could not parse code block as Rust code + --> $DIR/invalid-syntax.rs:58:5 + | +LL | /// ```edition2018 + | _____^ +LL | | /// /_ +LL | | /// ``` + | |_______^ + | + = note: error from rustc: unknown start of token: / + +warning: doc comment contains an invalid Rust code block + --> $DIR/invalid-syntax.rs:63:1 + | +LL | / #[doc = "```"] +LL | | /// /_ +LL | | #[doc = "```"] + | |______________^ + | + = help: mark blocks that do not contain Rust code as text: ```text diff --git a/src/test/rustdoc/bad-codeblock-syntax.rs b/src/test/rustdoc/bad-codeblock-syntax.rs new file mode 100644 index 0000000000000..0ab2f68fcdebe --- /dev/null +++ b/src/test/rustdoc/bad-codeblock-syntax.rs @@ -0,0 +1,27 @@ +// @has bad_codeblock_syntax/fn.foo.html +// @has - '//*[@class="docblock"]/pre/code' '\_' +/// ``` +/// \_ +/// ``` +pub fn foo() {} + +// @has bad_codeblock_syntax/fn.bar.html +// @has - '//*[@class="docblock"]/pre/code' '`baz::foobar`' +/// ``` +/// `baz::foobar` +/// ``` +pub fn bar() {} + +// @has bad_codeblock_syntax/fn.quux.html +// @has - '//*[@class="docblock"]/pre/code' '\_' +/// ```rust +/// \_ +/// ``` +pub fn quux() {} + +// @has bad_codeblock_syntax/fn.ok.html +// @has - '//*[@class="docblock"]/pre/code[@class="language-text"]' '\_' +/// ```text +/// \_ +/// ``` +pub fn ok() {} From d19294feeea5f09409974b94ddd3f441b8871bb3 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Wed, 16 Jan 2019 09:27:43 +0900 Subject: [PATCH 04/22] Add new literal type Err --- src/librustc/ich/impls_syntax.rs | 1 + src/libsyntax/ext/quote.rs | 1 + src/libsyntax/parse/mod.rs | 1 + src/libsyntax/parse/token.rs | 2 ++ src/libsyntax/print/pprust.rs | 1 + 5 files changed, 6 insertions(+) diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs index 70ec72d73bc6c..6ffb771ffcc4e 100644 --- a/src/librustc/ich/impls_syntax.rs +++ b/src/librustc/ich/impls_syntax.rs @@ -329,6 +329,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/libsyntax/ext/quote.rs b/src/libsyntax/ext/quote.rs index c3124144009ab..17c88a30bcd0b 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 mk_lit!("Err", suf, i), 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/mod.rs b/src/libsyntax/parse/mod.rs index ea205530ca5cc..cbb503f56bc4a 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::Char(char_lit(&i.as_str(), diag).0))), // 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..69e934d64c6cd 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(_) => "error literal", Integer(_) => "integer literal", Float(_) => "float literal", Str_(_) | StrRaw(..) => "string literal", diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 2ad3d3a6d6487..123f9b49692d9 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), From ec8db2a94446f2ef4da7ac89bbe5e171fe17e46f Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Wed, 16 Jan 2019 09:28:06 +0900 Subject: [PATCH 05/22] Cancel process --- src/libsyntax/parse/lexer/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index 0e1c3b4b61f3a..666653f9edf80 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -1445,7 +1445,7 @@ impl<'a> StringReader<'a> { format!("\"{}\"", &self.src[start..end]), Applicability::MachineApplicable ).emit(); - return Ok(token::Literal(token::Str_(Symbol::intern("??")), None)) + FatalError.raise(); } if self.ch_is('\n') || self.is_eof() || self.ch_is('/') { // Only attempt to infer single line string literals. If we encounter From d33ee3fefa3fad88fee81b5abb316e94c387d72e Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Wed, 16 Jan 2019 09:28:26 +0900 Subject: [PATCH 06/22] Fix tests --- src/test/ui/parser/lex-bad-char-literals-3.rs | 1 - src/test/ui/parser/lex-bad-char-literals-3.stderr | 12 +----------- src/test/ui/parser/lex-bad-char-literals-5.rs | 1 - src/test/ui/parser/lex-bad-char-literals-5.stderr | 12 +----------- 4 files changed, 2 insertions(+), 24 deletions(-) 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..d14ec1cc51560 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,6 @@ // 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 ; fn main() {} 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..dde4a7db3aa79 100644 --- a/src/test/ui/parser/lex-bad-char-literals-3.stderr +++ b/src/test/ui/parser/lex-bad-char-literals-3.stderr @@ -8,15 +8,5 @@ help: if you meant to write a `str` literal, use double quotes LL | "●●" //~ ERROR: character literal may only contain one codepoint | ^^^^ -error[E0308]: mismatched types - --> $DIR/lex-bad-char-literals-3.rs:3:5 - | -LL | '●●' //~ ERROR: character literal may only contain one codepoint - | ^^^^ expected char, found reference - | - = note: expected type `char` - found type `&'static str` - -error: aborting due to 2 previous errors +error: aborting due to previous error -For more information about this error, try `rustc --explain E0308`. 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..1236e76de420e 100644 --- a/src/test/ui/parser/lex-bad-char-literals-5.rs +++ b/src/test/ui/parser/lex-bad-char-literals-5.rs @@ -2,7 +2,6 @@ // 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 ; fn main() {} 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..4f734eaeff353 100644 --- a/src/test/ui/parser/lex-bad-char-literals-5.stderr +++ b/src/test/ui/parser/lex-bad-char-literals-5.stderr @@ -8,15 +8,5 @@ help: if you meant to write a `str` literal, use double quotes LL | "/x10/x10" //~ ERROR: character literal may only contain one codepoint | ^^^^^^^^^^ -error[E0308]: mismatched types - --> $DIR/lex-bad-char-literals-5.rs:4:5 - | -LL | '/x10/x10' //~ ERROR: character literal may only contain one codepoint - | ^^^^^^^^^^ expected char, found reference - | - = note: expected type `char` - found type `&'static str` - -error: aborting due to 2 previous errors +error: aborting due to previous error -For more information about this error, try `rustc --explain E0308`. From 1a51bb8174e97251a37fcd83ff8750b7773e762a Mon Sep 17 00:00:00 2001 From: tyler Date: Tue, 15 Jan 2019 20:09:06 -0800 Subject: [PATCH 07/22] OSX: fix #57534 registering thread dtors while running thread dtors --- src/libstd/sys/unix/fast_thread_local.rs | 61 +++++++++++++++++------- src/libstd/thread/local.rs | 8 +--- 2 files changed, 45 insertions(+), 24 deletions(-) diff --git a/src/libstd/sys/unix/fast_thread_local.rs b/src/libstd/sys/unix/fast_thread_local.rs index d48d701dd50ea..742ffd12b883d 100644 --- a/src/libstd/sys/unix/fast_thread_local.rs +++ b/src/libstd/sys/unix/fast_thread_local.rs @@ -33,30 +33,57 @@ pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) { register_dtor_fallback(t, dtor); } -// macOS's analog of the above linux function is this _tlv_atexit function. -// The disassembly of thread_local globals in C++ (at least produced by -// clang) will have this show up in the output. +// This implementation is very similar to register_dtor_fallback in +// sys_common/thread_local.rs. The main difference is that we want to hook into +// macOS's analog of the above linux function, _tlv_atexit. OSX will run the +// registered dtors before any TLS slots get freed, and when the main thread +// exits. +// +// Unfortunately, calling _tlv_atexit while tls dtors are running is UB. The +// workaround below is to register, via _tlv_atexit, a custom DTOR list once per +// thread. thread_local dtors are pushed to the DTOR list without calling +// _tlv_atexit. #[cfg(target_os = "macos")] pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) { + use cell::Cell; + use ptr; + + #[thread_local] + static REGISTERED: Cell = Cell::new(false); + if !REGISTERED.get() { + _tlv_atexit(run_dtors, ptr::null_mut()); + REGISTERED.set(true); + } + + type List = Vec<(*mut u8, unsafe extern fn(*mut u8))>; + + #[thread_local] + static DTORS: Cell<*mut List> = Cell::new(ptr::null_mut()); + if DTORS.get().is_null() { + let v: Box = box Vec::new(); + DTORS.set(Box::into_raw(v)); + } + extern { fn _tlv_atexit(dtor: unsafe extern fn(*mut u8), arg: *mut u8); } - _tlv_atexit(dtor, t); + + let list: &mut List = &mut *DTORS.get(); + list.push((t, dtor)); + + unsafe extern fn run_dtors(_: *mut u8) { + let mut ptr = DTORS.replace(ptr::null_mut()); + while !ptr.is_null() { + let list = Box::from_raw(ptr); + for (ptr, dtor) in list.into_iter() { + dtor(ptr); + } + ptr = DTORS.replace(ptr::null_mut()); + } + } } pub fn requires_move_before_drop() -> bool { - // The macOS implementation of TLS apparently had an odd aspect to it - // where the pointer we have may be overwritten while this destructor - // is running. Specifically if a TLS destructor re-accesses TLS it may - // trigger a re-initialization of all TLS variables, paving over at - // least some destroyed ones with initial values. - // - // This means that if we drop a TLS value in place on macOS that we could - // revert the value to its original state halfway through the - // destructor, which would be bad! - // - // Hence, we use `ptr::read` on macOS (to move to a "safe" location) - // instead of drop_in_place. - cfg!(target_os = "macos") + false } diff --git a/src/libstd/thread/local.rs b/src/libstd/thread/local.rs index efd231e017679..5d2eb5f8e7320 100644 --- a/src/libstd/thread/local.rs +++ b/src/libstd/thread/local.rs @@ -69,9 +69,6 @@ use mem; /// destroyed, but not all platforms have this guard. Those platforms that do /// not guard typically have a synthetic limit after which point no more /// destructors are run. -/// 3. On macOS, initializing TLS during destruction of other TLS slots can -/// sometimes cancel *all* destructors for the current thread, whether or not -/// the slots have already had their destructors run or not. /// /// [`with`]: ../../std/thread/struct.LocalKey.html#method.with /// [`thread_local!`]: ../../std/macro.thread_local.html @@ -604,11 +601,8 @@ mod tests { } // Note that this test will deadlock if TLS destructors aren't run (this - // requires the destructor to be run to pass the test). macOS has a known bug - // where dtors-in-dtors may cancel other destructors, so we just ignore this - // test on macOS. + // requires the destructor to be run to pass the test). #[test] - #[cfg_attr(target_os = "macos", ignore)] fn dtors_in_dtors_in_dtors() { struct S1(Sender<()>); thread_local!(static K1: UnsafeCell> = UnsafeCell::new(None)); From 9b8c3c4cff4302a50fc8c82a18f10fc97b0fb3b7 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Wed, 16 Jan 2019 13:13:58 -0800 Subject: [PATCH 08/22] [rustbuild] Rebuild std after changes to codegen backends Use `clear_if_dirty` on std for backend changes, just as we do for changes to rustc itself, so new codegen is correctly applied to all later compiler stages. Fixes #48298. --- src/bootstrap/builder.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 9c58f5b179fd8..31adab64f609d 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -660,6 +660,15 @@ impl<'a> Builder<'a> { } } + /// Get the paths to all of the compiler's codegen backends. + fn codegen_backends(&self, compiler: Compiler) -> impl Iterator { + fs::read_dir(self.sysroot_codegen_backends(compiler)) + .into_iter() + .flatten() + .filter_map(Result::ok) + .map(|entry| entry.path()) + } + pub fn rustdoc(&self, host: Interned) -> PathBuf { self.ensure(tool::Rustdoc { host }) } @@ -750,6 +759,9 @@ impl<'a> Builder<'a> { match mode { Mode::Std => { self.clear_if_dirty(&my_out, &self.rustc(compiler)); + for backend in self.codegen_backends(compiler) { + self.clear_if_dirty(&my_out, &backend); + } }, Mode::Test => { self.clear_if_dirty(&my_out, &libstd_stamp); From f0d3df39cbe1a3afaaabddbc5764b4057c713dd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Steinbrink?= Date: Tue, 15 Jan 2019 21:53:37 +0100 Subject: [PATCH 09/22] Use a faster early exit during region expansion Turns out that the equality check for regions is rather expensive, and the current early exit check works in such a way, that the comparison is even done twice. As we only really care about the case of equal scopes, we can perform a faster, more specialized check and move it up one level, so we can eventually skip the additional full comparison as well. --- src/librustc/infer/lexical_region_resolve/mod.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/librustc/infer/lexical_region_resolve/mod.rs b/src/librustc/infer/lexical_region_resolve/mod.rs index 39ce8cc621b49..24ead37403138 100644 --- a/src/librustc/infer/lexical_region_resolve/mod.rs +++ b/src/librustc/infer/lexical_region_resolve/mod.rs @@ -236,6 +236,14 @@ impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> { match *b_data { VarValue::Value(cur_region) => { + // Identical scopes can show up quite often, if the fixed point + // iteration converges slowly, skip them + if let (ReScope(a_scope), ReScope(cur_scope)) = (a_region, cur_region) { + if a_scope == cur_scope { + return false; + } + } + let mut lub = self.lub_concrete_regions(a_region, cur_region); if lub == cur_region { return false; @@ -275,12 +283,6 @@ impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> { fn lub_concrete_regions(&self, a: Region<'tcx>, b: Region<'tcx>) -> Region<'tcx> { let tcx = self.tcx(); - // Equal scopes can show up quite often, if the fixed point - // iteration converges slowly, skip them - if a == b { - return a; - } - match (a, b) { (&ty::ReClosureBound(..), _) | (_, &ty::ReClosureBound(..)) From c2863dd1b43f4f1fe63a209922f7e72db53f9663 Mon Sep 17 00:00:00 2001 From: lenoil98 Date: Thu, 17 Jan 2019 13:20:00 -0500 Subject: [PATCH 10/22] Update bootstrap.py Add PowerPC64 support on FreeBSD --- src/bootstrap/bootstrap.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index f3dbae6909a4d..e8c1594bda343 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -230,6 +230,9 @@ def default_build_triple(): err = "unknown OS type: {}".format(ostype) sys.exit(err) + if cputype == 'powerpc' and ostype == 'unknown-freebsd': + cputype = subprocess.check_output( + ['uname', '-p']).strip().decode(default_encoding) cputype_mapper = { 'BePC': 'i686', 'aarch64': 'aarch64', From 32662c2953bfc05e0cbef30ee51647f679bb1f4f Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Fri, 18 Jan 2019 05:20:27 +0900 Subject: [PATCH 11/22] Change from error to invalid --- src/libsyntax/parse/token.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 69e934d64c6cd..99041fd7cd634 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -74,7 +74,7 @@ impl Lit { match *self { Byte(_) => "byte literal", Char(_) => "char literal", - Err(_) => "error literal", + Err(_) => "invalid literal", Integer(_) => "integer literal", Float(_) => "float literal", Str_(_) | StrRaw(..) => "string literal", From bde3795d465c1a1768afa49cc5e79cea93cb99f3 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Fri, 18 Jan 2019 05:22:00 +0900 Subject: [PATCH 12/22] Continue cheking --- src/libsyntax/parse/lexer/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index 666653f9edf80..2bf7ff4bd7a28 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -1445,7 +1445,7 @@ impl<'a> StringReader<'a> { format!("\"{}\"", &self.src[start..end]), Applicability::MachineApplicable ).emit(); - FatalError.raise(); + return Ok(token::Literal(token::Char(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 From 7e2e61c618b53ccaa5d64b57b4c1872bc73746aa Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Fri, 18 Jan 2019 05:23:25 +0900 Subject: [PATCH 13/22] Change from mk_lit! to cx.expr --- src/libsyntax/ext/quote.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libsyntax/ext/quote.rs b/src/libsyntax/ext/quote.rs index 17c88a30bcd0b..01cb1341b9f36 100644 --- a/src/libsyntax/ext/quote.rs +++ b/src/libsyntax/ext/quote.rs @@ -646,7 +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 mk_lit!("Err", 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), From 8bbb63c60055b896b5daa619f76a3a81c585344e Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Fri, 18 Jan 2019 05:23:56 +0900 Subject: [PATCH 14/22] Add token::Err --- src/librustdoc/html/highlight.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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, From b721c1a885537de960733a54f86ba7a6f24a4857 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Fri, 18 Jan 2019 05:24:17 +0900 Subject: [PATCH 15/22] Fix tests --- src/test/ui/parser/lex-bad-char-literals-3.rs | 5 ++++- .../ui/parser/lex-bad-char-literals-3.stderr | 22 ++++++++++++++++++- src/test/ui/parser/lex-bad-char-literals-5.rs | 5 ++++- .../ui/parser/lex-bad-char-literals-5.stderr | 22 ++++++++++++++++++- src/test/ui/str/str-as-char.fixed | 4 ++-- src/test/ui/str/str-as-char.rs | 4 ++-- src/test/ui/str/str-as-char.stderr | 16 +++++++++++--- 7 files changed, 67 insertions(+), 11 deletions(-) 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 d14ec1cc51560..10a8cd4a53eab 100644 --- a/src/test/ui/parser/lex-bad-char-literals-3.rs +++ b/src/test/ui/parser/lex-bad-char-literals-3.rs @@ -3,4 +3,7 @@ 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 + //~^ ERROR: mismatched types +} 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 dde4a7db3aa79..9b4e69870cae8 100644 --- a/src/test/ui/parser/lex-bad-char-literals-3.stderr +++ b/src/test/ui/parser/lex-bad-char-literals-3.stderr @@ -8,5 +8,25 @@ help: if you meant to write a `str` literal, use double quotes LL | "●●" //~ ERROR: character literal may only contain one codepoint | ^^^^ -error: aborting due to previous error +error: character literal may only contain one codepoint + --> $DIR/lex-bad-char-literals-3.rs:7:20 + | +LL | let ch: &str = '●●'; //~ ERROR: character literal may only contain one codepoint + | ^^^^ +help: if you meant to write a `str` literal, use double quotes + | +LL | let ch: &str = "●●"; //~ ERROR: character literal may only contain one codepoint + | ^^^^ + +error[E0308]: mismatched types + --> $DIR/lex-bad-char-literals-3.rs:7:20 + | +LL | let ch: &str = '●●'; //~ ERROR: character literal may only contain one codepoint + | ^^^^ expected &str, found char + | + = note: expected type `&str` + found type `char` + +error: aborting due to 3 previous errors +For more information about this error, try `rustc --explain E0308`. 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 1236e76de420e..964099c3fa98d 100644 --- a/src/test/ui/parser/lex-bad-char-literals-5.rs +++ b/src/test/ui/parser/lex-bad-char-literals-5.rs @@ -4,4 +4,7 @@ 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 + //~^ ERROR: mismatched types +} 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 4f734eaeff353..177d8c599a894 100644 --- a/src/test/ui/parser/lex-bad-char-literals-5.stderr +++ b/src/test/ui/parser/lex-bad-char-literals-5.stderr @@ -8,5 +8,25 @@ help: if you meant to write a `str` literal, use double quotes LL | "/x10/x10" //~ ERROR: character literal may only contain one codepoint | ^^^^^^^^^^ -error: aborting due to previous error +error: character literal may only contain one codepoint + --> $DIR/lex-bad-char-literals-5.rs:8:20 + | +LL | let ch: &str = '/x10/x10'; //~ ERROR: character literal may only contain one codepoint + | ^^^^^^^^^^ +help: if you meant to write a `str` literal, use double quotes + | +LL | let ch: &str = "/x10/x10"; //~ ERROR: character literal may only contain one codepoint + | ^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/lex-bad-char-literals-5.rs:8:20 + | +LL | let ch: &str = '/x10/x10'; //~ ERROR: character literal may only contain one codepoint + | ^^^^^^^^^^ expected &str, found char + | + = note: expected type `&str` + found type `char` + +error: aborting due to 3 previous errors +For more information about this error, try `rustc --explain E0308`. 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 From c502a79fa1a15de88623bc01d9a1c38db3ea2c1b Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Sun, 20 Jan 2019 04:37:29 +0900 Subject: [PATCH 16/22] [WIP] Improve error behavior --- src/libsyntax/parse/lexer/mod.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index 2bf7ff4bd7a28..fcaa35d1fca73 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::Char(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 @@ -1455,8 +1456,9 @@ impl<'a> StringReader<'a> { } } - self.fatal_span_verbose(start_with_quote, pos, - String::from("character literal may only contain one codepoint")).raise(); + self.err_span_(start_with_quote, pos, + "character literal may only contain one codepoint"); + self.bump(); } let id = if valid { From e9af312932baee90d260b41711f7ea95ad51bc07 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Sun, 20 Jan 2019 04:37:58 +0900 Subject: [PATCH 17/22] [WIP] Fix tests --- src/test/ui/parser/lex-bad-char-literals-2.rs | 2 +- .../ui/parser/lex-bad-char-literals-2.stderr | 9 ++- src/test/ui/parser/lex-bad-char-literals-4.rs | 2 +- .../ui/parser/lex-bad-char-literals-4.stderr | 16 +++++- src/test/ui/parser/lex-bad-char-literals-6.rs | 12 ++++ .../ui/parser/lex-bad-char-literals-6.stderr | 56 +++++++++++++++++++ 6 files changed, 91 insertions(+), 6 deletions(-) create mode 100644 src/test/ui/parser/lex-bad-char-literals-6.rs create mode 100644 src/test/ui/parser/lex-bad-char-literals-6.stderr 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..80999a4afcf44 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' | ^^^^^^ -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-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..129f28aa3e8fd 100644 --- a/src/test/ui/parser/lex-bad-char-literals-4.stderr +++ b/src/test/ui/parser/lex-bad-char-literals-4.stderr @@ -1,8 +1,20 @@ -error: character literal may only contain one codepoint: '● +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: '● | ^^ -error: aborting due to previous error +error: character literal may only contain one codepoint + --> $DIR/lex-bad-char-literals-4.rs:4:70 + | +LL | '● //~ ERROR: character literal may only contain one codepoint: '● + | ^^ + +error: expected one of `.`, `;`, `?`, or an operator, found `~` + --> $DIR/lex-bad-char-literals-4.rs:4:11 + | +LL | '● //~ ERROR: character literal may only contain one codepoint: '● + | ^ expected one of `.`, `;`, `?`, or an operator here + +error: aborting due to 3 previous errors 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..8567a8680db26 --- /dev/null +++ b/src/test/ui/parser/lex-bad-char-literals-6.rs @@ -0,0 +1,12 @@ +fn main() { + let x: &str = 'ab'; //~ ERROR: character literal may only contain one codepoint + //~^ ERROR: mismatched types + 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 +} \ No newline at end of file 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..f1fcaaf687c7f --- /dev/null +++ b/src/test/ui/parser/lex-bad-char-literals-6.stderr @@ -0,0 +1,56 @@ +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 + | ^^^^ + +error: character literal may only contain one codepoint + --> $DIR/lex-bad-char-literals-6.rs:3:19 + | +LL | let y: char = 'cd'; //~ ERROR: character literal may only contain one codepoint + | ^^^^ + +error: character literal may only contain one codepoint + --> $DIR/lex-bad-char-literals-6.rs:4:13 + | +LL | let z = 'ef'; //~ ERROR: character literal may only contain one codepoint + | ^^^^ + +error[E0308]: mismatched types + --> $DIR/lex-bad-char-literals-6.rs:2:19 + | +LL | let x: &str = 'ab'; //~ ERROR: character literal may only contain one codepoint + | ^^^^ expected &str, found char + | + = note: expected type `&str` + found type `char` + +error[E0277]: can't compare `&str` with `char` + --> $DIR/lex-bad-char-literals-6.rs:6:10 + | +LL | if x == y {} // no error here + | ^^ 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:10:20 + | +LL | let a: usize = ""; // type error here to confirm we got past the parser + | ^^ 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:8:10 + | +LL | if x == z {} // no error here + | ^^ no implementation for `&str == char` + | + = help: the trait `std::cmp::PartialEq` is not implemented for `&str` + +error: aborting due to 7 previous errors + +Some errors occurred: E0277, E0308. +For more information about an error, try `rustc --explain E0277`. From a4ff1dcc534e9ae132e5b201a8f6e7dd06fbd9ee Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Sun, 20 Jan 2019 14:51:54 +0900 Subject: [PATCH 18/22] Mark incorrect recovered `char` literals as `TyErr` to avoid type errors --- src/librustc/ich/impls_syntax.rs | 1 + src/librustc_mir/hair/constant.rs | 8 ++++++++ src/librustc_typeck/check/mod.rs | 3 ++- src/libsyntax/ast.rs | 3 +++ src/libsyntax/attr/mod.rs | 1 + src/libsyntax/parse/mod.rs | 2 +- src/libsyntax/parse/token.rs | 3 +-- src/libsyntax/print/pprust.rs | 8 ++++++++ src/libsyntax_ext/concat.rs | 1 + 9 files changed, 26 insertions(+), 4 deletions(-) diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs index 6ffb771ffcc4e..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), 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/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/parse/mod.rs b/src/libsyntax/parse/mod.rs index cbb503f56bc4a..9e55f359b5ec2 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -466,7 +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::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 99041fd7cd634..f06e975a6d95a 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -473,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 123f9b49692d9..383baffa266dd 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -604,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()); From 6e59c6432612f87c7cb1309e89c41e1f0d9e0e25 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Sun, 20 Jan 2019 14:53:16 +0900 Subject: [PATCH 19/22] Revert change --- src/libsyntax/parse/lexer/mod.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index fcaa35d1fca73..cf51d3ed58d53 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -1456,9 +1456,8 @@ impl<'a> StringReader<'a> { } } - self.err_span_(start_with_quote, pos, - "character literal may only contain one codepoint"); - self.bump(); + self.fatal_span_verbose(start_with_quote, pos, + String::from("character literal may only contain one codepoint")).raise(); } let id = if valid { From 7ce25144195196d8b9f8d058490720ee0677798c Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Sun, 20 Jan 2019 14:53:28 +0900 Subject: [PATCH 20/22] Fix tests --- .../ui/parser/lex-bad-char-literals-2.stderr | 2 +- src/test/ui/parser/lex-bad-char-literals-3.rs | 11 +++---- .../ui/parser/lex-bad-char-literals-3.stderr | 28 +++++----------- .../ui/parser/lex-bad-char-literals-4.stderr | 18 ++-------- src/test/ui/parser/lex-bad-char-literals-5.rs | 11 +++---- .../ui/parser/lex-bad-char-literals-5.stderr | 28 +++++----------- src/test/ui/parser/lex-bad-char-literals-6.rs | 21 +++++++----- .../ui/parser/lex-bad-char-literals-6.stderr | 33 +++++++------------ 8 files changed, 56 insertions(+), 96 deletions(-) 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 80999a4afcf44..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,7 +1,7 @@ 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[E0601]: `main` function not found in crate `lex_bad_char_literals_2` 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 10a8cd4a53eab..efd597d11faa4 100644 --- a/src/test/ui/parser/lex-bad-char-literals-3.rs +++ b/src/test/ui/parser/lex-bad-char-literals-3.rs @@ -1,9 +1,8 @@ -// 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 -; +static c: char = '●●'; +//~^ ERROR: character literal may only contain one codepoint + fn main() { - let ch: &str = '●●'; //~ ERROR: character literal may only contain one codepoint - //~^ ERROR: mismatched types + 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 9b4e69870cae8..1e7a386ca8b2a 100644 --- a/src/test/ui/parser/lex-bad-char-literals-3.stderr +++ b/src/test/ui/parser/lex-bad-char-literals-3.stderr @@ -1,32 +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: character literal may only contain one codepoint - --> $DIR/lex-bad-char-literals-3.rs:7:20 + --> $DIR/lex-bad-char-literals-3.rs:6:20 | -LL | let ch: &str = '●●'; //~ ERROR: character literal may only contain one codepoint +LL | let ch: &str = '●●'; | ^^^^ help: if you meant to write a `str` literal, use double quotes | -LL | let ch: &str = "●●"; //~ ERROR: character literal may only contain one codepoint +LL | let ch: &str = "●●"; | ^^^^ -error[E0308]: mismatched types - --> $DIR/lex-bad-char-literals-3.rs:7:20 - | -LL | let ch: &str = '●●'; //~ ERROR: character literal may only contain one codepoint - | ^^^^ expected &str, found char - | - = note: expected type `&str` - found type `char` - -error: aborting due to 3 previous errors +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.stderr b/src/test/ui/parser/lex-bad-char-literals-4.stderr index 129f28aa3e8fd..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,20 +1,8 @@ -error: character literal may only contain one codepoint +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: character literal may only contain one codepoint - --> $DIR/lex-bad-char-literals-4.rs:4:70 - | -LL | '● //~ ERROR: character literal may only contain one codepoint: '● - | ^^ - -error: expected one of `.`, `;`, `?`, or an operator, found `~` - --> $DIR/lex-bad-char-literals-4.rs:4:11 - | -LL | '● //~ ERROR: character literal may only contain one codepoint: '● - | ^ expected one of `.`, `;`, `?`, or an operator here - -error: aborting due to 3 previous errors +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 964099c3fa98d..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,10 +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 -; +static c: char = '\x10\x10'; +//~^ ERROR: character literal may only contain one codepoint fn main() { - let ch: &str = '\x10\x10'; //~ ERROR: character literal may only contain one codepoint - //~^ ERROR: mismatched types + 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 177d8c599a894..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,32 +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: character literal may only contain one codepoint - --> $DIR/lex-bad-char-literals-5.rs:8:20 + --> $DIR/lex-bad-char-literals-5.rs:5:20 | -LL | let ch: &str = '/x10/x10'; //~ ERROR: character literal may only contain one codepoint +LL | let ch: &str = '/x10/x10'; | ^^^^^^^^^^ help: if you meant to write a `str` literal, use double quotes | -LL | let ch: &str = "/x10/x10"; //~ ERROR: character literal may only contain one codepoint +LL | let ch: &str = "/x10/x10"; | ^^^^^^^^^^ -error[E0308]: mismatched types - --> $DIR/lex-bad-char-literals-5.rs:8:20 - | -LL | let ch: &str = '/x10/x10'; //~ ERROR: character literal may only contain one codepoint - | ^^^^^^^^^^ expected &str, found char - | - = note: expected type `&str` - found type `char` - -error: aborting due to 3 previous errors +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 index 8567a8680db26..4379b4fa6d777 100644 --- a/src/test/ui/parser/lex-bad-char-literals-6.rs +++ b/src/test/ui/parser/lex-bad-char-literals-6.rs @@ -1,12 +1,17 @@ fn main() { - let x: &str = 'ab'; //~ ERROR: character literal may only contain one codepoint - //~^ ERROR: mismatched types - let y: char = 'cd'; //~ ERROR: character literal may only contain one codepoint - let z = 'ef'; //~ ERROR: character literal may only contain one codepoint + 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 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` + if x == z {} + //~^ ERROR: can't compare `&str` with `char` - let a: usize = ""; //~ ERROR: mismatched types -} \ No newline at end of file + 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 index f1fcaaf687c7f..df99726034878 100644 --- a/src/test/ui/parser/lex-bad-char-literals-6.stderr +++ b/src/test/ui/parser/lex-bad-char-literals-6.stderr @@ -1,56 +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 +LL | let x: &str = 'ab'; | ^^^^ error: character literal may only contain one codepoint - --> $DIR/lex-bad-char-literals-6.rs:3:19 + --> $DIR/lex-bad-char-literals-6.rs:4:19 | -LL | let y: char = 'cd'; //~ ERROR: character literal may only contain one codepoint +LL | let y: char = 'cd'; | ^^^^ error: character literal may only contain one codepoint - --> $DIR/lex-bad-char-literals-6.rs:4:13 + --> $DIR/lex-bad-char-literals-6.rs:6:13 | -LL | let z = 'ef'; //~ ERROR: character literal may only contain one codepoint +LL | let z = 'ef'; | ^^^^ -error[E0308]: mismatched types - --> $DIR/lex-bad-char-literals-6.rs:2:19 - | -LL | let x: &str = 'ab'; //~ ERROR: character literal may only contain one codepoint - | ^^^^ expected &str, found char - | - = note: expected type `&str` - found type `char` - error[E0277]: can't compare `&str` with `char` - --> $DIR/lex-bad-char-literals-6.rs:6:10 + --> $DIR/lex-bad-char-literals-6.rs:9:10 | -LL | if x == y {} // no error here +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:10:20 + --> $DIR/lex-bad-char-literals-6.rs:15:20 | -LL | let a: usize = ""; // type error here to confirm we got past the parser +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:8:10 + --> $DIR/lex-bad-char-literals-6.rs:12:10 | -LL | if x == z {} // no error here +LL | if x == z {} | ^^ no implementation for `&str == char` | = help: the trait `std::cmp::PartialEq` is not implemented for `&str` -error: aborting due to 7 previous errors +error: aborting due to 6 previous errors Some errors occurred: E0277, E0308. For more information about an error, try `rustc --explain E0277`. From 4005d3a8cb082f84f6bfb8c2168387a747aabf1e Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Sun, 20 Jan 2019 14:59:10 +0900 Subject: [PATCH 21/22] Remove whitespace --- src/test/ui/parser/lex-bad-char-literals-3.rs | 3 +-- src/test/ui/parser/lex-bad-char-literals-3.stderr | 6 +++--- 2 files changed, 4 insertions(+), 5 deletions(-) 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 efd597d11faa4..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,6 @@ -static c: char = '●●'; +static c: char = '●●'; //~^ ERROR: character literal may only contain one codepoint - 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 1e7a386ca8b2a..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,15 +1,15 @@ error: character literal may only contain one codepoint --> $DIR/lex-bad-char-literals-3.rs:1:18 | -LL | static c: char = '●●'; +LL | static c: char = '●●'; | ^^^^ help: if you meant to write a `str` literal, use double quotes | -LL | static c: char = "●●"; +LL | static c: char = "●●"; | ^^^^ error: character literal may only contain one codepoint - --> $DIR/lex-bad-char-literals-3.rs:6:20 + --> $DIR/lex-bad-char-literals-3.rs:5:20 | LL | let ch: &str = '●●'; | ^^^^ From c949d8ee69268c5c176c89834782b2654e0766ad Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sun, 20 Jan 2019 15:31:43 -0800 Subject: [PATCH 22/22] Update cargo --- src/tools/cargo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/cargo b/src/tools/cargo index ffe65875fd050..907c0febe7045 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit ffe65875fd05018599ad07e7389e99050c7915be +Subproject commit 907c0febe7045fa02dff2a35c5e36d3bd59ea50d