From ee1902157ec737626376e94ef2e6887ed5ac8329 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 30 Aug 2020 19:17:17 -0400 Subject: Fix clippy --- src/tools/clippy/clippy_lints/src/utils/ast_utils.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/tools/clippy/clippy_lints/src/utils/ast_utils.rs b/src/tools/clippy/clippy_lints/src/utils/ast_utils.rs index 7b419431c0f..3c3f8b26e3a 100644 --- a/src/tools/clippy/clippy_lints/src/utils/ast_utils.rs +++ b/src/tools/clippy/clippy_lints/src/utils/ast_utils.rs @@ -191,7 +191,7 @@ pub fn eq_stmt(l: &Stmt, r: &Stmt) -> bool { (Item(l), Item(r)) => eq_item(l, r, eq_item_kind), (Expr(l), Expr(r)) | (Semi(l), Semi(r)) => eq_expr(l, r), (Empty, Empty) => true, - (MacCall(l), MacCall(r)) => l.1 == r.1 && eq_mac_call(&l.0, &r.0) && over(&l.2, &r.2, |l, r| eq_attr(l, r)), + (MacCall(l), MacCall(r)) => l.style == r.style && eq_mac_call(&l.mac, &r.mac) && over(&l.attrs, &r.attrs, |l, r| eq_attr(l, r)), _ => false, } } -- cgit 1.4.1-3-g733a5 From 23f0ccfe5d9999a54dfcc4f5ba953981ba092aa7 Mon Sep 17 00:00:00 2001 From: Mateusz MikuĊ‚a Date: Thu, 30 Jul 2020 22:10:48 +0200 Subject: Stabilise link-self-contained option --- compiler/rustc_codegen_ssa/src/back/link.rs | 6 +++--- compiler/rustc_interface/src/tests.rs | 1 + compiler/rustc_session/src/options.rs | 6 +++--- src/doc/rustc/src/codegen-options/index.md | 20 ++++++++++++++++---- 4 files changed, 23 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index bfcf979d125..8e272282f40 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -1084,7 +1084,7 @@ fn get_crt_libs_path(sess: &Session) -> Option { fn get_object_file_path(sess: &Session, name: &str, self_contained: bool) -> PathBuf { // prefer system {,dll}crt2.o libs, see get_crt_libs_path comment for more details - if sess.opts.debugging_opts.link_self_contained.is_none() + if sess.opts.cg.link_self_contained.is_none() && sess.target.target.llvm_target.contains("windows-gnu") { if let Some(compiler_libs_path) = get_crt_libs_path(sess) { @@ -1289,7 +1289,7 @@ fn link_output_kind(sess: &Session, crate_type: CrateType) -> LinkOutputKind { /// Whether we link to our own CRT objects instead of relying on gcc to pull them. /// We only provide such support for a very limited number of targets. fn crt_objects_fallback(sess: &Session, crate_type: CrateType) -> bool { - if let Some(self_contained) = sess.opts.debugging_opts.link_self_contained { + if let Some(self_contained) = sess.opts.cg.link_self_contained { return self_contained; } @@ -1499,7 +1499,7 @@ fn link_local_crate_native_libs_and_dependent_crate_libs<'a, B: ArchiveBuilder<' /// Add sysroot and other globally set directories to the directory search list. fn add_library_search_dirs(cmd: &mut dyn Linker, sess: &Session, self_contained: bool) { // Prefer system mingw-w64 libs, see get_crt_libs_path comment for more details. - if sess.opts.debugging_opts.link_self_contained.is_none() + if sess.opts.cg.link_self_contained.is_none() && cfg!(windows) && sess.target.target.llvm_target.contains("windows-gnu") { diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index cb906b3d911..ada8dc90494 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -402,6 +402,7 @@ fn test_codegen_options_tracking_hash() { // `link_arg` is omitted because it just forwards to `link_args`. untracked!(link_args, vec![String::from("abc"), String::from("def")]); untracked!(link_dead_code, Some(true)); + untracked!(link_self_contained, Some(true)); untracked!(linker, Some(PathBuf::from("linker"))); untracked!(linker_flavor, Some(LinkerFlavor::Gcc)); untracked!(no_stack_check, true); diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 82330d9a533..25d988e87fd 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -719,6 +719,9 @@ options! {CodegenOptions, CodegenSetter, basic_codegen_options, "extra arguments to append to the linker invocation (space separated)"), link_dead_code: Option = (None, parse_opt_bool, [UNTRACKED], "keep dead code at link time (useful for code coverage) (default: no)"), + link_self_contained: Option = (None, parse_opt_bool, [UNTRACKED], + "control whether to link Rust provided C objects/libraries or rely + on C toolchain installed in the system"), linker: Option = (None, parse_opt_pathbuf, [UNTRACKED], "system linker to link outputs with"), linker_flavor: Option = (None, parse_linker_flavor, [UNTRACKED], @@ -894,9 +897,6 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "keep hygiene data after analysis (default: no)"), link_native_libraries: bool = (true, parse_bool, [UNTRACKED], "link native libraries in the linker invocation (default: yes)"), - link_self_contained: Option = (None, parse_opt_bool, [TRACKED], - "control whether to link Rust provided C objects/libraries or rely - on C toolchain installed in the system"), link_only: bool = (false, parse_bool, [TRACKED], "link the `.rlink` file generated by `-Z no-link` (default: no)"), llvm_time_trace: bool = (false, parse_bool, [UNTRACKED], diff --git a/src/doc/rustc/src/codegen-options/index.md b/src/doc/rustc/src/codegen-options/index.md index 7b0280d5b78..bed10ca16d3 100644 --- a/src/doc/rustc/src/codegen-options/index.md +++ b/src/doc/rustc/src/codegen-options/index.md @@ -44,13 +44,13 @@ incremental builds the default is 256 which allows caching to be more granular. ## control-flow-guard -This flag controls whether LLVM enables the Windows [Control Flow -Guard](https://docs.microsoft.com/en-us/windows/win32/secbp/control-flow-guard) -platform security feature. This flag is currently ignored for non-Windows targets. +This flag controls whether LLVM enables the Windows [Control Flow +Guard](https://docs.microsoft.com/en-us/windows/win32/secbp/control-flow-guard) +platform security feature. This flag is currently ignored for non-Windows targets. It takes one of the following values: * `y`, `yes`, `on`, `checks`, or no value: enable Control Flow Guard. -* `nochecks`: emit Control Flow Guard metadata without runtime enforcement checks (this +* `nochecks`: emit Control Flow Guard metadata without runtime enforcement checks (this should only be used for testing purposes as it does not provide security enforcement). * `n`, `no`, `off`: do not enable Control Flow Guard (the default). @@ -200,6 +200,18 @@ the following values: An example of when this flag might be useful is when trying to construct code coverage metrics. +## link-self-contained + +On targets that support it this flag controls whether the linker will use libraries and objects +shipped with Rust instead or those in the system. +It takes one of the following values: + +* no value: rustc will use heuristic to disable self-contained mode if system has necessary tools. +* `y`, `yes`, `on`: use only libraries/objects shipped with Rust. +* `n`, `no`, or `off`: rely on the user or the linker to provide non-Rust libraries/objects. + +This allows overriding cases when detection fails or user wants to use shipped libraries. + ## linker This flag controls which linker `rustc` invokes to link your code. It takes a -- cgit 1.4.1-3-g733a5 From 6b5869a0ae3488ee19c2c4cb30cd589f68a3d2a8 Mon Sep 17 00:00:00 2001 From: Rich Kadel Date: Sat, 29 Aug 2020 10:55:46 -0700 Subject: Add new `-Z dump-mir-spanview` option Similar to `-Z dump-mir-graphviz`, this adds the option to write HTML+CSS files that allow users to analyze the spans associated with MIR elements (by individual statement, just terminator, or overall basic block). This PR was split out from PR #76004, and exposes an API for spanview HTML+CSS files that is also used to analyze code regions chosen for coverage instrumentation (in a follow-on PR). Rust compiler MCP rust-lang/compiler-team#278 Relevant issue: #34701 - Implement support for LLVMs code coverage instrumentation --- compiler/rustc_mir/src/util/mod.rs | 1 + compiler/rustc_mir/src/util/pretty.rs | 11 + compiler/rustc_mir/src/util/spanview.rs | 461 +++++++++++++++++++++ compiler/rustc_session/src/config.rs | 15 + compiler/rustc_session/src/options.rs | 36 ++ src/test/mir-opt/spanview-block.rs | 5 + src/test/mir-opt/spanview-statement.rs | 5 + src/test/mir-opt/spanview-terminator.rs | 5 + .../mir-opt/spanview_block.main.mir_map.0.html | 67 +++ .../mir-opt/spanview_statement.main.mir_map.0.html | 67 +++ .../spanview_terminator.main.mir_map.0.html | 66 +++ 11 files changed, 739 insertions(+) create mode 100644 compiler/rustc_mir/src/util/spanview.rs create mode 100644 src/test/mir-opt/spanview-block.rs create mode 100644 src/test/mir-opt/spanview-statement.rs create mode 100644 src/test/mir-opt/spanview-terminator.rs create mode 100644 src/test/mir-opt/spanview_block.main.mir_map.0.html create mode 100644 src/test/mir-opt/spanview_statement.main.mir_map.0.html create mode 100644 src/test/mir-opt/spanview_terminator.main.mir_map.0.html (limited to 'src') diff --git a/compiler/rustc_mir/src/util/mod.rs b/compiler/rustc_mir/src/util/mod.rs index 8bbe207c077..ed0fafb1aac 100644 --- a/compiler/rustc_mir/src/util/mod.rs +++ b/compiler/rustc_mir/src/util/mod.rs @@ -9,6 +9,7 @@ mod alignment; pub mod collect_writes; mod graphviz; pub(crate) mod pretty; +pub(crate) mod spanview; pub use self::aggregate::expand_aggregate; pub use self::alignment::is_disaligned; diff --git a/compiler/rustc_mir/src/util/pretty.rs b/compiler/rustc_mir/src/util/pretty.rs index 2a9cbc7fc0e..db57766620e 100644 --- a/compiler/rustc_mir/src/util/pretty.rs +++ b/compiler/rustc_mir/src/util/pretty.rs @@ -6,6 +6,7 @@ use std::io::{self, Write}; use std::path::{Path, PathBuf}; use super::graphviz::write_mir_fn_graphviz; +use super::spanview::write_mir_fn_spanview; use crate::transform::MirSource; use either::Either; use rustc_data_structures::fx::FxHashMap; @@ -147,6 +148,16 @@ fn dump_matched_mir_node<'tcx, F>( write_mir_fn_graphviz(tcx, source.def_id(), body, false, &mut file)?; }; } + + if let Some(spanview) = tcx.sess.opts.debugging_opts.dump_mir_spanview { + let _: io::Result<()> = try { + let mut file = + create_dump_file(tcx, "html", pass_num, pass_name, disambiguator, source)?; + if source.def_id().is_local() { + write_mir_fn_spanview(tcx, source.def_id(), body, spanview, &mut file)?; + } + }; + } } /// Returns the path to the filename where we should dump a given MIR. diff --git a/compiler/rustc_mir/src/util/spanview.rs b/compiler/rustc_mir/src/util/spanview.rs new file mode 100644 index 00000000000..b2f2b5fc1e6 --- /dev/null +++ b/compiler/rustc_mir/src/util/spanview.rs @@ -0,0 +1,461 @@ +use rustc_hir::def_id::DefId; +use rustc_middle::hir; +use rustc_middle::mir::*; +use rustc_middle::ty::TyCtxt; +use rustc_session::config::MirSpanview; +use rustc_span::{BytePos, Pos, Span}; + +use std::io::{self, Write}; +use std::iter::Peekable; + +pub const TOOLTIP_INDENT: &str = " "; + +const NEW_LINE_SPAN: &str = "\n"; +const HEADER: &str = r#" + + + coverage_of_if_else - Code Regions + + +"#; + +const FOOTER: &str = r#" + +"#; + +/// Metadata to highlight the span of a MIR BasicBlock, Statement, or Terminator. +pub struct SpanViewable { + pub span: Span, + pub title: String, + pub tooltip: String, +} + +/// Write a spanview HTML+CSS file to analyze MIR element spans. +pub fn write_mir_fn_spanview<'tcx, W>( + tcx: TyCtxt<'tcx>, + def_id: DefId, + body: &Body<'tcx>, + spanview: MirSpanview, + w: &mut W, +) -> io::Result<()> +where + W: Write, +{ + let body_span = hir_body(tcx, def_id).value.span; + let mut span_viewables = Vec::new(); + for (bb, data) in body.basic_blocks().iter_enumerated() { + match spanview { + MirSpanview::Statement => { + for (i, statement) in data.statements.iter().enumerate() { + if let Some(span_viewable) = + statement_span_viewable(tcx, body_span, bb, i, statement) + { + span_viewables.push(span_viewable); + } + } + if let Some(span_viewable) = terminator_span_viewable(tcx, body_span, bb, data) { + span_viewables.push(span_viewable); + } + } + MirSpanview::Terminator => { + if let Some(span_viewable) = terminator_span_viewable(tcx, body_span, bb, data) { + span_viewables.push(span_viewable); + } + } + MirSpanview::Block => { + if let Some(span_viewable) = block_span_viewable(tcx, body_span, bb, data) { + span_viewables.push(span_viewable); + } + } + } + } + write_spanview_document(tcx, def_id, span_viewables, w)?; + Ok(()) +} + +/// Generate a spanview HTML+CSS document for the given local function `def_id`, and a pre-generated +/// list `SpanViewable`s. +pub fn write_spanview_document<'tcx, W>( + tcx: TyCtxt<'tcx>, + def_id: DefId, + mut span_viewables: Vec, + w: &mut W, +) -> io::Result<()> +where + W: Write, +{ + let fn_span = fn_span(tcx, def_id); + writeln!(w, "{}", HEADER)?; + let mut next_pos = fn_span.lo(); + let end_pos = fn_span.hi(); + let source_map = tcx.sess.source_map(); + let start = source_map.lookup_char_pos(next_pos); + write!( + w, + r#"
{}"#, + start.line - 1, + " ".repeat(start.col.to_usize()) + )?; + span_viewables.sort_unstable_by(|a, b| { + let a = a.span; + let b = b.span; + if a.lo() == b.lo() { + // Sort hi() in reverse order so shorter spans are attempted after longer spans. + // This should give shorter spans a higher "layer", so they are not covered by + // the longer spans. + b.hi().partial_cmp(&a.hi()) + } else { + a.lo().partial_cmp(&b.lo()) + } + .unwrap() + }); + let mut ordered_span_viewables = span_viewables.iter().peekable(); + let mut alt = false; + while ordered_span_viewables.peek().is_some() { + next_pos = write_span_viewables(tcx, next_pos, &mut ordered_span_viewables, false, 1, w)?; + alt = !alt; + } + if next_pos < end_pos { + write_coverage_gap(tcx, next_pos, end_pos, w)?; + } + write!(w, r#"
"#)?; + writeln!(w, "{}", FOOTER)?; + Ok(()) +} + +/// Format a string showing the start line and column, and end line and column within a file. +pub fn source_range_no_file<'tcx>(tcx: TyCtxt<'tcx>, span: &Span) -> String { + let source_map = tcx.sess.source_map(); + let start = source_map.lookup_char_pos(span.lo()); + let end = source_map.lookup_char_pos(span.hi()); + format!("{}:{}-{}:{}", start.line, start.col.to_usize() + 1, end.line, end.col.to_usize() + 1) +} + +pub fn statement_kind_name(statement: &Statement<'_>) -> &'static str { + use StatementKind::*; + match statement.kind { + Assign(..) => "Assign", + FakeRead(..) => "FakeRead", + SetDiscriminant { .. } => "SetDiscriminant", + StorageLive(..) => "StorageLive", + StorageDead(..) => "StorageDead", + LlvmInlineAsm(..) => "LlvmInlineAsm", + Retag(..) => "Retag", + AscribeUserType(..) => "AscribeUserType", + Coverage(..) => "Coverage", + Nop => "Nop", + } +} + +pub fn terminator_kind_name(term: &Terminator<'_>) -> &'static str { + use TerminatorKind::*; + match term.kind { + Goto { .. } => "Goto", + SwitchInt { .. } => "SwitchInt", + Resume => "Resume", + Abort => "Abort", + Return => "Return", + Unreachable => "Unreachable", + Drop { .. } => "Drop", + DropAndReplace { .. } => "DropAndReplace", + Call { .. } => "Call", + Assert { .. } => "Assert", + Yield { .. } => "Yield", + GeneratorDrop => "GeneratorDrop", + FalseEdge { .. } => "FalseEdge", + FalseUnwind { .. } => "FalseUnwind", + InlineAsm { .. } => "InlineAsm", + } +} + +fn statement_span_viewable<'tcx>( + tcx: TyCtxt<'tcx>, + body_span: Span, + bb: BasicBlock, + i: usize, + statement: &Statement<'tcx>, +) -> Option { + let span = statement.source_info.span; + if !body_span.contains(span) { + return None; + } + let title = format!("bb{}[{}]", bb.index(), i); + let tooltip = tooltip(tcx, &title, span, vec![statement.clone()], &None); + Some(SpanViewable { span, title, tooltip }) +} + +fn terminator_span_viewable<'tcx>( + tcx: TyCtxt<'tcx>, + body_span: Span, + bb: BasicBlock, + data: &BasicBlockData<'tcx>, +) -> Option { + let term = data.terminator(); + let span = term.source_info.span; + if !body_span.contains(span) { + return None; + } + let title = format!("bb{}`{}`", bb.index(), terminator_kind_name(term)); + let tooltip = tooltip(tcx, &title, span, vec![], &data.terminator); + Some(SpanViewable { span, title, tooltip }) +} + +fn block_span_viewable<'tcx>( + tcx: TyCtxt<'tcx>, + body_span: Span, + bb: BasicBlock, + data: &BasicBlockData<'tcx>, +) -> Option { + let span = compute_block_span(data, body_span); + if !body_span.contains(span) { + return None; + } + let title = format!("bb{}", bb.index()); + let tooltip = tooltip(tcx, &title, span, data.statements.clone(), &data.terminator); + Some(SpanViewable { span, title, tooltip }) +} + +fn compute_block_span<'tcx>(data: &BasicBlockData<'tcx>, body_span: Span) -> Span { + let mut span = data.terminator().source_info.span; + for statement_span in data.statements.iter().map(|statement| statement.source_info.span) { + // Only combine Spans from the function's body_span. + if body_span.contains(statement_span) { + span = span.to(statement_span); + } + } + span +} + +/// Recursively process each ordered span. Spans that overlap will have progressively varying +/// styles, such as increased padding for each overlap. Non-overlapping adjacent spans will +/// have alternating style choices, to help distinguish between them if, visually adjacent. +/// The `layer` is incremented for each overlap, and the `alt` bool alternates between true +/// and false, for each adjacent non-overlapping span. Source code between the spans (code +/// that is not in any coverage region) has neutral styling. +fn write_span_viewables<'tcx, 'b, W>( + tcx: TyCtxt<'tcx>, + next_pos: BytePos, + ordered_span_viewables: &mut Peekable>, + alt: bool, + layer: usize, + w: &mut W, +) -> io::Result +where + W: Write, +{ + let span_viewable = + ordered_span_viewables.next().expect("ordered_span_viewables should have some"); + if next_pos < span_viewable.span.lo() { + write_coverage_gap(tcx, next_pos, span_viewable.span.lo(), w)?; + } + let mut remaining_span = span_viewable.span; + let mut subalt = false; + loop { + let next_span_viewable = match ordered_span_viewables.peek() { + None => break, + Some(span_viewable) => *span_viewable, + }; + if !next_span_viewable.span.overlaps(remaining_span) { + break; + } + write_span( + tcx, + remaining_span.until(next_span_viewable.span), + Some(span_viewable), + alt, + layer, + w, + )?; + let next_pos = write_span_viewables( + tcx, + next_span_viewable.span.lo(), + ordered_span_viewables, + subalt, + layer + 1, + w, + )?; + subalt = !subalt; + if next_pos < remaining_span.hi() { + remaining_span = remaining_span.with_lo(next_pos); + } else { + return Ok(next_pos); + } + } + write_span(tcx, remaining_span, Some(span_viewable), alt, layer, w) +} + +fn write_coverage_gap<'tcx, W>( + tcx: TyCtxt<'tcx>, + lo: BytePos, + hi: BytePos, + w: &mut W, +) -> io::Result +where + W: Write, +{ + write_span(tcx, Span::with_root_ctxt(lo, hi), None, false, 0, w) +} + +fn write_span<'tcx, W>( + tcx: TyCtxt<'tcx>, + span: Span, + span_viewable: Option<&SpanViewable>, + alt: bool, + layer: usize, + w: &mut W, +) -> io::Result +where + W: Write, +{ + let source_map = tcx.sess.source_map(); + let snippet = source_map + .span_to_snippet(span) + .unwrap_or_else(|err| bug!("span_to_snippet error for span {:?}: {:?}", span, err)); + let labeled_snippet = if let Some(SpanViewable { title, .. }) = span_viewable { + if span.is_empty() { + format!(r#"@{}"#, title) + } else { + format!(r#"@{}: {}"#, title, escape_html(&snippet)) + } + } else { + snippet + }; + let maybe_alt = if layer > 0 { + if alt { " odd" } else { " even" } + } else { + "" + }; + let maybe_tooltip = if let Some(SpanViewable { tooltip, .. }) = span_viewable { + format!(" title=\"{}\"", escape_attr(tooltip)) + } else { + "".to_owned() + }; + if layer == 1 { + write!(w, "")?; + } + for (i, line) in labeled_snippet.lines().enumerate() { + if i > 0 { + write!(w, "{}", NEW_LINE_SPAN)?; + } + write!( + w, + r#"{}"#, + maybe_alt, layer, maybe_tooltip, line + )?; + } + if layer == 1 { + write!(w, "")?; + } + Ok(span.hi()) +} + +fn tooltip<'tcx>( + tcx: TyCtxt<'tcx>, + title: &str, + span: Span, + statements: Vec>, + terminator: &Option>, +) -> String { + let source_map = tcx.sess.source_map(); + let mut text = Vec::new(); + text.push(format!("{}: {}:", title, &source_map.span_to_string(span))); + for statement in statements { + let source_range = source_range_no_file(tcx, &statement.source_info.span); + text.push(format!( + "\n{}{}: {}: {}", + TOOLTIP_INDENT, + source_range, + statement_kind_name(&statement), + format!("{:?}", statement) + )); + } + if let Some(term) = terminator { + let source_range = source_range_no_file(tcx, &term.source_info.span); + text.push(format!( + "\n{}{}: {}: {:?}", + TOOLTIP_INDENT, + source_range, + terminator_kind_name(term), + term.kind + )); + } + text.join("") +} + +fn fn_span<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Span { + let hir_id = + tcx.hir().local_def_id_to_hir_id(def_id.as_local().expect("expected DefId is local")); + tcx.hir().span(hir_id) +} + +fn hir_body<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx rustc_hir::Body<'tcx> { + let hir_node = tcx.hir().get_if_local(def_id).expect("expected DefId is local"); + let fn_body_id = hir::map::associated_body(hir_node).expect("HIR node is a function with body"); + tcx.hir().body(fn_body_id) +} + +fn escape_html(s: &str) -> String { + s.replace("&", "&").replace("<", "<").replace(">", ">") +} + +fn escape_attr(s: &str) -> String { + s.replace("&", "&") + .replace("\"", """) + .replace("'", "'") + .replace("<", "<") + .replace(">", ">") +} diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 0a2a535598a..6861314a88f 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -163,6 +163,21 @@ pub enum LtoCli { Unspecified, } +/// The different settings that the `-Z dump_mir_spanview` flag can have. `Statement` generates a +/// document highlighting each span of every statement (including terminators). `Terminator` and +/// `Block` highlight a single span per `BasicBlock`: the span of the block's `Terminator`, or a +/// computed span for the block, representing the entire range, covering the block's terminator and +/// all of its statements. +#[derive(Clone, Copy, PartialEq, Hash, Debug)] +pub enum MirSpanview { + /// Default `-Z dump_mir_spanview` or `-Z dump_mir_spanview=statement` + Statement, + /// `-Z dump_mir_spanview=terminator` + Terminator, + /// `-Z dump_mir_spanview=block` + Block, +} + #[derive(Clone, PartialEq, Hash)] pub enum LinkerPluginLto { LinkerPlugin(PathBuf), diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index ee30c16108a..bcf65a1c4d2 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -255,6 +255,7 @@ macro_rules! options { pub const parse_strip: &str = "either `none`, `debuginfo`, or `symbols`"; pub const parse_linker_flavor: &str = ::rustc_target::spec::LinkerFlavor::one_of(); pub const parse_optimization_fuel: &str = "crate=integer"; + pub const parse_mir_spanview: &str = "`statement` (default), `terminator`, or `block`"; pub const parse_unpretty: &str = "`string` or `string=string`"; pub const parse_treat_err_as_bug: &str = "either no value or a number bigger than 0"; pub const parse_lto: &str = @@ -551,6 +552,36 @@ macro_rules! options { } } + fn parse_mir_spanview(slot: &mut Option, v: Option<&str>) -> bool { + if v.is_some() { + let mut bool_arg = None; + if parse_opt_bool(&mut bool_arg, v) { + *slot = if bool_arg.unwrap() { + Some(MirSpanview::Statement) + } else { + None + }; + return true + } + } + + let v = match v { + None => { + *slot = Some(MirSpanview::Statement); + return true; + } + Some(v) => v, + }; + + *slot = Some(match v.trim_end_matches("s") { + "statement" | "stmt" => MirSpanview::Statement, + "terminator" | "term" => MirSpanview::Terminator, + "block" | "basicblock" => MirSpanview::Block, + _ => return false, + }); + true + } + fn parse_treat_err_as_bug(slot: &mut Option, v: Option<&str>) -> bool { match v { Some(s) => { *slot = s.parse().ok().filter(|&x| x != 0); slot.unwrap_or(0) != 0 } @@ -849,6 +880,11 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "exclude the pass number when dumping MIR (used in tests) (default: no)"), dump_mir_graphviz: bool = (false, parse_bool, [UNTRACKED], "in addition to `.mir` files, create graphviz `.dot` files (default: no)"), + dump_mir_spanview: Option = (None, parse_mir_spanview, [UNTRACKED], + "in addition to `.mir` files, create `.html` files to view spans for \ + all `statement`s (including terminators), only `terminator` spans, or \ + computed `block` spans (one span encompassing a block's terminator and \ + all statements)."), emit_stack_sizes: bool = (false, parse_bool, [UNTRACKED], "emit a section containing stack size metadata (default: no)"), fewer_names: bool = (false, parse_bool, [TRACKED], diff --git a/src/test/mir-opt/spanview-block.rs b/src/test/mir-opt/spanview-block.rs new file mode 100644 index 00000000000..fc1d6e0ede6 --- /dev/null +++ b/src/test/mir-opt/spanview-block.rs @@ -0,0 +1,5 @@ +// Test spanview block output +// compile-flags: -Z dump-mir-spanview=block + +// EMIT_MIR spanview_block.main.mir_map.0.html +fn main() {} diff --git a/src/test/mir-opt/spanview-statement.rs b/src/test/mir-opt/spanview-statement.rs new file mode 100644 index 00000000000..a43ad5e71a3 --- /dev/null +++ b/src/test/mir-opt/spanview-statement.rs @@ -0,0 +1,5 @@ +// Test spanview output (the default value for `-Z dump-mir-spanview` is "statement") +// compile-flags: -Z dump-mir-spanview + +// EMIT_MIR spanview_statement.main.mir_map.0.html +fn main() {} diff --git a/src/test/mir-opt/spanview-terminator.rs b/src/test/mir-opt/spanview-terminator.rs new file mode 100644 index 00000000000..92e1411eadb --- /dev/null +++ b/src/test/mir-opt/spanview-terminator.rs @@ -0,0 +1,5 @@ +// Test spanview terminator output +// compile-flags: -Z dump-mir-spanview=terminator + +// EMIT_MIR spanview_terminator.main.mir_map.0.html +fn main() {} diff --git a/src/test/mir-opt/spanview_block.main.mir_map.0.html b/src/test/mir-opt/spanview_block.main.mir_map.0.html new file mode 100644 index 00000000000..7c1b7bc3b84 --- /dev/null +++ b/src/test/mir-opt/spanview_block.main.mir_map.0.html @@ -0,0 +1,67 @@ + + + + coverage_of_if_else - Code Regions + + + +
fn main() @bb0: {}@bb2
+ + diff --git a/src/test/mir-opt/spanview_statement.main.mir_map.0.html b/src/test/mir-opt/spanview_statement.main.mir_map.0.html new file mode 100644 index 00000000000..f8662a3277a --- /dev/null +++ b/src/test/mir-opt/spanview_statement.main.mir_map.0.html @@ -0,0 +1,67 @@ + + + + coverage_of_if_else - Code Regions + + + +
fn main() @bb0[0]: {}@bb0`Goto`@bb2`Return`
+ + diff --git a/src/test/mir-opt/spanview_terminator.main.mir_map.0.html b/src/test/mir-opt/spanview_terminator.main.mir_map.0.html new file mode 100644 index 00000000000..d0a11a8d262 --- /dev/null +++ b/src/test/mir-opt/spanview_terminator.main.mir_map.0.html @@ -0,0 +1,66 @@ + + + + coverage_of_if_else - Code Regions + + + +
fn main() {}@bb0`Goto`@bb2`Return`
+ + -- cgit 1.4.1-3-g733a5 From be2947d0b7cc7fb13601c41676285bb3f6d548c3 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Mon, 31 Aug 2020 00:04:01 -0400 Subject: Give a better error message for duplicate built-in macros Previously, this would say no such macro existed, but this was misleading, since the macro _did_ exist, it was just already seen. - Say where the macro was previously defined - Add long-form error message --- compiler/rustc_error_codes/src/error_codes.rs | 1 + .../rustc_error_codes/src/error_codes/E0773.md | 38 ++++++++++++++++++++++ compiler/rustc_resolve/src/lib.rs | 8 ++++- compiler/rustc_resolve/src/macros.rs | 22 ++++++++++--- src/test/ui/macros/duplicate-builtin.rs | 17 ++++++++++ src/test/ui/macros/duplicate-builtin.stderr | 21 ++++++++++++ src/test/ui/macros/unknown-builtin.rs | 4 +-- src/test/ui/macros/unknown-builtin.stderr | 9 ++++- 8 files changed, 112 insertions(+), 8 deletions(-) create mode 100644 compiler/rustc_error_codes/src/error_codes/E0773.md create mode 100644 src/test/ui/macros/duplicate-builtin.rs create mode 100644 src/test/ui/macros/duplicate-builtin.stderr (limited to 'src') diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs index 4e5e77f80c2..789a1fc35a6 100644 --- a/compiler/rustc_error_codes/src/error_codes.rs +++ b/compiler/rustc_error_codes/src/error_codes.rs @@ -454,6 +454,7 @@ E0768: include_str!("./error_codes/E0768.md"), E0769: include_str!("./error_codes/E0769.md"), E0770: include_str!("./error_codes/E0770.md"), E0771: include_str!("./error_codes/E0771.md"), +E0773: include_str!("./error_codes/E0773.md"), ; // E0006, // merged with E0005 // E0008, // cannot bind by-move into a pattern guard diff --git a/compiler/rustc_error_codes/src/error_codes/E0773.md b/compiler/rustc_error_codes/src/error_codes/E0773.md new file mode 100644 index 00000000000..b19a58bf33d --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0773.md @@ -0,0 +1,38 @@ +A builtin-macro was defined more than once. + +Erroneous code example: + +```compile_fail,E0773 +#![feature(decl_macro)] +#![feature(rustc_attrs)] + +#[rustc_builtin_macro] +pub macro test($item:item) { + /* compiler built-in */ +} + +mod inner { + #[rustc_builtin_macro] + pub macro test($item:item) { + /* compiler built-in */ + } +} +``` + +To fix the issue, remove the duplicate declaration: + +``` +#![feature(decl_macro)] +#![feature(rustc_attrs)] + +#[rustc_builtin_macro] +pub macro test($item:item) { + /* compiler built-in */ +} +``` + +In very rare edge cases, this may happen when loading `core` or `std` twice, +once with `check` metadata and once with `build` metadata. +For more information, see [#75176]. + +[#75176]: https://github.com/rust-lang/rust/pull/75176#issuecomment-683234468 diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 5892edf7652..50729086ec6 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -867,6 +867,12 @@ pub struct ExternPreludeEntry<'a> { pub introduced_by_item: bool, } +/// Used for better errors for E0773 +enum BuiltinMacroState { + NotYetSeen(SyntaxExtension), + AlreadySeen(Span), +} + /// The main resolver class. /// /// This is the visitor that walks the whole crate. @@ -960,7 +966,7 @@ pub struct Resolver<'a> { crate_loader: CrateLoader<'a>, macro_names: FxHashSet, - builtin_macros: FxHashMap, + builtin_macros: FxHashMap, registered_attrs: FxHashSet, registered_tools: FxHashSet, macro_use_prelude: FxHashMap>, diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 51518d63ae9..bea71389647 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -3,7 +3,7 @@ use crate::imports::ImportResolver; use crate::Namespace::*; -use crate::{AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, Determinacy}; +use crate::{AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, BuiltinMacroState, Determinacy}; use crate::{CrateLint, ParentScope, ResolutionError, Resolver, Scope, ScopeSet, Weak}; use crate::{ModuleKind, ModuleOrUniformRoot, NameBinding, PathResult, Segment, ToNameBinding}; use rustc_ast::{self as ast, NodeId}; @@ -11,6 +11,7 @@ use rustc_ast_lowering::ResolverAstLowering; use rustc_ast_pretty::pprust; use rustc_attr::StabilityLevel; use rustc_data_structures::fx::FxHashSet; +use rustc_errors::struct_span_err; use rustc_expand::base::{Indeterminate, InvocationRes, ResolverExpand, SyntaxExtension}; use rustc_expand::compile_declarative_macro; use rustc_expand::expand::{AstFragment, AstFragmentKind, Invocation, InvocationKind}; @@ -166,7 +167,7 @@ impl<'a> ResolverExpand for Resolver<'a> { } fn register_builtin_macro(&mut self, ident: Ident, ext: SyntaxExtension) { - if self.builtin_macros.insert(ident.name, ext).is_some() { + if self.builtin_macros.insert(ident.name, BuiltinMacroState::NotYetSeen(ext)).is_some() { self.session .span_err(ident.span, &format!("built-in macro `{}` was already defined", ident)); } @@ -1076,10 +1077,23 @@ impl<'a> Resolver<'a> { if result.is_builtin { // The macro was marked with `#[rustc_builtin_macro]`. - if let Some(ext) = self.builtin_macros.remove(&item.ident.name) { + if let Some(builtin_macro) = self.builtin_macros.get_mut(&item.ident.name) { // The macro is a built-in, replace its expander function // while still taking everything else from the source code. - result.kind = ext.kind; + // If we already loaded this builtin macro, give a better error message than 'no such builtin macro'. + match mem::replace(builtin_macro, BuiltinMacroState::AlreadySeen(item.span)) { + BuiltinMacroState::NotYetSeen(ext) => result.kind = ext.kind, + BuiltinMacroState::AlreadySeen(span) => { + struct_span_err!( + self.session, + item.span, + E0773, + "attempted to define built-in macro more than once" + ) + .span_note(span, "previously defined here") + .emit(); + } + } } else { let msg = format!("cannot find a built-in macro with name `{}`", item.ident); self.session.span_err(item.span, &msg); diff --git a/src/test/ui/macros/duplicate-builtin.rs b/src/test/ui/macros/duplicate-builtin.rs new file mode 100644 index 00000000000..35f0f429059 --- /dev/null +++ b/src/test/ui/macros/duplicate-builtin.rs @@ -0,0 +1,17 @@ +// compile-flags:--crate-type lib +#![feature(decl_macro)] +#![feature(rustc_attrs)] + +#[rustc_builtin_macro] +pub macro test($item:item) { +//~^ NOTE previously defined + /* compiler built-in */ +} + +mod inner { + #[rustc_builtin_macro] + pub macro test($item:item) { + //~^ ERROR attempted to define built-in macro more than once [E0773] + /* compiler built-in */ + } +} diff --git a/src/test/ui/macros/duplicate-builtin.stderr b/src/test/ui/macros/duplicate-builtin.stderr new file mode 100644 index 00000000000..58accea27bb --- /dev/null +++ b/src/test/ui/macros/duplicate-builtin.stderr @@ -0,0 +1,21 @@ +error[E0773]: attempted to define built-in macro more than once + --> $DIR/duplicate-builtin.rs:13:5 + | +LL | / pub macro test($item:item) { +LL | | +LL | | /* compiler built-in */ +LL | | } + | |_____^ + | +note: previously defined here + --> $DIR/duplicate-builtin.rs:6:1 + | +LL | / pub macro test($item:item) { +LL | | +LL | | /* compiler built-in */ +LL | | } + | |_^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0773`. diff --git a/src/test/ui/macros/unknown-builtin.rs b/src/test/ui/macros/unknown-builtin.rs index a96b99ae4ff..16f9139e647 100644 --- a/src/test/ui/macros/unknown-builtin.rs +++ b/src/test/ui/macros/unknown-builtin.rs @@ -1,4 +1,4 @@ -// error-pattern: cannot find a built-in macro with name `line` +// error-pattern: attempted to define built-in macro more than once #![feature(rustc_attrs)] @@ -6,7 +6,7 @@ macro_rules! unknown { () => () } //~ ERROR cannot find a built-in macro with name `unknown` #[rustc_builtin_macro] -macro_rules! line { () => () } +macro_rules! line { () => () } //~ NOTE previously defined here fn main() { line!(); diff --git a/src/test/ui/macros/unknown-builtin.stderr b/src/test/ui/macros/unknown-builtin.stderr index 4b650b2c475..7b04e05293e 100644 --- a/src/test/ui/macros/unknown-builtin.stderr +++ b/src/test/ui/macros/unknown-builtin.stderr @@ -4,7 +4,7 @@ error: cannot find a built-in macro with name `unknown` LL | macro_rules! unknown { () => () } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: cannot find a built-in macro with name `line` +error[E0773]: attempted to define built-in macro more than once --> $SRC_DIR/core/src/macros/mod.rs:LL:COL | LL | / macro_rules! line { @@ -13,6 +13,13 @@ LL | | /* compiler built-in */ LL | | }; LL | | } | |_____^ + | +note: previously defined here + --> $DIR/unknown-builtin.rs:9:1 + | +LL | macro_rules! line { () => () } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0773`. -- cgit 1.4.1-3-g733a5 From 7eb4b1b4b96642197b1bdeac4998d4d5f725f0cf Mon Sep 17 00:00:00 2001 From: Jes Bak Hansen Date: Tue, 1 Sep 2020 20:45:21 +0200 Subject: Document lint missing_doc_code_examples is nightly-only --- src/doc/rustdoc/src/lints.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/doc/rustdoc/src/lints.md b/src/doc/rustdoc/src/lints.md index d1d6bc1c1fe..8e2869fef55 100644 --- a/src/doc/rustdoc/src/lints.md +++ b/src/doc/rustdoc/src/lints.md @@ -51,7 +51,7 @@ warning: missing documentation for a function ## missing_doc_code_examples -This lint is **allowed by default**. It detects when a documentation block +This lint is **allowed by default** and is **nightly-only**. It detects when a documentation block is missing a code example. For example: ```rust -- cgit 1.4.1-3-g733a5 From cd08deff3c9c0de3ecd78883a3df4c9089b715d1 Mon Sep 17 00:00:00 2001 From: CDirkx Date: Tue, 1 Sep 2020 20:59:46 +0200 Subject: Add test for `Ipv6Addr` methods in a const context --- src/test/ui/consts/std/net/ipv6.rs | 53 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 src/test/ui/consts/std/net/ipv6.rs (limited to 'src') diff --git a/src/test/ui/consts/std/net/ipv6.rs b/src/test/ui/consts/std/net/ipv6.rs new file mode 100644 index 00000000000..d9ea1064be8 --- /dev/null +++ b/src/test/ui/consts/std/net/ipv6.rs @@ -0,0 +1,53 @@ +// run-pass + +#![feature(ip)] +#![feature(const_ipv6)] + +use std::net::{Ipv4Addr, Ipv6Addr, Ipv6MulticastScope}; + +fn main() { + const IP_ADDRESS : Ipv6Addr = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1); + assert_eq!(IP_ADDRESS, Ipv6Addr::LOCALHOST); + + const SEGMENTS : [u16; 8] = IP_ADDRESS.segments(); + assert_eq!(SEGMENTS, [0 ,0 ,0 ,0 ,0 ,0 ,0, 1]); + + const OCTETS : [u8; 16] = IP_ADDRESS.octets(); + assert_eq!(OCTETS, [0 ,0 ,0 ,0 ,0 ,0 ,0, 0 ,0 ,0 ,0 ,0 ,0 ,0, 0, 1]); + + const IS_UNSPECIFIED : bool = IP_ADDRESS.is_unspecified(); + assert!(!IS_UNSPECIFIED); + + const IS_LOOPBACK : bool = IP_ADDRESS.is_loopback(); + assert!(IS_LOOPBACK); + + const IS_GLOBAL : bool = IP_ADDRESS.is_global(); + assert!(!IS_GLOBAL); + + const IS_UNIQUE_LOCAL : bool = IP_ADDRESS.is_unique_local(); + assert!(!IS_UNIQUE_LOCAL); + + const IS_UNICAST_LINK_LOCAL_STRICT : bool = IP_ADDRESS.is_unicast_link_local_strict(); + assert!(!IS_UNICAST_LINK_LOCAL_STRICT); + + const IS_UNICAST_LINK_LOCAL : bool = IP_ADDRESS.is_unicast_link_local(); + assert!(!IS_UNICAST_LINK_LOCAL); + + const IS_UNICAST_SITE_LOCAL : bool = IP_ADDRESS.is_unicast_site_local(); + assert!(!IS_UNICAST_SITE_LOCAL); + + const IS_DOCUMENTATION : bool = IP_ADDRESS.is_documentation(); + assert!(!IS_DOCUMENTATION); + + const IS_UNICAST_GLOBAL : bool = IP_ADDRESS.is_unicast_global(); + assert!(!IS_UNICAST_GLOBAL); + + const MULTICAST_SCOPE : Option = IP_ADDRESS.multicast_scope(); + assert_eq!(MULTICAST_SCOPE, None); + + const IS_MULTICAST : bool = IP_ADDRESS.is_multicast(); + assert!(!IS_MULTICAST); + + const IP_V4 : Option = IP_ADDRESS.to_ipv4(); + assert_eq!(IP_V4.unwrap(), Ipv4Addr::new(0, 0, 0, 1)); +} \ No newline at end of file -- cgit 1.4.1-3-g733a5 From 9afe97c932ee964ee35d196c902870ab572f2544 Mon Sep 17 00:00:00 2001 From: CDirkx Date: Tue, 1 Sep 2020 21:36:45 +0200 Subject: Add trailing newline to `ipv6.rs` --- src/test/ui/consts/std/net/ipv6.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/test/ui/consts/std/net/ipv6.rs b/src/test/ui/consts/std/net/ipv6.rs index d9ea1064be8..e3841c38c22 100644 --- a/src/test/ui/consts/std/net/ipv6.rs +++ b/src/test/ui/consts/std/net/ipv6.rs @@ -50,4 +50,4 @@ fn main() { const IP_V4 : Option = IP_ADDRESS.to_ipv4(); assert_eq!(IP_V4.unwrap(), Ipv4Addr::new(0, 0, 0, 1)); -} \ No newline at end of file +} -- cgit 1.4.1-3-g733a5 From c86d249e94ae45fff1c882c98d85aaf49133f0b6 Mon Sep 17 00:00:00 2001 From: Camelid Date: Sun, 30 Aug 2020 13:45:17 -0700 Subject: Use "Fira Sans" for crate list font Fira Sans is what's used for module lists and other item lists. Previously, the default body font, "Source Serif Pro", was used for crate lists, which didn't visually match other item lists. --- src/librustdoc/html/render/mod.rs | 5 +++-- src/librustdoc/html/static/themes/ayu.css | 3 +++ src/test/rustdoc/index-page.rs | 4 ++-- 3 files changed, 8 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 470e9d5ae76..e4aba8963c7 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -1062,12 +1062,13 @@ themePicker.onblur = handleThemeButtonsBlur; let content = format!( "

\ List of all crates\ -

    {}
", + \ +
    {}
", krates .iter() .map(|s| { format!( - "
  • {}
  • ", + "
  • {}
  • ", ensure_trailing_slash(s), s ) diff --git a/src/librustdoc/html/static/themes/ayu.css b/src/librustdoc/html/static/themes/ayu.css index f910bfffc22..b4571018270 100644 --- a/src/librustdoc/html/static/themes/ayu.css +++ b/src/librustdoc/html/static/themes/ayu.css @@ -178,6 +178,9 @@ pre { .content span.externcrate, .content span.mod, .content a.mod { color: #acccf9; } +.content ul.crate a.crate { + font: 16px/1.6 "Fira Sans"; +} .content span.struct, .content a.struct { color: #ffa0a5; } diff --git a/src/test/rustdoc/index-page.rs b/src/test/rustdoc/index-page.rs index f0476f083b8..be668a1276a 100644 --- a/src/test/rustdoc/index-page.rs +++ b/src/test/rustdoc/index-page.rs @@ -6,6 +6,6 @@ // @has foo/../index.html // @has - '//span[@class="in-band"]' 'List of all crates' -// @has - '//ul[@class="mod"]//a[@href="foo/index.html"]' 'foo' -// @has - '//ul[@class="mod"]//a[@href="all_item_types/index.html"]' 'all_item_types' +// @has - '//ul[@class="crate mod"]//a[@href="foo/index.html"]' 'foo' +// @has - '//ul[@class="crate mod"]//a[@href="all_item_types/index.html"]' 'all_item_types' pub struct Foo; -- cgit 1.4.1-3-g733a5 From b1491eacfc2f2ff05ff2a1d3b557c30e15c5f81f Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 2 Sep 2020 00:22:47 +0300 Subject: lexer: Tiny improvement to shebang detection Lexer now discerns between regular comments and doc comments, so use that. The change only affects the choice of reported errors. --- compiler/rustc_lexer/src/lib.rs | 14 +++++++++----- src/test/ui/parser/shebang/shebang-doc-comment.rs | 5 +---- src/test/ui/parser/shebang/shebang-doc-comment.stderr | 8 ++++---- 3 files changed, 14 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs index b7d6194cd77..44999bbe857 100644 --- a/compiler/rustc_lexer/src/lib.rs +++ b/compiler/rustc_lexer/src/lib.rs @@ -191,12 +191,16 @@ pub fn strip_shebang(input: &str) -> Option { // For simplicity we consider any line starting with `#!` a shebang, // regardless of restrictions put on shebangs by specific platforms. if let Some(input_tail) = input.strip_prefix("#!") { - // Ok, this is a shebang but if the next non-whitespace token is `[` or maybe - // a doc comment (due to `TokenKind::(Line,Block)Comment` ambiguity at lexer level), + // Ok, this is a shebang but if the next non-whitespace token is `[`, // then it may be valid Rust code, so consider it Rust code. - let next_non_whitespace_token = tokenize(input_tail).map(|tok| tok.kind).find(|tok| - !matches!(tok, TokenKind::Whitespace | TokenKind::LineComment { .. } | TokenKind::BlockComment { .. }) - ); + let next_non_whitespace_token = tokenize(input_tail).map(|tok| tok.kind).find(|tok| { + !matches!( + tok, + TokenKind::Whitespace + | TokenKind::LineComment { doc_style: None } + | TokenKind::BlockComment { doc_style: None, .. } + ) + }); if next_non_whitespace_token != Some(TokenKind::OpenBracket) { // No other choice than to consider this a shebang. return Some(2 + input_tail.lines().next().unwrap_or_default().len()); diff --git a/src/test/ui/parser/shebang/shebang-doc-comment.rs b/src/test/ui/parser/shebang/shebang-doc-comment.rs index 7dbb9eebc75..72866753e0e 100644 --- a/src/test/ui/parser/shebang/shebang-doc-comment.rs +++ b/src/test/ui/parser/shebang/shebang-doc-comment.rs @@ -1,6 +1,3 @@ #!///bin/bash [allow(unused_variables)] -//~^^ ERROR expected `[`, found doc comment - -// Doc comment is misinterpreted as a whitespace (regular comment) during shebang detection. -// Even if it wasn't, it would still result in an error, just a different one. +//~^ ERROR expected item, found `[` diff --git a/src/test/ui/parser/shebang/shebang-doc-comment.stderr b/src/test/ui/parser/shebang/shebang-doc-comment.stderr index f524f556837..2227d45ec5a 100644 --- a/src/test/ui/parser/shebang/shebang-doc-comment.stderr +++ b/src/test/ui/parser/shebang/shebang-doc-comment.stderr @@ -1,8 +1,8 @@ -error: expected `[`, found doc comment `///bin/bash` - --> $DIR/shebang-doc-comment.rs:1:3 +error: expected item, found `[` + --> $DIR/shebang-doc-comment.rs:2:1 | -LL | #!///bin/bash - | ^^^^^^^^^^^ expected `[` +LL | [allow(unused_variables)] + | ^ expected item error: aborting due to previous error -- cgit 1.4.1-3-g733a5