diff --git a/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs b/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs index 8e1b69a1d7413..e20b86dd4523c 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs @@ -4,7 +4,7 @@ use rustc_index::bit_set::BitSet; use rustc_middle::mir::visit::Visitor; -use rustc_middle::mir::{self, BasicBlock, Local, Location}; +use rustc_middle::mir::{self, BasicBlock, Local, Location, Statement, StatementKind}; use std::marker::PhantomData; @@ -120,6 +120,15 @@ where self.super_assign(place, rvalue, location); } + fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { + match statement.kind { + StatementKind::StorageDead(local) => { + self.qualifs_per_local.remove(local); + } + _ => self.super_statement(statement, location), + } + } + fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Location) { // The effect of assignment to the return place in `TerminatorKind::Call` is not applied // here; that occurs in `apply_call_return_effect`. diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index a93d18950dba9..f35ca2659fd65 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -1957,7 +1957,7 @@ declare_lint! { /// [issue #50504]: https://github.com/rust-lang/rust/issues/50504 /// [future-incompatible]: ../index.md#future-incompatible-lints pub PROC_MACRO_DERIVE_RESOLUTION_FALLBACK, - Warn, + Deny, "detects proc macro derives using inaccessible names from parent modules", @future_incompatible = FutureIncompatibleInfo { reference: "issue #83583 ", @@ -3253,7 +3253,7 @@ declare_lint! { /// [issue #83125]: https://github.com/rust-lang/rust/issues/83125 /// [future-incompatible]: ../index.md#future-incompatible-lints pub PROC_MACRO_BACK_COMPAT, - Warn, + Deny, "detects usage of old versions of certain proc-macro crates", @future_incompatible = FutureIncompatibleInfo { reference: "issue #83125 ", diff --git a/compiler/rustc_typeck/src/variance/constraints.rs b/compiler/rustc_typeck/src/variance/constraints.rs index 1c8ac10818c03..33c27ce86ddb5 100644 --- a/compiler/rustc_typeck/src/variance/constraints.rs +++ b/compiler/rustc_typeck/src/variance/constraints.rs @@ -223,8 +223,8 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { self.add_constraints_from_region(current, lt, variance_i) } GenericArgKind::Type(ty) => self.add_constraints_from_ty(current, ty, variance_i), - GenericArgKind::Const(_) => { - // Consts impose no constraints. + GenericArgKind::Const(val) => { + self.add_constraints_from_const(current, val, variance_i) } } } @@ -263,7 +263,8 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { self.add_constraints_from_mt(current, &ty::TypeAndMut { ty, mutbl }, variance); } - ty::Array(typ, _) => { + ty::Array(typ, len) => { + self.add_constraints_from_const(current, len, variance); self.add_constraints_from_ty(current, typ, variance); } @@ -385,13 +386,32 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { self.add_constraints_from_region(current, lt, variance_i) } GenericArgKind::Type(ty) => self.add_constraints_from_ty(current, ty, variance_i), - GenericArgKind::Const(_) => { - // Consts impose no constraints. + GenericArgKind::Const(val) => { + self.add_constraints_from_const(current, val, variance) } } } } + /// Adds constraints appropriate for a const expression `val` + /// in a context with ambient variance `variance` + fn add_constraints_from_const( + &mut self, + current: &CurrentItem, + val: &ty::Const<'tcx>, + variance: VarianceTermPtr<'a>, + ) { + debug!("add_constraints_from_const(val={:?}, variance={:?})", val, variance); + + match &val.val { + ty::ConstKind::Unevaluated(uv) => { + let substs = uv.substs(self.tcx()); + self.add_constraints_from_invariant_substs(current, substs, variance); + } + _ => {} + } + } + /// Adds constraints appropriate for a function with signature /// `sig` appearing in a context with ambient variance `variance` fn add_constraints_from_sig( diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index b2aa500a0fd8f..1a5cf5ab8226a 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -1449,6 +1449,10 @@ fn _assert_sync_and_send() { /// global state in order to more accurately query the amount of available /// parallelism. /// +/// Resource limits can be changed during the runtime of a program, therefore the value is +/// not cached and instead recomputed every time this function is called. It should not be +/// called from hot code. +/// /// The value returned by this function should be considered a simplified /// approximation of the actual amount of parallelism available at any given /// time. To get a more detailed or precise overview of the amount of diff --git a/src/doc/rustdoc/src/unstable-features.md b/src/doc/rustdoc/src/unstable-features.md index 917959976411c..51f365be922fa 100644 --- a/src/doc/rustdoc/src/unstable-features.md +++ b/src/doc/rustdoc/src/unstable-features.md @@ -455,3 +455,27 @@ Calculating code examples follows these rules: * static * typedef 2. If one of the previously listed items has a code example, then it'll be counted. + +### `--with-examples`: include examples of uses of items as documentation + +This option, combined with `--scrape-examples-target-crate` and +`--scrape-examples-output-path`, is used to implement the functionality in [RFC +#3123](https://github.com/rust-lang/rfcs/pull/3123). Uses of an item (currently +functions / call-sites) are found in a crate and its reverse-dependencies, and +then the uses are included as documentation for that item. This feature is +intended to be used via `cargo doc --scrape-examples`, but the rustdoc-only +workflow looks like: + +```bash +$ rustdoc examples/ex.rs -Z unstable-options \ + --extern foobar=target/deps/libfoobar.rmeta \ + --scrape-examples-target-crate foobar \ + --scrape-examples-output-path output.calls +$ rustdoc src/lib.rs -Z unstable-options --with-examples output.calls +``` + +First, the library must be checked to generate an `rmeta`. Then a +reverse-dependency like `examples/ex.rs` is given to rustdoc with the target +crate being documented (`foobar`) and a path to output the calls +(`output.calls`). Then, the generated calls file can be passed via +`--with-examples` to the subsequent documentation of `foobar`. diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 075efd29b5969..7a1c561c8e531 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2062,7 +2062,8 @@ fn clean_use_statement( impl Clean for (&hir::ForeignItem<'_>, Option) { fn clean(&self, cx: &mut DocContext<'_>) -> Item { let (item, renamed) = self; - cx.with_param_env(item.def_id.to_def_id(), |cx| { + let def_id = item.def_id.to_def_id(); + cx.with_param_env(def_id, |cx| { let kind = match item.kind { hir::ForeignItemKind::Fn(ref decl, ref names, ref generics) => { let abi = cx.tcx.hir().get_foreign_abi(item.hir_id()); diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index ac440a395155c..7342478c3ec0d 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -25,6 +25,7 @@ use crate::html::render::StylePath; use crate::html::static_files; use crate::opts; use crate::passes::{self, Condition, DefaultPassOption}; +use crate::scrape_examples::{AllCallLocations, ScrapeExamplesOptions}; use crate::theme; #[derive(Clone, Copy, PartialEq, Eq, Debug)] @@ -158,6 +159,10 @@ crate struct Options { crate json_unused_externs: bool, /// Whether to skip capturing stdout and stderr of tests. crate nocapture: bool, + + /// Configuration for scraping examples from the current crate. If this option is Some(..) then + /// the compiler will scrape examples and not generate documentation. + crate scrape_examples_options: Option, } impl fmt::Debug for Options { @@ -202,6 +207,7 @@ impl fmt::Debug for Options { .field("run_check", &self.run_check) .field("no_run", &self.no_run) .field("nocapture", &self.nocapture) + .field("scrape_examples_options", &self.scrape_examples_options) .finish() } } @@ -280,6 +286,7 @@ crate struct RenderOptions { crate emit: Vec, /// If `true`, HTML source pages will generate links for items to their definition. crate generate_link_to_definition: bool, + crate call_locations: AllCallLocations, } #[derive(Copy, Clone, Debug, PartialEq, Eq)] @@ -671,6 +678,10 @@ impl Options { return Err(1); } + let scrape_examples_options = ScrapeExamplesOptions::new(&matches, &diag)?; + let with_examples = matches.opt_strs("with-examples"); + let call_locations = crate::scrape_examples::load_call_locations(with_examples, &diag)?; + let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format); Ok(Options { @@ -737,10 +748,12 @@ impl Options { ), emit, generate_link_to_definition, + call_locations, }, crate_name, output_format, json_unused_externs, + scrape_examples_options, }) } diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index 8ed69962875a6..fa8ad2a37e726 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -12,6 +12,7 @@ use crate::html::render::Context; use std::collections::VecDeque; use std::fmt::{Display, Write}; +use rustc_data_structures::fx::FxHashMap; use rustc_lexer::{LiteralKind, TokenKind}; use rustc_span::edition::Edition; use rustc_span::symbol::Symbol; @@ -30,6 +31,10 @@ crate struct ContextInfo<'a, 'b, 'c> { crate root_path: &'c str, } +/// Decorations are represented as a map from CSS class to vector of character ranges. +/// Each range will be wrapped in a span with that class. +crate struct DecorationInfo(crate FxHashMap<&'static str, Vec<(u32, u32)>>); + /// Highlights `src`, returning the HTML output. crate fn render_with_highlighting( src: &str, @@ -40,6 +45,7 @@ crate fn render_with_highlighting( edition: Edition, extra_content: Option, context_info: Option>, + decoration_info: Option, ) { debug!("highlighting: ================\n{}\n==============", src); if let Some((edition_info, class)) = tooltip { @@ -56,7 +62,7 @@ crate fn render_with_highlighting( } write_header(out, class, extra_content); - write_code(out, &src, edition, context_info); + write_code(out, &src, edition, context_info, decoration_info); write_footer(out, playground_button); } @@ -89,17 +95,23 @@ fn write_code( src: &str, edition: Edition, context_info: Option>, + decoration_info: Option, ) { // This replace allows to fix how the code source with DOS backline characters is displayed. let src = src.replace("\r\n", "\n"); - Classifier::new(&src, edition, context_info.as_ref().map(|c| c.file_span).unwrap_or(DUMMY_SP)) - .highlight(&mut |highlight| { - match highlight { - Highlight::Token { text, class } => string(out, Escape(text), class, &context_info), - Highlight::EnterSpan { class } => enter_span(out, class), - Highlight::ExitSpan => exit_span(out), - }; - }); + Classifier::new( + &src, + edition, + context_info.as_ref().map(|c| c.file_span).unwrap_or(DUMMY_SP), + decoration_info, + ) + .highlight(&mut |highlight| { + match highlight { + Highlight::Token { text, class } => string(out, Escape(text), class, &context_info), + Highlight::EnterSpan { class } => enter_span(out, class), + Highlight::ExitSpan => exit_span(out), + }; + }); } fn write_footer(out: &mut Buffer, playground_button: Option<&str>) { @@ -127,6 +139,7 @@ enum Class { PreludeTy, PreludeVal, QuestionMark, + Decoration(&'static str), } impl Class { @@ -150,6 +163,7 @@ impl Class { Class::PreludeTy => "prelude-ty", Class::PreludeVal => "prelude-val", Class::QuestionMark => "question-mark", + Class::Decoration(kind) => kind, } } @@ -248,6 +262,24 @@ impl Iterator for PeekIter<'a> { } } +/// Custom spans inserted into the source. Eg --scrape-examples uses this to highlight function calls +struct Decorations { + starts: Vec<(u32, &'static str)>, + ends: Vec, +} + +impl Decorations { + fn new(info: DecorationInfo) -> Self { + let (starts, ends) = info + .0 + .into_iter() + .map(|(kind, ranges)| ranges.into_iter().map(move |(lo, hi)| ((lo, kind), hi))) + .flatten() + .unzip(); + Decorations { starts, ends } + } +} + /// Processes program tokens, classifying strings of text by highlighting /// category (`Class`). struct Classifier<'a> { @@ -259,13 +291,20 @@ struct Classifier<'a> { byte_pos: u32, file_span: Span, src: &'a str, + decorations: Option, } impl<'a> Classifier<'a> { /// Takes as argument the source code to HTML-ify, the rust edition to use and the source code /// file span which will be used later on by the `span_correspondance_map`. - fn new(src: &str, edition: Edition, file_span: Span) -> Classifier<'_> { + fn new( + src: &str, + edition: Edition, + file_span: Span, + decoration_info: Option, + ) -> Classifier<'_> { let tokens = PeekIter::new(TokenIter { src }); + let decorations = decoration_info.map(Decorations::new); Classifier { tokens, in_attribute: false, @@ -275,6 +314,7 @@ impl<'a> Classifier<'a> { byte_pos: 0, file_span, src, + decorations, } } @@ -356,6 +396,19 @@ impl<'a> Classifier<'a> { /// token is used. fn highlight(mut self, sink: &mut dyn FnMut(Highlight<'a>)) { loop { + if let Some(decs) = self.decorations.as_mut() { + let byte_pos = self.byte_pos; + let n_starts = decs.starts.iter().filter(|(i, _)| byte_pos >= *i).count(); + for (_, kind) in decs.starts.drain(0..n_starts) { + sink(Highlight::EnterSpan { class: Class::Decoration(kind) }); + } + + let n_ends = decs.ends.iter().filter(|i| byte_pos >= **i).count(); + for _ in decs.ends.drain(0..n_ends) { + sink(Highlight::ExitSpan); + } + } + if self .tokens .peek() @@ -657,7 +710,7 @@ fn string( // https://github.com/rust-lang/rust/blob/60f1a2fc4b535ead9c85ce085fdce49b1b097531/src/librustdoc/html/render/context.rs#L315-L338 match href { LinkFromSrc::Local(span) => context - .href_from_span(*span) + .href_from_span(*span, true) .map(|s| format!("{}{}", context_info.root_path, s)), LinkFromSrc::External(def_id) => { format::href_with_root_path(*def_id, context, Some(context_info.root_path)) diff --git a/src/librustdoc/html/highlight/fixtures/decorations.html b/src/librustdoc/html/highlight/fixtures/decorations.html new file mode 100644 index 0000000000000..45f567880c9d9 --- /dev/null +++ b/src/librustdoc/html/highlight/fixtures/decorations.html @@ -0,0 +1,2 @@ +let x = 1; +let y = 2; \ No newline at end of file diff --git a/src/librustdoc/html/highlight/tests.rs b/src/librustdoc/html/highlight/tests.rs index 450bbfea1ea86..1fea7e983b448 100644 --- a/src/librustdoc/html/highlight/tests.rs +++ b/src/librustdoc/html/highlight/tests.rs @@ -1,6 +1,7 @@ -use super::write_code; +use super::{write_code, DecorationInfo}; use crate::html::format::Buffer; use expect_test::expect_file; +use rustc_data_structures::fx::FxHashMap; use rustc_span::create_default_session_globals_then; use rustc_span::edition::Edition; @@ -22,7 +23,7 @@ fn test_html_highlighting() { let src = include_str!("fixtures/sample.rs"); let html = { let mut out = Buffer::new(); - write_code(&mut out, src, Edition::Edition2018, None); + write_code(&mut out, src, Edition::Edition2018, None, None); format!("{}
{}
\n", STYLE, out.into_inner()) }; expect_file!["fixtures/sample.html"].assert_eq(&html); @@ -36,7 +37,7 @@ fn test_dos_backline() { println!(\"foo\");\r\n\ }\r\n"; let mut html = Buffer::new(); - write_code(&mut html, src, Edition::Edition2018, None); + write_code(&mut html, src, Edition::Edition2018, None, None); expect_file!["fixtures/dos_line.html"].assert_eq(&html.into_inner()); }); } @@ -50,7 +51,7 @@ let x = super::b::foo; let y = Self::whatever;"; let mut html = Buffer::new(); - write_code(&mut html, src, Edition::Edition2018, None); + write_code(&mut html, src, Edition::Edition2018, None, None); expect_file!["fixtures/highlight.html"].assert_eq(&html.into_inner()); }); } @@ -60,7 +61,21 @@ fn test_union_highlighting() { create_default_session_globals_then(|| { let src = include_str!("fixtures/union.rs"); let mut html = Buffer::new(); - write_code(&mut html, src, Edition::Edition2018, None); + write_code(&mut html, src, Edition::Edition2018, None, None); expect_file!["fixtures/union.html"].assert_eq(&html.into_inner()); }); } + +#[test] +fn test_decorations() { + create_default_session_globals_then(|| { + let src = "let x = 1; +let y = 2;"; + let mut decorations = FxHashMap::default(); + decorations.insert("example", vec![(0, 10)]); + + let mut html = Buffer::new(); + write_code(&mut html, src, Edition::Edition2018, None, Some(DecorationInfo(decorations))); + expect_file!["fixtures/decorations.html"].assert_eq(&html.into_inner()); + }); +} diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs index 6ed603c96bbf2..bd06f88cb3587 100644 --- a/src/librustdoc/html/layout.rs +++ b/src/librustdoc/html/layout.rs @@ -22,6 +22,8 @@ crate struct Layout { /// If false, the `select` element to have search filtering by crates on rendered docs /// won't be generated. crate generate_search_filter: bool, + /// If true, then scrape-examples.js will be included in the output HTML file + crate scrape_examples_extension: bool, } #[derive(Serialize)] diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index c46439b851050..bda0f0aa3f13e 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -360,6 +360,7 @@ impl<'a, I: Iterator>> Iterator for CodeBlocks<'_, 'a, I> { edition, None, None, + None, ); Some(Event::Html(s.into_inner().into())) } diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs index 011d3cfcf72d7..d7ef8513d6a89 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs @@ -34,6 +34,7 @@ use crate::html::escape::Escape; use crate::html::format::Buffer; use crate::html::markdown::{self, plain_text_summary, ErrorCodes, IdMap}; use crate::html::{layout, sources}; +use crate::scrape_examples::AllCallLocations; /// Major driving force in all rustdoc rendering. This contains information /// about where in the tree-like hierarchy rendering is occurring and controls @@ -123,6 +124,8 @@ crate struct SharedContext<'tcx> { crate span_correspondance_map: FxHashMap, /// The [`Cache`] used during rendering. crate cache: Cache, + + crate call_locations: AllCallLocations, } impl SharedContext<'_> { @@ -291,10 +294,10 @@ impl<'tcx> Context<'tcx> { /// may happen, for example, with externally inlined items where the source /// of their crate documentation isn't known. pub(super) fn src_href(&self, item: &clean::Item) -> Option { - self.href_from_span(item.span(self.tcx())) + self.href_from_span(item.span(self.tcx()), true) } - crate fn href_from_span(&self, span: clean::Span) -> Option { + crate fn href_from_span(&self, span: clean::Span, with_lines: bool) -> Option { if span.is_dummy() { return None; } @@ -341,16 +344,26 @@ impl<'tcx> Context<'tcx> { (&*symbol, &path) }; - let loline = span.lo(self.sess()).line; - let hiline = span.hi(self.sess()).line; - let lines = - if loline == hiline { loline.to_string() } else { format!("{}-{}", loline, hiline) }; + let anchor = if with_lines { + let loline = span.lo(self.sess()).line; + let hiline = span.hi(self.sess()).line; + format!( + "#{}", + if loline == hiline { + loline.to_string() + } else { + format!("{}-{}", loline, hiline) + } + ) + } else { + "".to_string() + }; Some(format!( - "{root}src/{krate}/{path}#{lines}", + "{root}src/{krate}/{path}{anchor}", root = Escape(&root), krate = krate, path = path, - lines = lines + anchor = anchor )) } } @@ -388,6 +401,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { generate_redirect_map, show_type_layout, generate_link_to_definition, + call_locations, .. } = options; @@ -412,6 +426,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { krate: krate.name.to_string(), css_file_extension: extension_css, generate_search_filter, + scrape_examples_extension: !call_locations.is_empty(), }; let mut issue_tracker_base_url = None; let mut include_sources = true; @@ -474,6 +489,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { templates, span_correspondance_map: matches, cache, + call_locations, }; // Add the default themes to the `Vec` of stylepaths diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 69c5c2c4abc2a..bd6cb9c298842 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -40,20 +40,25 @@ crate use span_map::{collect_spans_and_sources, LinkFromSrc}; use std::collections::VecDeque; use std::default::Default; use std::fmt; +use std::fs; +use std::iter::Peekable; use std::path::PathBuf; use std::str; use std::string::ToString; use rustc_ast_pretty::pprust; use rustc_attr::{ConstStability, Deprecation, StabilityLevel}; -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir as hir; use rustc_hir::def::CtorKind; use rustc_hir::def_id::DefId; use rustc_hir::Mutability; use rustc_middle::middle::stability; use rustc_middle::ty::TyCtxt; -use rustc_span::symbol::{kw, sym, Symbol}; +use rustc_span::{ + symbol::{kw, sym, Symbol}, + BytePos, FileName, RealFileName, +}; use serde::ser::SerializeSeq; use serde::{Serialize, Serializer}; @@ -68,7 +73,10 @@ use crate::html::format::{ href, print_abi_with_space, print_constness_with_space, print_default_space, print_generic_bounds, print_where_clause, Buffer, HrefError, PrintWithSpace, }; +use crate::html::highlight; use crate::html::markdown::{HeadingOffset, Markdown, MarkdownHtml, MarkdownSummaryLine}; +use crate::html::sources; +use crate::scrape_examples::CallData; /// A pair of name and its optional document. crate type NameDoc = (String, Option); @@ -585,6 +593,14 @@ fn document_full_inner( render_markdown(w, cx, &s, item.links(cx), heading_offset); } } + + let kind = match &*item.kind { + clean::ItemKind::StrippedItem(box kind) | kind => kind, + }; + + if let clean::ItemKind::FunctionItem(..) | clean::ItemKind::MethodItem(..) = kind { + render_call_locations(w, cx, item); + } } /// Add extra information about an item such as: @@ -2490,3 +2506,221 @@ fn collect_paths_for_type(first_ty: clean::Type, cache: &Cache) -> Vec { } out } + +const MAX_FULL_EXAMPLES: usize = 5; +const NUM_VISIBLE_LINES: usize = 10; + +/// Generates the HTML for example call locations generated via the --scrape-examples flag. +fn render_call_locations(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item) { + let tcx = cx.tcx(); + let def_id = item.def_id.expect_def_id(); + let key = tcx.def_path_hash(def_id); + let call_locations = match cx.shared.call_locations.get(&key) { + Some(call_locations) => call_locations, + _ => { + return; + } + }; + + // Generate a unique ID so users can link to this section for a given method + let id = cx.id_map.borrow_mut().derive("scraped-examples"); + write!( + w, + "
\ + \ +
\ + Examples found in repository\ +
", + id = id + ); + + // Generate the HTML for a single example, being the title and code block + let write_example = |w: &mut Buffer, (path, call_data): (&PathBuf, &CallData)| -> bool { + let contents = match fs::read_to_string(&path) { + Ok(contents) => contents, + Err(err) => { + let span = item.span(tcx).inner(); + tcx.sess + .span_err(span, &format!("failed to read file {}: {}", path.display(), err)); + return false; + } + }; + + // To reduce file sizes, we only want to embed the source code needed to understand the example, not + // the entire file. So we find the smallest byte range that covers all items enclosing examples. + assert!(!call_data.locations.is_empty()); + let min_loc = + call_data.locations.iter().min_by_key(|loc| loc.enclosing_item.byte_span.0).unwrap(); + let byte_min = min_loc.enclosing_item.byte_span.0; + let line_min = min_loc.enclosing_item.line_span.0; + let max_loc = + call_data.locations.iter().max_by_key(|loc| loc.enclosing_item.byte_span.1).unwrap(); + let byte_max = max_loc.enclosing_item.byte_span.1; + let line_max = max_loc.enclosing_item.line_span.1; + + // The output code is limited to that byte range. + let contents_subset = &contents[(byte_min as usize)..(byte_max as usize)]; + + // The call locations need to be updated to reflect that the size of the program has changed. + // Specifically, the ranges are all subtracted by `byte_min` since that's the new zero point. + let (mut byte_ranges, line_ranges): (Vec<_>, Vec<_>) = call_data + .locations + .iter() + .map(|loc| { + let (byte_lo, byte_hi) = loc.call_expr.byte_span; + let (line_lo, line_hi) = loc.call_expr.line_span; + let byte_range = (byte_lo - byte_min, byte_hi - byte_min); + let line_range = (line_lo - line_min, line_hi - line_min); + let (anchor, line_title) = if line_lo == line_hi { + (format!("{}", line_lo + 1), format!("line {}", line_lo + 1)) + } else { + ( + format!("{}-{}", line_lo + 1, line_hi + 1), + format!("lines {}-{}", line_lo + 1, line_hi + 1), + ) + }; + let line_url = format!("{}{}#{}", cx.root_path(), call_data.url, anchor); + + (byte_range, (line_range, line_url, line_title)) + }) + .unzip(); + + let (_, init_url, init_title) = &line_ranges[0]; + let needs_expansion = line_max - line_min > NUM_VISIBLE_LINES; + let locations_encoded = serde_json::to_string(&line_ranges).unwrap(); + + write!( + w, + "
\ +
\ + {name} ({title})\ +
\ +
", + expanded_cls = if needs_expansion { "" } else { "expanded" }, + name = call_data.display_name, + url = init_url, + title = init_title, + // The locations are encoded as a data attribute, so they can be read + // later by the JS for interactions. + locations = Escape(&locations_encoded) + ); + + if line_ranges.len() > 1 { + write!(w, r#" "#); + } + + if needs_expansion { + write!(w, r#""#); + } + + // Look for the example file in the source map if it exists, otherwise return a dummy span + let file_span = (|| { + let source_map = tcx.sess.source_map(); + let crate_src = tcx.sess.local_crate_source_file.as_ref()?; + let abs_crate_src = crate_src.canonicalize().ok()?; + let crate_root = abs_crate_src.parent()?.parent()?; + let rel_path = path.strip_prefix(crate_root).ok()?; + let files = source_map.files(); + let file = files.iter().find(|file| match &file.name { + FileName::Real(RealFileName::LocalPath(other_path)) => rel_path == other_path, + _ => false, + })?; + Some(rustc_span::Span::with_root_ctxt( + file.start_pos + BytePos(byte_min), + file.start_pos + BytePos(byte_max), + )) + })() + .unwrap_or(rustc_span::DUMMY_SP); + + // The root path is the inverse of Context::current + let root_path = vec!["../"; cx.current.len() - 1].join(""); + + let mut decoration_info = FxHashMap::default(); + decoration_info.insert("highlight focus", vec![byte_ranges.remove(0)]); + decoration_info.insert("highlight", byte_ranges); + + sources::print_src( + w, + contents_subset, + call_data.edition, + file_span, + cx, + &root_path, + Some(highlight::DecorationInfo(decoration_info)), + sources::SourceContext::Embedded { offset: line_min }, + ); + write!(w, "
"); + + true + }; + + // The call locations are output in sequence, so that sequence needs to be determined. + // Ideally the most "relevant" examples would be shown first, but there's no general algorithm + // for determining relevance. Instead, we prefer the smallest examples being likely the easiest to + // understand at a glance. + let ordered_locations = { + let sort_criterion = |(_, call_data): &(_, &CallData)| { + // Use the first location because that's what the user will see initially + let (lo, hi) = call_data.locations[0].enclosing_item.byte_span; + hi - lo + }; + + let mut locs = call_locations.into_iter().collect::>(); + locs.sort_by_key(sort_criterion); + locs + }; + + let mut it = ordered_locations.into_iter().peekable(); + + // An example may fail to write if its source can't be read for some reason, so this method + // continues iterating until a write suceeds + let write_and_skip_failure = |w: &mut Buffer, it: &mut Peekable<_>| { + while let Some(example) = it.next() { + if write_example(&mut *w, example) { + break; + } + } + }; + + // Write just one example that's visible by default in the method's description. + write_and_skip_failure(w, &mut it); + + // Then add the remaining examples in a hidden section. + if it.peek().is_some() { + write!( + w, + "
\ + \ + More examples\ + \ +
\ +
\ +
" + ); + + // Only generate inline code for MAX_FULL_EXAMPLES number of examples. Otherwise we could + // make the page arbitrarily huge! + for _ in 0..MAX_FULL_EXAMPLES { + write_and_skip_failure(w, &mut it); + } + + // For the remaining examples, generate a
    containing links to the source files. + if it.peek().is_some() { + write!(w, r#""); + } + + write!(w, "
"); + } + + write!(w, "
"); +} diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 58cd1018c316f..f452836962227 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -1159,6 +1159,7 @@ fn item_macro(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Mac it.span(cx.tcx()).inner().edition(), None, None, + None, ); }); document(w, cx, it, None, HeadingOffset::H2) diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs index e4c2556118aeb..31aaf46d7d595 100644 --- a/src/librustdoc/html/render/write_shared.rs +++ b/src/librustdoc/html/render/write_shared.rs @@ -304,6 +304,15 @@ pub(super) fn write_shared( )?; } + if cx.shared.layout.scrape_examples_extension { + cx.write_minify( + SharedResource::InvocationSpecific { basename: "scrape-examples.js" }, + static_files::SCRAPE_EXAMPLES_JS, + options.enable_minification, + &options.emit, + )?; + } + if let Some(ref css) = cx.shared.layout.css_file_extension { let buffer = try_err!(fs::read_to_string(css), css); // This varies based on the invocation, so it can't go through the write_minify wrapper. diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs index 71c64231a210e..ffefc5450cd73 100644 --- a/src/librustdoc/html/sources.rs +++ b/src/librustdoc/html/sources.rs @@ -204,7 +204,16 @@ impl SourceCollector<'_, 'tcx> { &page, "", |buf: &mut _| { - print_src(buf, contents, self.cx.shared.edition(), file_span, &self.cx, &root_path) + print_src( + buf, + contents, + self.cx.shared.edition(), + file_span, + &self.cx, + &root_path, + None, + SourceContext::Standalone, + ) }, &self.cx.shared.style_files, ); @@ -241,15 +250,22 @@ where } } +crate enum SourceContext { + Standalone, + Embedded { offset: usize }, +} + /// Wrapper struct to render the source code of a file. This will do things like /// adding line numbers to the left-hand side. -fn print_src( +crate fn print_src( buf: &mut Buffer, s: &str, edition: Edition, file_span: rustc_span::Span, context: &Context<'_>, root_path: &str, + decoration_info: Option, + source_context: SourceContext, ) { let lines = s.lines().count(); let mut line_numbers = Buffer::empty_from(buf); @@ -261,7 +277,14 @@ fn print_src( } line_numbers.write_str("
");
     for i in 1..=lines {
-        writeln!(line_numbers, "{0:1$}", i, cols);
+        match source_context {
+            SourceContext::Standalone => {
+                writeln!(line_numbers, "{0:1$}", i, cols)
+            }
+            SourceContext::Embedded { offset } => {
+                writeln!(line_numbers, "{0:1$}", i + offset, cols)
+            }
+        }
     }
     line_numbers.write_str("
"); highlight::render_with_highlighting( @@ -273,5 +296,6 @@ fn print_src( edition, Some(line_numbers), Some(highlight::ContextInfo { context, file_span, root_path }), + decoration_info, ); } diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index e41c993a5285d..8139f115cbb39 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -467,6 +467,11 @@ nav.sub { overflow-x: auto; } +.rustdoc:not(.source) .example-wrap > pre.line-numbers { + width: auto; + overflow-x: visible; +} + .rustdoc .example-wrap > pre { margin: 0; } @@ -1980,3 +1985,166 @@ details.undocumented[open] > summary::before { overflow-wrap: anywhere; } } + + +/* Begin: styles for --scrape-examples feature */ + +.scraped-example-title { + font-family: 'Fira Sans'; +} + +.scraped-example:not(.expanded) .code-wrapper pre.line-numbers { + overflow: hidden; + max-height: 240px; +} + +.scraped-example:not(.expanded) .code-wrapper .example-wrap pre.rust { + overflow-y: hidden; + max-height: 240px; + padding-bottom: 0; +} + +.scraped-example .code-wrapper .prev { + position: absolute; + top: 0.25em; + right: 2.25em; + z-index: 100; + cursor: pointer; +} + +.scraped-example .code-wrapper .next { + position: absolute; + top: 0.25em; + right: 1.25em; + z-index: 100; + cursor: pointer; +} + +.scraped-example .code-wrapper .expand { + position: absolute; + top: 0.25em; + right: 0.25em; + z-index: 100; + cursor: pointer; +} + +.scraped-example .code-wrapper { + position: relative; + display: flex; + flex-direction: row; + flex-wrap: wrap; + width: 100%; +} + +.scraped-example:not(.expanded) .code-wrapper:before { + content: " "; + width: 100%; + height: 5px; + position: absolute; + z-index: 100; + top: 0; + background: linear-gradient(to bottom, rgba(255, 255, 255, 1), rgba(255, 255, 255, 0)); +} + +.scraped-example:not(.expanded) .code-wrapper:after { + content: " "; + width: 100%; + height: 5px; + position: absolute; + z-index: 100; + bottom: 0; + background: linear-gradient(to top, rgba(255, 255, 255, 1), rgba(255, 255, 255, 0)); +} + +.scraped-example:not(.expanded) .code-wrapper { + overflow: hidden; + max-height: 240px; +} + +.scraped-example .code-wrapper .line-numbers { + margin: 0; + padding: 14px 0; +} + +.scraped-example .code-wrapper .line-numbers span { + padding: 0 14px; +} + +.scraped-example .code-wrapper .example-wrap { + flex: 1; + overflow-x: auto; + overflow-y: hidden; + margin-bottom: 0; +} + +.scraped-example .code-wrapper .example-wrap pre.rust { + overflow-x: inherit; + width: inherit; + overflow-y: hidden; +} + +.scraped-example .example-wrap .rust span.highlight { + background: #fcffd6; +} + +.scraped-example .example-wrap .rust span.highlight.focus { + background: #f6fdb0; +} + +.more-examples-toggle { + margin-top: 10px; +} + +.more-examples-toggle summary { + color: #999; + font-family: 'Fira Sans'; +} + +.more-scraped-examples { + margin-left: 25px; + display: flex; + flex-direction: row; + width: calc(100% - 25px); +} + +.more-scraped-examples-inner { + /* 20px is width of toggle-line + toggle-line-inner */ + width: calc(100% - 20px); +} + +.toggle-line { + align-self: stretch; + margin-right: 10px; + margin-top: 5px; + padding: 0 4px; + cursor: pointer; +} + +.toggle-line:hover .toggle-line-inner { + background: #aaa; +} + +.toggle-line-inner { + min-width: 2px; + background: #ddd; + height: 100%; +} + +.more-scraped-examples .scraped-example { + margin-bottom: 20px; +} + +.more-scraped-examples .scraped-example:last-child { + margin-bottom: 0; +} + +.example-links a { + margin-top: 20px; + font-family: 'Fira Sans'; +} + +.example-links ul { + margin-bottom: 0; +} + +/* End: styles for --scrape-examples feature */ diff --git a/src/librustdoc/html/static/css/themes/ayu.css b/src/librustdoc/html/static/css/themes/ayu.css index ccb1a707032bb..f9c84dc3e318d 100644 --- a/src/librustdoc/html/static/css/themes/ayu.css +++ b/src/librustdoc/html/static/css/themes/ayu.css @@ -613,3 +613,22 @@ div.files > .selected { input:checked + .slider { background-color: #ffb454 !important; } + +.scraped-example .example-wrap .rust span.highlight { + background: rgb(91, 59, 1); +} +.scraped-example .example-wrap .rust span.highlight.focus { + background: rgb(124, 75, 15); +} +.scraped-example:not(.expanded) .code-wrapper:before { + background: linear-gradient(to bottom, rgba(15, 20, 25, 1), rgba(15, 20, 25, 0)); +} +.scraped-example:not(.expanded) .code-wrapper:after { + background: linear-gradient(to top, rgba(15, 20, 25, 1), rgba(15, 20, 25, 0)); +} +.toggle-line-inner { + background: #616161; +} +.toggle-line:hover .toggle-line-inner { + background: ##898989; +} diff --git a/src/librustdoc/html/static/css/themes/dark.css b/src/librustdoc/html/static/css/themes/dark.css index 93801af46ecc5..9a38277d55905 100644 --- a/src/librustdoc/html/static/css/themes/dark.css +++ b/src/librustdoc/html/static/css/themes/dark.css @@ -485,3 +485,22 @@ div.files > .selected { .setting-line > .title { border-bottom-color: #ddd; } + +.scraped-example .example-wrap .rust span.highlight { + background: rgb(91, 59, 1); +} +.scraped-example .example-wrap .rust span.highlight.focus { + background: rgb(124, 75, 15); +} +.scraped-example:not(.expanded) .code-wrapper:before { + background: linear-gradient(to bottom, rgba(53, 53, 53, 1), rgba(53, 53, 53, 0)); +} +.scraped-example:not(.expanded) .code-wrapper:after { + background: linear-gradient(to top, rgba(53, 53, 53, 1), rgba(53, 53, 53, 0)); +} +.toggle-line-inner { + background: #616161; +} +.toggle-line:hover .toggle-line-inner { + background: ##898989; +} diff --git a/src/librustdoc/html/static/js/scrape-examples.js b/src/librustdoc/html/static/js/scrape-examples.js new file mode 100644 index 0000000000000..664b187e33e9f --- /dev/null +++ b/src/librustdoc/html/static/js/scrape-examples.js @@ -0,0 +1,86 @@ +/* global addClass, hasClass, removeClass, onEach */ + +(function () { + // Scroll code block to put the given code location in the middle of the viewer + function scrollToLoc(elt, loc) { + var wrapper = elt.querySelector(".code-wrapper"); + var halfHeight = wrapper.offsetHeight / 2; + var lines = elt.querySelector('.line-numbers'); + var offsetMid = (lines.children[loc[0]].offsetTop + + lines.children[loc[1]].offsetTop) / 2; + var scrollOffset = offsetMid - halfHeight; + lines.scrollTo(0, scrollOffset); + elt.querySelector(".rust").scrollTo(0, scrollOffset); + } + + function updateScrapedExample(example) { + var locs = JSON.parse(example.attributes.getNamedItem("data-locs").textContent); + var locIndex = 0; + var highlights = example.querySelectorAll('.highlight'); + var link = example.querySelector('.scraped-example-title a'); + + if (locs.length > 1) { + // Toggle through list of examples in a given file + var onChangeLoc = function(changeIndex) { + removeClass(highlights[locIndex], 'focus'); + changeIndex(); + scrollToLoc(example, locs[locIndex][0]); + addClass(highlights[locIndex], 'focus'); + + var url = locs[locIndex][1]; + var title = locs[locIndex][2]; + + link.href = url; + link.innerHTML = title; + }; + + example.querySelector('.prev') + .addEventListener('click', function() { + onChangeLoc(function() { + locIndex = (locIndex - 1 + locs.length) % locs.length; + }); + }); + + example.querySelector('.next') + .addEventListener('click', function() { + onChangeLoc(function() { + locIndex = (locIndex + 1) % locs.length; + }); + }); + } + + var expandButton = example.querySelector('.expand'); + if (expandButton) { + expandButton.addEventListener('click', function () { + if (hasClass(example, "expanded")) { + removeClass(example, "expanded"); + scrollToLoc(example, locs[0][0]); + } else { + addClass(example, "expanded"); + } + }); + } + + // Start with the first example in view + scrollToLoc(example, locs[0][0]); + } + + var firstExamples = document.querySelectorAll('.scraped-example-list > .scraped-example'); + onEach(firstExamples, updateScrapedExample); + onEach(document.querySelectorAll('.more-examples-toggle'), function(toggle) { + // Allow users to click the left border of the
section to close it, + // since the section can be large and finding the [+] button is annoying. + toggle.querySelector('.toggle-line').addEventListener('click', function() { + toggle.open = false; + }); + + var moreExamples = toggle.querySelectorAll('.scraped-example'); + toggle.querySelector('summary').addEventListener('click', function() { + // Wrapping in setTimeout ensures the update happens after the elements are actually + // visible. This is necessary since updateScrapedExample calls scrollToLoc which + // depends on offsetHeight, a property that requires an element to be visible to + // compute correctly. + setTimeout(function() { onEach(moreExamples, updateScrapedExample); }); + }, {once: true}); + }); +})(); diff --git a/src/librustdoc/html/static_files.rs b/src/librustdoc/html/static_files.rs index 924e3f1d29dc9..9029933ad100e 100644 --- a/src/librustdoc/html/static_files.rs +++ b/src/librustdoc/html/static_files.rs @@ -35,6 +35,10 @@ crate static SETTINGS_JS: &str = include_str!("static/js/settings.js"); /// Storage, used to store documentation settings. crate static STORAGE_JS: &str = include_str!("static/js/storage.js"); +/// The file contents of `scraped-examples.js`, which contains functionality related to the +/// --scrape-examples flag that inserts automatically-found examples of usages of items. +crate static SCRAPE_EXAMPLES_JS: &str = include_str!("static/js/scrape-examples.js"); + /// The file contents of `brush.svg`, the icon used for the theme-switch button. crate static BRUSH_SVG: &[u8] = include_bytes!("static/images/brush.svg"); diff --git a/src/librustdoc/html/templates/page.html b/src/librustdoc/html/templates/page.html index 38dc3b30e72ac..b0174d59a7be2 100644 --- a/src/librustdoc/html/templates/page.html +++ b/src/librustdoc/html/templates/page.html @@ -109,6 +109,9 @@ data-search-js="{{static_root_path | safe}}search{{page.resource_suffix}}.js"> {#- -#} {#- -#} + {%- if layout.scrape_examples_extension -%} + {#- -#} + {%- endif -%} {%- for script in page.static_extra_scripts -%} {#- -#} {% endfor %} diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index ff0a6ef6cb74f..17e00e4b66271 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -48,11 +48,13 @@ extern crate rustc_interface; extern crate rustc_lexer; extern crate rustc_lint; extern crate rustc_lint_defs; +extern crate rustc_macros; extern crate rustc_metadata; extern crate rustc_middle; extern crate rustc_parse; extern crate rustc_passes; extern crate rustc_resolve; +extern crate rustc_serialize; extern crate rustc_session; extern crate rustc_span; extern crate rustc_target; @@ -120,6 +122,7 @@ mod json; crate mod lint; mod markdown; mod passes; +mod scrape_examples; mod theme; mod visit_ast; mod visit_lib; @@ -619,6 +622,30 @@ fn opts() -> Vec { "Make the identifiers in the HTML source code pages navigable", ) }), + unstable("scrape-examples-output-path", |o| { + o.optopt( + "", + "scrape-examples-output-path", + "", + "collect function call information and output at the given path", + ) + }), + unstable("scrape-examples-target-crate", |o| { + o.optmulti( + "", + "scrape-examples-target-crate", + "", + "collect function call information for functions from the target crate", + ) + }), + unstable("with-examples", |o| { + o.optmulti( + "", + "with-examples", + "", + "path to function call information (for displaying examples in the documentation)", + ) + }), ] } @@ -732,6 +759,7 @@ fn main_options(options: config::Options) -> MainResult { // FIXME: fix this clone (especially render_options) let manual_passes = options.manual_passes.clone(); let render_options = options.render_options.clone(); + let scrape_examples_options = options.scrape_examples_options.clone(); let config = core::create_config(options); interface::create_compiler_and_run(config, |compiler| { @@ -768,6 +796,10 @@ fn main_options(options: config::Options) -> MainResult { }); info!("finished with rustc"); + if let Some(options) = scrape_examples_options { + return scrape_examples::run(krate, render_opts, cache, tcx, options); + } + cache.crate_version = crate_version; if show_coverage { diff --git a/src/librustdoc/scrape_examples.rs b/src/librustdoc/scrape_examples.rs new file mode 100644 index 0000000000000..fc54e55b87655 --- /dev/null +++ b/src/librustdoc/scrape_examples.rs @@ -0,0 +1,266 @@ +//! This module analyzes crates to find call sites that can serve as examples in the documentation. + +use crate::clean; +use crate::config; +use crate::formats; +use crate::formats::renderer::FormatRenderer; +use crate::html::render::Context; + +use rustc_data_structures::fx::FxHashMap; +use rustc_hir::{ + self as hir, + intravisit::{self, Visitor}, + HirId, +}; +use rustc_interface::interface; +use rustc_macros::{Decodable, Encodable}; +use rustc_middle::hir::map::Map; +use rustc_middle::ty::{self, TyCtxt}; +use rustc_serialize::{ + opaque::{Decoder, FileEncoder}, + Decodable, Encodable, +}; +use rustc_session::getopts; +use rustc_span::{ + def_id::{CrateNum, DefPathHash, LOCAL_CRATE}, + edition::Edition, + BytePos, FileName, SourceFile, +}; + +use std::fs; +use std::path::PathBuf; + +#[derive(Debug, Clone)] +crate struct ScrapeExamplesOptions { + output_path: PathBuf, + target_crates: Vec, +} + +impl ScrapeExamplesOptions { + crate fn new( + matches: &getopts::Matches, + diag: &rustc_errors::Handler, + ) -> Result, i32> { + let output_path = matches.opt_str("scrape-examples-output-path"); + let target_crates = matches.opt_strs("scrape-examples-target-crate"); + match (output_path, !target_crates.is_empty()) { + (Some(output_path), true) => Ok(Some(ScrapeExamplesOptions { + output_path: PathBuf::from(output_path), + target_crates, + })), + (Some(_), false) | (None, true) => { + diag.err(&format!("must use --scrape-examples-output-path and --scrape-examples-target-crate together")); + Err(1) + } + (None, false) => Ok(None), + } + } +} + +#[derive(Encodable, Decodable, Debug, Clone)] +crate struct SyntaxRange { + crate byte_span: (u32, u32), + crate line_span: (usize, usize), +} + +impl SyntaxRange { + fn new(span: rustc_span::Span, file: &SourceFile) -> Self { + let get_pos = |bytepos: BytePos| file.original_relative_byte_pos(bytepos).0; + let get_line = |bytepos: BytePos| file.lookup_line(bytepos).unwrap(); + + SyntaxRange { + byte_span: (get_pos(span.lo()), get_pos(span.hi())), + line_span: (get_line(span.lo()), get_line(span.hi())), + } + } +} + +#[derive(Encodable, Decodable, Debug, Clone)] +crate struct CallLocation { + crate call_expr: SyntaxRange, + crate enclosing_item: SyntaxRange, +} + +impl CallLocation { + fn new( + tcx: TyCtxt<'_>, + expr_span: rustc_span::Span, + expr_id: HirId, + source_file: &SourceFile, + ) -> Self { + let enclosing_item_span = + tcx.hir().span_with_body(tcx.hir().get_parent_item(expr_id)).source_callsite(); + assert!(enclosing_item_span.contains(expr_span)); + + CallLocation { + call_expr: SyntaxRange::new(expr_span, source_file), + enclosing_item: SyntaxRange::new(enclosing_item_span, source_file), + } + } +} + +#[derive(Encodable, Decodable, Debug, Clone)] +crate struct CallData { + crate locations: Vec, + crate url: String, + crate display_name: String, + crate edition: Edition, +} + +crate type FnCallLocations = FxHashMap; +crate type AllCallLocations = FxHashMap; + +/// Visitor for traversing a crate and finding instances of function calls. +struct FindCalls<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + map: Map<'tcx>, + cx: Context<'tcx>, + target_crates: Vec, + calls: &'a mut AllCallLocations, +} + +impl<'a, 'tcx> Visitor<'tcx> for FindCalls<'a, 'tcx> +where + 'tcx: 'a, +{ + type Map = Map<'tcx>; + + fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap { + intravisit::NestedVisitorMap::OnlyBodies(self.map) + } + + fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) { + intravisit::walk_expr(self, ex); + + // Get type of function if expression is a function call + let tcx = self.tcx; + let (ty, span) = match ex.kind { + hir::ExprKind::Call(f, _) => { + let types = tcx.typeck(ex.hir_id.owner); + (types.node_type(f.hir_id), ex.span) + } + hir::ExprKind::MethodCall(_, _, _, span) => { + let types = tcx.typeck(ex.hir_id.owner); + let def_id = types.type_dependent_def_id(ex.hir_id).unwrap(); + (tcx.type_of(def_id), span) + } + _ => { + return; + } + }; + + // If this span comes from a macro expansion, then the source code may not actually show + // a use of the given item, so it would be a poor example. Hence, we skip all uses in macros. + if span.from_expansion() { + return; + } + + // Save call site if the function resolves to a concrete definition + if let ty::FnDef(def_id, _) = ty.kind() { + // Ignore functions not from the crate being documented + if self.target_crates.iter().all(|krate| *krate != def_id.krate) { + return; + } + + let file = tcx.sess.source_map().lookup_char_pos(span.lo()).file; + let file_path = match file.name.clone() { + FileName::Real(real_filename) => real_filename.into_local_path(), + _ => None, + }; + + if let Some(file_path) = file_path { + let abs_path = fs::canonicalize(file_path.clone()).unwrap(); + let cx = &self.cx; + let mk_call_data = || { + let clean_span = crate::clean::types::Span::new(span); + let url = cx.href_from_span(clean_span, false).unwrap(); + let display_name = file_path.display().to_string(); + let edition = span.edition(); + CallData { locations: Vec::new(), url, display_name, edition } + }; + + let fn_key = tcx.def_path_hash(*def_id); + let fn_entries = self.calls.entry(fn_key).or_default(); + + let location = CallLocation::new(tcx, span, ex.hir_id, &file); + fn_entries.entry(abs_path).or_insert_with(mk_call_data).locations.push(location); + } + } + } +} + +crate fn run( + krate: clean::Crate, + renderopts: config::RenderOptions, + cache: formats::cache::Cache, + tcx: TyCtxt<'_>, + options: ScrapeExamplesOptions, +) -> interface::Result<()> { + let inner = move || -> Result<(), String> { + // Generates source files for examples + let (cx, _) = Context::init(krate, renderopts, cache, tcx).map_err(|e| e.to_string())?; + + // Collect CrateIds corresponding to provided target crates + // If two different versions of the crate in the dependency tree, then examples will be collcted from both. + let all_crates = tcx + .crates(()) + .iter() + .chain([&LOCAL_CRATE]) + .map(|crate_num| (crate_num, tcx.crate_name(*crate_num))) + .collect::>(); + let target_crates = options + .target_crates + .into_iter() + .map(|target| all_crates.iter().filter(move |(_, name)| name.as_str() == target)) + .flatten() + .map(|(crate_num, _)| **crate_num) + .collect::>(); + + debug!("All crates in TyCtxt: {:?}", all_crates); + debug!("Scrape examples target_crates: {:?}", target_crates); + + // Run call-finder on all items + let mut calls = FxHashMap::default(); + let mut finder = FindCalls { calls: &mut calls, tcx, map: tcx.hir(), cx, target_crates }; + tcx.hir().visit_all_item_likes(&mut finder.as_deep_visitor()); + + // Save output to provided path + let mut encoder = FileEncoder::new(options.output_path).map_err(|e| e.to_string())?; + calls.encode(&mut encoder).map_err(|e| e.to_string())?; + encoder.flush().map_err(|e| e.to_string())?; + + Ok(()) + }; + + if let Err(e) = inner() { + tcx.sess.fatal(&e); + } + + Ok(()) +} + +// Note: the Handler must be passed in explicitly because sess isn't available while parsing options +crate fn load_call_locations( + with_examples: Vec, + diag: &rustc_errors::Handler, +) -> Result { + let inner = || { + let mut all_calls: AllCallLocations = FxHashMap::default(); + for path in with_examples { + let bytes = fs::read(&path).map_err(|e| format!("{} (for path {})", e, path))?; + let mut decoder = Decoder::new(&bytes, 0); + let calls = AllCallLocations::decode(&mut decoder)?; + + for (function, fn_calls) in calls.into_iter() { + all_calls.entry(function).or_default().extend(fn_calls.into_iter()); + } + } + + Ok(all_calls) + }; + + inner().map_err(|e: String| { + diag.err(&format!("failed to load examples: {}", e)); + 1 + }) +} diff --git a/src/test/run-make/rustdoc-scrape-examples-multiple/Makefile b/src/test/run-make/rustdoc-scrape-examples-multiple/Makefile new file mode 100644 index 0000000000000..897805e4405b9 --- /dev/null +++ b/src/test/run-make/rustdoc-scrape-examples-multiple/Makefile @@ -0,0 +1,5 @@ +deps := ex ex2 + +-include ./scrape.mk + +all: scrape diff --git a/src/test/run-make/rustdoc-scrape-examples-multiple/examples/ex.rs b/src/test/run-make/rustdoc-scrape-examples-multiple/examples/ex.rs new file mode 100644 index 0000000000000..01b730c6149ce --- /dev/null +++ b/src/test/run-make/rustdoc-scrape-examples-multiple/examples/ex.rs @@ -0,0 +1,4 @@ +fn main() { + foobar::ok(); + foobar::ok(); +} diff --git a/src/test/run-make/rustdoc-scrape-examples-multiple/examples/ex2.rs b/src/test/run-make/rustdoc-scrape-examples-multiple/examples/ex2.rs new file mode 100644 index 0000000000000..f83cf2f270914 --- /dev/null +++ b/src/test/run-make/rustdoc-scrape-examples-multiple/examples/ex2.rs @@ -0,0 +1,3 @@ +fn main() { + foobar::ok(); +} diff --git a/src/test/run-make/rustdoc-scrape-examples-multiple/scrape.mk b/src/test/run-make/rustdoc-scrape-examples-multiple/scrape.mk new file mode 100644 index 0000000000000..1fa1fae1a0b71 --- /dev/null +++ b/src/test/run-make/rustdoc-scrape-examples-multiple/scrape.mk @@ -0,0 +1,20 @@ +-include ../../run-make-fulldeps/tools.mk + +OUTPUT_DIR := "$(TMPDIR)/rustdoc" + +$(TMPDIR)/%.calls: $(TMPDIR)/libfoobar.rmeta + $(RUSTDOC) examples/$*.rs --crate-name $* --crate-type bin --output $(OUTPUT_DIR) \ + --extern foobar=$(TMPDIR)/libfoobar.rmeta \ + -Z unstable-options \ + --scrape-examples-output-path $@ \ + --scrape-examples-target-crate foobar + +$(TMPDIR)/lib%.rmeta: src/lib.rs + $(RUSTC) src/lib.rs --crate-name $* --crate-type lib --emit=metadata + +scrape: $(foreach d,$(deps),$(TMPDIR)/$(d).calls) + $(RUSTDOC) src/lib.rs --crate-name foobar --crate-type lib --output $(OUTPUT_DIR) \ + -Z unstable-options \ + $(foreach d,$(deps),--with-examples $(TMPDIR)/$(d).calls) + + $(HTMLDOCCK) $(OUTPUT_DIR) src/lib.rs diff --git a/src/test/run-make/rustdoc-scrape-examples-multiple/src/lib.rs b/src/test/run-make/rustdoc-scrape-examples-multiple/src/lib.rs new file mode 100644 index 0000000000000..bd59584bbbf4f --- /dev/null +++ b/src/test/run-make/rustdoc-scrape-examples-multiple/src/lib.rs @@ -0,0 +1,4 @@ +// @has foobar/fn.ok.html '//*[@class="docblock scraped-example-list"]//*[@class="prev"]' '' +// @has foobar/fn.ok.html '//*[@class="more-scraped-examples"]' '' + +pub fn ok() {} diff --git a/src/test/run-make/rustdoc-scrape-examples-ordering/Makefile b/src/test/run-make/rustdoc-scrape-examples-ordering/Makefile new file mode 100644 index 0000000000000..339d539bfd57d --- /dev/null +++ b/src/test/run-make/rustdoc-scrape-examples-ordering/Makefile @@ -0,0 +1,5 @@ +deps := ex1 ex2 + +-include ../rustdoc-scrape-examples-multiple/scrape.mk + +all: scrape diff --git a/src/test/run-make/rustdoc-scrape-examples-ordering/examples/ex1.rs b/src/test/run-make/rustdoc-scrape-examples-ordering/examples/ex1.rs new file mode 100644 index 0000000000000..d6d5982087658 --- /dev/null +++ b/src/test/run-make/rustdoc-scrape-examples-ordering/examples/ex1.rs @@ -0,0 +1,9 @@ +fn main() { + foobar::ok(); + + // this is a + + // BIG + + // item +} diff --git a/src/test/run-make/rustdoc-scrape-examples-ordering/examples/ex2.rs b/src/test/run-make/rustdoc-scrape-examples-ordering/examples/ex2.rs new file mode 100644 index 0000000000000..a1133117f861e --- /dev/null +++ b/src/test/run-make/rustdoc-scrape-examples-ordering/examples/ex2.rs @@ -0,0 +1,4 @@ +fn main() { + foobar::ok(); + // small item +} diff --git a/src/test/run-make/rustdoc-scrape-examples-ordering/src/lib.rs b/src/test/run-make/rustdoc-scrape-examples-ordering/src/lib.rs new file mode 100644 index 0000000000000..f1b7686d36800 --- /dev/null +++ b/src/test/run-make/rustdoc-scrape-examples-ordering/src/lib.rs @@ -0,0 +1,4 @@ +// @has foobar/fn.ok.html '//*[@class="docblock scraped-example-list"]' 'ex2' +// @has foobar/fn.ok.html '//*[@class="more-scraped-examples"]' 'ex1' + +pub fn ok() {} diff --git a/src/test/run-make/rustdoc-scrape-examples-remap/Makefile b/src/test/run-make/rustdoc-scrape-examples-remap/Makefile new file mode 100644 index 0000000000000..dce8b83eefe4e --- /dev/null +++ b/src/test/run-make/rustdoc-scrape-examples-remap/Makefile @@ -0,0 +1,5 @@ +deps := ex + +-include ../rustdoc-scrape-examples-multiple/scrape.mk + +all: scrape diff --git a/src/test/run-make/rustdoc-scrape-examples-remap/examples/ex.rs b/src/test/run-make/rustdoc-scrape-examples-remap/examples/ex.rs new file mode 100644 index 0000000000000..1438fdba7072c --- /dev/null +++ b/src/test/run-make/rustdoc-scrape-examples-remap/examples/ex.rs @@ -0,0 +1,4 @@ +fn main() { + foobar::b::foo(); + foobar::c::foo(); +} diff --git a/src/test/run-make/rustdoc-scrape-examples-remap/src/a.rs b/src/test/run-make/rustdoc-scrape-examples-remap/src/a.rs new file mode 100644 index 0000000000000..b76b4321d62aa --- /dev/null +++ b/src/test/run-make/rustdoc-scrape-examples-remap/src/a.rs @@ -0,0 +1 @@ +pub fn foo() {} diff --git a/src/test/run-make/rustdoc-scrape-examples-remap/src/lib.rs b/src/test/run-make/rustdoc-scrape-examples-remap/src/lib.rs new file mode 100644 index 0000000000000..f525a4270dde1 --- /dev/null +++ b/src/test/run-make/rustdoc-scrape-examples-remap/src/lib.rs @@ -0,0 +1,8 @@ +// @has foobar/b/fn.foo.html '//*[@class="scraped-example expanded"]' 'ex.rs' +// @has foobar/c/fn.foo.html '//*[@class="scraped-example expanded"]' 'ex.rs' + +#[path = "a.rs"] +pub mod b; + +#[path = "a.rs"] +pub mod c; diff --git a/src/test/rustdoc-ui/scrape-examples-wrong-options-1.rs b/src/test/rustdoc-ui/scrape-examples-wrong-options-1.rs new file mode 100644 index 0000000000000..a1f005c32ee0f --- /dev/null +++ b/src/test/rustdoc-ui/scrape-examples-wrong-options-1.rs @@ -0,0 +1 @@ +// compile-flags: -Z unstable-options --scrape-examples-target-crate foobar diff --git a/src/test/rustdoc-ui/scrape-examples-wrong-options-1.stderr b/src/test/rustdoc-ui/scrape-examples-wrong-options-1.stderr new file mode 100644 index 0000000000000..eb8e9f799681f --- /dev/null +++ b/src/test/rustdoc-ui/scrape-examples-wrong-options-1.stderr @@ -0,0 +1,2 @@ +error: must use --scrape-examples-output-path and --scrape-examples-target-crate together + diff --git a/src/test/rustdoc-ui/scrape-examples-wrong-options-2.rs b/src/test/rustdoc-ui/scrape-examples-wrong-options-2.rs new file mode 100644 index 0000000000000..4aacec7f09493 --- /dev/null +++ b/src/test/rustdoc-ui/scrape-examples-wrong-options-2.rs @@ -0,0 +1 @@ +// compile-flags: -Z unstable-options --scrape-examples-output-path ex.calls diff --git a/src/test/rustdoc-ui/scrape-examples-wrong-options-2.stderr b/src/test/rustdoc-ui/scrape-examples-wrong-options-2.stderr new file mode 100644 index 0000000000000..eb8e9f799681f --- /dev/null +++ b/src/test/rustdoc-ui/scrape-examples-wrong-options-2.stderr @@ -0,0 +1,2 @@ +error: must use --scrape-examples-output-path and --scrape-examples-target-crate together + diff --git a/src/test/ui/const-generics/issues/issue-67375.full.stderr b/src/test/ui/const-generics/issues/issue-67375.full.stderr index 0f0e339655bca..0cf69879a5c20 100644 --- a/src/test/ui/const-generics/issues/issue-67375.full.stderr +++ b/src/test/ui/const-generics/issues/issue-67375.full.stderr @@ -8,15 +8,5 @@ LL | inner: [(); { [|_: &T| {}; 0].len() }], | = help: consider moving this anonymous constant into a `const` function -error[E0392]: parameter `T` is never used - --> $DIR/issue-67375.rs:5:12 - | -LL | struct Bug { - | ^ unused parameter - | - = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` - = help: if you intended `T` to be a const parameter, use `const T: usize` instead - -error: aborting due to 2 previous errors +error: aborting due to previous error -For more information about this error, try `rustc --explain E0392`. diff --git a/src/test/ui/const-generics/issues/issue-67375.rs b/src/test/ui/const-generics/issues/issue-67375.rs index b5b842a15ae0c..8b4b276bae0ba 100644 --- a/src/test/ui/const-generics/issues/issue-67375.rs +++ b/src/test/ui/const-generics/issues/issue-67375.rs @@ -3,7 +3,7 @@ #![cfg_attr(full, feature(generic_const_exprs))] struct Bug { - //~^ ERROR parameter `T` is never used + //[min]~^ ERROR parameter `T` is never used inner: [(); { [|_: &T| {}; 0].len() }], //[min]~^ ERROR generic parameters may not be used in const operations //[full]~^^ ERROR overly complex generic constant diff --git a/src/test/ui/const-generics/issues/issue-67945-1.full.stderr b/src/test/ui/const-generics/issues/issue-67945-1.full.stderr index 1edc7828caad2..8e18fcdffab70 100644 --- a/src/test/ui/const-generics/issues/issue-67945-1.full.stderr +++ b/src/test/ui/const-generics/issues/issue-67945-1.full.stderr @@ -12,16 +12,6 @@ LL | let x: S = MaybeUninit::uninit(); = note: expected type parameter `S` found union `MaybeUninit<_>` -error[E0392]: parameter `S` is never used - --> $DIR/issue-67945-1.rs:7:12 - | -LL | struct Bug { - | ^ unused parameter - | - = help: consider removing `S`, referring to it in a field, or using a marker such as `PhantomData` - = help: if you intended `S` to be a const parameter, use `const S: usize` instead - -error: aborting due to 2 previous errors +error: aborting due to previous error -Some errors have detailed explanations: E0308, E0392. -For more information about an error, try `rustc --explain E0308`. +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/const-generics/issues/issue-67945-1.rs b/src/test/ui/const-generics/issues/issue-67945-1.rs index 7b7e8428639c7..99f88bc8e1055 100644 --- a/src/test/ui/const-generics/issues/issue-67945-1.rs +++ b/src/test/ui/const-generics/issues/issue-67945-1.rs @@ -5,7 +5,7 @@ use std::mem::MaybeUninit; struct Bug { - //~^ ERROR parameter `S` is never used + //[min]~^ ERROR parameter `S` is never used A: [(); { let x: S = MaybeUninit::uninit(); //[min]~^ ERROR generic parameters may not be used in const operations diff --git a/src/test/ui/consts/promoted-storage.rs b/src/test/ui/consts/promoted-storage.rs new file mode 100644 index 0000000000000..52ef685e8f4f8 --- /dev/null +++ b/src/test/ui/consts/promoted-storage.rs @@ -0,0 +1,20 @@ +// Check that storage statements reset local qualification. +// check-pass +use std::cell::Cell; + +const C: Option> = { + let mut c = None; + let mut i = 0; + while i == 0 { + let mut x = None; + c = x; + x = Some(Cell::new(0)); + let _ = x; + i += 1; + } + c +}; + +fn main() { + let _: &'static _ = &C; +} diff --git a/src/test/ui/proc-macro/generate-mod.rs b/src/test/ui/proc-macro/generate-mod.rs index e5f967416c922..471f317edf964 100644 --- a/src/test/ui/proc-macro/generate-mod.rs +++ b/src/test/ui/proc-macro/generate-mod.rs @@ -13,15 +13,15 @@ generate_mod::check!(); //~ ERROR cannot find type `FromOutside` in this scope //~| ERROR cannot find type `OuterAttr` in this scope struct S; -#[derive(generate_mod::CheckDerive)] //~ WARN cannot find type `FromOutside` in this scope - //~| WARN cannot find type `OuterDerive` in this scope +#[derive(generate_mod::CheckDerive)] //~ ERROR cannot find type `FromOutside` in this scope + //~| ERROR cannot find type `OuterDerive` in this scope //~| WARN this was previously accepted //~| WARN this was previously accepted struct Z; fn inner_block() { - #[derive(generate_mod::CheckDerive)] //~ WARN cannot find type `FromOutside` in this scope - //~| WARN cannot find type `OuterDerive` in this scope + #[derive(generate_mod::CheckDerive)] //~ ERROR cannot find type `FromOutside` in this scope + //~| ERROR cannot find type `OuterDerive` in this scope //~| WARN this was previously accepted //~| WARN this was previously accepted struct InnerZ; diff --git a/src/test/ui/proc-macro/generate-mod.stderr b/src/test/ui/proc-macro/generate-mod.stderr index be58cc40ed299..a2c1b82b15f68 100644 --- a/src/test/ui/proc-macro/generate-mod.stderr +++ b/src/test/ui/proc-macro/generate-mod.stderr @@ -38,18 +38,18 @@ LL | #[generate_mod::check_attr] OuterAttr = note: this error originates in the attribute macro `generate_mod::check_attr` (in Nightly builds, run with -Z macro-backtrace for more info) -warning: cannot find type `FromOutside` in this scope +error: cannot find type `FromOutside` in this scope --> $DIR/generate-mod.rs:16:10 | LL | #[derive(generate_mod::CheckDerive)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import | - = note: `#[warn(proc_macro_derive_resolution_fallback)]` on by default + = note: `#[deny(proc_macro_derive_resolution_fallback)]` on by default = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #83583 - = note: this warning originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info) -warning: cannot find type `OuterDerive` in this scope +error: cannot find type `OuterDerive` in this scope --> $DIR/generate-mod.rs:16:10 | LL | #[derive(generate_mod::CheckDerive)] @@ -57,9 +57,9 @@ LL | #[derive(generate_mod::CheckDerive)] | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #83583 - = note: this warning originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info) -warning: cannot find type `FromOutside` in this scope +error: cannot find type `FromOutside` in this scope --> $DIR/generate-mod.rs:23:14 | LL | #[derive(generate_mod::CheckDerive)] @@ -67,9 +67,9 @@ LL | #[derive(generate_mod::CheckDerive)] | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #83583 - = note: this warning originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info) -warning: cannot find type `OuterDerive` in this scope +error: cannot find type `OuterDerive` in this scope --> $DIR/generate-mod.rs:23:14 | LL | #[derive(generate_mod::CheckDerive)] @@ -77,25 +77,25 @@ LL | #[derive(generate_mod::CheckDerive)] | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #83583 - = note: this warning originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 4 previous errors; 4 warnings emitted +error: aborting due to 8 previous errors For more information about this error, try `rustc --explain E0412`. Future incompatibility report: Future breakage diagnostic: -warning: cannot find type `FromOutside` in this scope +error: cannot find type `FromOutside` in this scope --> $DIR/generate-mod.rs:16:10 | LL | #[derive(generate_mod::CheckDerive)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import | - = note: `#[warn(proc_macro_derive_resolution_fallback)]` on by default + = note: `#[deny(proc_macro_derive_resolution_fallback)]` on by default = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #83583 - = note: this warning originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info) Future breakage diagnostic: -warning: cannot find type `OuterDerive` in this scope +error: cannot find type `OuterDerive` in this scope --> $DIR/generate-mod.rs:16:10 | LL | #[derive(generate_mod::CheckDerive)] @@ -103,10 +103,10 @@ LL | #[derive(generate_mod::CheckDerive)] | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #83583 - = note: this warning originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info) Future breakage diagnostic: -warning: cannot find type `FromOutside` in this scope +error: cannot find type `FromOutside` in this scope --> $DIR/generate-mod.rs:23:14 | LL | #[derive(generate_mod::CheckDerive)] @@ -114,10 +114,10 @@ LL | #[derive(generate_mod::CheckDerive)] | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #83583 - = note: this warning originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info) Future breakage diagnostic: -warning: cannot find type `OuterDerive` in this scope +error: cannot find type `OuterDerive` in this scope --> $DIR/generate-mod.rs:23:14 | LL | #[derive(generate_mod::CheckDerive)] @@ -125,7 +125,7 @@ LL | #[derive(generate_mod::CheckDerive)] | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #83583 - = note: this warning originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info) Future breakage diagnostic: warning: cannot find type `FromOutside` in this scope diff --git a/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.rs b/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.rs index 2b742771d6f2c..3a2a6fa2253fa 100644 --- a/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.rs +++ b/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.rs @@ -1,4 +1,3 @@ -// check-pass // aux-build:pin-project-internal-0.4.0.rs // compile-flags: -Z span-debug @@ -24,7 +23,7 @@ mod no_version { } struct Foo; - impl_macros!(Foo); //~ WARN using an old version + impl_macros!(Foo); //~ ERROR using an old version //~| WARN this was previously arrays!(Foo); other!(Foo); @@ -41,9 +40,9 @@ mod with_version { } struct Foo; - impl_macros!(Foo); //~ WARN using an old version + impl_macros!(Foo); //~ ERROR using an old version //~| WARN this was previously - arrays!(Foo); //~ WARN using an old version + arrays!(Foo); //~ ERROR using an old version //~| WARN this was previously other!(Foo); } @@ -52,7 +51,7 @@ mod actix_web_test { include!("actix-web/src/extract.rs"); struct Foo; - tuple_from_req!(Foo); //~ WARN using an old version + tuple_from_req!(Foo); //~ ERROR using an old version //~| WARN this was previously } @@ -60,7 +59,7 @@ mod actix_web_version_test { include!("actix-web-2.0.0/src/extract.rs"); struct Foo; - tuple_from_req!(Foo); //~ WARN using an old version + tuple_from_req!(Foo); //~ ERROR using an old version //~| WARN this was previously } diff --git a/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.stderr b/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.stderr index 1a56291896c76..bd9ba6a09fce5 100644 --- a/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.stderr +++ b/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.stderr @@ -1,27 +1,27 @@ -warning: using an old version of `time-macros-impl` +error: using an old version of `time-macros-impl` --> $DIR/time-macros-impl/src/lib.rs:5:32 | LL | #[my_macro] struct One($name); | ^^^^^ | - ::: $DIR/group-compat-hack.rs:27:5 + ::: $DIR/group-compat-hack.rs:26:5 | LL | impl_macros!(Foo); | ----------------- in this macro invocation | - = note: `#[warn(proc_macro_back_compat)]` on by default + = note: `#[deny(proc_macro_back_compat)]` on by default = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #83125 = note: the `time-macros-impl` crate will stop compiling in futures version of Rust. Please update to the latest version of the `time` crate to avoid breakage - = note: this warning originates in the macro `impl_macros` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `impl_macros` (in Nightly builds, run with -Z macro-backtrace for more info) -warning: using an old version of `time-macros-impl` +error: using an old version of `time-macros-impl` --> $DIR/time-macros-impl-0.1.0/src/lib.rs:5:32 | LL | #[my_macro] struct One($name); | ^^^^^ | - ::: $DIR/group-compat-hack.rs:44:5 + ::: $DIR/group-compat-hack.rs:43:5 | LL | impl_macros!(Foo); | ----------------- in this macro invocation @@ -29,15 +29,15 @@ LL | impl_macros!(Foo); = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #83125 = note: the `time-macros-impl` crate will stop compiling in futures version of Rust. Please update to the latest version of the `time` crate to avoid breakage - = note: this warning originates in the macro `impl_macros` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `impl_macros` (in Nightly builds, run with -Z macro-backtrace for more info) -warning: using an old version of `js-sys` +error: using an old version of `js-sys` --> $DIR/js-sys-0.3.17/src/lib.rs:5:32 | LL | #[my_macro] struct Two($name); | ^^^^^ | - ::: $DIR/group-compat-hack.rs:46:5 + ::: $DIR/group-compat-hack.rs:45:5 | LL | arrays!(Foo); | ------------ in this macro invocation @@ -45,15 +45,15 @@ LL | arrays!(Foo); = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #83125 = note: older versions of the `js-sys` crate will stop compiling in future versions of Rust; please update to `js-sys` v0.3.40 or above - = note: this warning originates in the macro `arrays` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `arrays` (in Nightly builds, run with -Z macro-backtrace for more info) -warning: using an old version of `actix-web` +error: using an old version of `actix-web` --> $DIR/actix-web/src/extract.rs:5:34 | LL | #[my_macro] struct Three($T); | ^^ | - ::: $DIR/group-compat-hack.rs:55:5 + ::: $DIR/group-compat-hack.rs:54:5 | LL | tuple_from_req!(Foo); | -------------------- in this macro invocation @@ -61,15 +61,15 @@ LL | tuple_from_req!(Foo); = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #83125 = note: the version of `actix-web` you are using might stop compiling in future versions of Rust; please update to the latest version of the `actix-web` crate to avoid breakage - = note: this warning originates in the macro `tuple_from_req` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `tuple_from_req` (in Nightly builds, run with -Z macro-backtrace for more info) -warning: using an old version of `actix-web` +error: using an old version of `actix-web` --> $DIR/actix-web-2.0.0/src/extract.rs:5:34 | LL | #[my_macro] struct Three($T); | ^^ | - ::: $DIR/group-compat-hack.rs:63:5 + ::: $DIR/group-compat-hack.rs:62:5 | LL | tuple_from_req!(Foo); | -------------------- in this macro invocation @@ -77,36 +77,36 @@ LL | tuple_from_req!(Foo); = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #83125 = note: the version of `actix-web` you are using might stop compiling in future versions of Rust; please update to the latest version of the `actix-web` crate to avoid breakage - = note: this warning originates in the macro `tuple_from_req` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `tuple_from_req` (in Nightly builds, run with -Z macro-backtrace for more info) -warning: 5 warnings emitted +error: aborting due to 5 previous errors Future incompatibility report: Future breakage diagnostic: -warning: using an old version of `time-macros-impl` +error: using an old version of `time-macros-impl` --> $DIR/time-macros-impl/src/lib.rs:5:32 | LL | #[my_macro] struct One($name); | ^^^^^ | - ::: $DIR/group-compat-hack.rs:27:5 + ::: $DIR/group-compat-hack.rs:26:5 | LL | impl_macros!(Foo); | ----------------- in this macro invocation | - = note: `#[warn(proc_macro_back_compat)]` on by default + = note: `#[deny(proc_macro_back_compat)]` on by default = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #83125 = note: the `time-macros-impl` crate will stop compiling in futures version of Rust. Please update to the latest version of the `time` crate to avoid breakage - = note: this warning originates in the macro `impl_macros` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `impl_macros` (in Nightly builds, run with -Z macro-backtrace for more info) Future breakage diagnostic: -warning: using an old version of `time-macros-impl` +error: using an old version of `time-macros-impl` --> $DIR/time-macros-impl-0.1.0/src/lib.rs:5:32 | LL | #[my_macro] struct One($name); | ^^^^^ | - ::: $DIR/group-compat-hack.rs:44:5 + ::: $DIR/group-compat-hack.rs:43:5 | LL | impl_macros!(Foo); | ----------------- in this macro invocation @@ -114,16 +114,16 @@ LL | impl_macros!(Foo); = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #83125 = note: the `time-macros-impl` crate will stop compiling in futures version of Rust. Please update to the latest version of the `time` crate to avoid breakage - = note: this warning originates in the macro `impl_macros` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `impl_macros` (in Nightly builds, run with -Z macro-backtrace for more info) Future breakage diagnostic: -warning: using an old version of `js-sys` +error: using an old version of `js-sys` --> $DIR/js-sys-0.3.17/src/lib.rs:5:32 | LL | #[my_macro] struct Two($name); | ^^^^^ | - ::: $DIR/group-compat-hack.rs:46:5 + ::: $DIR/group-compat-hack.rs:45:5 | LL | arrays!(Foo); | ------------ in this macro invocation @@ -131,16 +131,16 @@ LL | arrays!(Foo); = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #83125 = note: older versions of the `js-sys` crate will stop compiling in future versions of Rust; please update to `js-sys` v0.3.40 or above - = note: this warning originates in the macro `arrays` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `arrays` (in Nightly builds, run with -Z macro-backtrace for more info) Future breakage diagnostic: -warning: using an old version of `actix-web` +error: using an old version of `actix-web` --> $DIR/actix-web/src/extract.rs:5:34 | LL | #[my_macro] struct Three($T); | ^^ | - ::: $DIR/group-compat-hack.rs:55:5 + ::: $DIR/group-compat-hack.rs:54:5 | LL | tuple_from_req!(Foo); | -------------------- in this macro invocation @@ -148,16 +148,16 @@ LL | tuple_from_req!(Foo); = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #83125 = note: the version of `actix-web` you are using might stop compiling in future versions of Rust; please update to the latest version of the `actix-web` crate to avoid breakage - = note: this warning originates in the macro `tuple_from_req` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `tuple_from_req` (in Nightly builds, run with -Z macro-backtrace for more info) Future breakage diagnostic: -warning: using an old version of `actix-web` +error: using an old version of `actix-web` --> $DIR/actix-web-2.0.0/src/extract.rs:5:34 | LL | #[my_macro] struct Three($T); | ^^ | - ::: $DIR/group-compat-hack.rs:63:5 + ::: $DIR/group-compat-hack.rs:62:5 | LL | tuple_from_req!(Foo); | -------------------- in this macro invocation @@ -165,5 +165,5 @@ LL | tuple_from_req!(Foo); = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #83125 = note: the version of `actix-web` you are using might stop compiling in future versions of Rust; please update to the latest version of the `actix-web` crate to avoid breakage - = note: this warning originates in the macro `tuple_from_req` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `tuple_from_req` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.stdout b/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.stdout index 82d6bc33bf95b..51312b10ad176 100644 --- a/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.stdout +++ b/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.stdout @@ -1,11 +1,11 @@ -Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/time-macros-impl/src/lib.rs:5:21: 5:27 (#6) }, Ident { ident: "One", span: $DIR/time-macros-impl/src/lib.rs:5:28: 5:31 (#6) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:27:18: 27:21 (#0) }], span: $DIR/time-macros-impl/src/lib.rs:5:31: 5:38 (#6) }, Punct { ch: ';', spacing: Alone, span: $DIR/time-macros-impl/src/lib.rs:5:38: 5:39 (#6) }] -Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/js-sys/src/lib.rs:5:21: 5:27 (#10) }, Ident { ident: "Two", span: $DIR/js-sys/src/lib.rs:5:28: 5:31 (#10) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:29:13: 29:16 (#0) }], span: $DIR/js-sys/src/lib.rs:5:32: 5:37 (#10) }], span: $DIR/js-sys/src/lib.rs:5:31: 5:38 (#10) }, Punct { ch: ';', spacing: Alone, span: $DIR/js-sys/src/lib.rs:5:38: 5:39 (#10) }] -Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/group-compat-hack.rs:22:25: 22:31 (#14) }, Ident { ident: "Three", span: $DIR/group-compat-hack.rs:22:32: 22:37 (#14) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:30:12: 30:15 (#0) }], span: $DIR/group-compat-hack.rs:22:38: 22:43 (#14) }], span: $DIR/group-compat-hack.rs:22:37: 22:44 (#14) }, Punct { ch: ';', spacing: Alone, span: $DIR/group-compat-hack.rs:22:44: 22:45 (#14) }] -Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:21: 5:27 (#20) }, Ident { ident: "One", span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:28: 5:31 (#20) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:44:18: 44:21 (#0) }], span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:31: 5:38 (#20) }, Punct { ch: ';', spacing: Alone, span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:38: 5:39 (#20) }] -Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/js-sys-0.3.17/src/lib.rs:5:21: 5:27 (#24) }, Ident { ident: "Two", span: $DIR/js-sys-0.3.17/src/lib.rs:5:28: 5:31 (#24) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:46:13: 46:16 (#0) }], span: $DIR/js-sys-0.3.17/src/lib.rs:5:31: 5:38 (#24) }, Punct { ch: ';', spacing: Alone, span: $DIR/js-sys-0.3.17/src/lib.rs:5:38: 5:39 (#24) }] -Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/group-compat-hack.rs:39:25: 39:31 (#28) }, Ident { ident: "Three", span: $DIR/group-compat-hack.rs:39:32: 39:37 (#28) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:48:12: 48:15 (#0) }], span: $DIR/group-compat-hack.rs:39:38: 39:43 (#28) }], span: $DIR/group-compat-hack.rs:39:37: 39:44 (#28) }, Punct { ch: ';', spacing: Alone, span: $DIR/group-compat-hack.rs:39:44: 39:45 (#28) }] -Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/actix-web/src/extract.rs:5:21: 5:27 (#33) }, Ident { ident: "Three", span: $DIR/actix-web/src/extract.rs:5:28: 5:33 (#33) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:55:21: 55:24 (#0) }], span: $DIR/actix-web/src/extract.rs:5:33: 5:37 (#33) }, Punct { ch: ';', spacing: Alone, span: $DIR/actix-web/src/extract.rs:5:37: 5:38 (#33) }] -Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/actix-web-2.0.0/src/extract.rs:5:21: 5:27 (#38) }, Ident { ident: "Three", span: $DIR/actix-web-2.0.0/src/extract.rs:5:28: 5:33 (#38) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:63:21: 63:24 (#0) }], span: $DIR/actix-web-2.0.0/src/extract.rs:5:33: 5:37 (#38) }, Punct { ch: ';', spacing: Alone, span: $DIR/actix-web-2.0.0/src/extract.rs:5:37: 5:38 (#38) }] -Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/actori-web/src/extract.rs:5:21: 5:27 (#43) }, Ident { ident: "Four", span: $DIR/actori-web/src/extract.rs:5:28: 5:32 (#43) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:71:21: 71:24 (#0) }], span: $DIR/actori-web/src/extract.rs:5:33: 5:35 (#43) }], span: $DIR/actori-web/src/extract.rs:5:32: 5:36 (#43) }, Punct { ch: ';', spacing: Alone, span: $DIR/actori-web/src/extract.rs:5:36: 5:37 (#43) }] -Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/actori-web-2.0.0/src/extract.rs:5:21: 5:27 (#48) }, Ident { ident: "Four", span: $DIR/actori-web-2.0.0/src/extract.rs:5:28: 5:32 (#48) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:78:21: 78:24 (#0) }], span: $DIR/actori-web-2.0.0/src/extract.rs:5:33: 5:35 (#48) }], span: $DIR/actori-web-2.0.0/src/extract.rs:5:32: 5:36 (#48) }, Punct { ch: ';', spacing: Alone, span: $DIR/actori-web-2.0.0/src/extract.rs:5:36: 5:37 (#48) }] -Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/js-sys-0.3.40/src/lib.rs:5:21: 5:27 (#53) }, Ident { ident: "Two", span: $DIR/js-sys-0.3.40/src/lib.rs:5:28: 5:31 (#53) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:84:13: 84:16 (#0) }], span: $DIR/js-sys-0.3.40/src/lib.rs:5:32: 5:37 (#53) }], span: $DIR/js-sys-0.3.40/src/lib.rs:5:31: 5:38 (#53) }, Punct { ch: ';', spacing: Alone, span: $DIR/js-sys-0.3.40/src/lib.rs:5:38: 5:39 (#53) }] +Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/time-macros-impl/src/lib.rs:5:21: 5:27 (#6) }, Ident { ident: "One", span: $DIR/time-macros-impl/src/lib.rs:5:28: 5:31 (#6) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:26:18: 26:21 (#0) }], span: $DIR/time-macros-impl/src/lib.rs:5:31: 5:38 (#6) }, Punct { ch: ';', spacing: Alone, span: $DIR/time-macros-impl/src/lib.rs:5:38: 5:39 (#6) }] +Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/js-sys/src/lib.rs:5:21: 5:27 (#10) }, Ident { ident: "Two", span: $DIR/js-sys/src/lib.rs:5:28: 5:31 (#10) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:28:13: 28:16 (#0) }], span: $DIR/js-sys/src/lib.rs:5:32: 5:37 (#10) }], span: $DIR/js-sys/src/lib.rs:5:31: 5:38 (#10) }, Punct { ch: ';', spacing: Alone, span: $DIR/js-sys/src/lib.rs:5:38: 5:39 (#10) }] +Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/group-compat-hack.rs:21:25: 21:31 (#14) }, Ident { ident: "Three", span: $DIR/group-compat-hack.rs:21:32: 21:37 (#14) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:29:12: 29:15 (#0) }], span: $DIR/group-compat-hack.rs:21:38: 21:43 (#14) }], span: $DIR/group-compat-hack.rs:21:37: 21:44 (#14) }, Punct { ch: ';', spacing: Alone, span: $DIR/group-compat-hack.rs:21:44: 21:45 (#14) }] +Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:21: 5:27 (#20) }, Ident { ident: "One", span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:28: 5:31 (#20) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:43:18: 43:21 (#0) }], span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:31: 5:38 (#20) }, Punct { ch: ';', spacing: Alone, span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:38: 5:39 (#20) }] +Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/js-sys-0.3.17/src/lib.rs:5:21: 5:27 (#24) }, Ident { ident: "Two", span: $DIR/js-sys-0.3.17/src/lib.rs:5:28: 5:31 (#24) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:45:13: 45:16 (#0) }], span: $DIR/js-sys-0.3.17/src/lib.rs:5:31: 5:38 (#24) }, Punct { ch: ';', spacing: Alone, span: $DIR/js-sys-0.3.17/src/lib.rs:5:38: 5:39 (#24) }] +Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/group-compat-hack.rs:38:25: 38:31 (#28) }, Ident { ident: "Three", span: $DIR/group-compat-hack.rs:38:32: 38:37 (#28) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:47:12: 47:15 (#0) }], span: $DIR/group-compat-hack.rs:38:38: 38:43 (#28) }], span: $DIR/group-compat-hack.rs:38:37: 38:44 (#28) }, Punct { ch: ';', spacing: Alone, span: $DIR/group-compat-hack.rs:38:44: 38:45 (#28) }] +Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/actix-web/src/extract.rs:5:21: 5:27 (#33) }, Ident { ident: "Three", span: $DIR/actix-web/src/extract.rs:5:28: 5:33 (#33) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:54:21: 54:24 (#0) }], span: $DIR/actix-web/src/extract.rs:5:33: 5:37 (#33) }, Punct { ch: ';', spacing: Alone, span: $DIR/actix-web/src/extract.rs:5:37: 5:38 (#33) }] +Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/actix-web-2.0.0/src/extract.rs:5:21: 5:27 (#38) }, Ident { ident: "Three", span: $DIR/actix-web-2.0.0/src/extract.rs:5:28: 5:33 (#38) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:62:21: 62:24 (#0) }], span: $DIR/actix-web-2.0.0/src/extract.rs:5:33: 5:37 (#38) }, Punct { ch: ';', spacing: Alone, span: $DIR/actix-web-2.0.0/src/extract.rs:5:37: 5:38 (#38) }] +Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/actori-web/src/extract.rs:5:21: 5:27 (#43) }, Ident { ident: "Four", span: $DIR/actori-web/src/extract.rs:5:28: 5:32 (#43) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:70:21: 70:24 (#0) }], span: $DIR/actori-web/src/extract.rs:5:33: 5:35 (#43) }], span: $DIR/actori-web/src/extract.rs:5:32: 5:36 (#43) }, Punct { ch: ';', spacing: Alone, span: $DIR/actori-web/src/extract.rs:5:36: 5:37 (#43) }] +Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/actori-web-2.0.0/src/extract.rs:5:21: 5:27 (#48) }, Ident { ident: "Four", span: $DIR/actori-web-2.0.0/src/extract.rs:5:28: 5:32 (#48) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:77:21: 77:24 (#0) }], span: $DIR/actori-web-2.0.0/src/extract.rs:5:33: 5:35 (#48) }], span: $DIR/actori-web-2.0.0/src/extract.rs:5:32: 5:36 (#48) }, Punct { ch: ';', spacing: Alone, span: $DIR/actori-web-2.0.0/src/extract.rs:5:36: 5:37 (#48) }] +Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/js-sys-0.3.40/src/lib.rs:5:21: 5:27 (#53) }, Ident { ident: "Two", span: $DIR/js-sys-0.3.40/src/lib.rs:5:28: 5:31 (#53) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:83:13: 83:16 (#0) }], span: $DIR/js-sys-0.3.40/src/lib.rs:5:32: 5:37 (#53) }], span: $DIR/js-sys-0.3.40/src/lib.rs:5:31: 5:38 (#53) }, Punct { ch: ';', spacing: Alone, span: $DIR/js-sys-0.3.40/src/lib.rs:5:38: 5:39 (#53) }] diff --git a/src/test/ui/proc-macro/issue-73933-procedural-masquerade.rs b/src/test/ui/proc-macro/issue-73933-procedural-masquerade.rs index abc3d2691a307..113235051b2b9 100644 --- a/src/test/ui/proc-macro/issue-73933-procedural-masquerade.rs +++ b/src/test/ui/proc-macro/issue-73933-procedural-masquerade.rs @@ -1,11 +1,10 @@ -// check-pass // aux-build:test-macros.rs #[macro_use] extern crate test_macros; #[derive(Print)] -enum ProceduralMasqueradeDummyType { //~ WARN using +enum ProceduralMasqueradeDummyType { //~ ERROR using //~| WARN this was previously Input } diff --git a/src/test/ui/proc-macro/issue-73933-procedural-masquerade.stderr b/src/test/ui/proc-macro/issue-73933-procedural-masquerade.stderr index 4d6edab08e2cf..dff71c9eacd4d 100644 --- a/src/test/ui/proc-macro/issue-73933-procedural-masquerade.stderr +++ b/src/test/ui/proc-macro/issue-73933-procedural-masquerade.stderr @@ -1,24 +1,24 @@ -warning: using `procedural-masquerade` crate - --> $DIR/issue-73933-procedural-masquerade.rs:8:6 +error: using `procedural-masquerade` crate + --> $DIR/issue-73933-procedural-masquerade.rs:7:6 | LL | enum ProceduralMasqueradeDummyType { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `#[warn(proc_macro_back_compat)]` on by default + = note: `#[deny(proc_macro_back_compat)]` on by default = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #83125 = note: The `procedural-masquerade` crate has been unnecessary since Rust 1.30.0. Versions of this crate below 0.1.7 will eventually stop compiling. -warning: 1 warning emitted +error: aborting due to previous error Future incompatibility report: Future breakage diagnostic: -warning: using `procedural-masquerade` crate - --> $DIR/issue-73933-procedural-masquerade.rs:8:6 +error: using `procedural-masquerade` crate + --> $DIR/issue-73933-procedural-masquerade.rs:7:6 | LL | enum ProceduralMasqueradeDummyType { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `#[warn(proc_macro_back_compat)]` on by default + = note: `#[deny(proc_macro_back_compat)]` on by default = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #83125 = note: The `procedural-masquerade` crate has been unnecessary since Rust 1.30.0. Versions of this crate below 0.1.7 will eventually stop compiling. diff --git a/src/test/ui/proc-macro/issue-73933-procedural-masquerade.stdout b/src/test/ui/proc-macro/issue-73933-procedural-masquerade.stdout index 8edd68f8a3b84..8a8fbf0682470 100644 --- a/src/test/ui/proc-macro/issue-73933-procedural-masquerade.stdout +++ b/src/test/ui/proc-macro/issue-73933-procedural-masquerade.stdout @@ -3,20 +3,20 @@ PRINT-DERIVE RE-COLLECTED (DISPLAY): enum ProceduralMasqueradeDummyType { Input PRINT-DERIVE INPUT (DEBUG): TokenStream [ Ident { ident: "enum", - span: #0 bytes(100..104), + span: #0 bytes(86..90), }, Ident { ident: "ProceduralMasqueradeDummyType", - span: #0 bytes(105..134), + span: #0 bytes(91..120), }, Group { delimiter: Brace, stream: TokenStream [ Ident { ident: "Input", - span: #0 bytes(186..191), + span: #0 bytes(173..178), }, ], - span: #0 bytes(135..193), + span: #0 bytes(121..180), }, ] diff --git a/src/test/ui/variance/variance-associated-consts.rs b/src/test/ui/variance/variance-associated-consts.rs new file mode 100644 index 0000000000000..da55bc96244f2 --- /dev/null +++ b/src/test/ui/variance/variance-associated-consts.rs @@ -0,0 +1,17 @@ +// Test that the variance computation considers types that +// appear in const expressions to be invariant. + +#![feature(rustc_attrs)] +#![allow(incomplete_features)] +#![feature(generic_const_exprs)] + +trait Trait { + const Const: usize; +} + +#[rustc_variance] +struct Foo { //~ ERROR [o] + field: [u8; ::Const] +} + +fn main() { } diff --git a/src/test/ui/variance/variance-associated-consts.stderr b/src/test/ui/variance/variance-associated-consts.stderr new file mode 100644 index 0000000000000..d1bf34781dfb2 --- /dev/null +++ b/src/test/ui/variance/variance-associated-consts.stderr @@ -0,0 +1,10 @@ +error[E0208]: [o] + --> $DIR/variance-associated-consts.rs:13:1 + | +LL | / struct Foo { +LL | | field: [u8; ::Const] +LL | | } + | |_^ + +error: aborting due to previous error +