From dae4c7b1ff62da4901caf28653baa3133a40496c Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 18 Nov 2018 03:25:59 +0300 Subject: [PATCH] resolve: Implement edition hygiene for imports and absolute paths Use per-span hygiene in a few other places in resolve Prefer `rust_2015`/`rust_2018` helpers to comparing editions --- src/librustc/ty/context.rs | 11 +-- src/librustc/ty/item_path.rs | 3 +- src/librustc_resolve/build_reduced_graph.rs | 19 +++--- src/librustc_resolve/error_reporting.rs | 5 +- src/librustc_resolve/lib.rs | 67 +++++++++---------- src/librustc_resolve/macros.rs | 5 +- src/libsyntax/parse/parser.rs | 29 ++++---- src/libsyntax_pos/lib.rs | 10 +++ src/libsyntax_pos/symbol.rs | 3 +- .../auxiliary/edition-imports-2015.rs | 19 ++++++ .../proc-macro/edition-imports-2018.rs | 24 +++++++ src/test/ui/editions/auxiliary/absolute.rs | 1 + .../auxiliary/edition-imports-2015.rs | 17 +++++ .../auxiliary/edition-imports-2018.rs | 17 +++++ src/test/ui/editions/edition-imports-2015.rs | 28 ++++++++ .../ui/editions/edition-imports-2015.stderr | 10 +++ src/test/ui/editions/edition-imports-2018.rs | 33 +++++++++ 17 files changed, 226 insertions(+), 75 deletions(-) create mode 100644 src/test/ui-fulldeps/proc-macro/auxiliary/edition-imports-2015.rs create mode 100644 src/test/ui-fulldeps/proc-macro/edition-imports-2018.rs create mode 100644 src/test/ui/editions/auxiliary/absolute.rs create mode 100644 src/test/ui/editions/auxiliary/edition-imports-2015.rs create mode 100644 src/test/ui/editions/auxiliary/edition-imports-2018.rs create mode 100644 src/test/ui/editions/edition-imports-2015.rs create mode 100644 src/test/ui/editions/edition-imports-2015.stderr create mode 100644 src/test/ui/editions/edition-imports-2018.rs diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 22d5ea6e4bc..d383d8375a9 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -1478,15 +1478,8 @@ pub fn all_pat_vars_are_implicit_refs_within_guards(self) -> bool { /// done with either: `-Ztwo-phase-borrows`, `#![feature(nll)]`, /// or by opting into an edition after 2015. pub fn two_phase_borrows(self) -> bool { - if self.features().nll || self.sess.opts.debugging_opts.two_phase_borrows { - return true; - } - - match self.sess.edition() { - Edition::Edition2015 => false, - Edition::Edition2018 => true, - _ => true, - } + self.sess.rust_2018() || self.features().nll || + self.sess.opts.debugging_opts.two_phase_borrows } /// What mode(s) of borrowck should we run? AST? MIR? both? diff --git a/src/librustc/ty/item_path.rs b/src/librustc/ty/item_path.rs index f6c90ab0a1a..350e55288ea 100644 --- a/src/librustc/ty/item_path.rs +++ b/src/librustc/ty/item_path.rs @@ -14,7 +14,6 @@ use middle::cstore::{ExternCrate, ExternCrateSource}; use syntax::ast; use syntax::symbol::{keywords, LocalInternedString, Symbol}; -use syntax_pos::edition::Edition; use std::cell::Cell; use std::fmt::Debug; @@ -140,7 +139,7 @@ pub fn push_krate_path(self, buffer: &mut T, cnum: CrateNum, pushed_prelude_c debug!("push_krate_path: name={:?}", name); buffer.push(&name); } - } else if self.sess.edition() == Edition::Edition2018 && !pushed_prelude_crate { + } else if self.sess.rust_2018() && !pushed_prelude_crate { SHOULD_PREFIX_WITH_CRATE.with(|flag| { // We only add the `crate::` keyword where appropriate. In particular, // when we've not previously pushed a prelude crate to this path. diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 72fe7355e4c..3f0780191fb 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -133,14 +133,17 @@ fn build_reduced_graph_for_use_tree( // The root is prepended lazily, when the first non-empty prefix or terminating glob // appears, so imports in braced groups can have roots prepended independently. let is_glob = if let ast::UseTreeKind::Glob = use_tree.kind { true } else { false }; - let crate_root = if !self.session.rust_2018() && - prefix_iter.peek().map_or(is_glob, |seg| !seg.ident.is_path_segment_keyword()) { - Some(Segment::from_ident(Ident::new( - keywords::CrateRoot.name(), use_tree.prefix.span.shrink_to_lo() - ))) - } else { - None - }; + let crate_root = match prefix_iter.peek() { + Some(seg) if !seg.ident.is_path_segment_keyword() && seg.ident.span.rust_2015() => { + Some(seg.ident.span.ctxt()) + } + None if is_glob && use_tree.span.rust_2015() => { + Some(use_tree.span.ctxt()) + } + _ => None, + }.map(|ctxt| Segment::from_ident(Ident::new( + keywords::CrateRoot.name(), use_tree.prefix.span.shrink_to_lo().with_ctxt(ctxt) + ))); let prefix = crate_root.into_iter().chain(prefix_iter).collect::>(); debug!("build_reduced_graph_for_use_tree: prefix={:?}", prefix); diff --git a/src/librustc_resolve/error_reporting.rs b/src/librustc_resolve/error_reporting.rs index 263d23d133e..e2a6303f579 100644 --- a/src/librustc_resolve/error_reporting.rs +++ b/src/librustc_resolve/error_reporting.rs @@ -33,7 +33,8 @@ pub(crate) fn make_path_suggestion( (Some(fst), Some(snd)) if fst.ident.name == keywords::CrateRoot.name() && !snd.ident.is_path_segment_keyword() => {} // `ident::...` on 2018 - (Some(fst), _) if self.session.rust_2018() && !fst.ident.is_path_segment_keyword() => { + (Some(fst), _) if fst.ident.span.rust_2018() && + !fst.ident.is_path_segment_keyword() => { // Insert a placeholder that's later replaced by `self`/`super`/etc. path.insert(0, Segment::from_ident(keywords::Invalid.ident())); } @@ -141,7 +142,7 @@ fn make_external_crate_suggestion( mut path: Vec, parent_scope: &ParentScope<'b>, ) -> Option<(Vec, Option)> { - if !self.session.rust_2018() { + if path[1].ident.span.rust_2015() { return None; } diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 443b1ccdef8..2e7ed80c91b 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -2354,14 +2354,10 @@ fn resolve_adt(&mut self, item: &Item, generics: &Generics) { } fn future_proof_import(&mut self, use_tree: &ast::UseTree) { - if !self.session.rust_2018() { - return; - } - let segments = &use_tree.prefix.segments; if !segments.is_empty() { let ident = segments[0].ident; - if ident.is_path_segment_keyword() { + if ident.is_path_segment_keyword() || ident.span.rust_2015() { return; } @@ -3181,10 +3177,10 @@ fn smart_resolve_path_fragment(&mut self, // Try to lookup the name in more relaxed fashion for better error reporting. let ident = path.last().unwrap().ident; - let candidates = this.lookup_import_candidates(ident.name, ns, is_expected); + let candidates = this.lookup_import_candidates(ident, ns, is_expected); if candidates.is_empty() && is_expected(Def::Enum(DefId::local(CRATE_DEF_INDEX))) { let enum_candidates = - this.lookup_import_candidates(ident.name, ns, is_enum_variant); + this.lookup_import_candidates(ident, ns, is_enum_variant); let mut enum_candidates = enum_candidates.iter() .map(|suggestion| import_candidate_to_paths(&suggestion)).collect::>(); enum_candidates.sort(); @@ -3772,7 +3768,7 @@ fn resolve_path( continue; } if name == keywords::Extern.name() || - name == keywords::CrateRoot.name() && self.session.rust_2018() { + name == keywords::CrateRoot.name() && ident.span.rust_2018() { module = Some(ModuleOrUniformRoot::UniformRoot(UniformRootKind::ExternPrelude)); continue; @@ -3875,7 +3871,7 @@ fn resolve_path( let msg = if module_def == self.graph_root.def() { let is_mod = |def| match def { Def::Mod(..) => true, _ => false }; let mut candidates = - self.lookup_import_candidates(name, TypeNS, is_mod); + self.lookup_import_candidates(ident, TypeNS, is_mod); candidates.sort_by_cached_key(|c| { (c.path.segments.len(), c.path.to_string()) }); @@ -3911,11 +3907,6 @@ fn lint_if_path_starts_with_module( path_span: Span, second_binding: Option<&NameBinding>, ) { - // In the 2018 edition this lint is a hard error, so nothing to do - if self.session.rust_2018() { - return - } - let (diag_id, diag_span) = match crate_lint { CrateLint::No => return, CrateLint::SimplePath(id) => (id, path_span), @@ -3924,8 +3915,9 @@ fn lint_if_path_starts_with_module( }; let first_name = match path.get(0) { - Some(ident) => ident.ident.name, - None => return, + // In the 2018 edition this lint is a hard error, so nothing to do + Some(seg) if seg.ident.span.rust_2015() => seg.ident.name, + _ => return, }; // We're only interested in `use` paths which should start with @@ -4507,7 +4499,7 @@ fn get_traits_in_module_containing_item(&mut self, } fn lookup_import_candidates_from_module(&mut self, - lookup_name: Name, + lookup_ident: Ident, namespace: Namespace, start_module: &'a ModuleData<'a>, crate_name: Ident, @@ -4534,11 +4526,11 @@ fn lookup_import_candidates_from_module(&mut self, if !name_binding.is_importable() { return; } // collect results based on the filter function - if ident.name == lookup_name && ns == namespace { + if ident.name == lookup_ident.name && ns == namespace { if filter_fn(name_binding.def()) { // create the path let mut segms = path_segments.clone(); - if self.session.rust_2018() { + if lookup_ident.span.rust_2018() { // crate-local absolute paths start with `crate::` in edition 2018 // FIXME: may also be stabilized for Rust 2015 (Issues #45477, #44660) segms.insert( @@ -4572,7 +4564,7 @@ fn lookup_import_candidates_from_module(&mut self, let is_extern_crate_that_also_appears_in_prelude = name_binding.is_extern_crate() && - self.session.rust_2018(); + lookup_ident.span.rust_2018(); let is_visible_to_user = !in_module_is_extern || name_binding.vis == ty::Visibility::Public; @@ -4599,16 +4591,16 @@ fn lookup_import_candidates_from_module(&mut self, /// NOTE: The method does not look into imports, but this is not a problem, /// since we report the definitions (thus, the de-aliased imports). fn lookup_import_candidates(&mut self, - lookup_name: Name, + lookup_ident: Ident, namespace: Namespace, filter_fn: FilterFn) -> Vec where FilterFn: Fn(Def) -> bool { let mut suggestions = self.lookup_import_candidates_from_module( - lookup_name, namespace, self.graph_root, keywords::Crate.ident(), &filter_fn); + lookup_ident, namespace, self.graph_root, keywords::Crate.ident(), &filter_fn); - if self.session.rust_2018() { + if lookup_ident.span.rust_2018() { let extern_prelude_names = self.extern_prelude.clone(); for (ident, _) in extern_prelude_names.into_iter() { if let Some(crate_id) = self.crate_loader.maybe_process_path_extern(ident.name, @@ -4620,7 +4612,7 @@ fn lookup_import_candidates(&mut self, self.populate_module_if_necessary(&crate_root); suggestions.extend(self.lookup_import_candidates_from_module( - lookup_name, namespace, crate_root, ident, &filter_fn)); + lookup_ident, namespace, crate_root, ident, &filter_fn)); } } } @@ -4712,19 +4704,26 @@ fn resolve_visibility(&mut self, vis: &ast::Visibility) -> ty::Visibility { ast::VisibilityKind::Restricted { ref path, id, .. } => { // For visibilities we are not ready to provide correct implementation of "uniform // paths" right now, so on 2018 edition we only allow module-relative paths for now. - let first_ident = path.segments[0].ident; - if self.session.rust_2018() && !first_ident.is_path_segment_keyword() { + // On 2015 edition visibilities are resolved as crate-relative by default, + // so we are prepending a root segment if necessary. + let ident = path.segments.get(0).expect("empty path in visibility").ident; + let crate_root = if ident.is_path_segment_keyword() { + None + } else if ident.span.rust_2018() { let msg = "relative paths are not supported in visibilities on 2018 edition"; - self.session.struct_span_err(first_ident.span, msg) + self.session.struct_span_err(ident.span, msg) .span_suggestion(path.span, "try", format!("crate::{}", path)) .emit(); return ty::Visibility::Public; - } - // On 2015 visibilities are resolved as crate-relative by default, - // add starting root segment if necessary. - let segments = path.make_root().iter().chain(path.segments.iter()) - .map(|seg| Segment { ident: seg.ident, id: Some(seg.id) }) - .collect::>(); + } else { + let ctxt = ident.span.ctxt(); + Some(Segment::from_ident(Ident::new( + keywords::CrateRoot.name(), path.span.shrink_to_lo().with_ctxt(ctxt) + ))) + }; + + let segments = crate_root.into_iter() + .chain(path.segments.iter().map(|seg| seg.into())).collect::>(); let def = self.smart_resolve_path_fragment( id, None, @@ -4837,7 +4836,7 @@ fn report_ambiguity_error(&self, ambiguity_error: &AmbiguityError) { help_msgs.push(format!("consider adding an explicit import of \ `{ident}` to disambiguate", ident = ident)) } - if b.is_extern_crate() && self.session.rust_2018() { + if b.is_extern_crate() && ident.span.rust_2018() { help_msgs.push(format!("use `::{ident}` to refer to this {thing} unambiguously", ident = ident, thing = b.descr())) } diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 581756dc6bf..6fa9110fedb 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -605,6 +605,7 @@ struct Flags: u8 { assert!(force || !record_used); // `record_used` implies `force` assert!(macro_kind.is_none() || !is_import); // `is_import` implies no macro kind + let rust_2015 = ident.span.rust_2015(); ident = ident.modern(); // Make sure `self`, `super` etc produce an error when passed to here. @@ -696,7 +697,7 @@ struct Flags: u8 { } } WhereToResolve::MacroUsePrelude => { - if use_prelude || self.session.rust_2015() { + if use_prelude || rust_2015 { match self.macro_use_prelude.get(&ident.name).cloned() { Some(binding) => Ok((binding, Flags::PRELUDE | Flags::MISC_FROM_PRELUDE)), @@ -725,7 +726,7 @@ struct Flags: u8 { } } WhereToResolve::LegacyPluginHelpers => { - if (use_prelude || self.session.rust_2015()) && + if (use_prelude || rust_2015) && self.session.plugin_attributes.borrow().iter() .any(|(name, _)| ident.name == &**name) { let binding = (Def::NonMacroAttr(NonMacroAttrKind::LegacyPluginHelper), diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index e2f09affd4f..c82ebd6aa51 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -43,7 +43,7 @@ use ast::{RangeEnd, RangeSyntax}; use {ast, attr}; use source_map::{self, SourceMap, Spanned, respan}; -use syntax_pos::{self, Span, MultiSpan, BytePos, FileName, edition::Edition}; +use syntax_pos::{self, Span, MultiSpan, BytePos, FileName}; use errors::{self, Applicability, DiagnosticBuilder, DiagnosticId}; use parse::{self, SeqSep, classify, token}; use parse::lexer::TokenAndSpan; @@ -1404,11 +1404,7 @@ fn parse_trait_item_(&mut self, // definition... // We don't allow argument names to be left off in edition 2018. - if p.span.edition() >= Edition::Edition2018 { - p.parse_arg_general(true) - } else { - p.parse_arg_general(false) - } + p.parse_arg_general(p.span.rust_2018()) })?; generics.where_clause = self.parse_where_clause()?; @@ -1601,9 +1597,9 @@ fn parse_ty_common(&mut self, allow_plus: bool, allow_qpath_recovery: bool) impl_dyn_multi = bounds.len() > 1 || self.prev_token_kind == PrevTokenKind::Plus; TyKind::ImplTrait(ast::DUMMY_NODE_ID, bounds) } else if self.check_keyword(keywords::Dyn) && - (self.span.edition() == Edition::Edition2018 || + (self.span.rust_2018() || self.look_ahead(1, |t| t.can_begin_bound() && - !can_continue_type_after_non_fn_ident(t))) { + !can_continue_type_after_non_fn_ident(t))) { self.bump(); // `dyn` // Always parse bounds greedily for better error recovery. let bounds = self.parse_generic_bounds()?; @@ -2084,8 +2080,9 @@ pub fn parse_path(&mut self, style: PathStyle) -> PResult<'a, ast::Path> { let lo = self.meta_var_span.unwrap_or(self.span); let mut segments = Vec::new(); + let mod_sep_ctxt = self.span.ctxt(); if self.eat(&token::ModSep) { - segments.push(PathSegment::crate_root(lo.shrink_to_lo())); + segments.push(PathSegment::crate_root(lo.shrink_to_lo().with_ctxt(mod_sep_ctxt))); } self.parse_path_segments(&mut segments, style, enable_warning)?; @@ -2423,8 +2420,7 @@ fn parse_bottom_expr(&mut self) -> PResult<'a, P> { hi = path.span; return Ok(self.mk_expr(lo.to(hi), ExprKind::Path(Some(qself), path), attrs)); } - if self.span.edition() >= Edition::Edition2018 && - self.check_keyword(keywords::Async) + if self.span.rust_2018() && self.check_keyword(keywords::Async) { if self.is_async_block() { // check for `async {` and `async move {` return self.parse_async_block(attrs); @@ -3440,7 +3436,7 @@ fn parse_lambda_expr(&mut self, } else { Movability::Movable }; - let asyncness = if self.span.edition() >= Edition::Edition2018 { + let asyncness = if self.span.rust_2018() { self.parse_asyncness() } else { IsAsync::NotAsync @@ -4562,9 +4558,7 @@ fn is_do_catch_block(&mut self) -> bool { fn is_try_block(&mut self) -> bool { self.token.is_keyword(keywords::Try) && self.look_ahead(1, |t| *t == token::OpenDelim(token::Brace)) && - - self.span.edition() >= Edition::Edition2018 && - + self.span.rust_2018() && // prevent `while try {} {}`, `if try {} {} else {}`, etc. !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL) } @@ -7648,8 +7642,11 @@ fn parse_use_tree(&mut self) -> PResult<'a, UseTree> { self.check(&token::BinOp(token::Star)) || self.is_import_coupler() { // `use *;` or `use ::*;` or `use {...};` or `use ::{...};` + let mod_sep_ctxt = self.span.ctxt(); if self.eat(&token::ModSep) { - prefix.segments.push(PathSegment::crate_root(lo.shrink_to_lo())); + prefix.segments.push( + PathSegment::crate_root(lo.shrink_to_lo().with_ctxt(mod_sep_ctxt)) + ); } if self.eat(&token::BinOp(token::Star)) { diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index a780a38ff96..65f6d27239b 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -325,6 +325,16 @@ pub fn edition(self) -> edition::Edition { |einfo| einfo.edition) } + #[inline] + pub fn rust_2015(&self) -> bool { + self.edition() == edition::Edition::Edition2015 + } + + #[inline] + pub fn rust_2018(&self) -> bool { + self.edition() >= edition::Edition::Edition2018 + } + /// Return the source callee. /// /// Returns `None` if the supplied span has no expansion trace, diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs index 361353c82e2..e333a4f2176 100644 --- a/src/libsyntax_pos/symbol.rs +++ b/src/libsyntax_pos/symbol.rs @@ -12,7 +12,6 @@ //! allows bidirectional lookup; i.e. given a value, one can easily find the //! type, and vice versa. -use edition::Edition; use hygiene::SyntaxContext; use {Span, DUMMY_SP, GLOBALS}; @@ -444,7 +443,7 @@ pub fn is_used_keyword(self) -> bool { pub fn is_unused_keyword(self) -> bool { // Note: `span.edition()` is relatively expensive, don't call it unless necessary. self.name >= keywords::Abstract.name() && self.name <= keywords::Yield.name() || - self.name.is_unused_keyword_2018() && self.span.edition() == Edition::Edition2018 + self.name.is_unused_keyword_2018() && self.span.rust_2018() } /// Returns `true` if the token is either a special identifier or a keyword. diff --git a/src/test/ui-fulldeps/proc-macro/auxiliary/edition-imports-2015.rs b/src/test/ui-fulldeps/proc-macro/auxiliary/edition-imports-2015.rs new file mode 100644 index 00000000000..5bb818f7d23 --- /dev/null +++ b/src/test/ui-fulldeps/proc-macro/auxiliary/edition-imports-2015.rs @@ -0,0 +1,19 @@ +// edition:2015 +// no-prefer-dynamic + +#![crate_type = "proc-macro"] + +extern crate proc_macro; + +use proc_macro::TokenStream; + +#[proc_macro_derive(Derive2015)] +pub fn derive_2015(_: TokenStream) -> TokenStream { + " + use import::Path; + + fn check_absolute() { + let x = ::absolute::Path; + } + ".parse().unwrap() +} diff --git a/src/test/ui-fulldeps/proc-macro/edition-imports-2018.rs b/src/test/ui-fulldeps/proc-macro/edition-imports-2018.rs new file mode 100644 index 00000000000..f8d6bc5e078 --- /dev/null +++ b/src/test/ui-fulldeps/proc-macro/edition-imports-2018.rs @@ -0,0 +1,24 @@ +// compile-pass +// edition:2018 +// aux-build:edition-imports-2015.rs + +#[macro_use] +extern crate edition_imports_2015; + +mod import { + pub struct Path; +} +mod absolute { + pub struct Path; +} + +mod check { + #[derive(Derive2015)] // OK + struct S; + + fn check() { + Path; + } +} + +fn main() {} diff --git a/src/test/ui/editions/auxiliary/absolute.rs b/src/test/ui/editions/auxiliary/absolute.rs new file mode 100644 index 00000000000..d596f97355f --- /dev/null +++ b/src/test/ui/editions/auxiliary/absolute.rs @@ -0,0 +1 @@ +pub struct Path; diff --git a/src/test/ui/editions/auxiliary/edition-imports-2015.rs b/src/test/ui/editions/auxiliary/edition-imports-2015.rs new file mode 100644 index 00000000000..fb1a89d4022 --- /dev/null +++ b/src/test/ui/editions/auxiliary/edition-imports-2015.rs @@ -0,0 +1,17 @@ +// edition:2015 + +#[macro_export] +macro_rules! gen_imports { () => { + use import::Path; + // use std::collections::LinkedList; // FIXME + + fn check_absolute() { + ::absolute::Path; + // ::std::collections::LinkedList::::new(); // FIXME + } +}} + +#[macro_export] +macro_rules! gen_glob { () => { + use *; +}} diff --git a/src/test/ui/editions/auxiliary/edition-imports-2018.rs b/src/test/ui/editions/auxiliary/edition-imports-2018.rs new file mode 100644 index 00000000000..b08dc499a0d --- /dev/null +++ b/src/test/ui/editions/auxiliary/edition-imports-2018.rs @@ -0,0 +1,17 @@ +// edition:2018 + +#[macro_export] +macro_rules! gen_imports { () => { + use import::Path; + use std::collections::LinkedList; + + fn check_absolute() { + ::absolute::Path; + ::std::collections::LinkedList::::new(); + } +}} + +#[macro_export] +macro_rules! gen_glob { () => { + use *; +}} diff --git a/src/test/ui/editions/edition-imports-2015.rs b/src/test/ui/editions/edition-imports-2015.rs new file mode 100644 index 00000000000..b89ca28e279 --- /dev/null +++ b/src/test/ui/editions/edition-imports-2015.rs @@ -0,0 +1,28 @@ +// edition:2015 +// compile-flags:--extern absolute +// aux-build:edition-imports-2018.rs +// aux-build:absolute.rs + +#![feature(uniform_paths)] + +#[macro_use] +extern crate edition_imports_2018; + +mod check { + mod import { + pub struct Path; + } + + gen_imports!(); // OK + + fn check() { + Path; + LinkedList::::new(); + } +} + +mod check_glob { + gen_glob!(); //~ ERROR cannot glob-import all possible crates +} + +fn main() {} diff --git a/src/test/ui/editions/edition-imports-2015.stderr b/src/test/ui/editions/edition-imports-2015.stderr new file mode 100644 index 00000000000..fb6b2e64ef5 --- /dev/null +++ b/src/test/ui/editions/edition-imports-2015.stderr @@ -0,0 +1,10 @@ +error: cannot glob-import all possible crates + --> $DIR/edition-imports-2015.rs:25:5 + | +LL | gen_glob!(); //~ ERROR cannot glob-import all possible crates + | ^^^^^^^^^^^^ + | + = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) + +error: aborting due to previous error + diff --git a/src/test/ui/editions/edition-imports-2018.rs b/src/test/ui/editions/edition-imports-2018.rs new file mode 100644 index 00000000000..cef4ce3bf16 --- /dev/null +++ b/src/test/ui/editions/edition-imports-2018.rs @@ -0,0 +1,33 @@ +// compile-pass +// edition:2018 +// aux-build:edition-imports-2015.rs + +#[macro_use] +extern crate edition_imports_2015; + +mod import { + pub struct Path; +} +mod absolute { + pub struct Path; +} + +mod check { + gen_imports!(); // OK + + fn check() { + Path; + // LinkedList::::new(); // FIXME + } +} + +mod check_glob { + gen_glob!(); // OK + + fn check() { + import::Path; + absolute::Path; + } +} + +fn main() {} -- 2.44.0