mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-28 11:07:42 +00:00
Rollup merge of #33044 - petrochenkov:prefix, r=eddyb
syntax: Parse import prefixes as paths Fixes https://github.com/rust-lang/rust/issues/10415 r? @eddyb (This partially intersects with https://github.com/rust-lang/rust/pull/33041)
This commit is contained in:
commit
02e40d910a
@ -28,9 +28,9 @@ use rustc::hir::def::*;
|
|||||||
use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId};
|
use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId};
|
||||||
use rustc::ty::{self, VariantKind};
|
use rustc::ty::{self, VariantKind};
|
||||||
|
|
||||||
use syntax::ast::Name;
|
use syntax::ast::{Name, NodeId};
|
||||||
use syntax::attr::AttrMetaMethods;
|
use syntax::attr::AttrMetaMethods;
|
||||||
use syntax::parse::token::{special_idents, SELF_KEYWORD_NAME, SUPER_KEYWORD_NAME};
|
use syntax::parse::token::keywords;
|
||||||
use syntax::codemap::{Span, DUMMY_SP};
|
use syntax::codemap::{Span, DUMMY_SP};
|
||||||
|
|
||||||
use rustc::hir;
|
use rustc::hir;
|
||||||
@ -100,6 +100,37 @@ impl<'b, 'tcx:'b> Resolver<'b, 'tcx> {
|
|||||||
block.stmts.iter().any(is_item)
|
block.stmts.iter().any(is_item)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn sanity_check_import(&self, view_path: &hir::ViewPath, id: NodeId) {
|
||||||
|
let path = match view_path.node {
|
||||||
|
ViewPathSimple(_, ref path) |
|
||||||
|
ViewPathGlob (ref path) |
|
||||||
|
ViewPathList(ref path, _) => path
|
||||||
|
};
|
||||||
|
|
||||||
|
// Check for type parameters
|
||||||
|
let found_param = path.segments.iter().any(|segment| {
|
||||||
|
!segment.parameters.types().is_empty() ||
|
||||||
|
!segment.parameters.lifetimes().is_empty() ||
|
||||||
|
!segment.parameters.bindings().is_empty()
|
||||||
|
});
|
||||||
|
if found_param {
|
||||||
|
self.session.span_err(path.span,
|
||||||
|
"type or lifetime parameter is found in import path");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checking for special identifiers in path
|
||||||
|
// prevent `self` or `super` at beginning of global path
|
||||||
|
if path.global && path.segments.len() > 0 {
|
||||||
|
let first = path.segments[0].identifier.name;
|
||||||
|
if first == keywords::Super.to_name() || first == keywords::SelfValue.to_name() {
|
||||||
|
self.session.add_lint(
|
||||||
|
lint::builtin::SUPER_OR_SELF_IN_GLOBAL_PATH, id, path.span,
|
||||||
|
format!("expected identifier, found keyword `{}`", first)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Constructs the reduced graph for one item.
|
/// Constructs the reduced graph for one item.
|
||||||
fn build_reduced_graph_for_item(&mut self, item: &Item, parent_ref: &mut Module<'b>) {
|
fn build_reduced_graph_for_item(&mut self, item: &Item, parent_ref: &mut Module<'b>) {
|
||||||
let parent = *parent_ref;
|
let parent = *parent_ref;
|
||||||
@ -114,10 +145,8 @@ impl<'b, 'tcx:'b> Resolver<'b, 'tcx> {
|
|||||||
// Extract and intern the module part of the path. For
|
// Extract and intern the module part of the path. For
|
||||||
// globs and lists, the path is found directly in the AST;
|
// globs and lists, the path is found directly in the AST;
|
||||||
// for simple paths we have to munge the path a little.
|
// for simple paths we have to munge the path a little.
|
||||||
let is_global;
|
|
||||||
let module_path: Vec<Name> = match view_path.node {
|
let module_path: Vec<Name> = match view_path.node {
|
||||||
ViewPathSimple(_, ref full_path) => {
|
ViewPathSimple(_, ref full_path) => {
|
||||||
is_global = full_path.global;
|
|
||||||
full_path.segments
|
full_path.segments
|
||||||
.split_last()
|
.split_last()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
@ -129,7 +158,6 @@ impl<'b, 'tcx:'b> Resolver<'b, 'tcx> {
|
|||||||
|
|
||||||
ViewPathGlob(ref module_ident_path) |
|
ViewPathGlob(ref module_ident_path) |
|
||||||
ViewPathList(ref module_ident_path, _) => {
|
ViewPathList(ref module_ident_path, _) => {
|
||||||
is_global = module_ident_path.global;
|
|
||||||
module_ident_path.segments
|
module_ident_path.segments
|
||||||
.iter()
|
.iter()
|
||||||
.map(|seg| seg.identifier.name)
|
.map(|seg| seg.identifier.name)
|
||||||
@ -137,22 +165,10 @@ impl<'b, 'tcx:'b> Resolver<'b, 'tcx> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Checking for special identifiers in path
|
self.sanity_check_import(view_path, item.id);
|
||||||
// prevent `self` or `super` at beginning of global path
|
|
||||||
if is_global && (module_path.first() == Some(&SELF_KEYWORD_NAME) ||
|
|
||||||
module_path.first() == Some(&SUPER_KEYWORD_NAME)) {
|
|
||||||
self.session.add_lint(
|
|
||||||
lint::builtin::SUPER_OR_SELF_IN_GLOBAL_PATH,
|
|
||||||
item.id,
|
|
||||||
item.span,
|
|
||||||
format!("expected identifier, found keyword `{}`",
|
|
||||||
module_path.first().unwrap().as_str()));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Build up the import directives.
|
// Build up the import directives.
|
||||||
let is_prelude = item.attrs.iter().any(|attr| {
|
let is_prelude = item.attrs.iter().any(|attr| attr.name() == "prelude_import");
|
||||||
attr.name() == special_idents::prelude_import.name.as_str()
|
|
||||||
});
|
|
||||||
|
|
||||||
match view_path.node {
|
match view_path.node {
|
||||||
ViewPathSimple(binding, ref full_path) => {
|
ViewPathSimple(binding, ref full_path) => {
|
||||||
|
@ -81,6 +81,8 @@ type ItemInfo = (Ident, ItemKind, Option<Vec<Attribute> >);
|
|||||||
pub enum PathParsingMode {
|
pub enum PathParsingMode {
|
||||||
/// A path with no type parameters; e.g. `foo::bar::Baz`
|
/// A path with no type parameters; e.g. `foo::bar::Baz`
|
||||||
NoTypesAllowed,
|
NoTypesAllowed,
|
||||||
|
/// Same as `NoTypesAllowed`, but may end with `::{` or `::*`, which are left unparsed
|
||||||
|
ImportPrefix,
|
||||||
/// A path with a lifetime and type parameters, with no double colons
|
/// A path with a lifetime and type parameters, with no double colons
|
||||||
/// before the type parameters; e.g. `foo::bar<'a>::Baz<T>`
|
/// before the type parameters; e.g. `foo::bar<'a>::Baz<T>`
|
||||||
LifetimeAndTypesWithoutColons,
|
LifetimeAndTypesWithoutColons,
|
||||||
@ -591,20 +593,6 @@ impl<'a> Parser<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_path_list_item(&mut self) -> PResult<'a, ast::PathListItem> {
|
|
||||||
let lo = self.span.lo;
|
|
||||||
let node = if self.eat_keyword(keywords::SelfValue) {
|
|
||||||
let rename = self.parse_rename()?;
|
|
||||||
ast::PathListItemKind::Mod { id: ast::DUMMY_NODE_ID, rename: rename }
|
|
||||||
} else {
|
|
||||||
let ident = self.parse_ident()?;
|
|
||||||
let rename = self.parse_rename()?;
|
|
||||||
ast::PathListItemKind::Ident { name: ident, rename: rename, id: ast::DUMMY_NODE_ID }
|
|
||||||
};
|
|
||||||
let hi = self.last_span.hi;
|
|
||||||
Ok(spanned(lo, hi, node))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Check if the next token is `tok`, and return `true` if so.
|
/// Check if the next token is `tok`, and return `true` if so.
|
||||||
///
|
///
|
||||||
/// This method will automatically add `tok` to `expected_tokens` if `tok` is not
|
/// This method will automatically add `tok` to `expected_tokens` if `tok` is not
|
||||||
@ -1763,8 +1751,8 @@ impl<'a> Parser<'a> {
|
|||||||
LifetimeAndTypesWithColons => {
|
LifetimeAndTypesWithColons => {
|
||||||
self.parse_path_segments_with_colons()?
|
self.parse_path_segments_with_colons()?
|
||||||
}
|
}
|
||||||
NoTypesAllowed => {
|
NoTypesAllowed | ImportPrefix => {
|
||||||
self.parse_path_segments_without_types()?
|
self.parse_path_segments_without_types(mode == ImportPrefix)?
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
path.segments.extend(segments);
|
path.segments.extend(segments);
|
||||||
@ -1801,8 +1789,8 @@ impl<'a> Parser<'a> {
|
|||||||
LifetimeAndTypesWithColons => {
|
LifetimeAndTypesWithColons => {
|
||||||
self.parse_path_segments_with_colons()?
|
self.parse_path_segments_with_colons()?
|
||||||
}
|
}
|
||||||
NoTypesAllowed => {
|
NoTypesAllowed | ImportPrefix => {
|
||||||
self.parse_path_segments_without_types()?
|
self.parse_path_segments_without_types(mode == ImportPrefix)?
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1920,7 +1908,8 @@ impl<'a> Parser<'a> {
|
|||||||
|
|
||||||
/// Examples:
|
/// Examples:
|
||||||
/// - `a::b::c`
|
/// - `a::b::c`
|
||||||
pub fn parse_path_segments_without_types(&mut self) -> PResult<'a, Vec<ast::PathSegment>> {
|
pub fn parse_path_segments_without_types(&mut self, import_prefix: bool)
|
||||||
|
-> PResult<'a, Vec<ast::PathSegment>> {
|
||||||
let mut segments = Vec::new();
|
let mut segments = Vec::new();
|
||||||
loop {
|
loop {
|
||||||
// First, parse an identifier.
|
// First, parse an identifier.
|
||||||
@ -1932,9 +1921,11 @@ impl<'a> Parser<'a> {
|
|||||||
parameters: ast::PathParameters::none()
|
parameters: ast::PathParameters::none()
|
||||||
});
|
});
|
||||||
|
|
||||||
// If we do not see a `::`, stop.
|
// If we do not see a `::` or see `::{`/`::*`, stop.
|
||||||
if !self.eat(&token::ModSep) {
|
if !self.check(&token::ModSep) || import_prefix && self.is_import_coupler() {
|
||||||
return Ok(segments);
|
return Ok(segments);
|
||||||
|
} else {
|
||||||
|
self.bump();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -6127,106 +6118,67 @@ impl<'a> Parser<'a> {
|
|||||||
self.parse_item_(attrs, true, false)
|
self.parse_item_(attrs, true, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parse_path_list_items(&mut self) -> PResult<'a, Vec<ast::PathListItem>> {
|
||||||
|
self.parse_unspanned_seq(&token::OpenDelim(token::Brace),
|
||||||
|
&token::CloseDelim(token::Brace),
|
||||||
|
SeqSep::trailing_allowed(token::Comma), |this| {
|
||||||
|
let lo = this.span.lo;
|
||||||
|
let node = if this.eat_keyword(keywords::SelfValue) {
|
||||||
|
let rename = this.parse_rename()?;
|
||||||
|
ast::PathListItemKind::Mod { id: ast::DUMMY_NODE_ID, rename: rename }
|
||||||
|
} else {
|
||||||
|
let ident = this.parse_ident()?;
|
||||||
|
let rename = this.parse_rename()?;
|
||||||
|
ast::PathListItemKind::Ident { name: ident, rename: rename, id: ast::DUMMY_NODE_ID }
|
||||||
|
};
|
||||||
|
let hi = this.last_span.hi;
|
||||||
|
Ok(spanned(lo, hi, node))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/// Matches view_path : MOD? non_global_path as IDENT
|
/// `::{` or `::*`
|
||||||
/// | MOD? non_global_path MOD_SEP LBRACE RBRACE
|
fn is_import_coupler(&mut self) -> bool {
|
||||||
/// | MOD? non_global_path MOD_SEP LBRACE ident_seq RBRACE
|
self.check(&token::ModSep) &&
|
||||||
/// | MOD? non_global_path MOD_SEP STAR
|
self.look_ahead(1, |t| *t == token::OpenDelim(token::Brace) ||
|
||||||
/// | MOD? non_global_path
|
*t == token::BinOp(token::Star))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Matches ViewPath:
|
||||||
|
/// MOD_SEP? non_global_path
|
||||||
|
/// MOD_SEP? non_global_path as IDENT
|
||||||
|
/// MOD_SEP? non_global_path MOD_SEP STAR
|
||||||
|
/// MOD_SEP? non_global_path MOD_SEP LBRACE item_seq RBRACE
|
||||||
|
/// MOD_SEP? LBRACE item_seq RBRACE
|
||||||
fn parse_view_path(&mut self) -> PResult<'a, P<ViewPath>> {
|
fn parse_view_path(&mut self) -> PResult<'a, P<ViewPath>> {
|
||||||
let lo = self.span.lo;
|
let lo = self.span.lo;
|
||||||
|
if self.check(&token::OpenDelim(token::Brace)) || self.is_import_coupler() {
|
||||||
// Allow a leading :: because the paths are absolute either way.
|
// `{foo, bar}` or `::{foo, bar}`
|
||||||
// This occurs with "use $crate::..." in macros.
|
let prefix = ast::Path {
|
||||||
let is_global = self.eat(&token::ModSep);
|
global: self.eat(&token::ModSep),
|
||||||
|
segments: Vec::new(),
|
||||||
if self.check(&token::OpenDelim(token::Brace)) {
|
|
||||||
// use {foo,bar}
|
|
||||||
let idents = self.parse_unspanned_seq(
|
|
||||||
&token::OpenDelim(token::Brace),
|
|
||||||
&token::CloseDelim(token::Brace),
|
|
||||||
SeqSep::trailing_allowed(token::Comma),
|
|
||||||
|p| p.parse_path_list_item())?;
|
|
||||||
let path = ast::Path {
|
|
||||||
span: mk_sp(lo, self.span.hi),
|
span: mk_sp(lo, self.span.hi),
|
||||||
global: is_global,
|
|
||||||
segments: Vec::new()
|
|
||||||
};
|
};
|
||||||
return Ok(P(spanned(lo, self.span.hi, ViewPathList(path, idents))));
|
let items = self.parse_path_list_items()?;
|
||||||
}
|
Ok(P(spanned(lo, self.span.hi, ViewPathList(prefix, items))))
|
||||||
|
} else {
|
||||||
let first_ident = self.parse_ident()?;
|
let prefix = self.parse_path(ImportPrefix)?;
|
||||||
let mut path = vec!(first_ident);
|
if self.is_import_coupler() {
|
||||||
if let token::ModSep = self.token {
|
// `foo::bar::{a, b}` or `foo::bar::*`
|
||||||
// foo::bar or foo::{a,b,c} or foo::*
|
|
||||||
while self.check(&token::ModSep) {
|
|
||||||
self.bump();
|
self.bump();
|
||||||
|
if self.check(&token::BinOp(token::Star)) {
|
||||||
match self.token {
|
|
||||||
token::Ident(..) => {
|
|
||||||
let ident = self.parse_ident()?;
|
|
||||||
path.push(ident);
|
|
||||||
}
|
|
||||||
|
|
||||||
// foo::bar::{a,b,c}
|
|
||||||
token::OpenDelim(token::Brace) => {
|
|
||||||
let idents = self.parse_unspanned_seq(
|
|
||||||
&token::OpenDelim(token::Brace),
|
|
||||||
&token::CloseDelim(token::Brace),
|
|
||||||
SeqSep::trailing_allowed(token::Comma),
|
|
||||||
|p| p.parse_path_list_item()
|
|
||||||
)?;
|
|
||||||
let path = ast::Path {
|
|
||||||
span: mk_sp(lo, self.span.hi),
|
|
||||||
global: is_global,
|
|
||||||
segments: path.into_iter().map(|identifier| {
|
|
||||||
ast::PathSegment {
|
|
||||||
identifier: identifier,
|
|
||||||
parameters: ast::PathParameters::none(),
|
|
||||||
}
|
|
||||||
}).collect()
|
|
||||||
};
|
|
||||||
return Ok(P(spanned(lo, self.span.hi, ViewPathList(path, idents))));
|
|
||||||
}
|
|
||||||
|
|
||||||
// foo::bar::*
|
|
||||||
token::BinOp(token::Star) => {
|
|
||||||
self.bump();
|
self.bump();
|
||||||
let path = ast::Path {
|
Ok(P(spanned(lo, self.span.hi, ViewPathGlob(prefix))))
|
||||||
span: mk_sp(lo, self.span.hi),
|
} else {
|
||||||
global: is_global,
|
let items = self.parse_path_list_items()?;
|
||||||
segments: path.into_iter().map(|identifier| {
|
Ok(P(spanned(lo, self.span.hi, ViewPathList(prefix, items))))
|
||||||
ast::PathSegment {
|
|
||||||
identifier: identifier,
|
|
||||||
parameters: ast::PathParameters::none(),
|
|
||||||
}
|
|
||||||
}).collect()
|
|
||||||
};
|
|
||||||
return Ok(P(spanned(lo, self.span.hi, ViewPathGlob(path))));
|
|
||||||
}
|
|
||||||
|
|
||||||
// fall-through for case foo::bar::;
|
|
||||||
token::Semi => {
|
|
||||||
self.span_err(self.span, "expected identifier or `{` or `*`, found `;`");
|
|
||||||
}
|
|
||||||
|
|
||||||
_ => break
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// `foo::bar` or `foo::bar as baz`
|
||||||
|
let rename = self.parse_rename()?.
|
||||||
|
unwrap_or(prefix.segments.last().unwrap().identifier);
|
||||||
|
Ok(P(spanned(lo, self.last_span.hi, ViewPathSimple(rename, prefix))))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let mut rename_to = path[path.len() - 1];
|
|
||||||
let path = ast::Path {
|
|
||||||
span: mk_sp(lo, self.last_span.hi),
|
|
||||||
global: is_global,
|
|
||||||
segments: path.into_iter().map(|identifier| {
|
|
||||||
ast::PathSegment {
|
|
||||||
identifier: identifier,
|
|
||||||
parameters: ast::PathParameters::none(),
|
|
||||||
}
|
|
||||||
}).collect()
|
|
||||||
};
|
|
||||||
rename_to = self.parse_rename()?.unwrap_or(rename_to);
|
|
||||||
Ok(P(spanned(lo, self.last_span.hi, ViewPathSimple(rename_to, path))))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_rename(&mut self) -> PResult<'a, Option<Ident>> {
|
fn parse_rename(&mut self) -> PResult<'a, Option<Ident>> {
|
||||||
|
26
src/test/compile-fail/import-prefix-macro-1.rs
Normal file
26
src/test/compile-fail/import-prefix-macro-1.rs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
mod a {
|
||||||
|
pub mod b {
|
||||||
|
pub mod c {
|
||||||
|
pub struct S;
|
||||||
|
pub struct Z;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! import {
|
||||||
|
($p: path) => (use $p {S, Z}); //~ERROR expected one of `::`, `;`, or `as`, found `{`
|
||||||
|
}
|
||||||
|
|
||||||
|
import! { a::b::c }
|
||||||
|
|
||||||
|
fn main() {}
|
26
src/test/compile-fail/import-prefix-macro-2.rs
Normal file
26
src/test/compile-fail/import-prefix-macro-2.rs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
mod a {
|
||||||
|
pub mod b {
|
||||||
|
pub mod c {
|
||||||
|
pub struct S;
|
||||||
|
pub struct Z;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! import {
|
||||||
|
($p: path) => (use ::$p {S, Z}); //~ERROR expected identifier, found `a::b::c`
|
||||||
|
}
|
||||||
|
|
||||||
|
import! { a::b::c }
|
||||||
|
|
||||||
|
fn main() {}
|
25
src/test/compile-fail/import-ty-params.rs
Normal file
25
src/test/compile-fail/import-ty-params.rs
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
mod a {
|
||||||
|
pub mod b {
|
||||||
|
pub mod c {
|
||||||
|
pub struct S<T>(T);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! import {
|
||||||
|
($p: path) => (use $p;);
|
||||||
|
}
|
||||||
|
|
||||||
|
import! { a::b::c::S<u8> } //~ERROR type or lifetime parameter is found in import path
|
||||||
|
|
||||||
|
fn main() {}
|
13
src/test/compile-fail/self_type_keyword-2.rs
Normal file
13
src/test/compile-fail/self_type_keyword-2.rs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
use self::Self as Foo; //~ ERROR unresolved import `self::Self`
|
||||||
|
|
||||||
|
pub fn main() {}
|
@ -39,9 +39,6 @@ pub fn main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
use self::Self as Foo;
|
|
||||||
//~^ ERROR expected identifier, found keyword `Self`
|
|
||||||
|
|
||||||
use std::option::Option as Self;
|
use std::option::Option as Self;
|
||||||
//~^ ERROR expected identifier, found keyword `Self`
|
//~^ ERROR expected identifier, found keyword `Self`
|
||||||
|
|
||||||
|
@ -10,4 +10,4 @@
|
|||||||
|
|
||||||
// compile-flags: -Z parse-only
|
// compile-flags: -Z parse-only
|
||||||
|
|
||||||
use std::any::; //~ ERROR expected identifier or `{` or `*`, found `;`
|
use std::any::; //~ ERROR expected identifier, found `;`
|
||||||
|
35
src/test/run-pass/import-prefix-macro.rs
Normal file
35
src/test/run-pass/import-prefix-macro.rs
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
mod a {
|
||||||
|
pub mod b {
|
||||||
|
pub mod c {
|
||||||
|
pub struct S;
|
||||||
|
pub struct Z;
|
||||||
|
}
|
||||||
|
pub struct W;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! import {
|
||||||
|
(1 $p: path) => (use $p;);
|
||||||
|
(2 $p: path) => (use $p::{Z};);
|
||||||
|
(3 $p: path) => (use $p::*;);
|
||||||
|
}
|
||||||
|
|
||||||
|
import! { 1 a::b::c::S }
|
||||||
|
import! { 2 a::b::c }
|
||||||
|
import! { 3 a::b }
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let s = S;
|
||||||
|
let z = Z;
|
||||||
|
let w = W;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user