From 6876f9bcdc94c5e0c8cde03040b428f24f19a051 Mon Sep 17 00:00:00 2001 From: Mark Mansi Date: Mon, 26 Aug 2019 18:06:24 -0500 Subject: [PATCH 01/24] filter linkcheck spurious failure --- src/tools/rustbook/src/main.rs | 54 ++++++++++++++++++++++------------ 1 file changed, 35 insertions(+), 19 deletions(-) diff --git a/src/tools/rustbook/src/main.rs b/src/tools/rustbook/src/main.rs index 95530b210afd6..0915600bb3875 100644 --- a/src/tools/rustbook/src/main.rs +++ b/src/tools/rustbook/src/main.rs @@ -1,18 +1,18 @@ -use clap::{crate_version}; +use clap::crate_version; use std::env; use std::path::{Path, PathBuf}; -use clap::{App, ArgMatches, SubCommand, AppSettings}; +use clap::{App, AppSettings, ArgMatches, SubCommand}; +use mdbook::errors::Result as Result3; use mdbook::MDBook; -use mdbook::errors::{Result as Result3}; +use failure::Error; #[cfg(feature = "linkcheck")] use mdbook::renderer::RenderContext; #[cfg(feature = "linkcheck")] use mdbook_linkcheck::{self, errors::BrokenLinks}; -use failure::Error; fn main() { let d_message = "-d, --dest-dir=[dest-dir] @@ -21,18 +21,22 @@ fn main() { 'A directory for your book{n}(Defaults to Current Directory when omitted)'"; let matches = App::new("rustbook") - .about("Build a book with mdBook") - .author("Steve Klabnik ") - .version(&*format!("v{}", crate_version!())) - .setting(AppSettings::SubcommandRequired) - .subcommand(SubCommand::with_name("build") - .about("Build the book from the markdown files") - .arg_from_usage(d_message) - .arg_from_usage(dir_message)) - .subcommand(SubCommand::with_name("linkcheck") - .about("Run linkcheck with mdBook 3") - .arg_from_usage(dir_message)) - .get_matches(); + .about("Build a book with mdBook") + .author("Steve Klabnik ") + .version(&*format!("v{}", crate_version!())) + .setting(AppSettings::SubcommandRequired) + .subcommand( + SubCommand::with_name("build") + .about("Build the book from the markdown files") + .arg_from_usage(d_message) + .arg_from_usage(dir_message), + ) + .subcommand( + SubCommand::with_name("linkcheck") + .about("Run linkcheck with mdBook 3") + .arg_from_usage(dir_message), + ) + .get_matches(); // Check which subcomamnd the user ran... match matches.subcommand() { @@ -46,23 +50,35 @@ fn main() { ::std::process::exit(101); } - }, + } ("linkcheck", Some(sub_matches)) => { if let Err(err) = linkcheck(sub_matches) { eprintln!("Error: {}", err); + // HACK: ignore timeouts + #[allow(unused_mut)] + let mut actually_broken = false; + #[cfg(feature = "linkcheck")] { if let Ok(broken_links) = err.downcast::() { for cause in broken_links.links().iter() { eprintln!("\tCaused By: {}", cause); + + if cause.contains("timed out") { + actually_broken = true; + } } } } - ::std::process::exit(101); + if actually_broken { + std::process::exit(101); + } else { + std::process::exit(0); + } } - }, + } (_, _) => unreachable!(), }; } From 2e59c4afd16ea7b887f3d81b5aeea8669b843afe Mon Sep 17 00:00:00 2001 From: Mark Mansi Date: Thu, 29 Aug 2019 13:03:22 -0500 Subject: [PATCH 02/24] fix bugs + review comments --- src/tools/rustbook/src/main.rs | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/src/tools/rustbook/src/main.rs b/src/tools/rustbook/src/main.rs index 0915600bb3875..e155f3f7607f3 100644 --- a/src/tools/rustbook/src/main.rs +++ b/src/tools/rustbook/src/main.rs @@ -56,21 +56,22 @@ fn main() { eprintln!("Error: {}", err); // HACK: ignore timeouts - #[allow(unused_mut)] - let mut actually_broken = false; - - #[cfg(feature = "linkcheck")] - { - if let Ok(broken_links) = err.downcast::() { - for cause in broken_links.links().iter() { - eprintln!("\tCaused By: {}", cause); - - if cause.contains("timed out") { - actually_broken = true; - } - } + let actually_broken = { + #[cfg(feature = "linkcheck")] + { + err.downcast::() + .unwrap_or(false) + .links() + .iter() + .inspect(|cause| eprintln!("\tCaused By: {}", cause)) + .any(|cause| !cause.contains("timed out")); } - } + + #[cfg(not(feature = "linkcheck"))] + { + false + } + }; if actually_broken { std::process::exit(101); From 3f6db849f7270b9126e6609a87058c1bc3aef1da Mon Sep 17 00:00:00 2001 From: Mark Mansi Date: Fri, 30 Aug 2019 14:05:39 -0500 Subject: [PATCH 03/24] actually compiles now? --- src/tools/rustbook/src/main.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/tools/rustbook/src/main.rs b/src/tools/rustbook/src/main.rs index e155f3f7607f3..b2111442310ef 100644 --- a/src/tools/rustbook/src/main.rs +++ b/src/tools/rustbook/src/main.rs @@ -60,11 +60,14 @@ fn main() { #[cfg(feature = "linkcheck")] { err.downcast::() + .map(|broken_links| { + broken_links + .links() + .iter() + .inspect(|cause| eprintln!("\tCaused By: {}", cause)) + .any(|cause| !format!("{}", cause).contains("timed out")) + }) .unwrap_or(false) - .links() - .iter() - .inspect(|cause| eprintln!("\tCaused By: {}", cause)) - .any(|cause| !cause.contains("timed out")); } #[cfg(not(feature = "linkcheck"))] From 0133941f47b039d652f5d9f2617b7d3884298515 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sun, 25 Aug 2019 19:59:51 +0100 Subject: [PATCH 04/24] Add an ExpnKind for AST passes --- src/librustc/ich/impls_syntax.rs | 8 ++++++++ src/librustc/lint/mod.rs | 2 +- src/libsyntax_pos/hygiene.rs | 24 +++++++++++++++++++++++- src/libsyntax_pos/lib.rs | 1 + 4 files changed, 33 insertions(+), 2 deletions(-) diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs index 05e2c7854b49c..532485b5d77bb 100644 --- a/src/librustc/ich/impls_syntax.rs +++ b/src/librustc/ich/impls_syntax.rs @@ -411,9 +411,17 @@ impl_stable_hash_for!(struct ::syntax_pos::hygiene::ExpnData { impl_stable_hash_for!(enum ::syntax_pos::hygiene::ExpnKind { Root, Macro(kind, descr), + AstPass(kind), Desugaring(kind) }); +impl_stable_hash_for!(enum ::syntax_pos::hygiene::AstPass { + StdImports, + TestHarness, + ProcMacroHarness, + PluginMacroDefs, +}); + impl_stable_hash_for!(enum ::syntax_pos::hygiene::DesugaringKind { CondTemporary, Async, diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs index 2b58627cdea56..1b133819a73bf 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/mod.rs @@ -888,7 +888,7 @@ pub fn in_external_macro(sess: &Session, span: Span) -> bool { let expn_data = span.ctxt().outer_expn_data(); match expn_data.kind { ExpnKind::Root | ExpnKind::Desugaring(DesugaringKind::ForLoop) => false, - ExpnKind::Desugaring(_) => true, // well, it's "external" + ExpnKind::AstPass(_) | ExpnKind::Desugaring(_) => true, // well, it's "external" ExpnKind::Macro(MacroKind::Bang, _) => { if expn_data.def_site.is_dummy() { // dummy span for the def_site means it's an external macro diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs index 733f6f0449065..237a02f2f667a 100644 --- a/src/libsyntax_pos/hygiene.rs +++ b/src/libsyntax_pos/hygiene.rs @@ -639,8 +639,9 @@ pub enum ExpnKind { /// No expansion, aka root expansion. Only `ExpnId::root()` has this kind. Root, /// Expansion produced by a macro. - /// FIXME: Some code injected by the compiler before HIR lowering also gets this kind. Macro(MacroKind, Symbol), + /// Transform done by the compiler on the AST. + AstPass(AstPass), /// Desugaring done by the compiler during HIR lowering. Desugaring(DesugaringKind) } @@ -650,6 +651,7 @@ impl ExpnKind { match *self { ExpnKind::Root => kw::PathRoot, ExpnKind::Macro(_, descr) => descr, + ExpnKind::AstPass(kind) => Symbol::intern(kind.descr()), ExpnKind::Desugaring(kind) => Symbol::intern(kind.descr()), } } @@ -683,6 +685,26 @@ impl MacroKind { } } +/// The kind of AST transform. +#[derive(Clone, Copy, PartialEq, Debug, RustcEncodable, RustcDecodable)] +pub enum AstPass { + StdImports, + TestHarness, + ProcMacroHarness, + PluginMacroDefs, +} + +impl AstPass { + fn descr(self) -> &'static str { + match self { + AstPass::StdImports => "standard library imports", + AstPass::TestHarness => "test harness", + AstPass::ProcMacroHarness => "proc macro harness", + AstPass::PluginMacroDefs => "plugin macro definitions", + } + } +} + /// The kind of compiler desugaring. #[derive(Clone, Copy, PartialEq, Debug, RustcEncodable, RustcDecodable)] pub enum DesugaringKind { diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index 3d8bfc77a8950..d800109cf8531 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -442,6 +442,7 @@ impl Span { let (pre, post) = match expn_data.kind { ExpnKind::Root => break, ExpnKind::Desugaring(..) => ("desugaring of ", ""), + ExpnKind::AstPass(..) => ("", ""), ExpnKind::Macro(macro_kind, _) => match macro_kind { MacroKind::Bang => ("", "!"), MacroKind::Attr => ("#[", "]"), From 4082cd95a8de6c8244e9b44908f9859e75acdeea Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sun, 25 Aug 2019 20:58:03 +0100 Subject: [PATCH 05/24] Allow ast passes to create hygienic spans --- src/librustc_resolve/build_reduced_graph.rs | 3 +- src/librustc_resolve/lib.rs | 22 ++++++++++++ src/librustc_resolve/macros.rs | 39 ++++++++++++++++++++- src/libsyntax/ext/base.rs | 10 +++++- src/libsyntax_pos/hygiene.rs | 2 +- 5 files changed, 72 insertions(+), 4 deletions(-) diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 9a794ade729c2..5a3b768301ce0 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -126,7 +126,8 @@ impl<'a> Resolver<'a> { crate fn macro_def_scope(&mut self, expn_id: ExpnId) -> Module<'a> { let def_id = match self.macro_defs.get(&expn_id) { Some(def_id) => *def_id, - None => return self.graph_root, + None => return self.ast_transform_scopes.get(&expn_id) + .unwrap_or(&self.graph_root), }; if let Some(id) = self.definitions.as_local_node_id(def_id) { self.local_macro_def_scopes[&id] diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 875ae449d94e0..b12bf4521e098 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -879,6 +879,10 @@ pub struct Resolver<'a> { /// There will be an anonymous module created around `g` with the ID of the /// entry block for `f`. block_map: NodeMap>, + /// A fake module that contains no definition and no prelude. Used so that + /// some AST passes can generate identifiers that only resolve to local or + /// language items. + empty_module: Module<'a>, module_map: FxHashMap>, extern_module_map: FxHashMap<(DefId, bool /* MacrosOnly? */), Module<'a>>, binding_parent_modules: FxHashMap>, Module<'a>>, @@ -913,6 +917,7 @@ pub struct Resolver<'a> { non_macro_attrs: [Lrc; 2], macro_defs: FxHashMap, local_macro_def_scopes: FxHashMap>, + ast_transform_scopes: FxHashMap>, unused_macros: NodeMap, proc_macro_stubs: NodeSet, /// Traces collected during macro resolution and validated when it's complete. @@ -1080,6 +1085,21 @@ impl<'a> Resolver<'a> { no_implicit_prelude: attr::contains_name(&krate.attrs, sym::no_implicit_prelude), ..ModuleData::new(None, root_module_kind, root_def_id, ExpnId::root(), krate.span) }); + let empty_module_kind = ModuleKind::Def( + DefKind::Mod, + root_def_id, + kw::Invalid, + ); + let empty_module = arenas.alloc_module(ModuleData { + no_implicit_prelude: true, + ..ModuleData::new( + Some(graph_root), + empty_module_kind, + root_def_id, + ExpnId::root(), + DUMMY_SP, + ) + }); let mut module_map = FxHashMap::default(); module_map.insert(DefId::local(CRATE_DEF_INDEX), graph_root); @@ -1139,10 +1159,12 @@ impl<'a> Resolver<'a> { label_res_map: Default::default(), export_map: FxHashMap::default(), trait_map: Default::default(), + empty_module, module_map, block_map: Default::default(), extern_module_map: FxHashMap::default(), binding_parent_modules: FxHashMap::default(), + ast_transform_scopes: FxHashMap::default(), glob_map: Default::default(), diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 719167eb057b2..fe7eae91945f7 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -8,6 +8,7 @@ use crate::{ModuleOrUniformRoot, KNOWN_TOOLS}; use crate::Namespace::*; use crate::resolve_imports::ImportResolver; use rustc::hir::def::{self, DefKind, NonMacroAttrKind}; +use rustc::hir::def_id; use rustc::middle::stability; use rustc::{ty, lint, span_bug}; use syntax::ast::{self, NodeId, Ident}; @@ -16,7 +17,7 @@ use syntax::edition::Edition; use syntax::ext::base::{self, Indeterminate, SpecialDerives}; use syntax::ext::base::{MacroKind, SyntaxExtension}; use syntax::ext::expand::{AstFragment, Invocation, InvocationKind}; -use syntax::ext::hygiene::{self, ExpnId, ExpnData, ExpnKind}; +use syntax::ext::hygiene::{self, ExpnId, ExpnData, ExpnKind, Transparency}; use syntax::ext::tt::macro_rules; use syntax::feature_gate::{emit_feature_err, is_builtin_attr_name}; use syntax::feature_gate::GateIssue; @@ -25,6 +26,7 @@ use syntax_pos::{Span, DUMMY_SP}; use std::{mem, ptr}; use rustc_data_structures::sync::Lrc; +use syntax_pos::hygiene::AstPass; type Res = def::Res; @@ -136,6 +138,41 @@ impl<'a> base::Resolver for Resolver<'a> { } } + // Create a Span with modern hygiene with a definition site of the provided + // module, or a fake empty `#[no_implicit_prelude]` module if no module is + // provided. + fn span_for_ast_pass( + &mut self, + base_span: Span, + pass: AstPass, + features: &[Symbol], + parent_module_id: Option, + ) -> Span { + let span = base_span.fresh_expansion_with_transparency( + ExpnData::allow_unstable( + ExpnKind::AstPass(pass), + base_span, + self.session.edition(), + features.into(), + ), + Transparency::Opaque, + ); + let expn_id = span.ctxt().outer_expn(); + let parent_scope = if let Some(module_id) = parent_module_id { + let parent_def_id = self.definitions.local_def_id(module_id); + self.definitions.add_parent_module_of_macro_def(expn_id, parent_def_id); + self.module_map[&parent_def_id] + } else { + self.definitions.add_parent_module_of_macro_def( + expn_id, + def_id::DefId::local(def_id::CRATE_DEF_INDEX), + ); + self.empty_module + }; + self.ast_transform_scopes.insert(expn_id, parent_scope); + span + } + fn resolve_imports(&mut self) { ImportResolver { r: self }.resolve_imports() } diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index a63c4181d5e03..3d274af99083c 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -15,7 +15,7 @@ use crate::tokenstream::{self, TokenStream, TokenTree}; use errors::{DiagnosticBuilder, DiagnosticId}; use smallvec::{smallvec, SmallVec}; use syntax_pos::{FileName, Span, MultiSpan, DUMMY_SP}; -use syntax_pos::hygiene::{ExpnData, ExpnKind}; +use syntax_pos::hygiene::{AstPass, ExpnData, ExpnKind}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::{self, Lrc}; @@ -660,6 +660,14 @@ pub trait Resolver { extra_placeholders: &[NodeId]); fn register_builtin_macro(&mut self, ident: ast::Ident, ext: SyntaxExtension); + fn span_for_ast_pass( + &mut self, + span: Span, + pass: AstPass, + features: &[Symbol], + parent_module_id: Option, + ) -> Span; + fn resolve_imports(&mut self); fn resolve_macro_invocation( diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs index 237a02f2f667a..99afe57ef5497 100644 --- a/src/libsyntax_pos/hygiene.rs +++ b/src/libsyntax_pos/hygiene.rs @@ -550,7 +550,7 @@ impl Span { /// The returned span belongs to the created expansion and has the new properties, /// but its location is inherited from the current span. pub fn fresh_expansion(self, expn_data: ExpnData) -> Span { - self.fresh_expansion_with_transparency(expn_data, Transparency::SemiTransparent) + self.fresh_expansion_with_transparency(expn_data, Transparency::Transparent) } pub fn fresh_expansion_with_transparency( From 6fcdb36ccb60cca5c26ac804770a47fc01e0c2dd Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sun, 25 Aug 2019 21:03:24 +0100 Subject: [PATCH 06/24] Make use of hygiene in AST passes --- src/librustc_interface/passes.rs | 27 +-- src/librustc_resolve/macros.rs | 10 - src/libsyntax/ext/base.rs | 2 - src/libsyntax_ext/plugin_macro_defs.rs | 4 +- src/libsyntax_ext/proc_macro_harness.rs | 86 +++++---- src/libsyntax_ext/standard_library_imports.rs | 130 +++++++++---- src/libsyntax_ext/test.rs | 19 +- src/libsyntax_ext/test_harness.rs | 175 +++++------------- src/test/ui/hygiene/auxiliary/not-libstd.rs | 1 + src/test/ui/hygiene/prelude-import-hygiene.rs | 29 +++ src/test/ui/imports/gensymed.rs | 4 +- src/test/ui/inaccessible-test-modules.stderr | 21 --- src/test/ui/test-attrs/decl-macro-test.rs | 22 +++ .../inaccessible-test-modules.rs | 4 +- .../inaccessible-test-modules.stderr | 21 +++ 15 files changed, 298 insertions(+), 257 deletions(-) create mode 100644 src/test/ui/hygiene/auxiliary/not-libstd.rs create mode 100644 src/test/ui/hygiene/prelude-import-hygiene.rs delete mode 100644 src/test/ui/inaccessible-test-modules.stderr create mode 100644 src/test/ui/test-attrs/decl-macro-test.rs rename src/test/ui/{ => test-attrs}/inaccessible-test-modules.rs (56%) create mode 100644 src/test/ui/test-attrs/inaccessible-test-modules.stderr diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs index 8b0b5a5b7a2bd..649cc8a2fb515 100644 --- a/src/librustc_interface/passes.rs +++ b/src/librustc_interface/passes.rs @@ -233,7 +233,7 @@ pub fn register_plugins<'a>( syntax::attr::inject(krate, &sess.parse_sess, &sess.opts.debugging_opts.crate_attr) }); - let (mut krate, features) = syntax::config::features( + let (krate, features) = syntax::config::features( krate, &sess.parse_sess, sess.edition(), @@ -268,16 +268,6 @@ pub fn register_plugins<'a>( middle::recursion_limit::update_limits(sess, &krate); }); - krate = time(sess, "crate injection", || { - let alt_std_name = sess.opts.alt_std_name.as_ref().map(|s| &**s); - let (krate, name) = - syntax_ext::standard_library_imports::inject(krate, alt_std_name, sess.edition()); - if let Some(name) = name { - sess.parse_sess.injected_crate_name.set(name); - } - krate - }); - let registrars = time(sess, "plugin loading", || { plugin::load::load_plugins( sess, @@ -370,6 +360,21 @@ fn configure_and_expand_inner<'a>( &resolver_arenas, ); syntax_ext::register_builtin_macros(&mut resolver, sess.edition()); + + krate = time(sess, "crate injection", || { + let alt_std_name = sess.opts.alt_std_name.as_ref().map(|s| Symbol::intern(s)); + let (krate, name) = syntax_ext::standard_library_imports::inject( + krate, + &mut resolver, + alt_std_name, + sess.edition(), + ); + if let Some(name) = name { + sess.parse_sess.injected_crate_name.set(name); + } + krate + }); + syntax_ext::plugin_macro_defs::inject( &mut krate, &mut resolver, plugin_info.syntax_exts, sess.edition() ); diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index fe7eae91945f7..20d281f1e997a 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -97,16 +97,6 @@ impl<'a> base::Resolver for Resolver<'a> { self.session.next_node_id() } - fn get_module_scope(&mut self, id: NodeId) -> ExpnId { - let expn_id = ExpnId::fresh(Some(ExpnData::default( - ExpnKind::Macro(MacroKind::Attr, sym::test_case), DUMMY_SP, self.session.edition() - ))); - let module = self.module_map[&self.definitions.local_def_id(id)]; - self.invocation_parent_scopes.insert(expn_id, ParentScope::module(module)); - self.definitions.set_invocation_parent(expn_id, module.def_id().unwrap().index); - expn_id - } - fn resolve_dollar_crates(&mut self) { hygiene::update_dollar_crate_names(|ctxt| { let ident = Ident::new(kw::DollarCrate, DUMMY_SP.with_ctxt(ctxt)); diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 3d274af99083c..962447e8cf07f 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -653,8 +653,6 @@ bitflags::bitflags! { pub trait Resolver { fn next_node_id(&mut self) -> NodeId; - fn get_module_scope(&mut self, id: NodeId) -> ExpnId; - fn resolve_dollar_crates(&mut self); fn visit_ast_fragment_with_placeholders(&mut self, expn_id: ExpnId, fragment: &AstFragment, extra_placeholders: &[NodeId]); diff --git a/src/libsyntax_ext/plugin_macro_defs.rs b/src/libsyntax_ext/plugin_macro_defs.rs index dbfd8fe98f389..ccdc5bd81a04b 100644 --- a/src/libsyntax_ext/plugin_macro_defs.rs +++ b/src/libsyntax_ext/plugin_macro_defs.rs @@ -11,7 +11,7 @@ use syntax::source_map::respan; use syntax::symbol::sym; use syntax::tokenstream::*; use syntax_pos::{Span, DUMMY_SP}; -use syntax_pos::hygiene::{ExpnData, ExpnKind, MacroKind}; +use syntax_pos::hygiene::{ExpnData, ExpnKind, AstPass}; use std::mem; @@ -44,7 +44,7 @@ pub fn inject( if !named_exts.is_empty() { let mut extra_items = Vec::new(); let span = DUMMY_SP.fresh_expansion(ExpnData::allow_unstable( - ExpnKind::Macro(MacroKind::Attr, sym::plugin), DUMMY_SP, edition, + ExpnKind::AstPass(AstPass::PluginMacroDefs), DUMMY_SP, edition, [sym::rustc_attrs][..].into(), )); for (name, ext) in named_exts { diff --git a/src/libsyntax_ext/proc_macro_harness.rs b/src/libsyntax_ext/proc_macro_harness.rs index e772eaf834964..1cdaa1190fae3 100644 --- a/src/libsyntax_ext/proc_macro_harness.rs +++ b/src/libsyntax_ext/proc_macro_harness.rs @@ -3,8 +3,7 @@ use std::mem; use smallvec::smallvec; use syntax::ast::{self, Ident}; use syntax::attr; -use syntax::source_map::{ExpnData, ExpnKind, respan}; -use syntax::ext::base::{ExtCtxt, MacroKind}; +use syntax::ext::base::ExtCtxt; use syntax::ext::expand::{AstFragment, ExpansionConfig}; use syntax::ext::proc_macro::is_proc_macro_attr; use syntax::parse::ParseSess; @@ -12,6 +11,7 @@ use syntax::ptr::P; use syntax::symbol::{kw, sym}; use syntax::visit::{self, Visitor}; use syntax_pos::{Span, DUMMY_SP}; +use syntax_pos::hygiene::AstPass; struct ProcMacroDerive { trait_name: ast::Name, @@ -308,8 +308,7 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> { // Creates a new module which looks like: // -// #[doc(hidden)] -// mod $gensym { +// const _: () = { // extern crate proc_macro; // // use proc_macro::bridge::client::ProcMacro; @@ -327,32 +326,29 @@ fn mk_decls( custom_attrs: &[ProcMacroDef], custom_macros: &[ProcMacroDef], ) -> P { - let span = DUMMY_SP.fresh_expansion(ExpnData::allow_unstable( - ExpnKind::Macro(MacroKind::Attr, sym::proc_macro), DUMMY_SP, cx.parse_sess.edition, - [sym::rustc_attrs, sym::proc_macro_internals][..].into(), - )); - - let hidden = cx.meta_list_item_word(span, sym::hidden); - let doc = cx.meta_list(span, sym::doc, vec![hidden]); - let doc_hidden = cx.attribute(doc); - - let proc_macro = Ident::with_dummy_span(sym::proc_macro); + let span = cx.resolver.span_for_ast_pass( + DUMMY_SP, + AstPass::ProcMacroHarness, + &[sym::rustc_attrs, sym::proc_macro_internals], + None, + ); + + let proc_macro = Ident::new(sym::proc_macro, span); let krate = cx.item(span, proc_macro, Vec::new(), ast::ItemKind::ExternCrate(None)); - let bridge = Ident::from_str("bridge"); - let client = Ident::from_str("client"); - let proc_macro_ty = Ident::from_str("ProcMacro"); - let custom_derive = Ident::from_str("custom_derive"); - let attr = Ident::from_str("attr"); - let bang = Ident::from_str("bang"); - let crate_kw = Ident::with_dummy_span(kw::Crate); + let bridge = Ident::from_str_and_span("bridge", span); + let client = Ident::from_str_and_span("client", span); + let proc_macro_ty = Ident::from_str_and_span("ProcMacro", span); + let custom_derive = Ident::from_str_and_span("custom_derive", span); + let attr = Ident::from_str_and_span("attr", span); + let bang = Ident::from_str_and_span("bang", span); let decls = { let local_path = |sp: Span, name| { - cx.expr_path(cx.path(sp.with_ctxt(span.ctxt()), vec![crate_kw, name])) + cx.expr_path(cx.path(sp.with_ctxt(span.ctxt()), vec![name])) }; let proc_macro_ty_method_path = |method| cx.expr_path(cx.path(span, vec![ proc_macro, bridge, client, proc_macro_ty, method, @@ -381,7 +377,7 @@ fn mk_decls( let decls_static = cx.item_static( span, - Ident::from_str("_DECLS"), + Ident::from_str_and_span("_DECLS", span), cx.ty_rptr(span, cx.ty(span, ast::TyKind::Slice( cx.ty_path(cx.path(span, @@ -392,22 +388,44 @@ fn mk_decls( ).map(|mut i| { let attr = cx.meta_word(span, sym::rustc_proc_macro_decls); i.attrs.push(cx.attribute(attr)); - i.vis = respan(span, ast::VisibilityKind::Public); i }); - let module = cx.item_mod( - span, + let block = P(ast::Expr { + id: ast::DUMMY_NODE_ID, + attrs: syntax::ThinVec::new(), + node: ast::ExprKind::Block(P(ast::Block { + id: ast::DUMMY_NODE_ID, + rules: ast::BlockCheckMode::Default, + stmts: vec![ + ast::Stmt { + id: ast::DUMMY_NODE_ID, + node: ast::StmtKind::Item(krate), + span, + }, + ast::Stmt { + id: ast::DUMMY_NODE_ID, + node: ast::StmtKind::Item(decls_static), + span, + } + ], + span, + }), None), span, - ast::Ident::from_str("decls").gensym(), - vec![doc_hidden], - vec![krate, decls_static], - ).map(|mut i| { - i.vis = respan(span, ast::VisibilityKind::Public); - i }); + let anon_constant = cx.item_const( + span, + ast::Ident::new(kw::Underscore, span), + P(ast::Ty { + id: ast::DUMMY_NODE_ID, + node: ast::TyKind::Tup(Vec::new()), + span, + }), + block, + ); + // Integrate the new module into existing module structures. - let module = AstFragment::Items(smallvec![module]); - cx.monotonic_expander().fully_expand_fragment(module).make_items().pop().unwrap() + let items = AstFragment::Items(smallvec![anon_constant]); + cx.monotonic_expander().fully_expand_fragment(items).make_items().pop().unwrap() } diff --git a/src/libsyntax_ext/standard_library_imports.rs b/src/libsyntax_ext/standard_library_imports.rs index 8ca376341fcdb..61e423266fa05 100644 --- a/src/libsyntax_ext/standard_library_imports.rs +++ b/src/libsyntax_ext/standard_library_imports.rs @@ -1,52 +1,56 @@ use syntax::{ast, attr}; use syntax::edition::Edition; -use syntax::ext::hygiene::MacroKind; +use syntax::ext::hygiene::AstPass; +use syntax::ext::base::Resolver; use syntax::ptr::P; -use syntax::source_map::{ExpnData, ExpnKind, dummy_spanned, respan}; +use syntax::source_map::respan; use syntax::symbol::{Ident, Symbol, kw, sym}; use syntax_pos::DUMMY_SP; -use std::iter; - pub fn inject( - mut krate: ast::Crate, alt_std_name: Option<&str>, edition: Edition + mut krate: ast::Crate, + resolver: &mut dyn Resolver, + alt_std_name: Option, + edition: Edition, ) -> (ast::Crate, Option) { let rust_2018 = edition >= Edition::Edition2018; // the first name in this list is the crate name of the crate with the prelude - let names: &[&str] = if attr::contains_name(&krate.attrs, sym::no_core) { + let names: &[Symbol] = if attr::contains_name(&krate.attrs, sym::no_core) { return (krate, None); } else if attr::contains_name(&krate.attrs, sym::no_std) { if attr::contains_name(&krate.attrs, sym::compiler_builtins) { - &["core"] + &[sym::core] } else { - &["core", "compiler_builtins"] + &[sym::core, sym::compiler_builtins] } } else { - &["std"] + &[sym::std] }; + let span = resolver.span_for_ast_pass( + DUMMY_SP, + AstPass::StdImports, + &[sym::prelude_import], + None, + ); + // .rev() to preserve ordering above in combination with insert(0, ...) - let alt_std_name = alt_std_name.map(Symbol::intern); - for orig_name_str in names.iter().rev() { - // HACK(eddyb) gensym the injected crates on the Rust 2018 edition, - // so they don't accidentally interfere with the new import paths. - let orig_name_sym = Symbol::intern(orig_name_str); - let orig_name_ident = Ident::with_dummy_span(orig_name_sym); + for &orig_name_sym in names.iter().rev() { let (rename, orig_name) = if rust_2018 { - (orig_name_ident.gensym(), Some(orig_name_sym)) + (Ident::new(kw::Underscore, span), Some(orig_name_sym)) } else { - (orig_name_ident, None) + (Ident::with_dummy_span(orig_name_sym), None) }; krate.module.items.insert(0, P(ast::Item { attrs: vec![attr::mk_attr_outer( - attr::mk_word_item(ast::Ident::with_dummy_span(sym::macro_use)) + attr::mk_word_item(ast::Ident::new(sym::macro_use, span)) )], - vis: dummy_spanned(ast::VisibilityKind::Inherited), + vis: respan(span, ast::VisibilityKind::Inherited), node: ast::ItemKind::ExternCrate(alt_std_name.or(orig_name)), ident: rename, id: ast::DUMMY_NODE_ID, - span: DUMMY_SP, + span, tokens: None, })); } @@ -55,24 +59,22 @@ pub fn inject( // the prelude. let name = names[0]; - let span = DUMMY_SP.fresh_expansion(ExpnData::allow_unstable( - ExpnKind::Macro(MacroKind::Attr, sym::std_inject), DUMMY_SP, edition, - [sym::prelude_import][..].into(), - )); + let segments = if rust_2018 { + [name, sym::prelude, sym::v1].iter() + .map(|symbol| ast::PathSegment::from_ident(ast::Ident::new(*symbol, span))) + .collect() + } else { + [kw::PathRoot, name, sym::prelude, sym::v1].iter() + .map(|symbol| ast::PathSegment::from_ident(ast::Ident::with_dummy_span(*symbol))) + .collect() + }; - krate.module.items.insert(0, P(ast::Item { + let use_item = P(ast::Item { attrs: vec![attr::mk_attr_outer( attr::mk_word_item(ast::Ident::new(sym::prelude_import, span)))], vis: respan(span.shrink_to_lo(), ast::VisibilityKind::Inherited), node: ast::ItemKind::Use(P(ast::UseTree { - prefix: ast::Path { - segments: iter::once(ast::Ident::with_dummy_span(kw::PathRoot)) - .chain( - [name, "prelude", "v1"].iter().cloned() - .map(ast::Ident::from_str) - ).map(ast::PathSegment::from_ident).collect(), - span, - }, + prefix: ast::Path { segments, span }, kind: ast::UseTreeKind::Glob, span, })), @@ -80,7 +82,65 @@ pub fn inject( ident: ast::Ident::invalid(), span, tokens: None, - })); + }); + + let prelude_import_item = if rust_2018 { + let hygienic_extern_crate = P(ast::Item { + attrs: vec![], + vis: respan(span, ast::VisibilityKind::Inherited), + node: ast::ItemKind::ExternCrate(alt_std_name), + ident: ast::Ident::new(name, span), + id: ast::DUMMY_NODE_ID, + span, + tokens: None, + }); + + // Use an anonymous const to hide `extern crate std as hygienic_std` + // FIXME: Once inter-crate hygiene exists, this can just be `use_item`. + P(ast::Item { + attrs: Vec::new(), + vis: respan(span.shrink_to_lo(), ast::VisibilityKind::Inherited), + node: ast::ItemKind::Const( + P(ast::Ty { + id: ast::DUMMY_NODE_ID, + node: ast::TyKind::Tup(Vec::new()), + span, + }), + P(ast::Expr { + id: ast::DUMMY_NODE_ID, + attrs: syntax::ThinVec::new(), + node: ast::ExprKind::Block(P(ast::Block { + id: ast::DUMMY_NODE_ID, + rules: ast::BlockCheckMode::Default, + stmts: vec![ + ast::Stmt { + id: ast::DUMMY_NODE_ID, + node: ast::StmtKind::Item(use_item), + span, + }, + ast::Stmt { + id: ast::DUMMY_NODE_ID, + node: ast::StmtKind::Item(hygienic_extern_crate), + span, + } + ], + span, + }), None), + span, + }) + ), + id: ast::DUMMY_NODE_ID, + ident: ast::Ident::new(kw::Underscore, span), + span, + tokens: None, + }) + } else { + // Have `extern crate std` at the root, so don't need to create a named + // extern crate item. + use_item + }; + + krate.module.items.insert(0, prelude_import_item); - (krate, Some(Symbol::intern(name))) + (krate, Some(name)) } diff --git a/src/libsyntax_ext/test.rs b/src/libsyntax_ext/test.rs index 5fd87d3a0e5c6..be5aca73f5cb1 100644 --- a/src/libsyntax_ext/test.rs +++ b/src/libsyntax_ext/test.rs @@ -28,11 +28,11 @@ pub fn expand_test_case( if !ecx.ecfg.should_test { return vec![]; } - let sp = ecx.with_legacy_ctxt(attr_sp); + let sp = ecx.with_def_site_ctxt(attr_sp); let mut item = anno_item.expect_item(); item = item.map(|mut item| { item.vis = respan(item.vis.span, ast::VisibilityKind::Public); - item.ident = item.ident.gensym(); + item.ident.span = item.ident.span.with_ctxt(sp.ctxt()); item.attrs.push( ecx.attribute(ecx.meta_word(sp, sym::rustc_test_marker)) ); @@ -92,10 +92,9 @@ pub fn expand_test_or_bench( return vec![Annotatable::Item(item)]; } - let (sp, attr_sp) = (cx.with_legacy_ctxt(item.span), cx.with_legacy_ctxt(attr_sp)); + let (sp, attr_sp) = (cx.with_def_site_ctxt(item.span), cx.with_def_site_ctxt(attr_sp)); - // Gensym "test" so we can extern crate without conflicting with any local names - let test_id = cx.ident_of("test").gensym(); + let test_id = ast::Ident::new(sym::test, attr_sp); // creates test::$name let test_path = |name| { @@ -112,7 +111,7 @@ pub fn expand_test_or_bench( let test_fn = if is_bench { // A simple ident for a lambda - let b = cx.ident_of("b"); + let b = ast::Ident::from_str_and_span("b", attr_sp); cx.expr_call(sp, cx.expr_path(test_path("StaticBenchFn")), vec![ // |b| self::test::assert_test_result( @@ -143,7 +142,7 @@ pub fn expand_test_or_bench( ]) }; - let mut test_const = cx.item(sp, ast::Ident::new(item.ident.name, sp).gensym(), + let mut test_const = cx.item(sp, ast::Ident::new(item.ident.name, sp), vec![ // #[cfg(test)] cx.attribute(cx.meta_list(attr_sp, sym::cfg, vec![ @@ -192,17 +191,17 @@ pub fn expand_test_or_bench( )); test_const = test_const.map(|mut tc| { tc.vis.node = ast::VisibilityKind::Public; tc}); - // extern crate test as test_gensym + // extern crate test let test_extern = cx.item(sp, test_id, vec![], - ast::ItemKind::ExternCrate(Some(sym::test)) + ast::ItemKind::ExternCrate(None) ); log::debug!("synthetic test item:\n{}\n", pprust::item_to_string(&test_const)); vec![ - // Access to libtest under a gensymed name + // Access to libtest under a hygienic name Annotatable::Item(test_extern), // The generated test case Annotatable::Item(test_const), diff --git a/src/libsyntax_ext/test_harness.rs b/src/libsyntax_ext/test_harness.rs index 4a6ea0ebf85e5..6eb132979df8f 100644 --- a/src/libsyntax_ext/test_harness.rs +++ b/src/libsyntax_ext/test_harness.rs @@ -5,32 +5,29 @@ use smallvec::{smallvec, SmallVec}; use syntax::ast::{self, Ident}; use syntax::attr; use syntax::entry::{self, EntryPointType}; -use syntax::ext::base::{ExtCtxt, MacroKind, Resolver}; +use syntax::ext::base::{ExtCtxt, Resolver}; use syntax::ext::expand::{AstFragment, ExpansionConfig}; use syntax::feature_gate::Features; use syntax::mut_visit::{*, ExpectOne}; use syntax::parse::ParseSess; use syntax::ptr::P; -use syntax::source_map::{ExpnData, ExpnKind, dummy_spanned}; -use syntax::symbol::{kw, sym, Symbol}; +use syntax::source_map::respan; +use syntax::symbol::{sym, Symbol}; use syntax_pos::{Span, DUMMY_SP}; +use syntax_pos::hygiene::{AstPass, SyntaxContext, Transparency}; use std::{iter, mem}; struct Test { span: Span, - path: Vec, + ident: Ident, } struct TestCtxt<'a> { - span_diagnostic: &'a errors::Handler, - path: Vec, ext_cx: ExtCtxt<'a>, test_cases: Vec, reexport_test_harness_main: Option, test_runner: Option, - // top-level re-export submodule, filled out after folding is finished - toplevel_reexport: Option, } // Traverse the crate, collecting all the test functions, eliding any @@ -43,8 +40,8 @@ pub fn inject( span_diagnostic: &errors::Handler, features: &Features, ) { - // Check for #[reexport_test_harness_main = "some_name"] which - // creates a `use __test::main as some_name;`. This needs to be + // Check for #![reexport_test_harness_main = "some_name"] which gives the + // main test function the name `some_name` without hygiene. This needs to be // unconditional, so that the attribute is still marked as used in // non-test builds. let reexport_test_harness_main = @@ -56,16 +53,13 @@ pub fn inject( if should_test { generate_test_harness(sess, resolver, reexport_test_harness_main, - krate, span_diagnostic, features, test_runner) + krate, features, test_runner) } } struct TestHarnessGenerator<'a> { cx: TestCtxt<'a>, - tests: Vec, - - // submodule name, gensym'd identifier for re-exports - tested_submods: Vec<(Ident, Ident)>, + tests: Vec, } impl<'a> MutVisitor for TestHarnessGenerator<'a> { @@ -77,49 +71,46 @@ impl<'a> MutVisitor for TestHarnessGenerator<'a> { } fn flat_map_item(&mut self, i: P) -> SmallVec<[P; 1]> { - let ident = i.ident; - if ident.name != kw::Invalid { - self.cx.path.push(ident); - } - debug!("current path: {}", path_name_i(&self.cx.path)); - let mut item = i.into_inner(); if is_test_case(&item) { debug!("this is a test item"); let test = Test { span: item.span, - path: self.cx.path.clone(), + ident: item.ident, }; - self.cx.test_cases.push(test); - self.tests.push(item.ident); + self.tests.push(test); } // We don't want to recurse into anything other than mods, since // mods or tests inside of functions will break things if let ast::ItemKind::Mod(mut module) = item.node { let tests = mem::take(&mut self.tests); - let tested_submods = mem::take(&mut self.tested_submods); noop_visit_mod(&mut module, self); - let tests = mem::replace(&mut self.tests, tests); - let tested_submods = mem::replace(&mut self.tested_submods, tested_submods); + let mut tests = mem::replace(&mut self.tests, tests); - if !tests.is_empty() || !tested_submods.is_empty() { - let (it, sym) = mk_reexport_mod(&mut self.cx, item.id, tests, tested_submods); - module.items.push(it); - - if !self.cx.path.is_empty() { - self.tested_submods.push((self.cx.path[self.cx.path.len()-1], sym)); + if !tests.is_empty() { + let parent = if item.id == ast::DUMMY_NODE_ID { + ast::CRATE_NODE_ID } else { - debug!("pushing nothing, sym: {:?}", sym); - self.cx.toplevel_reexport = Some(sym); + item.id + }; + // Create an identifier that will hygienically resolve the test + // case name, even in another module. + let sp = self.cx.ext_cx.resolver.span_for_ast_pass( + module.inner, + AstPass::TestHarness, + &[], + Some(parent), + ); + let expn = sp.ctxt().outer_expn(); + for test in &mut tests { + test.ident.span = test.ident.span.apply_mark(expn, Transparency::Opaque); } + self.cx.test_cases.extend(tests); } item.node = ast::ItemKind::Mod(module); } - if ident.name != kw::Invalid { - self.cx.path.pop(); - } smallvec![P(item)] } @@ -181,59 +172,11 @@ impl MutVisitor for EntryPointCleaner { } } -/// Creates an item (specifically a module) that "pub use"s the tests passed in. -/// Each tested submodule will contain a similar reexport module that we will export -/// under the name of the original module. That is, `submod::__test_reexports` is -/// reexported like so `pub use submod::__test_reexports as submod`. -fn mk_reexport_mod(cx: &mut TestCtxt<'_>, - parent: ast::NodeId, - tests: Vec, - tested_submods: Vec<(Ident, Ident)>) - -> (P, Ident) { - let super_ = Ident::with_dummy_span(kw::Super); - - let items = tests.into_iter().map(|r| { - cx.ext_cx.item_use_simple(DUMMY_SP, dummy_spanned(ast::VisibilityKind::Public), - cx.ext_cx.path(DUMMY_SP, vec![super_, r])) - }).chain(tested_submods.into_iter().map(|(r, sym)| { - let path = cx.ext_cx.path(DUMMY_SP, vec![super_, r, sym]); - cx.ext_cx.item_use_simple_(DUMMY_SP, dummy_spanned(ast::VisibilityKind::Public), - Some(r), path) - })).collect(); - - let reexport_mod = ast::Mod { - inline: true, - inner: DUMMY_SP, - items, - }; - - let name = Ident::from_str("__test_reexports").gensym(); - let parent = if parent == ast::DUMMY_NODE_ID { ast::CRATE_NODE_ID } else { parent }; - cx.ext_cx.current_expansion.id = cx.ext_cx.resolver.get_module_scope(parent); - let module = P(ast::Item { - ident: name, - attrs: Vec::new(), - id: ast::DUMMY_NODE_ID, - node: ast::ItemKind::Mod(reexport_mod), - vis: dummy_spanned(ast::VisibilityKind::Public), - span: DUMMY_SP, - tokens: None, - }); - - // Integrate the new module into existing module structures. - let module = AstFragment::Items(smallvec![module]); - let module = - cx.ext_cx.monotonic_expander().fully_expand_fragment(module).make_items().pop().unwrap(); - - (module, name) -} - /// Crawl over the crate, inserting test reexports and the test main function fn generate_test_harness(sess: &ParseSess, resolver: &mut dyn Resolver, reexport_test_harness_main: Option, krate: &mut ast::Crate, - sd: &errors::Handler, features: &Features, test_runner: Option) { // Remove the entry points @@ -244,19 +187,15 @@ fn generate_test_harness(sess: &ParseSess, econfig.features = Some(features); let cx = TestCtxt { - span_diagnostic: sd, ext_cx: ExtCtxt::new(sess, econfig, resolver), - path: Vec::new(), test_cases: Vec::new(), reexport_test_harness_main, - toplevel_reexport: None, test_runner }; TestHarnessGenerator { cx, tests: Vec::new(), - tested_submods: Vec::new(), }.visit_crate(krate); } @@ -268,12 +207,14 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> P { // #![main] // test::test_main_static(&[..tests]); // } - let sp = DUMMY_SP.fresh_expansion(ExpnData::allow_unstable( - ExpnKind::Macro(MacroKind::Attr, sym::test_case), DUMMY_SP, cx.ext_cx.parse_sess.edition, - [sym::main, sym::test, sym::rustc_attrs][..].into(), - )); + let sp = cx.ext_cx.resolver.span_for_ast_pass( + DUMMY_SP, + AstPass::TestHarness, + &[sym::main, sym::test, sym::rustc_attrs], + None, + ); let ecx = &cx.ext_cx; - let test_id = Ident::with_dummy_span(sym::test); + let test_id = Ident::new(sym::test, sp); // test::test_main_static(...) let mut test_runner = cx.test_runner.clone().unwrap_or( @@ -285,14 +226,14 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> P { let test_main_path_expr = ecx.expr_path(test_runner); let call_test_main = ecx.expr_call(sp, test_main_path_expr, - vec![mk_tests_slice(cx)]); + vec![mk_tests_slice(cx, sp)]); let call_test_main = ecx.stmt_expr(call_test_main); // #![main] let main_meta = ecx.meta_word(sp, sym::main); let main_attr = ecx.attribute(main_meta); - // extern crate test as test_gensym + // extern crate test let test_extern_stmt = ecx.stmt_item(sp, ecx.item(sp, test_id, vec![], @@ -316,8 +257,8 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> P { // Honor the reexport_test_harness_main attribute let main_id = match cx.reexport_test_harness_main { - Some(sym) => Ident::new(sym, sp), - None => Ident::from_str_and_span("main", sp).gensym(), + Some(sym) => Ident::new(sym, sp.with_ctxt(SyntaxContext::root())), + None => Ident::from_str_and_span("main", sp), }; let main = P(ast::Item { @@ -325,7 +266,7 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> P { attrs: vec![main_attr], id: ast::DUMMY_NODE_ID, node: main, - vis: dummy_spanned(ast::VisibilityKind::Public), + vis: respan(sp, ast::VisibilityKind::Public), span: sp, tokens: None, }); @@ -335,44 +276,20 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> P { cx.ext_cx.monotonic_expander().fully_expand_fragment(main).make_items().pop().unwrap() } -fn path_name_i(idents: &[Ident]) -> String { - let mut path_name = "".to_string(); - let mut idents_iter = idents.iter().peekable(); - while let Some(ident) = idents_iter.next() { - path_name.push_str(&ident.as_str()); - if idents_iter.peek().is_some() { - path_name.push_str("::") - } - } - path_name -} - /// Creates a slice containing every test like so: -/// &[path::to::test1, path::to::test2] -fn mk_tests_slice(cx: &TestCtxt<'_>) -> P { +/// &[test1, test2] +fn mk_tests_slice(cx: &TestCtxt<'_>, sp: Span) -> P { debug!("building test vector from {} tests", cx.test_cases.len()); let ref ecx = cx.ext_cx; - ecx.expr_vec_slice(DUMMY_SP, + + ecx.expr_vec_slice(sp, cx.test_cases.iter().map(|test| { ecx.expr_addr_of(test.span, - ecx.expr_path(ecx.path(test.span, visible_path(cx, &test.path)))) + ecx.expr_path(ecx.path(test.span, vec![test.ident]))) }).collect()) } -/// Creates a path from the top-level __test module to the test via __test_reexports -fn visible_path(cx: &TestCtxt<'_>, path: &[Ident]) -> Vec{ - let mut visible_path = vec![]; - match cx.toplevel_reexport { - Some(id) => visible_path.push(id), - None => { - cx.span_diagnostic.bug("expected to find top-level re-export name, but found None"); - } - } - visible_path.extend_from_slice(path); - visible_path -} - fn is_test_case(i: &ast::Item) -> bool { attr::contains_name(&i.attrs, sym::rustc_test_marker) } diff --git a/src/test/ui/hygiene/auxiliary/not-libstd.rs b/src/test/ui/hygiene/auxiliary/not-libstd.rs new file mode 100644 index 0000000000000..babba293d03bd --- /dev/null +++ b/src/test/ui/hygiene/auxiliary/not-libstd.rs @@ -0,0 +1 @@ +pub fn not_in_lib_std() {} diff --git a/src/test/ui/hygiene/prelude-import-hygiene.rs b/src/test/ui/hygiene/prelude-import-hygiene.rs new file mode 100644 index 0000000000000..51e7bed6580b3 --- /dev/null +++ b/src/test/ui/hygiene/prelude-import-hygiene.rs @@ -0,0 +1,29 @@ +// Make sure that attribute used when injecting the prelude are resolved +// hygienically. + +// check-pass +// aux-build:not-libstd.rs + +//revisions: rust2015 rust2018 +//[rust2018] edition:2018 + +// The prelude import shouldn't see these as candidates for when it's trying to +// use the built-in macros. +extern crate core; +use core::prelude::v1::test as prelude_import; +use core::prelude::v1::test as macro_use; + +// Should not be used for the prelude import - not a concern in the 2015 edition +// because `std` is already declared in the crate root. +#[cfg(rust2018)] +extern crate not_libstd as std; + +#[cfg(rust2018)] +mod x { + // The extern crate item should override `std` in the extern prelude. + fn f() { + std::not_in_lib_std(); + } +} + +fn main() {} diff --git a/src/test/ui/imports/gensymed.rs b/src/test/ui/imports/gensymed.rs index 613ccc0b24234..7b53f0c536ad9 100644 --- a/src/test/ui/imports/gensymed.rs +++ b/src/test/ui/imports/gensymed.rs @@ -1,7 +1,9 @@ -// build-pass (FIXME(62277): could be check-pass?) +// check-pass // edition:2018 // aux-build:gensymed.rs extern crate gensymed; +use gensymed::*; + fn main() {} diff --git a/src/test/ui/inaccessible-test-modules.stderr b/src/test/ui/inaccessible-test-modules.stderr deleted file mode 100644 index b6a817e6b1d30..0000000000000 --- a/src/test/ui/inaccessible-test-modules.stderr +++ /dev/null @@ -1,21 +0,0 @@ -error[E0432]: unresolved import `__test` - --> $DIR/inaccessible-test-modules.rs:5:5 - | -LL | use __test as x; - | ------^^^^^ - | | - | no `__test` in the root - | help: a similar name exists in the module: `test` - -error[E0432]: unresolved import `__test_reexports` - --> $DIR/inaccessible-test-modules.rs:6:5 - | -LL | use __test_reexports as y; - | ----------------^^^^^ - | | - | no `__test_reexports` in the root - | help: a similar name exists in the module: `__test_reexports` - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0432`. diff --git a/src/test/ui/test-attrs/decl-macro-test.rs b/src/test/ui/test-attrs/decl-macro-test.rs new file mode 100644 index 0000000000000..fcbe9f49e5564 --- /dev/null +++ b/src/test/ui/test-attrs/decl-macro-test.rs @@ -0,0 +1,22 @@ +// Check that declarative macros can declare tests + +// check-pass +// compile-flags: --test + +#![feature(decl_macro)] + +macro create_test() { + #[test] + fn test() {} +} + +macro create_module_test() { + mod x { + #[test] + fn test() {} + } +} + +create_test!(); +create_test!(); +create_module_test!(); diff --git a/src/test/ui/inaccessible-test-modules.rs b/src/test/ui/test-attrs/inaccessible-test-modules.rs similarity index 56% rename from src/test/ui/inaccessible-test-modules.rs rename to src/test/ui/test-attrs/inaccessible-test-modules.rs index 7095ec290f8f2..f5b3479379480 100644 --- a/src/test/ui/inaccessible-test-modules.rs +++ b/src/test/ui/test-attrs/inaccessible-test-modules.rs @@ -2,8 +2,8 @@ // the `--test` harness creates modules with these textual names, but // they should be inaccessible from normal code. -use __test as x; //~ ERROR unresolved import `__test` -use __test_reexports as y; //~ ERROR unresolved import `__test_reexports` +use main as x; //~ ERROR unresolved import `main` +use test as y; //~ ERROR unresolved import `test` #[test] fn baz() {} diff --git a/src/test/ui/test-attrs/inaccessible-test-modules.stderr b/src/test/ui/test-attrs/inaccessible-test-modules.stderr new file mode 100644 index 0000000000000..a94ea1e79bc51 --- /dev/null +++ b/src/test/ui/test-attrs/inaccessible-test-modules.stderr @@ -0,0 +1,21 @@ +error[E0432]: unresolved import `main` + --> $DIR/inaccessible-test-modules.rs:5:5 + | +LL | use main as x; + | ----^^^^^ + | | + | no `main` in the root + | help: a similar name exists in the module: `main` + +error[E0432]: unresolved import `test` + --> $DIR/inaccessible-test-modules.rs:6:5 + | +LL | use test as y; + | ----^^^^^ + | | + | no `test` in the root + | help: a similar name exists in the module: `test` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0432`. From 2a82aec36ae86a1913473cb7e830a77b481641ea Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sun, 25 Aug 2019 21:21:07 +0100 Subject: [PATCH 07/24] Move tests for unit tests to their own directory --- .../ui/{test-shadowing => test-attrs}/auxiliary/test_macro.rs | 0 src/test/ui/{ => test-attrs}/test-allow-fail-attr.rs | 0 .../ui/{ => test-attrs}/test-attr-non-associated-functions.rs | 0 .../ui/{ => test-attrs}/test-attr-non-associated-functions.stderr | 0 .../ui/{test-shadowing => test-attrs}/test-cant-be-shadowed.rs | 0 .../test-fn-signature-verification-for-explicit-return-type.rs | 0 src/test/ui/{ => test-attrs}/test-main-not-dead-attr.rs | 0 src/test/ui/{ => test-attrs}/test-main-not-dead.rs | 0 src/test/ui/{ => test-attrs}/test-on-macro.rs | 0 src/test/ui/{ => test-attrs}/test-on-macro.stderr | 0 src/test/ui/{ => test-attrs}/test-runner-hides-buried-main.rs | 0 src/test/ui/{ => test-attrs}/test-runner-hides-main.rs | 0 src/test/ui/{ => test-attrs}/test-runner-hides-start.rs | 0 src/test/ui/{ => test-attrs}/test-should-fail-good-message.rs | 0 src/test/ui/{ => test-attrs}/test-should-panic-attr.rs | 0 src/test/ui/{ => test-attrs}/test-should-panic-attr.stderr | 0 src/test/ui/{ => test-attrs}/test-vs-cfg-test.rs | 0 src/test/ui/{ => test-attrs}/test-warns-dead-code.rs | 0 src/test/ui/{ => test-attrs}/test-warns-dead-code.stderr | 0 19 files changed, 0 insertions(+), 0 deletions(-) rename src/test/ui/{test-shadowing => test-attrs}/auxiliary/test_macro.rs (100%) rename src/test/ui/{ => test-attrs}/test-allow-fail-attr.rs (100%) rename src/test/ui/{ => test-attrs}/test-attr-non-associated-functions.rs (100%) rename src/test/ui/{ => test-attrs}/test-attr-non-associated-functions.stderr (100%) rename src/test/ui/{test-shadowing => test-attrs}/test-cant-be-shadowed.rs (100%) rename src/test/ui/{ => test-attrs}/test-fn-signature-verification-for-explicit-return-type.rs (100%) rename src/test/ui/{ => test-attrs}/test-main-not-dead-attr.rs (100%) rename src/test/ui/{ => test-attrs}/test-main-not-dead.rs (100%) rename src/test/ui/{ => test-attrs}/test-on-macro.rs (100%) rename src/test/ui/{ => test-attrs}/test-on-macro.stderr (100%) rename src/test/ui/{ => test-attrs}/test-runner-hides-buried-main.rs (100%) rename src/test/ui/{ => test-attrs}/test-runner-hides-main.rs (100%) rename src/test/ui/{ => test-attrs}/test-runner-hides-start.rs (100%) rename src/test/ui/{ => test-attrs}/test-should-fail-good-message.rs (100%) rename src/test/ui/{ => test-attrs}/test-should-panic-attr.rs (100%) rename src/test/ui/{ => test-attrs}/test-should-panic-attr.stderr (100%) rename src/test/ui/{ => test-attrs}/test-vs-cfg-test.rs (100%) rename src/test/ui/{ => test-attrs}/test-warns-dead-code.rs (100%) rename src/test/ui/{ => test-attrs}/test-warns-dead-code.stderr (100%) diff --git a/src/test/ui/test-shadowing/auxiliary/test_macro.rs b/src/test/ui/test-attrs/auxiliary/test_macro.rs similarity index 100% rename from src/test/ui/test-shadowing/auxiliary/test_macro.rs rename to src/test/ui/test-attrs/auxiliary/test_macro.rs diff --git a/src/test/ui/test-allow-fail-attr.rs b/src/test/ui/test-attrs/test-allow-fail-attr.rs similarity index 100% rename from src/test/ui/test-allow-fail-attr.rs rename to src/test/ui/test-attrs/test-allow-fail-attr.rs diff --git a/src/test/ui/test-attr-non-associated-functions.rs b/src/test/ui/test-attrs/test-attr-non-associated-functions.rs similarity index 100% rename from src/test/ui/test-attr-non-associated-functions.rs rename to src/test/ui/test-attrs/test-attr-non-associated-functions.rs diff --git a/src/test/ui/test-attr-non-associated-functions.stderr b/src/test/ui/test-attrs/test-attr-non-associated-functions.stderr similarity index 100% rename from src/test/ui/test-attr-non-associated-functions.stderr rename to src/test/ui/test-attrs/test-attr-non-associated-functions.stderr diff --git a/src/test/ui/test-shadowing/test-cant-be-shadowed.rs b/src/test/ui/test-attrs/test-cant-be-shadowed.rs similarity index 100% rename from src/test/ui/test-shadowing/test-cant-be-shadowed.rs rename to src/test/ui/test-attrs/test-cant-be-shadowed.rs diff --git a/src/test/ui/test-fn-signature-verification-for-explicit-return-type.rs b/src/test/ui/test-attrs/test-fn-signature-verification-for-explicit-return-type.rs similarity index 100% rename from src/test/ui/test-fn-signature-verification-for-explicit-return-type.rs rename to src/test/ui/test-attrs/test-fn-signature-verification-for-explicit-return-type.rs diff --git a/src/test/ui/test-main-not-dead-attr.rs b/src/test/ui/test-attrs/test-main-not-dead-attr.rs similarity index 100% rename from src/test/ui/test-main-not-dead-attr.rs rename to src/test/ui/test-attrs/test-main-not-dead-attr.rs diff --git a/src/test/ui/test-main-not-dead.rs b/src/test/ui/test-attrs/test-main-not-dead.rs similarity index 100% rename from src/test/ui/test-main-not-dead.rs rename to src/test/ui/test-attrs/test-main-not-dead.rs diff --git a/src/test/ui/test-on-macro.rs b/src/test/ui/test-attrs/test-on-macro.rs similarity index 100% rename from src/test/ui/test-on-macro.rs rename to src/test/ui/test-attrs/test-on-macro.rs diff --git a/src/test/ui/test-on-macro.stderr b/src/test/ui/test-attrs/test-on-macro.stderr similarity index 100% rename from src/test/ui/test-on-macro.stderr rename to src/test/ui/test-attrs/test-on-macro.stderr diff --git a/src/test/ui/test-runner-hides-buried-main.rs b/src/test/ui/test-attrs/test-runner-hides-buried-main.rs similarity index 100% rename from src/test/ui/test-runner-hides-buried-main.rs rename to src/test/ui/test-attrs/test-runner-hides-buried-main.rs diff --git a/src/test/ui/test-runner-hides-main.rs b/src/test/ui/test-attrs/test-runner-hides-main.rs similarity index 100% rename from src/test/ui/test-runner-hides-main.rs rename to src/test/ui/test-attrs/test-runner-hides-main.rs diff --git a/src/test/ui/test-runner-hides-start.rs b/src/test/ui/test-attrs/test-runner-hides-start.rs similarity index 100% rename from src/test/ui/test-runner-hides-start.rs rename to src/test/ui/test-attrs/test-runner-hides-start.rs diff --git a/src/test/ui/test-should-fail-good-message.rs b/src/test/ui/test-attrs/test-should-fail-good-message.rs similarity index 100% rename from src/test/ui/test-should-fail-good-message.rs rename to src/test/ui/test-attrs/test-should-fail-good-message.rs diff --git a/src/test/ui/test-should-panic-attr.rs b/src/test/ui/test-attrs/test-should-panic-attr.rs similarity index 100% rename from src/test/ui/test-should-panic-attr.rs rename to src/test/ui/test-attrs/test-should-panic-attr.rs diff --git a/src/test/ui/test-should-panic-attr.stderr b/src/test/ui/test-attrs/test-should-panic-attr.stderr similarity index 100% rename from src/test/ui/test-should-panic-attr.stderr rename to src/test/ui/test-attrs/test-should-panic-attr.stderr diff --git a/src/test/ui/test-vs-cfg-test.rs b/src/test/ui/test-attrs/test-vs-cfg-test.rs similarity index 100% rename from src/test/ui/test-vs-cfg-test.rs rename to src/test/ui/test-attrs/test-vs-cfg-test.rs diff --git a/src/test/ui/test-warns-dead-code.rs b/src/test/ui/test-attrs/test-warns-dead-code.rs similarity index 100% rename from src/test/ui/test-warns-dead-code.rs rename to src/test/ui/test-attrs/test-warns-dead-code.rs diff --git a/src/test/ui/test-warns-dead-code.stderr b/src/test/ui/test-attrs/test-warns-dead-code.stderr similarity index 100% rename from src/test/ui/test-warns-dead-code.stderr rename to src/test/ui/test-attrs/test-warns-dead-code.stderr From beb2f5b8ff89f3e973e085ce338a59e5203fecb0 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sun, 25 Aug 2019 21:31:42 +0100 Subject: [PATCH 08/24] Remove `Ident::{gensym, is_gensymed}` `gensym_if_underscore` still exists. The symbol interner can still create arbitray gensyms, this is just not exposed publicly. --- src/librustc_resolve/resolve_imports.rs | 8 ++------ src/libsyntax_pos/symbol.rs | 27 +++++++++++-------------- 2 files changed, 14 insertions(+), 21 deletions(-) diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index fd222a132a3f8..4e33ea018a074 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -1307,12 +1307,8 @@ impl<'a, 'b> ImportResolver<'a, 'b> { None => continue, }; - // Filter away ambiguous and gensymed imports. Gensymed imports - // (e.g. implicitly injected `std`) cannot be properly encoded in metadata, - // so they can cause name conflict errors downstream. - let is_good_import = binding.is_import() && !binding.is_ambiguity() && - // Note that as_str() de-gensyms the Symbol - !(ident.is_gensymed() && ident.name.as_str() != "_"); + // Filter away ambiguous imports. + let is_good_import = binding.is_import() && !binding.is_ambiguity(); if is_good_import || binding.is_macro_def() { let res = binding.res(); if res != Res::Err { diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs index 0b8f16bbc3b99..ce20e4407fe88 100644 --- a/src/libsyntax_pos/symbol.rs +++ b/src/libsyntax_pos/symbol.rs @@ -798,21 +798,15 @@ impl Ident { Ident::new(self.name, self.span.modern_and_legacy()) } - /// Transforms an identifier into one with the same name, but gensymed. - pub fn gensym(self) -> Ident { - let name = with_interner(|interner| interner.gensymed(self.name)); - Ident::new(name, self.span) - } - /// Transforms an underscore identifier into one with the same name, but /// gensymed. Leaves non-underscore identifiers unchanged. pub fn gensym_if_underscore(self) -> Ident { - if self.name == kw::Underscore { self.gensym() } else { self } - } - - // WARNING: this function is deprecated and will be removed in the future. - pub fn is_gensymed(self) -> bool { - with_interner(|interner| interner.is_gensymed(self.name)) + if self.name == kw::Underscore { + let name = with_interner(|interner| interner.gensymed(self.name)); + Ident::new(name, self.span) + } else { + self + } } pub fn as_str(self) -> LocalInternedString { @@ -865,9 +859,12 @@ impl UseSpecializedDecodable for Ident {} /// /// Examples: /// ``` -/// assert_eq!(Ident::from_str("x"), Ident::from_str("x")) -/// assert_ne!(Ident::from_str("x").gensym(), Ident::from_str("x")) -/// assert_ne!(Ident::from_str("x").gensym(), Ident::from_str("x").gensym()) +/// assert_eq!(Ident::from_str("_"), Ident::from_str("_")) +/// assert_ne!(Ident::from_str("_").gensym_if_underscore(), Ident::from_str("_")) +/// assert_ne!( +/// Ident::from_str("_").gensym_if_underscore(), +/// Ident::from_str("_").gensym_if_underscore(), +/// ) /// ``` /// Internally, a symbol is implemented as an index, and all operations /// (including hashing, equality, and ordering) operate on that index. The use From 846df20578189260ed3f4c9c824d324b6c9b7eac Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sun, 25 Aug 2019 22:36:13 +0100 Subject: [PATCH 09/24] Fix 2018 edition expanded pretty printing --- src/libsyntax/print/pprust.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 4dc00af486013..c18c8c18ae1f9 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -128,10 +128,14 @@ pub fn print_crate<'a>(cm: &'a SourceMap, let fake_attr = attr::mk_attr_inner(list); s.print_attribute(&fake_attr); - // #![no_std] - let no_std_meta = attr::mk_word_item(ast::Ident::with_dummy_span(sym::no_std)); - let fake_attr = attr::mk_attr_inner(no_std_meta); - s.print_attribute(&fake_attr); + // Currently on Rust 2018 we don't have `extern crate std;` at the crate + // root, so this is not needed, and actually breaks things. + if sess.edition == syntax_pos::edition::Edition::Edition2015 { + // #![no_std] + let no_std_meta = attr::mk_word_item(ast::Ident::with_dummy_span(sym::no_std)); + let fake_attr = attr::mk_attr_inner(no_std_meta); + s.print_attribute(&fake_attr); + } } s.print_mod(&krate.module, &krate.attrs); From 0b86782058c27ba694ec81ebe7108dceb0968a2b Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Tue, 27 Aug 2019 21:13:20 +0100 Subject: [PATCH 10/24] Don't call `diag_span_note_once` for suppressed lints --- src/librustc/lint/mod.rs | 44 ++++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs index 1b133819a73bf..fb7f14febf32e 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/mod.rs @@ -666,6 +666,30 @@ pub fn struct_lint_level<'a>(sess: &'a Session, (Level::Forbid, None) => sess.struct_err(msg), }; + // Check for future incompatibility lints and issue a stronger warning. + let lints = sess.lint_store.borrow(); + let lint_id = LintId::of(lint); + let future_incompatible = lints.future_incompatible(lint_id); + + // If this code originates in a foreign macro, aka something that this crate + // did not itself author, then it's likely that there's nothing this crate + // can do about it. We probably want to skip the lint entirely. + if err.span.primary_spans().iter().any(|s| in_external_macro(sess, *s)) { + // Any suggestions made here are likely to be incorrect, so anything we + // emit shouldn't be automatically fixed by rustfix. + err.allow_suggestions(false); + + // If this is a future incompatible lint it'll become a hard error, so + // we have to emit *something*. Also allow lints to whitelist themselves + // on a case-by-case basis for emission in a foreign macro. + if future_incompatible.is_none() && !lint.report_in_external_macro { + err.cancel(); + // Don't continue further, since we don't want to have + // `diag_span_note_once` called for a diagnostic that isn't emitted. + return err; + } + } + let name = lint.name_lower(); match src { LintSource::Default => { @@ -715,10 +739,6 @@ pub fn struct_lint_level<'a>(sess: &'a Session, err.code(DiagnosticId::Lint(name)); - // Check for future incompatibility lints and issue a stronger warning. - let lints = sess.lint_store.borrow(); - let lint_id = LintId::of(lint); - let future_incompatible = lints.future_incompatible(lint_id); if let Some(future_incompatible) = future_incompatible { const STANDARD_MESSAGE: &str = "this was previously accepted by the compiler but is being phased out; \ @@ -743,22 +763,6 @@ pub fn struct_lint_level<'a>(sess: &'a Session, err.note(&citation); } - // If this code originates in a foreign macro, aka something that this crate - // did not itself author, then it's likely that there's nothing this crate - // can do about it. We probably want to skip the lint entirely. - if err.span.primary_spans().iter().any(|s| in_external_macro(sess, *s)) { - // Any suggestions made here are likely to be incorrect, so anything we - // emit shouldn't be automatically fixed by rustfix. - err.allow_suggestions(false); - - // If this is a future incompatible lint it'll become a hard error, so - // we have to emit *something*. Also allow lints to whitelist themselves - // on a case-by-case basis for emission in a foreign macro. - if future_incompatible.is_none() && !lint.report_in_external_macro { - err.cancel() - } - } - return err } From c8cf9f5a025bb475804b5a90f54aca310b952526 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 28 Aug 2019 12:41:29 +0300 Subject: [PATCH 11/24] Add `with_{def_site,call_site,legacy}_ctxt,` methods to `Span` Use these to create call-site spans for AST passes when needed. --- src/librustc_resolve/macros.rs | 27 +++--- src/libsyntax/ext/base.rs | 14 +-- src/libsyntax_ext/proc_macro_harness.rs | 3 +- src/libsyntax_ext/standard_library_imports.rs | 8 +- src/libsyntax_ext/test_harness.rs | 10 +- src/libsyntax_pos/hygiene.rs | 2 +- src/libsyntax_pos/lib.rs | 19 ++++ .../dollar-crate-issue-57089.stdout | 32 +++---- .../dollar-crate-issue-62325.stdout | 44 ++++----- src/test/ui/proc-macro/dollar-crate.stdout | 96 +++++++++---------- 10 files changed, 138 insertions(+), 117 deletions(-) diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 20d281f1e997a..02022c98c3502 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -17,7 +17,7 @@ use syntax::edition::Edition; use syntax::ext::base::{self, Indeterminate, SpecialDerives}; use syntax::ext::base::{MacroKind, SyntaxExtension}; use syntax::ext::expand::{AstFragment, Invocation, InvocationKind}; -use syntax::ext::hygiene::{self, ExpnId, ExpnData, ExpnKind, Transparency}; +use syntax::ext::hygiene::{self, ExpnId, ExpnData, ExpnKind}; use syntax::ext::tt::macro_rules; use syntax::feature_gate::{emit_feature_err, is_builtin_attr_name}; use syntax::feature_gate::GateIssue; @@ -131,23 +131,20 @@ impl<'a> base::Resolver for Resolver<'a> { // Create a Span with modern hygiene with a definition site of the provided // module, or a fake empty `#[no_implicit_prelude]` module if no module is // provided. - fn span_for_ast_pass( + fn expansion_for_ast_pass( &mut self, - base_span: Span, + call_site: Span, pass: AstPass, features: &[Symbol], parent_module_id: Option, - ) -> Span { - let span = base_span.fresh_expansion_with_transparency( - ExpnData::allow_unstable( - ExpnKind::AstPass(pass), - base_span, - self.session.edition(), - features.into(), - ), - Transparency::Opaque, - ); - let expn_id = span.ctxt().outer_expn(); + ) -> ExpnId { + let expn_id = ExpnId::fresh(Some(ExpnData::allow_unstable( + ExpnKind::AstPass(pass), + call_site, + self.session.edition(), + features.into(), + ))); + let parent_scope = if let Some(module_id) = parent_module_id { let parent_def_id = self.definitions.local_def_id(module_id); self.definitions.add_parent_module_of_macro_def(expn_id, parent_def_id); @@ -160,7 +157,7 @@ impl<'a> base::Resolver for Resolver<'a> { self.empty_module }; self.ast_transform_scopes.insert(expn_id, parent_scope); - span + expn_id } fn resolve_imports(&mut self) { diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 962447e8cf07f..4c146611deab6 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -3,7 +3,7 @@ use crate::attr::{HasAttrs, Stability, Deprecation}; use crate::source_map::SourceMap; use crate::edition::Edition; use crate::ext::expand::{self, AstFragment, Invocation}; -use crate::ext::hygiene::{ExpnId, Transparency}; +use crate::ext::hygiene::ExpnId; use crate::mut_visit::{self, MutVisitor}; use crate::parse::{self, parser, DirectoryOwnership}; use crate::parse::token; @@ -658,13 +658,13 @@ pub trait Resolver { extra_placeholders: &[NodeId]); fn register_builtin_macro(&mut self, ident: ast::Ident, ext: SyntaxExtension); - fn span_for_ast_pass( + fn expansion_for_ast_pass( &mut self, - span: Span, + call_site: Span, pass: AstPass, features: &[Symbol], parent_module_id: Option, - ) -> Span; + ) -> ExpnId; fn resolve_imports(&mut self); @@ -750,20 +750,20 @@ impl<'a> ExtCtxt<'a> { /// Equivalent of `Span::def_site` from the proc macro API, /// except that the location is taken from the span passed as an argument. pub fn with_def_site_ctxt(&self, span: Span) -> Span { - span.with_ctxt_from_mark(self.current_expansion.id, Transparency::Opaque) + span.with_def_site_ctxt(self.current_expansion.id) } /// Equivalent of `Span::call_site` from the proc macro API, /// except that the location is taken from the span passed as an argument. pub fn with_call_site_ctxt(&self, span: Span) -> Span { - span.with_ctxt_from_mark(self.current_expansion.id, Transparency::Transparent) + span.with_call_site_ctxt(self.current_expansion.id) } /// Span with a context reproducing `macro_rules` hygiene (hygienic locals, unhygienic items). /// FIXME: This should be eventually replaced either with `with_def_site_ctxt` (preferably), /// or with `with_call_site_ctxt` (where necessary). pub fn with_legacy_ctxt(&self, span: Span) -> Span { - span.with_ctxt_from_mark(self.current_expansion.id, Transparency::SemiTransparent) + span.with_legacy_ctxt(self.current_expansion.id) } /// Returns span for the macro which originally caused the current expansion to happen. diff --git a/src/libsyntax_ext/proc_macro_harness.rs b/src/libsyntax_ext/proc_macro_harness.rs index 1cdaa1190fae3..8a4b78a3efa31 100644 --- a/src/libsyntax_ext/proc_macro_harness.rs +++ b/src/libsyntax_ext/proc_macro_harness.rs @@ -326,12 +326,13 @@ fn mk_decls( custom_attrs: &[ProcMacroDef], custom_macros: &[ProcMacroDef], ) -> P { - let span = cx.resolver.span_for_ast_pass( + let expn_id = cx.resolver.expansion_for_ast_pass( DUMMY_SP, AstPass::ProcMacroHarness, &[sym::rustc_attrs, sym::proc_macro_internals], None, ); + let span = DUMMY_SP.with_def_site_ctxt(expn_id); let proc_macro = Ident::new(sym::proc_macro, span); let krate = cx.item(span, diff --git a/src/libsyntax_ext/standard_library_imports.rs b/src/libsyntax_ext/standard_library_imports.rs index 61e423266fa05..e5dded9ea5319 100644 --- a/src/libsyntax_ext/standard_library_imports.rs +++ b/src/libsyntax_ext/standard_library_imports.rs @@ -28,19 +28,21 @@ pub fn inject( &[sym::std] }; - let span = resolver.span_for_ast_pass( + let expn_id = resolver.expansion_for_ast_pass( DUMMY_SP, AstPass::StdImports, &[sym::prelude_import], None, ); + let span = DUMMY_SP.with_def_site_ctxt(expn_id); + let call_site = DUMMY_SP.with_call_site_ctxt(expn_id); // .rev() to preserve ordering above in combination with insert(0, ...) for &orig_name_sym in names.iter().rev() { let (rename, orig_name) = if rust_2018 { (Ident::new(kw::Underscore, span), Some(orig_name_sym)) } else { - (Ident::with_dummy_span(orig_name_sym), None) + (Ident::new(orig_name_sym, call_site), None) }; krate.module.items.insert(0, P(ast::Item { attrs: vec![attr::mk_attr_outer( @@ -65,7 +67,7 @@ pub fn inject( .collect() } else { [kw::PathRoot, name, sym::prelude, sym::v1].iter() - .map(|symbol| ast::PathSegment::from_ident(ast::Ident::with_dummy_span(*symbol))) + .map(|symbol| ast::PathSegment::from_ident(ast::Ident::new(*symbol, call_site))) .collect() }; diff --git a/src/libsyntax_ext/test_harness.rs b/src/libsyntax_ext/test_harness.rs index 6eb132979df8f..eedd7fbee3806 100644 --- a/src/libsyntax_ext/test_harness.rs +++ b/src/libsyntax_ext/test_harness.rs @@ -97,15 +97,16 @@ impl<'a> MutVisitor for TestHarnessGenerator<'a> { }; // Create an identifier that will hygienically resolve the test // case name, even in another module. - let sp = self.cx.ext_cx.resolver.span_for_ast_pass( + let expn_id = self.cx.ext_cx.resolver.expansion_for_ast_pass( module.inner, AstPass::TestHarness, &[], Some(parent), ); - let expn = sp.ctxt().outer_expn(); for test in &mut tests { - test.ident.span = test.ident.span.apply_mark(expn, Transparency::Opaque); + // See the comment on `mk_main` for why we're using + // `apply_mark` directly. + test.ident.span = test.ident.span.apply_mark(expn_id, Transparency::Opaque); } self.cx.test_cases.extend(tests); } @@ -207,12 +208,13 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> P { // #![main] // test::test_main_static(&[..tests]); // } - let sp = cx.ext_cx.resolver.span_for_ast_pass( + let expn_id = cx.ext_cx.resolver.expansion_for_ast_pass( DUMMY_SP, AstPass::TestHarness, &[sym::main, sym::test, sym::rustc_attrs], None, ); + let sp = DUMMY_SP.with_def_site_ctxt(expn_id); let ecx = &cx.ext_cx; let test_id = Ident::new(sym::test, sp); diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs index 99afe57ef5497..f0e7344c1b986 100644 --- a/src/libsyntax_pos/hygiene.rs +++ b/src/libsyntax_pos/hygiene.rs @@ -360,7 +360,7 @@ impl SyntaxContext { } /// Extend a syntax context with a given expansion and transparency. - pub fn apply_mark(self, expn_id: ExpnId, transparency: Transparency) -> SyntaxContext { + crate fn apply_mark(self, expn_id: ExpnId, transparency: Transparency) -> SyntaxContext { HygieneData::with(|data| data.apply_mark(self, expn_id, transparency)) } diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index d800109cf8531..9a296f17aaf4a 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -514,6 +514,25 @@ impl Span { span.ctxt) } + /// Equivalent of `Span::def_site` from the proc macro API, + /// except that the location is taken from the `self` span. + pub fn with_def_site_ctxt(self, expn_id: ExpnId) -> Span { + self.with_ctxt_from_mark(expn_id, Transparency::Opaque) + } + + /// Equivalent of `Span::call_site` from the proc macro API, + /// except that the location is taken from the `self` span. + pub fn with_call_site_ctxt(&self, expn_id: ExpnId) -> Span { + self.with_ctxt_from_mark(expn_id, Transparency::Transparent) + } + + /// Span with a context reproducing `macro_rules` hygiene (hygienic locals, unhygienic items). + /// FIXME: This should be eventually replaced either with `with_def_site_ctxt` (preferably), + /// or with `with_call_site_ctxt` (where necessary). + pub fn with_legacy_ctxt(&self, expn_id: ExpnId) -> Span { + self.with_ctxt_from_mark(expn_id, Transparency::SemiTransparent) + } + /// Produces a span with the same location as `self` and context produced by a macro with the /// given ID and transparency, assuming that macro was defined directly and not produced by /// some other macro (which is the case for built-in and procedural macros). diff --git a/src/test/ui/proc-macro/dollar-crate-issue-57089.stdout b/src/test/ui/proc-macro/dollar-crate-issue-57089.stdout index 0fe02a9a34d18..ea06f6c1acaf9 100644 --- a/src/test/ui/proc-macro/dollar-crate-issue-57089.stdout +++ b/src/test/ui/proc-macro/dollar-crate-issue-57089.stdout @@ -2,40 +2,40 @@ PRINT-BANG INPUT (DISPLAY): struct M ($crate :: S) ; PRINT-BANG INPUT (DEBUG): TokenStream [ Ident { ident: "struct", - span: #2 bytes(LO..HI), + span: #3 bytes(LO..HI), }, Ident { ident: "M", - span: #2 bytes(LO..HI), + span: #3 bytes(LO..HI), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "$crate", - span: #2 bytes(LO..HI), + span: #3 bytes(LO..HI), }, Punct { ch: ':', spacing: Joint, - span: #2 bytes(LO..HI), + span: #3 bytes(LO..HI), }, Punct { ch: ':', spacing: Alone, - span: #2 bytes(LO..HI), + span: #3 bytes(LO..HI), }, Ident { ident: "S", - span: #2 bytes(LO..HI), + span: #3 bytes(LO..HI), }, ], - span: #2 bytes(LO..HI), + span: #3 bytes(LO..HI), }, Punct { ch: ';', spacing: Alone, - span: #2 bytes(LO..HI), + span: #3 bytes(LO..HI), }, ] PRINT-ATTR INPUT (DISPLAY): struct A(crate::S); @@ -43,39 +43,39 @@ PRINT-ATTR RE-COLLECTED (DISPLAY): struct A ($crate :: S) ; PRINT-ATTR INPUT (DEBUG): TokenStream [ Ident { ident: "struct", - span: #2 bytes(LO..HI), + span: #3 bytes(LO..HI), }, Ident { ident: "A", - span: #2 bytes(LO..HI), + span: #3 bytes(LO..HI), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "$crate", - span: #2 bytes(LO..HI), + span: #3 bytes(LO..HI), }, Punct { ch: ':', spacing: Joint, - span: #2 bytes(LO..HI), + span: #3 bytes(LO..HI), }, Punct { ch: ':', spacing: Alone, - span: #2 bytes(LO..HI), + span: #3 bytes(LO..HI), }, Ident { ident: "S", - span: #2 bytes(LO..HI), + span: #3 bytes(LO..HI), }, ], - span: #2 bytes(LO..HI), + span: #3 bytes(LO..HI), }, Punct { ch: ';', spacing: Alone, - span: #2 bytes(LO..HI), + span: #3 bytes(LO..HI), }, ] diff --git a/src/test/ui/proc-macro/dollar-crate-issue-62325.stdout b/src/test/ui/proc-macro/dollar-crate-issue-62325.stdout index a499e1362ec0b..7ee8078b2c5d2 100644 --- a/src/test/ui/proc-macro/dollar-crate-issue-62325.stdout +++ b/src/test/ui/proc-macro/dollar-crate-issue-62325.stdout @@ -3,55 +3,55 @@ PRINT-ATTR RE-COLLECTED (DISPLAY): struct A (identity ! ($crate :: S)) ; PRINT-ATTR INPUT (DEBUG): TokenStream [ Ident { ident: "struct", - span: #2 bytes(LO..HI), + span: #3 bytes(LO..HI), }, Ident { ident: "A", - span: #2 bytes(LO..HI), + span: #3 bytes(LO..HI), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "identity", - span: #2 bytes(LO..HI), + span: #3 bytes(LO..HI), }, Punct { ch: '!', spacing: Alone, - span: #2 bytes(LO..HI), + span: #3 bytes(LO..HI), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "$crate", - span: #2 bytes(LO..HI), + span: #3 bytes(LO..HI), }, Punct { ch: ':', spacing: Joint, - span: #2 bytes(LO..HI), + span: #3 bytes(LO..HI), }, Punct { ch: ':', spacing: Alone, - span: #2 bytes(LO..HI), + span: #3 bytes(LO..HI), }, Ident { ident: "S", - span: #2 bytes(LO..HI), + span: #3 bytes(LO..HI), }, ], - span: #2 bytes(LO..HI), + span: #3 bytes(LO..HI), }, ], - span: #2 bytes(LO..HI), + span: #3 bytes(LO..HI), }, Punct { ch: ';', spacing: Alone, - span: #2 bytes(LO..HI), + span: #3 bytes(LO..HI), }, ] PRINT-ATTR INPUT (DISPLAY): struct B(identity!(::dollar_crate_external :: S)); @@ -59,54 +59,54 @@ PRINT-ATTR RE-COLLECTED (DISPLAY): struct B (identity ! ($crate :: S)) ; PRINT-ATTR INPUT (DEBUG): TokenStream [ Ident { ident: "struct", - span: #7 bytes(LO..HI), + span: #8 bytes(LO..HI), }, Ident { ident: "B", - span: #7 bytes(LO..HI), + span: #8 bytes(LO..HI), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "identity", - span: #7 bytes(LO..HI), + span: #8 bytes(LO..HI), }, Punct { ch: '!', spacing: Alone, - span: #7 bytes(LO..HI), + span: #8 bytes(LO..HI), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "$crate", - span: #7 bytes(LO..HI), + span: #8 bytes(LO..HI), }, Punct { ch: ':', spacing: Joint, - span: #7 bytes(LO..HI), + span: #8 bytes(LO..HI), }, Punct { ch: ':', spacing: Alone, - span: #7 bytes(LO..HI), + span: #8 bytes(LO..HI), }, Ident { ident: "S", - span: #7 bytes(LO..HI), + span: #8 bytes(LO..HI), }, ], - span: #7 bytes(LO..HI), + span: #8 bytes(LO..HI), }, ], - span: #7 bytes(LO..HI), + span: #8 bytes(LO..HI), }, Punct { ch: ';', spacing: Alone, - span: #7 bytes(LO..HI), + span: #8 bytes(LO..HI), }, ] diff --git a/src/test/ui/proc-macro/dollar-crate.stdout b/src/test/ui/proc-macro/dollar-crate.stdout index da1d7549d0750..4f7e000265eb0 100644 --- a/src/test/ui/proc-macro/dollar-crate.stdout +++ b/src/test/ui/proc-macro/dollar-crate.stdout @@ -2,40 +2,40 @@ PRINT-BANG INPUT (DISPLAY): struct M ($crate :: S) ; PRINT-BANG INPUT (DEBUG): TokenStream [ Ident { ident: "struct", - span: #2 bytes(LO..HI), + span: #3 bytes(LO..HI), }, Ident { ident: "M", - span: #2 bytes(LO..HI), + span: #3 bytes(LO..HI), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "$crate", - span: #2 bytes(LO..HI), + span: #3 bytes(LO..HI), }, Punct { ch: ':', spacing: Joint, - span: #2 bytes(LO..HI), + span: #3 bytes(LO..HI), }, Punct { ch: ':', spacing: Alone, - span: #2 bytes(LO..HI), + span: #3 bytes(LO..HI), }, Ident { ident: "S", - span: #2 bytes(LO..HI), + span: #3 bytes(LO..HI), }, ], - span: #2 bytes(LO..HI), + span: #3 bytes(LO..HI), }, Punct { ch: ';', spacing: Alone, - span: #2 bytes(LO..HI), + span: #3 bytes(LO..HI), }, ] PRINT-ATTR INPUT (DISPLAY): struct A(crate::S); @@ -43,40 +43,40 @@ PRINT-ATTR RE-COLLECTED (DISPLAY): struct A ($crate :: S) ; PRINT-ATTR INPUT (DEBUG): TokenStream [ Ident { ident: "struct", - span: #2 bytes(LO..HI), + span: #3 bytes(LO..HI), }, Ident { ident: "A", - span: #2 bytes(LO..HI), + span: #3 bytes(LO..HI), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "$crate", - span: #2 bytes(LO..HI), + span: #3 bytes(LO..HI), }, Punct { ch: ':', spacing: Joint, - span: #2 bytes(LO..HI), + span: #3 bytes(LO..HI), }, Punct { ch: ':', spacing: Alone, - span: #2 bytes(LO..HI), + span: #3 bytes(LO..HI), }, Ident { ident: "S", - span: #2 bytes(LO..HI), + span: #3 bytes(LO..HI), }, ], - span: #2 bytes(LO..HI), + span: #3 bytes(LO..HI), }, Punct { ch: ';', spacing: Alone, - span: #2 bytes(LO..HI), + span: #3 bytes(LO..HI), }, ] PRINT-DERIVE INPUT (DISPLAY): struct D(crate::S); @@ -84,80 +84,80 @@ PRINT-DERIVE RE-COLLECTED (DISPLAY): struct D ($crate :: S) ; PRINT-DERIVE INPUT (DEBUG): TokenStream [ Ident { ident: "struct", - span: #2 bytes(LO..HI), + span: #3 bytes(LO..HI), }, Ident { ident: "D", - span: #2 bytes(LO..HI), + span: #3 bytes(LO..HI), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "$crate", - span: #2 bytes(LO..HI), + span: #3 bytes(LO..HI), }, Punct { ch: ':', spacing: Joint, - span: #2 bytes(LO..HI), + span: #3 bytes(LO..HI), }, Punct { ch: ':', spacing: Alone, - span: #2 bytes(LO..HI), + span: #3 bytes(LO..HI), }, Ident { ident: "S", - span: #2 bytes(LO..HI), + span: #3 bytes(LO..HI), }, ], - span: #2 bytes(LO..HI), + span: #3 bytes(LO..HI), }, Punct { ch: ';', spacing: Alone, - span: #2 bytes(LO..HI), + span: #3 bytes(LO..HI), }, ] PRINT-BANG INPUT (DISPLAY): struct M ($crate :: S) ; PRINT-BANG INPUT (DEBUG): TokenStream [ Ident { ident: "struct", - span: #9 bytes(LO..HI), + span: #10 bytes(LO..HI), }, Ident { ident: "M", - span: #9 bytes(LO..HI), + span: #10 bytes(LO..HI), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "$crate", - span: #9 bytes(LO..HI), + span: #10 bytes(LO..HI), }, Punct { ch: ':', spacing: Joint, - span: #9 bytes(LO..HI), + span: #10 bytes(LO..HI), }, Punct { ch: ':', spacing: Alone, - span: #9 bytes(LO..HI), + span: #10 bytes(LO..HI), }, Ident { ident: "S", - span: #9 bytes(LO..HI), + span: #10 bytes(LO..HI), }, ], - span: #9 bytes(LO..HI), + span: #10 bytes(LO..HI), }, Punct { ch: ';', spacing: Alone, - span: #9 bytes(LO..HI), + span: #10 bytes(LO..HI), }, ] PRINT-ATTR INPUT (DISPLAY): struct A(::dollar_crate_external::S); @@ -165,40 +165,40 @@ PRINT-ATTR RE-COLLECTED (DISPLAY): struct A ($crate :: S) ; PRINT-ATTR INPUT (DEBUG): TokenStream [ Ident { ident: "struct", - span: #9 bytes(LO..HI), + span: #10 bytes(LO..HI), }, Ident { ident: "A", - span: #9 bytes(LO..HI), + span: #10 bytes(LO..HI), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "$crate", - span: #9 bytes(LO..HI), + span: #10 bytes(LO..HI), }, Punct { ch: ':', spacing: Joint, - span: #9 bytes(LO..HI), + span: #10 bytes(LO..HI), }, Punct { ch: ':', spacing: Alone, - span: #9 bytes(LO..HI), + span: #10 bytes(LO..HI), }, Ident { ident: "S", - span: #9 bytes(LO..HI), + span: #10 bytes(LO..HI), }, ], - span: #9 bytes(LO..HI), + span: #10 bytes(LO..HI), }, Punct { ch: ';', spacing: Alone, - span: #9 bytes(LO..HI), + span: #10 bytes(LO..HI), }, ] PRINT-DERIVE INPUT (DISPLAY): struct D(::dollar_crate_external::S); @@ -206,39 +206,39 @@ PRINT-DERIVE RE-COLLECTED (DISPLAY): struct D ($crate :: S) ; PRINT-DERIVE INPUT (DEBUG): TokenStream [ Ident { ident: "struct", - span: #9 bytes(LO..HI), + span: #10 bytes(LO..HI), }, Ident { ident: "D", - span: #9 bytes(LO..HI), + span: #10 bytes(LO..HI), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "$crate", - span: #9 bytes(LO..HI), + span: #10 bytes(LO..HI), }, Punct { ch: ':', spacing: Joint, - span: #9 bytes(LO..HI), + span: #10 bytes(LO..HI), }, Punct { ch: ':', spacing: Alone, - span: #9 bytes(LO..HI), + span: #10 bytes(LO..HI), }, Ident { ident: "S", - span: #9 bytes(LO..HI), + span: #10 bytes(LO..HI), }, ], - span: #9 bytes(LO..HI), + span: #10 bytes(LO..HI), }, Punct { ch: ';', spacing: Alone, - span: #9 bytes(LO..HI), + span: #10 bytes(LO..HI), }, ] From e552840e79330f8a1f36fc676b71fa38b3123a50 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Wed, 28 Aug 2019 22:47:52 +0100 Subject: [PATCH 12/24] Document test harness generation Also ensure that we're consistently using the def-site span when appropriate. --- src/libsyntax_ext/test_harness.rs | 82 +++++++++++++++++++++---------- 1 file changed, 55 insertions(+), 27 deletions(-) diff --git a/src/libsyntax_ext/test_harness.rs b/src/libsyntax_ext/test_harness.rs index eedd7fbee3806..b93c11fad3823 100644 --- a/src/libsyntax_ext/test_harness.rs +++ b/src/libsyntax_ext/test_harness.rs @@ -25,6 +25,7 @@ struct Test { struct TestCtxt<'a> { ext_cx: ExtCtxt<'a>, + def_site: Span, test_cases: Vec, reexport_test_harness_main: Option, test_runner: Option, @@ -125,6 +126,7 @@ impl<'a> MutVisitor for TestHarnessGenerator<'a> { struct EntryPointCleaner { // Current depth in the ast depth: usize, + def_site: Span, } impl MutVisitor for EntryPointCleaner { @@ -141,8 +143,10 @@ impl MutVisitor for EntryPointCleaner { EntryPointType::MainAttr | EntryPointType::Start => item.map(|ast::Item {id, ident, attrs, node, vis, span, tokens}| { - let allow_ident = Ident::with_dummy_span(sym::allow); - let dc_nested = attr::mk_nested_word_item(Ident::from_str("dead_code")); + let allow_ident = Ident::new(sym::allow, self.def_site); + let dc_nested = attr::mk_nested_word_item( + Ident::from_str_and_span("dead_code", self.def_site), + ); let allow_dead_code_item = attr::mk_list_item(allow_ident, vec![dc_nested]); let allow_dead_code = attr::mk_attr_outer(allow_dead_code_item); @@ -180,15 +184,26 @@ fn generate_test_harness(sess: &ParseSess, krate: &mut ast::Crate, features: &Features, test_runner: Option) { - // Remove the entry points - let mut cleaner = EntryPointCleaner { depth: 0 }; - cleaner.visit_crate(krate); - let mut econfig = ExpansionConfig::default("test".to_string()); econfig.features = Some(features); + let ext_cx = ExtCtxt::new(sess, econfig, resolver); + + let expn_id = ext_cx.resolver.expansion_for_ast_pass( + DUMMY_SP, + AstPass::TestHarness, + &[sym::main, sym::test, sym::rustc_attrs], + None, + ); + let def_site = DUMMY_SP.with_def_site_ctxt(expn_id); + + // Remove the entry points + let mut cleaner = EntryPointCleaner { depth: 0, def_site }; + cleaner.visit_crate(krate); + let cx = TestCtxt { - ext_cx: ExtCtxt::new(sess, econfig, resolver), + ext_cx, + def_site, test_cases: Vec::new(), reexport_test_harness_main, test_runner @@ -202,27 +217,40 @@ fn generate_test_harness(sess: &ParseSess, /// Creates a function item for use as the main function of a test build. /// This function will call the `test_runner` as specified by the crate attribute +/// +/// By default this expands to +/// +/// #[main] +/// pub fn main() { +/// extern crate test; +/// test::test_main_static(&[ +/// &test_const1, +/// &test_const2, +/// &test_const3, +/// ]); +/// } +/// +/// Most of the Ident have the usual def-site hygiene for the AST pass. The +/// exception is the `test_const`s. These have a syntax context that has two +/// opaque marks: one from the expansion of `test` or `test_case`, and one +/// generated in `TestHarnessGenerator::flat_map_item`. When resolving this +/// identifier after failing to find a matching identifier in the root module +/// we remove the outer mark, and try resolving at its def-site, which will +/// then resolve to `test_const`. +/// +/// The expansion here can be controlled by two attributes: +/// +/// `reexport_test_harness_main` provides a different name for the `main` +/// function and `test_runner` provides a path that replaces +/// `test::test_main_static`. fn mk_main(cx: &mut TestCtxt<'_>) -> P { - // Writing this out by hand: - // pub fn main() { - // #![main] - // test::test_main_static(&[..tests]); - // } - let expn_id = cx.ext_cx.resolver.expansion_for_ast_pass( - DUMMY_SP, - AstPass::TestHarness, - &[sym::main, sym::test, sym::rustc_attrs], - None, - ); - let sp = DUMMY_SP.with_def_site_ctxt(expn_id); + let sp = cx.def_site; let ecx = &cx.ext_cx; let test_id = Ident::new(sym::test, sp); // test::test_main_static(...) let mut test_runner = cx.test_runner.clone().unwrap_or( - ecx.path(sp, vec![ - test_id, ecx.ident_of("test_main_static") - ])); + ecx.path(sp, vec![test_id, Ident::from_str_and_span("test_main_static", sp)])); test_runner.span = sp; @@ -231,10 +259,6 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> P { vec![mk_tests_slice(cx, sp)]); let call_test_main = ecx.stmt_expr(call_test_main); - // #![main] - let main_meta = ecx.meta_word(sp, sym::main); - let main_attr = ecx.attribute(main_meta); - // extern crate test let test_extern_stmt = ecx.stmt_item(sp, ecx.item(sp, test_id, @@ -242,6 +266,10 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> P { ast::ItemKind::ExternCrate(None) )); + // #[main] + let main_meta = ecx.meta_word(sp, sym::main); + let main_attr = ecx.attribute(main_meta); + // pub fn main() { ... } let main_ret_ty = ecx.ty(sp, ast::TyKind::Tup(vec![])); @@ -279,7 +307,7 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> P { } /// Creates a slice containing every test like so: -/// &[test1, test2] +/// &[&test1, &test2] fn mk_tests_slice(cx: &TestCtxt<'_>, sp: Span) -> P { debug!("building test vector from {} tests", cx.test_cases.len()); let ref ecx = cx.ext_cx; From afcf9b262d450edd1a7d54754e62f62d50052d8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 5 Sep 2019 13:15:42 -0700 Subject: [PATCH 13/24] Bail out when encountering likely missing turbofish in parser When encountering a likely intended turbofish without `::`, bubble up the diagnostic instead of emitting it to allow the parser to recover more gracefully and avoid uneccessary type errors that are likely to be wrong. --- src/libsyntax/parse/diagnostics.rs | 5 +- src/libsyntax/parse/parser/expr.rs | 2 +- src/test/ui/did_you_mean/issue-40396.rs | 11 --- src/test/ui/did_you_mean/issue-40396.stderr | 80 +------------------ .../require-parens-for-chained-comparison.rs | 3 +- ...quire-parens-for-chained-comparison.stderr | 15 +--- .../ui/parser/trait-object-lifetime-parens.rs | 1 - .../trait-object-lifetime-parens.stderr | 11 +-- 8 files changed, 12 insertions(+), 116 deletions(-) diff --git a/src/libsyntax/parse/diagnostics.rs b/src/libsyntax/parse/diagnostics.rs index d4e661d1a38b7..d050d4f4ce705 100644 --- a/src/libsyntax/parse/diagnostics.rs +++ b/src/libsyntax/parse/diagnostics.rs @@ -544,7 +544,7 @@ impl<'a> Parser<'a> { /// Produce an error if comparison operators are chained (RFC #558). /// We only need to check lhs, not rhs, because all comparison ops /// have same precedence and are left-associative - crate fn check_no_chained_comparison(&self, lhs: &Expr, outer_op: &AssocOp) { + crate fn check_no_chained_comparison(&self, lhs: &Expr, outer_op: &AssocOp) -> PResult<'a, ()> { debug_assert!(outer_op.is_comparison(), "check_no_chained_comparison: {:?} is not comparison", outer_op); @@ -563,11 +563,14 @@ impl<'a> Parser<'a> { err.help( "use `::<...>` instead of `<...>` if you meant to specify type arguments"); err.help("or use `(...)` if you meant to specify fn arguments"); + // These cases cause too many knock-down errors, bail out (#61329). + return Err(err); } err.emit(); } _ => {} } + Ok(()) } crate fn maybe_report_ambiguous_plus( diff --git a/src/libsyntax/parse/parser/expr.rs b/src/libsyntax/parse/parser/expr.rs index 5b9f0f1df6718..aeef216141299 100644 --- a/src/libsyntax/parse/parser/expr.rs +++ b/src/libsyntax/parse/parser/expr.rs @@ -231,7 +231,7 @@ impl<'a> Parser<'a> { self.bump(); if op.is_comparison() { - self.check_no_chained_comparison(&lhs, &op); + self.check_no_chained_comparison(&lhs, &op)?; } // Special cases: if op == AssocOp::As { diff --git a/src/test/ui/did_you_mean/issue-40396.rs b/src/test/ui/did_you_mean/issue-40396.rs index 63eec50c2d29f..6902779f33d23 100644 --- a/src/test/ui/did_you_mean/issue-40396.rs +++ b/src/test/ui/did_you_mean/issue-40396.rs @@ -1,27 +1,16 @@ fn foo() { (0..13).collect>(); //~^ ERROR chained comparison - //~| ERROR expected value, found struct `Vec` - //~| ERROR expected value, found builtin type `i32` - //~| ERROR attempted to take value of method `collect` } fn bar() { Vec::new(); //~^ ERROR chained comparison - //~| ERROR expected value, found struct `Vec` - //~| ERROR expected value, found builtin type `i32` - //~| ERROR cannot find function `new` in the crate root } fn qux() { (0..13).collect(); //~^ ERROR chained comparison - //~| ERROR chained comparison - //~| ERROR expected value, found struct `Vec` - //~| ERROR expected value, found builtin type `i32` - //~| ERROR attempted to take value of method `collect` - //~| ERROR mismatched types } fn main() {} diff --git a/src/test/ui/did_you_mean/issue-40396.stderr b/src/test/ui/did_you_mean/issue-40396.stderr index fe517ee34949d..7a08fda27e355 100644 --- a/src/test/ui/did_you_mean/issue-40396.stderr +++ b/src/test/ui/did_you_mean/issue-40396.stderr @@ -8,7 +8,7 @@ LL | (0..13).collect>(); = help: or use `(...)` if you meant to specify fn arguments error: chained comparison operators require parentheses - --> $DIR/issue-40396.rs:10:8 + --> $DIR/issue-40396.rs:7:8 | LL | Vec::new(); | ^^^^^^^ @@ -17,7 +17,7 @@ LL | Vec::new(); = help: or use `(...)` if you meant to specify fn arguments error: chained comparison operators require parentheses - --> $DIR/issue-40396.rs:18:20 + --> $DIR/issue-40396.rs:12:20 | LL | (0..13).collect(); | ^^^^^^^^ @@ -25,79 +25,5 @@ LL | (0..13).collect(); = help: use `::<...>` instead of `<...>` if you meant to specify type arguments = help: or use `(...)` if you meant to specify fn arguments -error: chained comparison operators require parentheses - --> $DIR/issue-40396.rs:18:24 - | -LL | (0..13).collect(); - | ^^^^^^ - | - = help: use `::<...>` instead of `<...>` if you meant to specify type arguments - = help: or use `(...)` if you meant to specify fn arguments - -error[E0423]: expected value, found struct `Vec` - --> $DIR/issue-40396.rs:2:21 - | -LL | (0..13).collect>(); - | ^^^ did you mean `Vec { /* fields */ }`? - -error[E0423]: expected value, found builtin type `i32` - --> $DIR/issue-40396.rs:2:25 - | -LL | (0..13).collect>(); - | ^^^ not a value - -error[E0423]: expected value, found struct `Vec` - --> $DIR/issue-40396.rs:10:5 - | -LL | Vec::new(); - | ^^^ did you mean `Vec { /* fields */ }`? - -error[E0423]: expected value, found builtin type `i32` - --> $DIR/issue-40396.rs:10:9 - | -LL | Vec::new(); - | ^^^ not a value - -error[E0425]: cannot find function `new` in the crate root - --> $DIR/issue-40396.rs:10:15 - | -LL | Vec::new(); - | ^^^ not found in the crate root - -error[E0423]: expected value, found struct `Vec` - --> $DIR/issue-40396.rs:18:21 - | -LL | (0..13).collect(); - | ^^^ did you mean `Vec { /* fields */ }`? - -error[E0423]: expected value, found builtin type `i32` - --> $DIR/issue-40396.rs:18:25 - | -LL | (0..13).collect(); - | ^^^ not a value - -error[E0615]: attempted to take value of method `collect` on type `std::ops::Range<{integer}>` - --> $DIR/issue-40396.rs:2:13 - | -LL | (0..13).collect>(); - | ^^^^^^^ help: use parentheses to call the method: `collect()` - -error[E0615]: attempted to take value of method `collect` on type `std::ops::Range<{integer}>` - --> $DIR/issue-40396.rs:18:13 - | -LL | (0..13).collect(); - | ^^^^^^^ help: use parentheses to call the method: `collect()` - -error[E0308]: mismatched types - --> $DIR/issue-40396.rs:18:29 - | -LL | (0..13).collect(); - | ^^ expected bool, found () - | - = note: expected type `bool` - found type `()` - -error: aborting due to 14 previous errors +error: aborting due to 3 previous errors -Some errors have detailed explanations: E0308, E0423, E0425, E0615. -For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/parser/require-parens-for-chained-comparison.rs b/src/test/ui/parser/require-parens-for-chained-comparison.rs index 525be5d20e27f..3dcc0c8f3d496 100644 --- a/src/test/ui/parser/require-parens-for-chained-comparison.rs +++ b/src/test/ui/parser/require-parens-for-chained-comparison.rs @@ -11,8 +11,7 @@ fn main() { //~| ERROR: mismatched types f(); - //~^ ERROR: chained comparison operators require parentheses - //~| ERROR: binary operation `<` cannot be applied to type `fn() {f::<_>}` + //~^ ERROR chained comparison operators require parentheses //~| HELP: use `::<...>` instead of `<...>` //~| HELP: or use `(...)` } diff --git a/src/test/ui/parser/require-parens-for-chained-comparison.stderr b/src/test/ui/parser/require-parens-for-chained-comparison.stderr index 76e548de045aa..e927f4c32484e 100644 --- a/src/test/ui/parser/require-parens-for-chained-comparison.stderr +++ b/src/test/ui/parser/require-parens-for-chained-comparison.stderr @@ -37,17 +37,6 @@ LL | false == 0 < 2; = note: expected type `bool` found type `{integer}` -error[E0369]: binary operation `<` cannot be applied to type `fn() {f::<_>}` - --> $DIR/require-parens-for-chained-comparison.rs:13:6 - | -LL | f(); - | -^- X - | | - | fn() {f::<_>} - | - = note: an implementation of `std::cmp::PartialOrd` might be missing for `fn() {f::<_>}` - -error: aborting due to 6 previous errors +error: aborting due to 5 previous errors -Some errors have detailed explanations: E0308, E0369. -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/parser/trait-object-lifetime-parens.rs b/src/test/ui/parser/trait-object-lifetime-parens.rs index 5bbda4296ca7e..c8b0eb684f33d 100644 --- a/src/test/ui/parser/trait-object-lifetime-parens.rs +++ b/src/test/ui/parser/trait-object-lifetime-parens.rs @@ -9,7 +9,6 @@ fn check<'a>() { let _: Box<('a) + Trait>; //~^ ERROR expected type, found `'a` //~| ERROR expected `:`, found `)` - //~| ERROR chained comparison operators require parentheses } fn main() {} diff --git a/src/test/ui/parser/trait-object-lifetime-parens.stderr b/src/test/ui/parser/trait-object-lifetime-parens.stderr index 7ffc26e9edead..319a308c0137c 100644 --- a/src/test/ui/parser/trait-object-lifetime-parens.stderr +++ b/src/test/ui/parser/trait-object-lifetime-parens.stderr @@ -16,15 +16,6 @@ error: expected `:`, found `)` LL | let _: Box<('a) + Trait>; | ^ expected `:` -error: chained comparison operators require parentheses - --> $DIR/trait-object-lifetime-parens.rs:9:15 - | -LL | let _: Box<('a) + Trait>; - | ^^^^^^^^^^^^^^^ - | - = help: use `::<...>` instead of `<...>` if you meant to specify type arguments - = help: or use `(...)` if you meant to specify fn arguments - error: expected type, found `'a` --> $DIR/trait-object-lifetime-parens.rs:9:17 | @@ -33,5 +24,5 @@ LL | let _: Box<('a) + Trait>; | | | while parsing the type for `_` -error: aborting due to 5 previous errors +error: aborting due to 4 previous errors From 3f3fc52bfa255e68d84ca40a497137f5c6bae4a8 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Thu, 5 Sep 2019 15:05:58 +0100 Subject: [PATCH 14/24] Simplify std lib injection --- src/librustc_interface/passes.rs | 2 +- src/librustc_resolve/diagnostics.rs | 8 ++ src/librustc_resolve/macros.rs | 5 +- src/librustc_resolve/resolve_imports.rs | 7 +- src/libsyntax_ext/proc_macro_harness.rs | 32 +---- src/libsyntax_ext/standard_library_imports.rs | 124 +++++------------- 6 files changed, 52 insertions(+), 126 deletions(-) diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs index 649cc8a2fb515..48c3ddf39a22b 100644 --- a/src/librustc_interface/passes.rs +++ b/src/librustc_interface/passes.rs @@ -366,8 +366,8 @@ fn configure_and_expand_inner<'a>( let (krate, name) = syntax_ext::standard_library_imports::inject( krate, &mut resolver, + &sess.parse_sess, alt_std_name, - sess.edition(), ); if let Some(name) = name { sess.parse_sess.injected_crate_name.set(name); diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index b79e0c2bd3b26..c479912b4ef81 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -604,6 +604,14 @@ impl<'a> Resolver<'a> { if lookup_ident.span.rust_2018() { let extern_prelude_names = self.extern_prelude.clone(); for (ident, _) in extern_prelude_names.into_iter() { + if ident.span.from_expansion() { + // Idents are adjusted to the root context before being + // resolved in the extern prelude, so reporting this to the + // user is no help. This skips the injected + // `extern crate std` in the 2018 edition, which would + // otherwise cause duplicate suggestions. + continue; + } if let Some(crate_id) = self.crate_loader.maybe_process_path_extern(ident.name, ident.span) { let crate_root = self.get_module(DefId { diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 02022c98c3502..cf99663beaf48 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -128,9 +128,8 @@ impl<'a> base::Resolver for Resolver<'a> { } } - // Create a Span with modern hygiene with a definition site of the provided - // module, or a fake empty `#[no_implicit_prelude]` module if no module is - // provided. + // Create a new Expansion with a definition site of the provided module, or + // a fake empty `#[no_implicit_prelude]` module if no module is provided. fn expansion_for_ast_pass( &mut self, call_site: Span, diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 4e33ea018a074..ca189e71800b3 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -1307,8 +1307,11 @@ impl<'a, 'b> ImportResolver<'a, 'b> { None => continue, }; - // Filter away ambiguous imports. - let is_good_import = binding.is_import() && !binding.is_ambiguity(); + // Filter away ambiguous imports and anything that has def-site + // hygiene. + // FIXME: Implement actual cross-crate hygiene. + let is_good_import = binding.is_import() && !binding.is_ambiguity() + && !ident.span.modern().from_expansion(); if is_good_import || binding.is_macro_def() { let res = binding.res(); if res != Res::Err { diff --git a/src/libsyntax_ext/proc_macro_harness.rs b/src/libsyntax_ext/proc_macro_harness.rs index 8a4b78a3efa31..31d32d23a645e 100644 --- a/src/libsyntax_ext/proc_macro_harness.rs +++ b/src/libsyntax_ext/proc_macro_harness.rs @@ -392,41 +392,19 @@ fn mk_decls( i }); - let block = P(ast::Expr { - id: ast::DUMMY_NODE_ID, - attrs: syntax::ThinVec::new(), - node: ast::ExprKind::Block(P(ast::Block { - id: ast::DUMMY_NODE_ID, - rules: ast::BlockCheckMode::Default, - stmts: vec![ - ast::Stmt { - id: ast::DUMMY_NODE_ID, - node: ast::StmtKind::Item(krate), - span, - }, - ast::Stmt { - id: ast::DUMMY_NODE_ID, - node: ast::StmtKind::Item(decls_static), - span, - } - ], - span, - }), None), + let block = cx.expr_block(cx.block( span, - }); + vec![cx.stmt_item(span, krate), cx.stmt_item(span, decls_static)], + )); let anon_constant = cx.item_const( span, ast::Ident::new(kw::Underscore, span), - P(ast::Ty { - id: ast::DUMMY_NODE_ID, - node: ast::TyKind::Tup(Vec::new()), - span, - }), + cx.ty(span, ast::TyKind::Tup(Vec::new())), block, ); - // Integrate the new module into existing module structures. + // Integrate the new item into existing module structures. let items = AstFragment::Items(smallvec![anon_constant]); cx.monotonic_expander().fully_expand_fragment(items).make_items().pop().unwrap() } diff --git a/src/libsyntax_ext/standard_library_imports.rs b/src/libsyntax_ext/standard_library_imports.rs index e5dded9ea5319..c577b1e33cfeb 100644 --- a/src/libsyntax_ext/standard_library_imports.rs +++ b/src/libsyntax_ext/standard_library_imports.rs @@ -1,19 +1,20 @@ use syntax::{ast, attr}; use syntax::edition::Edition; +use syntax::ext::expand::ExpansionConfig; use syntax::ext::hygiene::AstPass; -use syntax::ext::base::Resolver; +use syntax::ext::base::{ExtCtxt, Resolver}; +use syntax::parse::ParseSess; use syntax::ptr::P; -use syntax::source_map::respan; use syntax::symbol::{Ident, Symbol, kw, sym}; use syntax_pos::DUMMY_SP; pub fn inject( mut krate: ast::Crate, resolver: &mut dyn Resolver, + sess: &ParseSess, alt_std_name: Option, - edition: Edition, ) -> (ast::Crate, Option) { - let rust_2018 = edition >= Edition::Edition2018; + let rust_2018 = sess.edition >= Edition::Edition2018; // the first name in this list is the crate name of the crate with the prelude let names: &[Symbol] = if attr::contains_name(&krate.attrs, sym::no_core) { @@ -37,112 +38,49 @@ pub fn inject( let span = DUMMY_SP.with_def_site_ctxt(expn_id); let call_site = DUMMY_SP.with_call_site_ctxt(expn_id); + let ecfg = ExpansionConfig::default("std_lib_injection".to_string()); + let cx = ExtCtxt::new(sess, ecfg, resolver); + + // .rev() to preserve ordering above in combination with insert(0, ...) - for &orig_name_sym in names.iter().rev() { - let (rename, orig_name) = if rust_2018 { - (Ident::new(kw::Underscore, span), Some(orig_name_sym)) + for &name in names.iter().rev() { + let ident = if rust_2018 { + Ident::new(name, span) } else { - (Ident::new(orig_name_sym, call_site), None) + Ident::new(name, call_site) }; - krate.module.items.insert(0, P(ast::Item { - attrs: vec![attr::mk_attr_outer( - attr::mk_word_item(ast::Ident::new(sym::macro_use, span)) - )], - vis: respan(span, ast::VisibilityKind::Inherited), - node: ast::ItemKind::ExternCrate(alt_std_name.or(orig_name)), - ident: rename, - id: ast::DUMMY_NODE_ID, + krate.module.items.insert(0, cx.item( span, - tokens: None, - })); + ident, + vec![cx.attribute(cx.meta_word(span, sym::macro_use))], + ast::ItemKind::ExternCrate(alt_std_name), + )); } - // the crates have been injected, the assumption is that the first one is the one with - // the prelude. + // The crates have been injected, the assumption is that the first one is + // the one with the prelude. let name = names[0]; - let segments = if rust_2018 { + let import_path = if rust_2018 { [name, sym::prelude, sym::v1].iter() - .map(|symbol| ast::PathSegment::from_ident(ast::Ident::new(*symbol, span))) - .collect() + .map(|symbol| ast::Ident::new(*symbol, span)).collect() } else { [kw::PathRoot, name, sym::prelude, sym::v1].iter() - .map(|symbol| ast::PathSegment::from_ident(ast::Ident::new(*symbol, call_site))) - .collect() + .map(|symbol| ast::Ident::new(*symbol, span)).collect() }; - let use_item = P(ast::Item { - attrs: vec![attr::mk_attr_outer( - attr::mk_word_item(ast::Ident::new(sym::prelude_import, span)))], - vis: respan(span.shrink_to_lo(), ast::VisibilityKind::Inherited), - node: ast::ItemKind::Use(P(ast::UseTree { - prefix: ast::Path { segments, span }, + let use_item = cx.item( + span, + ast::Ident::invalid(), + vec![cx.attribute(cx.meta_word(span, sym::prelude_import))], + ast::ItemKind::Use(P(ast::UseTree { + prefix: cx.path(span, import_path), kind: ast::UseTreeKind::Glob, span, })), - id: ast::DUMMY_NODE_ID, - ident: ast::Ident::invalid(), - span, - tokens: None, - }); - - let prelude_import_item = if rust_2018 { - let hygienic_extern_crate = P(ast::Item { - attrs: vec![], - vis: respan(span, ast::VisibilityKind::Inherited), - node: ast::ItemKind::ExternCrate(alt_std_name), - ident: ast::Ident::new(name, span), - id: ast::DUMMY_NODE_ID, - span, - tokens: None, - }); - - // Use an anonymous const to hide `extern crate std as hygienic_std` - // FIXME: Once inter-crate hygiene exists, this can just be `use_item`. - P(ast::Item { - attrs: Vec::new(), - vis: respan(span.shrink_to_lo(), ast::VisibilityKind::Inherited), - node: ast::ItemKind::Const( - P(ast::Ty { - id: ast::DUMMY_NODE_ID, - node: ast::TyKind::Tup(Vec::new()), - span, - }), - P(ast::Expr { - id: ast::DUMMY_NODE_ID, - attrs: syntax::ThinVec::new(), - node: ast::ExprKind::Block(P(ast::Block { - id: ast::DUMMY_NODE_ID, - rules: ast::BlockCheckMode::Default, - stmts: vec![ - ast::Stmt { - id: ast::DUMMY_NODE_ID, - node: ast::StmtKind::Item(use_item), - span, - }, - ast::Stmt { - id: ast::DUMMY_NODE_ID, - node: ast::StmtKind::Item(hygienic_extern_crate), - span, - } - ], - span, - }), None), - span, - }) - ), - id: ast::DUMMY_NODE_ID, - ident: ast::Ident::new(kw::Underscore, span), - span, - tokens: None, - }) - } else { - // Have `extern crate std` at the root, so don't need to create a named - // extern crate item. - use_item - }; + ); - krate.module.items.insert(0, prelude_import_item); + krate.module.items.insert(0, use_item); (krate, Some(name)) } From bad8147d01df374e3daa37fe36446781df2eac2d Mon Sep 17 00:00:00 2001 From: Mark Mansi Date: Thu, 5 Sep 2019 16:52:44 -0500 Subject: [PATCH 15/24] fix reviewer comments --- src/tools/rustbook/src/main.rs | 66 +++++++++++++++++----------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/src/tools/rustbook/src/main.rs b/src/tools/rustbook/src/main.rs index b2111442310ef..d5dc9a79b5acb 100644 --- a/src/tools/rustbook/src/main.rs +++ b/src/tools/rustbook/src/main.rs @@ -8,6 +8,7 @@ use clap::{App, AppSettings, ArgMatches, SubCommand}; use mdbook::errors::Result as Result3; use mdbook::MDBook; +#[cfg(feature = "linkcheck")] use failure::Error; #[cfg(feature = "linkcheck")] use mdbook::renderer::RenderContext; @@ -52,36 +53,41 @@ fn main() { } } ("linkcheck", Some(sub_matches)) => { - if let Err(err) = linkcheck(sub_matches) { - eprintln!("Error: {}", err); - - // HACK: ignore timeouts - let actually_broken = { - #[cfg(feature = "linkcheck")] - { - err.downcast::() - .map(|broken_links| { - broken_links - .links() - .iter() - .inspect(|cause| eprintln!("\tCaused By: {}", cause)) - .any(|cause| !format!("{}", cause).contains("timed out")) - }) - .unwrap_or(false) - } - - #[cfg(not(feature = "linkcheck"))] - { - false + #[cfg(feature = "linkcheck")] + { + if let Err(err) = linkcheck(sub_matches) { + eprintln!("Error: {}", err); + + // HACK: ignore timeouts + let actually_broken = err + .downcast::() + .map(|broken_links| { + broken_links + .links() + .iter() + .inspect(|cause| eprintln!("\tCaused By: {}", cause)) + .fold(false, |already_broken, cause| { + already_broken || !format!("{}", cause).contains("timed out") + }) + }) + .unwrap_or(false); + + if actually_broken { + std::process::exit(101); + } else { + std::process::exit(0); } - }; - - if actually_broken { - std::process::exit(101); - } else { - std::process::exit(0); } } + + #[cfg(not(feature = "linkcheck"))] + { + // This avoids the `unused_binding` lint. + println!( + "mdbook-linkcheck is disabled, but arguments were passed: {:?}", + sub_matches + ); + } } (_, _) => unreachable!(), }; @@ -97,12 +103,6 @@ pub fn linkcheck(args: &ArgMatches<'_>) -> Result<(), Error> { mdbook_linkcheck::check_links(&render_ctx) } -#[cfg(not(feature = "linkcheck"))] -pub fn linkcheck(_args: &ArgMatches<'_>) -> Result<(), Error> { - println!("mdbook-linkcheck is disabled."); - Ok(()) -} - // Build command implementation pub fn build(args: &ArgMatches<'_>) -> Result3<()> { let book_dir = get_book_dir(args); From dc613c6d055c1b45f7e11e6ee03e4a3095d5b8a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 5 Sep 2019 15:29:31 -0700 Subject: [PATCH 16/24] Fix test --- src/test/ui-fulldeps/pprust-expr-roundtrip.rs | 47 ++++++++++--------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/src/test/ui-fulldeps/pprust-expr-roundtrip.rs b/src/test/ui-fulldeps/pprust-expr-roundtrip.rs index 09f58521e5d5c..89c17cf4b3aa3 100644 --- a/src/test/ui-fulldeps/pprust-expr-roundtrip.rs +++ b/src/test/ui-fulldeps/pprust-expr-roundtrip.rs @@ -32,13 +32,15 @@ use syntax::print::pprust; use syntax::ptr::P; -fn parse_expr(ps: &ParseSess, src: &str) -> P { +fn parse_expr(ps: &ParseSess, src: &str) -> Option> { let src_as_string = src.to_string(); - let mut p = parse::new_parser_from_source_str(ps, - FileName::Custom(src_as_string.clone()), - src_as_string); - p.parse_expr().unwrap() + let mut p = parse::new_parser_from_source_str( + ps, + FileName::Custom(src_as_string.clone()), + src_as_string, + ); + p.parse_expr().map_err(|mut e| e.cancel()).ok() } @@ -209,22 +211,23 @@ fn run() { let printed = pprust::expr_to_string(&e); println!("printed: {}", printed); - let mut parsed = parse_expr(&ps, &printed); - - // We want to know if `parsed` is structurally identical to `e`, ignoring trivial - // differences like placement of `Paren`s or the exact ranges of node spans. - // Unfortunately, there is no easy way to make this comparison. Instead, we add `Paren`s - // everywhere we can, then pretty-print. This should give an unambiguous representation of - // each `Expr`, and it bypasses nearly all of the parenthesization logic, so we aren't - // relying on the correctness of the very thing we're testing. - RemoveParens.visit_expr(&mut e); - AddParens.visit_expr(&mut e); - let text1 = pprust::expr_to_string(&e); - RemoveParens.visit_expr(&mut parsed); - AddParens.visit_expr(&mut parsed); - let text2 = pprust::expr_to_string(&parsed); - assert!(text1 == text2, - "exprs are not equal:\n e = {:?}\n parsed = {:?}", - text1, text2); + // Ignore expressions with chained comparisons that fail to parse + if let Some(mut parsed) = parse_expr(&ps, &printed) { + // We want to know if `parsed` is structurally identical to `e`, ignoring trivial + // differences like placement of `Paren`s or the exact ranges of node spans. + // Unfortunately, there is no easy way to make this comparison. Instead, we add `Paren`s + // everywhere we can, then pretty-print. This should give an unambiguous representation + // of each `Expr`, and it bypasses nearly all of the parenthesization logic, so we + // aren't relying on the correctness of the very thing we're testing. + RemoveParens.visit_expr(&mut e); + AddParens.visit_expr(&mut e); + let text1 = pprust::expr_to_string(&e); + RemoveParens.visit_expr(&mut parsed); + AddParens.visit_expr(&mut parsed); + let text2 = pprust::expr_to_string(&parsed); + assert!(text1 == text2, + "exprs are not equal:\n e = {:?}\n parsed = {:?}", + text1, text2); + } }); } From eedf555d0c041caa0a9e7c8cd4394716e637feaf Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Wed, 4 Sep 2019 15:21:46 +0300 Subject: [PATCH 17/24] rustc_codegen_llvm: give names to non-alloca variable values. --- src/librustc_codegen_llvm/debuginfo/mod.rs | 35 ++++++++++++++++++-- src/librustc_codegen_llvm/llvm/ffi.rs | 2 ++ src/librustc_codegen_ssa/mir/mod.rs | 16 ++++----- src/librustc_codegen_ssa/mir/statement.rs | 16 ++++++++- src/librustc_codegen_ssa/traits/debuginfo.rs | 2 +- src/test/codegen/var-names.rs | 15 +++++++++ 6 files changed, 73 insertions(+), 13 deletions(-) create mode 100644 src/test/codegen/var-names.rs diff --git a/src/librustc_codegen_llvm/debuginfo/mod.rs b/src/librustc_codegen_llvm/debuginfo/mod.rs index cad2bcdc05fc9..6dedf10f0ab83 100644 --- a/src/librustc_codegen_llvm/debuginfo/mod.rs +++ b/src/librustc_codegen_llvm/debuginfo/mod.rs @@ -32,7 +32,7 @@ use rustc_codegen_ssa::debuginfo::{FunctionDebugContext, MirDebugScope, Variable use libc::c_uint; use std::cell::RefCell; -use std::ffi::CString; +use std::ffi::{CStr, CString}; use syntax_pos::{self, Span, Pos}; use syntax::ast; @@ -224,8 +224,37 @@ impl DebugInfoBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> { gdb::insert_reference_to_gdb_debug_scripts_section_global(self) } - fn set_value_name(&mut self, value: &'ll Value, name: &str) { - let cname = SmallCStr::new(name); + fn set_var_name(&mut self, value: &'ll Value, name: impl ToString) { + // Avoid wasting time if LLVM value names aren't even enabled. + if self.sess().fewer_names() { + return; + } + + // Only function parameters and instructions are local to a function, + // don't change the name of anything else (e.g. globals). + let param_or_inst = unsafe { + llvm::LLVMIsAArgument(value).is_some() || + llvm::LLVMIsAInstruction(value).is_some() + }; + if !param_or_inst { + return; + } + + let old_name = unsafe { + CStr::from_ptr(llvm::LLVMGetValueName(value)) + }; + match old_name.to_str() { + Ok("") => {} + Ok(_) => { + // Avoid replacing the name if it already exists. + // While we could combine the names somehow, it'd + // get noisy quick, and the usefulness is dubious. + return; + } + Err(_) => return, + } + + let cname = CString::new(name.to_string()).unwrap(); unsafe { llvm::LLVMSetValueName(value, cname.as_ptr()); } diff --git a/src/librustc_codegen_llvm/llvm/ffi.rs b/src/librustc_codegen_llvm/llvm/ffi.rs index 9f9410560e373..b07214fdc03f3 100644 --- a/src/librustc_codegen_llvm/llvm/ffi.rs +++ b/src/librustc_codegen_llvm/llvm/ffi.rs @@ -806,6 +806,7 @@ extern "C" { pub fn LLVMRustRemoveFunctionAttributes(Fn: &Value, index: c_uint, attr: Attribute); // Operations on parameters + pub fn LLVMIsAArgument(Val: &Value) -> Option<&Value>; pub fn LLVMCountParams(Fn: &Value) -> c_uint; pub fn LLVMGetParam(Fn: &Value, Index: c_uint) -> &Value; @@ -818,6 +819,7 @@ extern "C" { pub fn LLVMDeleteBasicBlock(BB: &BasicBlock); // Operations on instructions + pub fn LLVMIsAInstruction(Val: &Value) -> Option<&Value>; pub fn LLVMGetFirstBasicBlock(Fn: &Value) -> &BasicBlock; // Operations on call sites diff --git a/src/librustc_codegen_ssa/mir/mod.rs b/src/librustc_codegen_ssa/mir/mod.rs index 8acb3ba06267e..00e9ca01f4dd2 100644 --- a/src/librustc_codegen_ssa/mir/mod.rs +++ b/src/librustc_codegen_ssa/mir/mod.rs @@ -518,19 +518,19 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( PassMode::Ignore(IgnoreMode::CVarArgs) => {} PassMode::Direct(_) => { let llarg = bx.get_param(llarg_idx); - bx.set_value_name(llarg, &name); + bx.set_var_name(llarg, &name); llarg_idx += 1; return local( OperandRef::from_immediate_or_packed_pair(bx, llarg, arg.layout)); } PassMode::Pair(..) => { - let a = bx.get_param(llarg_idx); - bx.set_value_name(a, &(name.clone() + ".0")); - llarg_idx += 1; + let (a, b) = (bx.get_param(llarg_idx), bx.get_param(llarg_idx + 1)); + llarg_idx += 2; - let b = bx.get_param(llarg_idx); - bx.set_value_name(b, &(name + ".1")); - llarg_idx += 1; + // FIXME(eddyb) these are scalar components, + // maybe extract the high-level fields? + bx.set_var_name(a, format_args!("{}.0", name)); + bx.set_var_name(b, format_args!("{}.1", name)); return local(OperandRef { val: OperandValue::Pair(a, b), @@ -546,7 +546,7 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // already put it in a temporary alloca and gave it up. // FIXME: lifetimes let llarg = bx.get_param(llarg_idx); - bx.set_value_name(llarg, &name); + bx.set_var_name(llarg, &name); llarg_idx += 1; PlaceRef::new_sized(llarg, arg.layout) } else if arg.is_unsized_indirect() { diff --git a/src/librustc_codegen_ssa/mir/statement.rs b/src/librustc_codegen_ssa/mir/statement.rs index 3617f3afaae41..594f45c833758 100644 --- a/src/librustc_codegen_ssa/mir/statement.rs +++ b/src/librustc_codegen_ssa/mir/statement.rs @@ -29,7 +29,21 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { self.codegen_rvalue_unsized(bx, cg_indirect_dest, rvalue) } LocalRef::Operand(None) => { - let (bx, operand) = self.codegen_rvalue_operand(bx, rvalue); + let (mut bx, operand) = self.codegen_rvalue_operand(bx, rvalue); + if let Some(name) = self.mir.local_decls[index].name { + match operand.val { + OperandValue::Ref(x, ..) | + OperandValue::Immediate(x) => { + bx.set_var_name(x, name); + } + OperandValue::Pair(a, b) => { + // FIXME(eddyb) these are scalar components, + // maybe extract the high-level fields? + bx.set_var_name(a, format_args!("{}.0", name)); + bx.set_var_name(b, format_args!("{}.1", name)); + } + } + } self.locals[index] = LocalRef::Operand(Some(operand)); bx } diff --git a/src/librustc_codegen_ssa/traits/debuginfo.rs b/src/librustc_codegen_ssa/traits/debuginfo.rs index be2fa7279aa7c..9c16b864ef21d 100644 --- a/src/librustc_codegen_ssa/traits/debuginfo.rs +++ b/src/librustc_codegen_ssa/traits/debuginfo.rs @@ -57,5 +57,5 @@ pub trait DebugInfoBuilderMethods<'tcx>: BackendTypes { span: Span, ); fn insert_reference_to_gdb_debug_scripts_section_global(&mut self); - fn set_value_name(&mut self, value: Self::Value, name: &str); + fn set_var_name(&mut self, value: Self::Value, name: impl ToString); } diff --git a/src/test/codegen/var-names.rs b/src/test/codegen/var-names.rs new file mode 100644 index 0000000000000..3140a7c6b6cc2 --- /dev/null +++ b/src/test/codegen/var-names.rs @@ -0,0 +1,15 @@ +// compile-flags: -O -C no-prepopulate-passes + +#![crate_type = "lib"] + +// CHECK-LABEL: define i32 @test(i32 %a, i32 %b) +#[no_mangle] +pub fn test(a: u32, b: u32) -> u32 { + let c = a + b; + // CHECK: %c = add i32 %a, %b + let d = c; + let e = d * a; + // CHECK-NEXT: %e = mul i32 %c, %a + e + // CHECK-NEXT: ret i32 %e +} From 10f46b69bc32bd1cb5f013ce904957aeb28603bb Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Fri, 6 Sep 2019 18:02:12 +0100 Subject: [PATCH 18/24] Move the HIR cfg to `rustc_ast_borrowck` No new code should be using it. --- src/librustc/lib.rs | 1 - src/librustc_ast_borrowck/borrowck/mod.rs | 2 +- .../borrowck/move_data.rs | 2 +- .../cfg/construct.rs | 12 +++---- .../cfg/graphviz.rs | 11 +++---- .../cfg/mod.rs | 31 ++++++++----------- src/librustc_ast_borrowck/dataflow.rs | 5 ++- src/librustc_ast_borrowck/graphviz.rs | 7 ++--- src/librustc_ast_borrowck/lib.rs | 1 + src/librustc_driver/pretty.rs | 3 +- 10 files changed, 32 insertions(+), 43 deletions(-) rename src/{librustc => librustc_ast_borrowck}/cfg/construct.rs (98%) rename src/{librustc => librustc_ast_borrowck}/cfg/graphviz.rs (94%) rename src/{librustc => librustc_ast_borrowck}/cfg/mod.rs (51%) diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 368f5bb64fe6c..bf4330a29a7df 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -97,7 +97,6 @@ pub mod query; #[macro_use] pub mod arena; -pub mod cfg; pub mod dep_graph; pub mod hir; pub mod ich; diff --git a/src/librustc_ast_borrowck/borrowck/mod.rs b/src/librustc_ast_borrowck/borrowck/mod.rs index 3bbd7ae5c352f..23d5480c60562 100644 --- a/src/librustc_ast_borrowck/borrowck/mod.rs +++ b/src/librustc_ast_borrowck/borrowck/mod.rs @@ -9,7 +9,6 @@ use InteriorKind::*; use rustc::hir::HirId; use rustc::hir::Node; -use rustc::cfg; use rustc::middle::borrowck::{BorrowCheckResult, SignalledError}; use rustc::hir::def_id::{DefId, LocalDefId}; use rustc::middle::mem_categorization as mc; @@ -28,6 +27,7 @@ use log::debug; use rustc::hir; +use crate::cfg; use crate::dataflow::{DataFlowContext, BitwiseOperator, DataFlowOperator, KillFrom}; pub mod check_loans; diff --git a/src/librustc_ast_borrowck/borrowck/move_data.rs b/src/librustc_ast_borrowck/borrowck/move_data.rs index 887a0e2f20e16..67d818161b1b5 100644 --- a/src/librustc_ast_borrowck/borrowck/move_data.rs +++ b/src/librustc_ast_borrowck/borrowck/move_data.rs @@ -4,7 +4,7 @@ use crate::dataflow::{DataFlowContext, BitwiseOperator, DataFlowOperator, KillFrom}; use crate::borrowck::*; -use rustc::cfg; +use crate::cfg; use rustc::ty::{self, TyCtxt}; use rustc::util::nodemap::FxHashMap; diff --git a/src/librustc/cfg/construct.rs b/src/librustc_ast_borrowck/cfg/construct.rs similarity index 98% rename from src/librustc/cfg/construct.rs rename to src/librustc_ast_borrowck/cfg/construct.rs index 0dad2dda837b5..339d92145c64f 100644 --- a/src/librustc/cfg/construct.rs +++ b/src/librustc_ast_borrowck/cfg/construct.rs @@ -1,11 +1,11 @@ use crate::cfg::*; -use crate::middle::region; use rustc_data_structures::graph::implementation as graph; -use crate::ty::{self, TyCtxt}; +use rustc::middle::region; +use rustc::ty::{self, TyCtxt}; -use crate::hir::{self, PatKind}; -use crate::hir::def_id::DefId; -use crate::hir::ptr::P; +use rustc::hir::{self, PatKind}; +use rustc::hir::def_id::DefId; +use rustc::hir::ptr::P; struct CFGBuilder<'a, 'tcx> { tcx: TyCtxt<'tcx>, @@ -30,7 +30,7 @@ struct LoopScope { break_index: CFGIndex, // where to go on a `break` } -pub fn construct(tcx: TyCtxt<'_>, body: &hir::Body) -> CFG { +pub(super) fn construct(tcx: TyCtxt<'_>, body: &hir::Body) -> CFG { let mut graph = graph::Graph::new(); let entry = graph.add_node(CFGNodeData::Entry); diff --git a/src/librustc/cfg/graphviz.rs b/src/librustc_ast_borrowck/cfg/graphviz.rs similarity index 94% rename from src/librustc/cfg/graphviz.rs rename to src/librustc_ast_borrowck/cfg/graphviz.rs index 918120057d4d3..46409f1a1cebf 100644 --- a/src/librustc/cfg/graphviz.rs +++ b/src/librustc_ast_borrowck/cfg/graphviz.rs @@ -1,15 +1,12 @@ /// This module provides linkage between rustc::middle::graph and /// libgraphviz traits. -// For clarity, rename the graphviz crate locally to dot. -use graphviz as dot; - use crate::cfg; -use crate::hir; -use crate::ty::TyCtxt; +use rustc::hir; +use rustc::ty::TyCtxt; -pub type Node<'a> = (cfg::CFGIndex, &'a cfg::CFGNode); -pub type Edge<'a> = &'a cfg::CFGEdge; +pub(crate) type Node<'a> = (cfg::CFGIndex, &'a cfg::CFGNode); +pub(crate) type Edge<'a> = &'a cfg::CFGEdge; pub struct LabelledCFG<'a, 'tcx> { pub tcx: TyCtxt<'tcx>, diff --git a/src/librustc/cfg/mod.rs b/src/librustc_ast_borrowck/cfg/mod.rs similarity index 51% rename from src/librustc/cfg/mod.rs rename to src/librustc_ast_borrowck/cfg/mod.rs index 88fc7fbfad51f..981199c91d513 100644 --- a/src/librustc/cfg/mod.rs +++ b/src/librustc_ast_borrowck/cfg/mod.rs @@ -2,18 +2,18 @@ //! Uses `Graph` as the underlying representation. use rustc_data_structures::graph::implementation as graph; -use crate::ty::TyCtxt; -use crate::hir; -use crate::hir::def_id::DefId; +use rustc::ty::TyCtxt; +use rustc::hir; +use rustc::hir::def_id::DefId; mod construct; pub mod graphviz; pub struct CFG { - pub owner_def_id: DefId, - pub graph: CFGGraph, - pub entry: CFGIndex, - pub exit: CFGIndex, + owner_def_id: DefId, + pub(crate) graph: CFGGraph, + pub(crate) entry: CFGIndex, + exit: CFGIndex, } #[derive(Copy, Clone, Debug, PartialEq)] @@ -26,7 +26,7 @@ pub enum CFGNodeData { } impl CFGNodeData { - pub fn id(&self) -> hir::ItemLocalId { + pub(crate) fn id(&self) -> hir::ItemLocalId { if let CFGNodeData::AST(id) = *self { id } else { @@ -37,24 +37,19 @@ impl CFGNodeData { #[derive(Debug)] pub struct CFGEdgeData { - pub exiting_scopes: Vec + pub(crate) exiting_scopes: Vec } -pub type CFGIndex = graph::NodeIndex; +pub(crate) type CFGIndex = graph::NodeIndex; -pub type CFGGraph = graph::Graph; +pub(crate) type CFGGraph = graph::Graph; -pub type CFGNode = graph::Node; +pub(crate) type CFGNode = graph::Node; -pub type CFGEdge = graph::Edge; +pub(crate) type CFGEdge = graph::Edge; impl CFG { pub fn new(tcx: TyCtxt<'_>, body: &hir::Body) -> CFG { construct::construct(tcx, body) } - - pub fn node_is_reachable(&self, id: hir::ItemLocalId) -> bool { - self.graph.depth_traverse(self.entry, graph::OUTGOING) - .any(|idx| self.graph.node_data(idx).id() == id) - } } diff --git a/src/librustc_ast_borrowck/dataflow.rs b/src/librustc_ast_borrowck/dataflow.rs index 3a4c8c924764e..a8562901d99c5 100644 --- a/src/librustc_ast_borrowck/dataflow.rs +++ b/src/librustc_ast_borrowck/dataflow.rs @@ -3,9 +3,7 @@ //! and thus uses bitvectors. Your job is simply to specify the so-called //! GEN and KILL bits for each expression. -use rustc::cfg; -use rustc::cfg::CFGIndex; -use rustc::ty::TyCtxt; +use crate::cfg::{self, CFGIndex}; use std::mem; use std::usize; use log::debug; @@ -16,6 +14,7 @@ use rustc::util::nodemap::FxHashMap; use rustc::hir; use rustc::hir::intravisit; use rustc::hir::print as pprust; +use rustc::ty::TyCtxt; #[derive(Copy, Clone, Debug)] pub enum EntryOrExit { diff --git a/src/librustc_ast_borrowck/graphviz.rs b/src/librustc_ast_borrowck/graphviz.rs index 7a8a23ca76afc..c077dc828aba2 100644 --- a/src/librustc_ast_borrowck/graphviz.rs +++ b/src/librustc_ast_borrowck/graphviz.rs @@ -4,13 +4,12 @@ pub use Variant::*; -pub use rustc::cfg::graphviz::{Node, Edge}; -use rustc::cfg::graphviz as cfg_dot; - +pub(crate) use crate::cfg::graphviz::{Node, Edge}; +use crate::cfg::graphviz as cfg_dot; +use crate::cfg::CFGIndex; use crate::borrowck::{self, BorrowckCtxt, LoanPath}; use crate::dataflow::{DataFlowOperator, DataFlowContext, EntryOrExit}; use log::debug; -use rustc::cfg::CFGIndex; use std::rc::Rc; #[derive(Debug, Copy, Clone)] diff --git a/src/librustc_ast_borrowck/lib.rs b/src/librustc_ast_borrowck/lib.rs index dc818278a4b74..aea97fea1a9fd 100644 --- a/src/librustc_ast_borrowck/lib.rs +++ b/src/librustc_ast_borrowck/lib.rs @@ -18,5 +18,6 @@ mod borrowck; pub mod graphviz; mod dataflow; +pub mod cfg; pub use borrowck::provide; diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index cb17401f6247b..c4d3ad946f9f6 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -1,7 +1,5 @@ //! The various pretty-printing routines. -use rustc::cfg; -use rustc::cfg::graphviz::LabelledCFG; use rustc::hir; use rustc::hir::map as hir_map; use rustc::hir::map::blocks; @@ -14,6 +12,7 @@ use rustc::util::common::ErrorReported; use rustc_interface::util::ReplaceBodyWithLoop; use rustc_ast_borrowck as borrowck; use rustc_ast_borrowck::graphviz as borrowck_dot; +use rustc_ast_borrowck::cfg::{self, graphviz::LabelledCFG}; use rustc_mir::util::{write_mir_pretty, write_mir_graphviz}; use syntax::ast; From f6481ed1c31d2a3c43fab73e58901f7c25360fcb Mon Sep 17 00:00:00 2001 From: varkor Date: Fri, 6 Sep 2019 19:21:20 +0100 Subject: [PATCH 19/24] Correct pluralisation of various diagnostic messages --- src/librustc/ty/error.rs | 4 +++- src/librustc_typeck/check/pat.rs | 33 +++++++++++++++++++++--------- src/libsyntax/ext/tt/transcribe.rs | 9 ++++++-- src/libsyntax_ext/format.rs | 2 +- 4 files changed, 34 insertions(+), 14 deletions(-) diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs index fe8f94ab1d314..f67526ea4a1d9 100644 --- a/src/librustc/ty/error.rs +++ b/src/librustc/ty/error.rs @@ -200,7 +200,9 @@ impl<'tcx> ty::TyS<'tcx> { ty::Array(_, n) => { let n = tcx.lift_to_global(&n).unwrap(); match n.try_eval_usize(tcx, ty::ParamEnv::empty()) { - Some(n) => format!("array of {} elements", n).into(), + Some(n) => { + format!("array of {} element{}", n, if n != 1 { "s" } else { "" }).into() + } None => "array".into(), } } diff --git a/src/librustc_typeck/check/pat.rs b/src/librustc_typeck/check/pat.rs index 24d0659391b04..8502b89de1469 100644 --- a/src/librustc_typeck/check/pat.rs +++ b/src/librustc_typeck/check/pat.rs @@ -1098,22 +1098,35 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn error_scrutinee_inconsistent_length(&self, span: Span, min_len: u64, size: u64) { struct_span_err!( - self.tcx.sess, span, E0527, - "pattern requires {} elements but array has {}", - min_len, size + self.tcx.sess, + span, + E0527, + "pattern requires {} element{} but array has {}", + min_len, + if min_len != 1 { "s" } else { "" }, + size, ) - .span_label(span, format!("expected {} elements", size)) + .span_label(span, format!("expected {} element{}", size, if size != 1 { "s" } else { "" })) .emit(); } fn error_scrutinee_with_rest_inconsistent_length(&self, span: Span, min_len: u64, size: u64) { struct_span_err!( - self.tcx.sess, span, E0528, - "pattern requires at least {} elements but array has {}", - min_len, size - ) - .span_label(span, format!("pattern cannot match array of {} elements", size)) - .emit(); + self.tcx.sess, + span, + E0528, + "pattern requires at least {} element{} but array has {}", + min_len, + if min_len != 1 { "s" } else { "" }, + size, + ).span_label( + span, + format!( + "pattern cannot match array of {} element{}", + size, + if size != 1 { "s" } else { "" }, + ), + ).emit(); } fn error_scrutinee_unfixed_length(&self, span: Span) { diff --git a/src/libsyntax/ext/tt/transcribe.rs b/src/libsyntax/ext/tt/transcribe.rs index 30d5df13dcedb..23735727fe8cf 100644 --- a/src/libsyntax/ext/tt/transcribe.rs +++ b/src/libsyntax/ext/tt/transcribe.rs @@ -345,8 +345,13 @@ impl LockstepIterSize { LockstepIterSize::Constraint(r_len, _) if l_len == r_len => self, LockstepIterSize::Constraint(r_len, r_id) => { let msg = format!( - "meta-variable `{}` repeats {} times, but `{}` repeats {} times", - l_id, l_len, r_id, r_len + "meta-variable `{}` repeats {} time{}, but `{}` repeats {} time{}", + l_id, + l_len, + if l_len != 1 { "s" } else { "" }, + r_id, + r_len, + if r_len != 1 { "s" } else { "" }, ); LockstepIterSize::Contradiction(msg) } diff --git a/src/libsyntax_ext/format.rs b/src/libsyntax_ext/format.rs index e29f12c50c526..dec84c8286292 100644 --- a/src/libsyntax_ext/format.rs +++ b/src/libsyntax_ext/format.rs @@ -291,7 +291,7 @@ impl<'a, 'b> Context<'a, 'b> { &format!( "{} positional argument{} in format string, but {}", count, - if count > 1 { "s" } else { "" }, + if count != 1 { "s" } else { "" }, self.describe_num_args(), ), ); From 0b97726e6c524d2cc0de4c2f5b1284eca010a7b2 Mon Sep 17 00:00:00 2001 From: varkor Date: Fri, 6 Sep 2019 19:21:26 +0100 Subject: [PATCH 20/24] Update ui tests --- src/test/ui/coercion/coercion-slice.rs | 2 +- src/test/ui/coercion/coercion-slice.stderr | 2 +- src/test/ui/issues/issue-15783.rs | 8 ++++---- src/test/ui/issues/issue-15783.stderr | 2 +- src/test/ui/match/match-vec-mismatch.stderr | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/test/ui/coercion/coercion-slice.rs b/src/test/ui/coercion/coercion-slice.rs index 312b634c9fd0b..b69edcf260637 100644 --- a/src/test/ui/coercion/coercion-slice.rs +++ b/src/test/ui/coercion/coercion-slice.rs @@ -4,5 +4,5 @@ fn main() { let _: &[i32] = [0]; //~^ ERROR mismatched types //~| expected type `&[i32]` - //~| expected &[i32], found array of 1 elements + //~| expected &[i32], found array of 1 element } diff --git a/src/test/ui/coercion/coercion-slice.stderr b/src/test/ui/coercion/coercion-slice.stderr index 6fa712371178b..ccd776e987938 100644 --- a/src/test/ui/coercion/coercion-slice.stderr +++ b/src/test/ui/coercion/coercion-slice.stderr @@ -4,7 +4,7 @@ error[E0308]: mismatched types LL | let _: &[i32] = [0]; | ^^^ | | - | expected &[i32], found array of 1 elements + | expected &[i32], found array of 1 element | help: consider borrowing here: `&[0]` | = note: expected type `&[i32]` diff --git a/src/test/ui/issues/issue-15783.rs b/src/test/ui/issues/issue-15783.rs index 77eae914fa1ca..5189f550cfbd6 100644 --- a/src/test/ui/issues/issue-15783.rs +++ b/src/test/ui/issues/issue-15783.rs @@ -6,9 +6,9 @@ fn main() { let name = "Foo"; let x = Some(&[name]); let msg = foo(x); -//~^ ERROR mismatched types -//~| expected type `std::option::Option<&[&str]>` -//~| found type `std::option::Option<&[&str; 1]>` -//~| expected slice, found array of 1 elements + //~^ ERROR mismatched types + //~| expected type `std::option::Option<&[&str]>` + //~| found type `std::option::Option<&[&str; 1]>` + //~| expected slice, found array of 1 element assert_eq!(msg, 3); } diff --git a/src/test/ui/issues/issue-15783.stderr b/src/test/ui/issues/issue-15783.stderr index 595fe4025ad48..1d54b2830d6c5 100644 --- a/src/test/ui/issues/issue-15783.stderr +++ b/src/test/ui/issues/issue-15783.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/issue-15783.rs:8:19 | LL | let msg = foo(x); - | ^ expected slice, found array of 1 elements + | ^ expected slice, found array of 1 element | = note: expected type `std::option::Option<&[&str]>` found type `std::option::Option<&[&str; 1]>` diff --git a/src/test/ui/match/match-vec-mismatch.stderr b/src/test/ui/match/match-vec-mismatch.stderr index 2f1bbb7621659..a3523bb689e6b 100644 --- a/src/test/ui/match/match-vec-mismatch.stderr +++ b/src/test/ui/match/match-vec-mismatch.stderr @@ -10,7 +10,7 @@ error[E0529]: expected an array or slice, found `std::string::String` LL | ['f', 'o', ..] => {} | ^^^^^^^^^^^^^^ pattern cannot match with input type `std::string::String` -error[E0527]: pattern requires 1 elements but array has 3 +error[E0527]: pattern requires 1 element but array has 3 --> $DIR/match-vec-mismatch.rs:20:9 | LL | [0] => {}, From 055d3798d40ca0eefa52fa152bf3c913240281af Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sat, 31 Aug 2019 16:03:54 +0300 Subject: [PATCH 21/24] reduce visibility --- src/libsyntax/parse/parser.rs | 22 +++++++++++----------- src/libsyntax/util/parser.rs | 2 +- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 49b05551bae86..ab5462baaf721 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -132,7 +132,7 @@ pub struct Parser<'a> { /// into modules, and sub-parsers have new values for this name. pub root_module_name: Option, crate expected_tokens: Vec, - crate token_cursor: TokenCursor, + token_cursor: TokenCursor, desugar_doc_comments: bool, /// `true` we should configure out of line modules as we parse. pub cfg_mods: bool, @@ -161,19 +161,19 @@ impl<'a> Drop for Parser<'a> { } #[derive(Clone)] -crate struct TokenCursor { - crate frame: TokenCursorFrame, - crate stack: Vec, +struct TokenCursor { + frame: TokenCursorFrame, + stack: Vec, } #[derive(Clone)] -crate struct TokenCursorFrame { - crate delim: token::DelimToken, - crate span: DelimSpan, - crate open_delim: bool, - crate tree_cursor: tokenstream::Cursor, - crate close_delim: bool, - crate last_token: LastToken, +struct TokenCursorFrame { + delim: token::DelimToken, + span: DelimSpan, + open_delim: bool, + tree_cursor: tokenstream::Cursor, + close_delim: bool, + last_token: LastToken, } /// This is used in `TokenCursorFrame` above to track tokens that are consumed diff --git a/src/libsyntax/util/parser.rs b/src/libsyntax/util/parser.rs index a501541c95909..fceaed360cdb4 100644 --- a/src/libsyntax/util/parser.rs +++ b/src/libsyntax/util/parser.rs @@ -69,7 +69,7 @@ pub enum Fixity { impl AssocOp { /// Creates a new AssocOP from a token - pub fn from_token(t: &Token) -> Option { + crate fn from_token(t: &Token) -> Option { use AssocOp::*; match t.kind { token::BinOpEq(k) => Some(AssignOp(k)), From a26ee8586c150e786ffaa47fba06ebcc671373d1 Mon Sep 17 00:00:00 2001 From: Matthew Maurer Date: Fri, 6 Sep 2019 12:41:54 -0700 Subject: [PATCH 22/24] Include compiler-rt in the source tarball In #60981 we switched to using src/llvm-project/compiler-rt inside compiler-builtins rather than a separate copy of it. In order to have the "c" feature turn on in builds from the source tarball, we need to include that path in its creation. fixes #64239 --- src/bootstrap/dist.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 0f4ac63651ca9..500d5766a899e 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -808,6 +808,7 @@ fn copy_src_dirs(builder: &Builder<'_>, src_dirs: &[&str], exclude_dirs: &[&str] "llvm-project/lld", "llvm-project\\lld", "llvm-project/lldb", "llvm-project\\lldb", "llvm-project/llvm", "llvm-project\\llvm", + "llvm-project/compiler-rt", "llvm-project\\compiler-rt", ]; if spath.contains("llvm-project") && !spath.ends_with("llvm-project") && !LLVM_PROJECTS.iter().any(|path| spath.contains(path)) From 7dd5c661081b12de72e5a869b9c80131f7a6b464 Mon Sep 17 00:00:00 2001 From: Aditya Atluri Date: Fri, 6 Sep 2019 12:54:42 -0700 Subject: [PATCH 23/24] Added more prereqs and note about default directory --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 724bc36ecc6fb..4c2e4eef6552f 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,7 @@ or reading the [rustc guide][rustcguidebuild]. * `cmake` 3.4.3 or later * `curl` * `git` + * `ssl` which comes in `libssl-dev` or `openssl-devel` 2. Clone the [source] with `git`: @@ -56,6 +57,8 @@ or reading the [rustc guide][rustcguidebuild]. an installation (using `./x.py install`) that you set the `prefix` value in the `[install]` section to a directory that you have write permissions. + Create install directory if you are not installing in default directory + 4. Build and install: ```sh From 3dde650efa3a8910cccaef38e89fe74272d67c91 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 6 Sep 2019 23:41:54 +0300 Subject: [PATCH 24/24] Move injection of attributes from command line to `libsyntax_ext` --- src/librustc_interface/passes.rs | 4 +- src/libsyntax/attr/mod.rs | 59 +++++++----------------------- src/libsyntax/parse/attr.rs | 2 +- src/libsyntax_ext/cmdline_attrs.rs | 30 +++++++++++++++ src/libsyntax_ext/lib.rs | 1 + 5 files changed, 48 insertions(+), 48 deletions(-) create mode 100644 src/libsyntax_ext/cmdline_attrs.rs diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs index 24b44964e4fd2..08ae3360eb94f 100644 --- a/src/librustc_interface/passes.rs +++ b/src/librustc_interface/passes.rs @@ -230,7 +230,9 @@ pub fn register_plugins<'a>( crate_name: &str, ) -> Result<(ast::Crate, PluginInfo)> { krate = time(sess, "attributes injection", || { - syntax::attr::inject(krate, &sess.parse_sess, &sess.opts.debugging_opts.crate_attr) + syntax_ext::cmdline_attrs::inject( + krate, &sess.parse_sess, &sess.opts.debugging_opts.crate_attr + ) }); let (mut krate, features) = syntax::config::features( diff --git a/src/libsyntax/attr/mod.rs b/src/libsyntax/attr/mod.rs index 0e5cfa73a9e3a..69de3150354e7 100644 --- a/src/libsyntax/attr/mod.rs +++ b/src/libsyntax/attr/mod.rs @@ -16,7 +16,7 @@ use crate::mut_visit::visit_clobber; use crate::source_map::{BytePos, Spanned, DUMMY_SP}; use crate::parse::lexer::comments::{doc_comment_style, strip_doc_comment_decoration}; use crate::parse::parser::Parser; -use crate::parse::{self, ParseSess, PResult}; +use crate::parse::{ParseSess, PResult}; use crate::parse::token::{self, Token}; use crate::ptr::P; use crate::symbol::{sym, Symbol}; @@ -25,7 +25,7 @@ use crate::tokenstream::{TokenStream, TokenTree, DelimSpan}; use crate::GLOBALS; use log::debug; -use syntax_pos::{FileName, Span}; +use syntax_pos::Span; use std::iter; use std::ops::DerefMut; @@ -381,28 +381,25 @@ crate fn mk_attr_id() -> AttrId { AttrId(id) } -/// Returns an inner attribute with the given value and span. -pub fn mk_attr_inner(item: MetaItem) -> Attribute { +pub fn mk_attr(style: AttrStyle, path: Path, tokens: TokenStream, span: Span) -> Attribute { Attribute { id: mk_attr_id(), - style: ast::AttrStyle::Inner, - path: item.path, - tokens: item.node.tokens(item.span), + style, + path, + tokens, is_sugared_doc: false, - span: item.span, + span, } } +/// Returns an inner attribute with the given value and span. +pub fn mk_attr_inner(item: MetaItem) -> Attribute { + mk_attr(AttrStyle::Inner, item.path, item.node.tokens(item.span), item.span) +} + /// Returns an outer attribute with the given value and span. pub fn mk_attr_outer(item: MetaItem) -> Attribute { - Attribute { - id: mk_attr_id(), - style: ast::AttrStyle::Outer, - path: item.path, - tokens: item.node.tokens(item.span), - is_sugared_doc: false, - span: item.span, - } + mk_attr(AttrStyle::Outer, item.path, item.node.tokens(item.span), item.span) } pub fn mk_sugared_doc_attr(text: Symbol, span: Span) -> Attribute { @@ -716,33 +713,3 @@ derive_has_attrs! { Item, Expr, Local, ast::ForeignItem, ast::StructField, ast::ImplItem, ast::TraitItem, ast::Arm, ast::Field, ast::FieldPat, ast::Variant, ast::Param } - -pub fn inject(mut krate: ast::Crate, parse_sess: &ParseSess, attrs: &[String]) -> ast::Crate { - for raw_attr in attrs { - let mut parser = parse::new_parser_from_source_str( - parse_sess, - FileName::cli_crate_attr_source_code(&raw_attr), - raw_attr.clone(), - ); - - let start_span = parser.token.span; - let (path, tokens) = panictry!(parser.parse_meta_item_unrestricted()); - let end_span = parser.token.span; - if parser.token != token::Eof { - parse_sess.span_diagnostic - .span_err(start_span.to(end_span), "invalid crate attribute"); - continue; - } - - krate.attrs.push(Attribute { - id: mk_attr_id(), - style: AttrStyle::Inner, - path, - tokens, - is_sugared_doc: false, - span: start_span.to(end_span), - }); - } - - krate -} diff --git a/src/libsyntax/parse/attr.rs b/src/libsyntax/parse/attr.rs index 671178223f503..d9c4baad49ded 100644 --- a/src/libsyntax/parse/attr.rs +++ b/src/libsyntax/parse/attr.rs @@ -176,7 +176,7 @@ impl<'a> Parser<'a> { /// PATH /// PATH `=` TOKEN_TREE /// The delimiters or `=` are still put into the resulting token stream. - crate fn parse_meta_item_unrestricted(&mut self) -> PResult<'a, (ast::Path, TokenStream)> { + pub fn parse_meta_item_unrestricted(&mut self) -> PResult<'a, (ast::Path, TokenStream)> { let meta = match self.token.kind { token::Interpolated(ref nt) => match **nt { Nonterminal::NtMeta(ref meta) => Some(meta.clone()), diff --git a/src/libsyntax_ext/cmdline_attrs.rs b/src/libsyntax_ext/cmdline_attrs.rs new file mode 100644 index 0000000000000..bb8e3df3db921 --- /dev/null +++ b/src/libsyntax_ext/cmdline_attrs.rs @@ -0,0 +1,30 @@ +//! Attributes injected into the crate root from command line using `-Z crate-attr`. + +use syntax::ast::{self, AttrStyle}; +use syntax::attr::mk_attr; +use syntax::panictry; +use syntax::parse::{self, token, ParseSess}; +use syntax_pos::FileName; + +pub fn inject(mut krate: ast::Crate, parse_sess: &ParseSess, attrs: &[String]) -> ast::Crate { + for raw_attr in attrs { + let mut parser = parse::new_parser_from_source_str( + parse_sess, + FileName::cli_crate_attr_source_code(&raw_attr), + raw_attr.clone(), + ); + + let start_span = parser.token.span; + let (path, tokens) = panictry!(parser.parse_meta_item_unrestricted()); + let end_span = parser.token.span; + if parser.token != token::Eof { + parse_sess.span_diagnostic + .span_err(start_span.to(end_span), "invalid crate attribute"); + continue; + } + + krate.attrs.push(mk_attr(AttrStyle::Inner, path, tokens, start_span.to(end_span))); + } + + krate +} diff --git a/src/libsyntax_ext/lib.rs b/src/libsyntax_ext/lib.rs index 26ef80b2b06df..5c0a63ebbe7cb 100644 --- a/src/libsyntax_ext/lib.rs +++ b/src/libsyntax_ext/lib.rs @@ -40,6 +40,7 @@ mod source_util; mod test; mod trace_macros; +pub mod cmdline_attrs; pub mod plugin_macro_defs; pub mod proc_macro_harness; pub mod standard_library_imports;