Support extern
in paths
This commit is contained in:
parent
b107f720e5
commit
32db83b16e
14 changed files with 185 additions and 26 deletions
|
@ -2982,6 +2982,8 @@ impl<'a> Resolver<'a> {
|
||||||
let msg = "There are too many initial `super`s.".to_string();
|
let msg = "There are too many initial `super`s.".to_string();
|
||||||
return PathResult::Failed(ident.span, msg, false);
|
return PathResult::Failed(ident.span, msg, false);
|
||||||
}
|
}
|
||||||
|
} else if i == 0 && ns == TypeNS && name == keywords::Extern.name() {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
allow_super = false;
|
allow_super = false;
|
||||||
|
|
||||||
|
@ -2996,16 +2998,19 @@ impl<'a> Resolver<'a> {
|
||||||
// `$crate::a::b`
|
// `$crate::a::b`
|
||||||
module = Some(self.resolve_crate_root(ident.node.ctxt));
|
module = Some(self.resolve_crate_root(ident.node.ctxt));
|
||||||
continue
|
continue
|
||||||
} else if i == 1 && self.session.features.borrow().extern_absolute_paths &&
|
} else if i == 1 && !token::Ident(ident.node).is_path_segment_keyword() {
|
||||||
path[0].node.name == keywords::CrateRoot.name() &&
|
let prev_name = path[0].node.name;
|
||||||
!token::Ident(ident.node).is_path_segment_keyword() {
|
if prev_name == keywords::Extern.name() ||
|
||||||
// `::extern_crate::a::b`
|
prev_name == keywords::CrateRoot.name() &&
|
||||||
let crate_id = self.crate_loader.resolve_crate_from_path(name, ident.span);
|
self.session.features.borrow().extern_absolute_paths {
|
||||||
let crate_root =
|
// `::extern_crate::a::b`
|
||||||
self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX });
|
let crate_id = self.crate_loader.resolve_crate_from_path(name, ident.span);
|
||||||
self.populate_module_if_necessary(crate_root);
|
let crate_root =
|
||||||
module = Some(crate_root);
|
self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX });
|
||||||
continue
|
self.populate_module_if_necessary(crate_root);
|
||||||
|
module = Some(crate_root);
|
||||||
|
continue
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3015,6 +3020,7 @@ impl<'a> Resolver<'a> {
|
||||||
name == keywords::SelfValue.name() && i != 0 ||
|
name == keywords::SelfValue.name() && i != 0 ||
|
||||||
name == keywords::SelfType.name() && i != 0 ||
|
name == keywords::SelfType.name() && i != 0 ||
|
||||||
name == keywords::Super.name() && i != 0 ||
|
name == keywords::Super.name() && i != 0 ||
|
||||||
|
name == keywords::Extern.name() && i != 0 ||
|
||||||
name == keywords::Crate.name() && i != 1 &&
|
name == keywords::Crate.name() && i != 1 &&
|
||||||
path[0].node.name != keywords::CrateRoot.name() {
|
path[0].node.name != keywords::CrateRoot.name() {
|
||||||
let name_str = if name == keywords::CrateRoot.name() {
|
let name_str = if name == keywords::CrateRoot.name() {
|
||||||
|
|
|
@ -604,17 +604,20 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
|
||||||
self.current_module = directive.parent;
|
self.current_module = directive.parent;
|
||||||
let ImportDirective { ref module_path, span, .. } = *directive;
|
let ImportDirective { ref module_path, span, .. } = *directive;
|
||||||
|
|
||||||
// Extern crate mode for absolute paths needs some
|
// FIXME: Last path segment is treated specially in import resolution, so extern crate
|
||||||
// special support for single-segment imports.
|
// mode for absolute paths needs some special support for single-segment imports.
|
||||||
let extern_absolute_paths = self.session.features.borrow().extern_absolute_paths;
|
if module_path.len() == 1 && (module_path[0].node.name == keywords::CrateRoot.name() ||
|
||||||
if module_path.len() == 1 && module_path[0].node.name == keywords::CrateRoot.name() {
|
module_path[0].node.name == keywords::Extern.name()) {
|
||||||
|
let is_extern = module_path[0].node.name == keywords::Extern.name() ||
|
||||||
|
self.session.features.borrow().extern_absolute_paths;
|
||||||
match directive.subclass {
|
match directive.subclass {
|
||||||
GlobImport { .. } if extern_absolute_paths => {
|
GlobImport { .. } if is_extern => {
|
||||||
return Some((directive.span,
|
return Some((directive.span,
|
||||||
"cannot glob-import all possible crates".to_string()));
|
"cannot glob-import all possible crates".to_string()));
|
||||||
}
|
}
|
||||||
SingleImport { source, target, .. } => {
|
SingleImport { source, target, .. } => {
|
||||||
let crate_root = if source.name == keywords::Crate.name() {
|
let crate_root = if source.name == keywords::Crate.name() &&
|
||||||
|
module_path[0].node.name != keywords::Extern.name() {
|
||||||
if target.name == keywords::Crate.name() {
|
if target.name == keywords::Crate.name() {
|
||||||
return Some((directive.span,
|
return Some((directive.span,
|
||||||
"crate root imports need to be explicitly named: \
|
"crate root imports need to be explicitly named: \
|
||||||
|
@ -622,8 +625,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
|
||||||
} else {
|
} else {
|
||||||
Some(self.resolve_crate_root(source.ctxt.modern()))
|
Some(self.resolve_crate_root(source.ctxt.modern()))
|
||||||
}
|
}
|
||||||
} else if extern_absolute_paths &&
|
} else if is_extern && !token::Ident(source).is_path_segment_keyword() {
|
||||||
!token::Ident(source).is_path_segment_keyword() {
|
|
||||||
let crate_id =
|
let crate_id =
|
||||||
self.crate_loader.resolve_crate_from_path(source.name, directive.span);
|
self.crate_loader.resolve_crate_from_path(source.name, directive.span);
|
||||||
let crate_root =
|
let crate_root =
|
||||||
|
|
|
@ -450,6 +450,9 @@ declare_features! (
|
||||||
|
|
||||||
// Allows use of the :lifetime macro fragment specifier
|
// Allows use of the :lifetime macro fragment specifier
|
||||||
(active, macro_lifetime_matcher, "1.24.0", Some(46895)),
|
(active, macro_lifetime_matcher, "1.24.0", Some(46895)),
|
||||||
|
|
||||||
|
// `extern` in paths
|
||||||
|
(active, extern_in_paths, "1.23.0", Some(44660)),
|
||||||
);
|
);
|
||||||
|
|
||||||
declare_features! (
|
declare_features! (
|
||||||
|
@ -1790,6 +1793,9 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
||||||
if segment.identifier.name == keywords::Crate.name() {
|
if segment.identifier.name == keywords::Crate.name() {
|
||||||
gate_feature_post!(&self, crate_in_paths, segment.span,
|
gate_feature_post!(&self, crate_in_paths, segment.span,
|
||||||
"`crate` in paths is experimental");
|
"`crate` in paths is experimental");
|
||||||
|
} else if segment.identifier.name == keywords::Extern.name() {
|
||||||
|
gate_feature_post!(&self, extern_in_paths, segment.span,
|
||||||
|
"`extern` in paths is experimental");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1387,7 +1387,7 @@ impl<'a> Parser<'a> {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
(ident, TraitItemKind::Const(ty, default), ast::Generics::default())
|
(ident, TraitItemKind::Const(ty, default), ast::Generics::default())
|
||||||
} else if self.token.is_path_start() {
|
} else if self.token.is_path_start() && !self.is_extern_non_path() {
|
||||||
// trait item macro.
|
// trait item macro.
|
||||||
// code copied from parse_macro_use_or_failure... abstraction!
|
// code copied from parse_macro_use_or_failure... abstraction!
|
||||||
let prev_span = self.prev_span;
|
let prev_span = self.prev_span;
|
||||||
|
@ -4037,6 +4037,10 @@ impl<'a> Parser<'a> {
|
||||||
self.token.is_keyword(keywords::Crate) && self.look_ahead(1, |t| t != &token::ModSep)
|
self.token.is_keyword(keywords::Crate) && self.look_ahead(1, |t| t != &token::ModSep)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_extern_non_path(&self) -> bool {
|
||||||
|
self.token.is_keyword(keywords::Extern) && self.look_ahead(1, |t| t != &token::ModSep)
|
||||||
|
}
|
||||||
|
|
||||||
fn eat_auto_trait(&mut self) -> bool {
|
fn eat_auto_trait(&mut self) -> bool {
|
||||||
if self.token.is_keyword(keywords::Auto)
|
if self.token.is_keyword(keywords::Auto)
|
||||||
&& self.look_ahead(1, |t| t.is_keyword(keywords::Trait))
|
&& self.look_ahead(1, |t| t.is_keyword(keywords::Trait))
|
||||||
|
@ -4152,10 +4156,12 @@ impl<'a> Parser<'a> {
|
||||||
// like a path (1 token), but it fact not a path.
|
// like a path (1 token), but it fact not a path.
|
||||||
// `union::b::c` - path, `union U { ... }` - not a path.
|
// `union::b::c` - path, `union U { ... }` - not a path.
|
||||||
// `crate::b::c` - path, `crate struct S;` - not a path.
|
// `crate::b::c` - path, `crate struct S;` - not a path.
|
||||||
|
// `extern::b::c` - path, `extern crate c;` - not a path.
|
||||||
} else if self.token.is_path_start() &&
|
} else if self.token.is_path_start() &&
|
||||||
!self.token.is_qpath_start() &&
|
!self.token.is_qpath_start() &&
|
||||||
!self.is_union_item() &&
|
!self.is_union_item() &&
|
||||||
!self.is_crate_vis() {
|
!self.is_crate_vis() &&
|
||||||
|
!self.is_extern_non_path() {
|
||||||
let pth = self.parse_path(PathStyle::Expr)?;
|
let pth = self.parse_path(PathStyle::Expr)?;
|
||||||
|
|
||||||
if !self.eat(&token::Not) {
|
if !self.eat(&token::Not) {
|
||||||
|
@ -5236,7 +5242,7 @@ impl<'a> Parser<'a> {
|
||||||
-> PResult<'a, (Ident, Vec<ast::Attribute>, ast::Generics,
|
-> PResult<'a, (Ident, Vec<ast::Attribute>, ast::Generics,
|
||||||
ast::ImplItemKind)> {
|
ast::ImplItemKind)> {
|
||||||
// code copied from parse_macro_use_or_failure... abstraction!
|
// code copied from parse_macro_use_or_failure... abstraction!
|
||||||
if self.token.is_path_start() {
|
if self.token.is_path_start() && !self.is_extern_non_path() {
|
||||||
// Method macro.
|
// Method macro.
|
||||||
|
|
||||||
let prev_span = self.prev_span;
|
let prev_span = self.prev_span;
|
||||||
|
@ -6238,7 +6244,8 @@ impl<'a> Parser<'a> {
|
||||||
return Ok(Some(item));
|
return Ok(Some(item));
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.eat_keyword(keywords::Extern) {
|
if self.check_keyword(keywords::Extern) && self.is_extern_non_path() {
|
||||||
|
self.bump(); // `extern`
|
||||||
if self.eat_keyword(keywords::Crate) {
|
if self.eat_keyword(keywords::Crate) {
|
||||||
return Ok(Some(self.parse_item_extern_crate(lo, visibility, attrs)?));
|
return Ok(Some(self.parse_item_extern_crate(lo, visibility, attrs)?));
|
||||||
}
|
}
|
||||||
|
|
|
@ -359,6 +359,7 @@ impl Token {
|
||||||
Some(id) => id.name == keywords::Super.name() ||
|
Some(id) => id.name == keywords::Super.name() ||
|
||||||
id.name == keywords::SelfValue.name() ||
|
id.name == keywords::SelfValue.name() ||
|
||||||
id.name == keywords::SelfType.name() ||
|
id.name == keywords::SelfType.name() ||
|
||||||
|
id.name == keywords::Extern.name() ||
|
||||||
id.name == keywords::Crate.name() ||
|
id.name == keywords::Crate.name() ||
|
||||||
id.name == keywords::DollarCrate.name(),
|
id.name == keywords::DollarCrate.name(),
|
||||||
None => false,
|
None => false,
|
||||||
|
|
|
@ -8,10 +8,8 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
// compile-flags: -Z parse-only
|
#![feature(extern_in_paths)]
|
||||||
|
|
||||||
// This file was auto-generated using 'src/etc/generate-keyword-tests.py extern'
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let extern = "foo"; //~ error: expected pattern, found keyword `extern`
|
let extern = 0; //~ ERROR expected unit struct/variant or constant, found module `extern`
|
||||||
}
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
// Copyright 2017 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.
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct S;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Z;
|
|
@ -0,0 +1,15 @@
|
||||||
|
// Copyright 2017 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.
|
||||||
|
|
||||||
|
#![feature(extern_in_paths)]
|
||||||
|
|
||||||
|
use extern::xcrate::S; //~ ERROR can't find crate for `xcrate`
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,15 @@
|
||||||
|
// Copyright 2017 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.
|
||||||
|
|
||||||
|
#![feature(extern_in_paths)]
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let s = extern::xcrate::S; //~ ERROR can't find crate for `xcrate`
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
// Copyright 2017 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.
|
||||||
|
|
||||||
|
#![feature(extern_in_paths)]
|
||||||
|
|
||||||
|
use extern::ycrate; //~ ERROR can't find crate for `ycrate`
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,23 @@
|
||||||
|
// Copyright 2017 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.
|
||||||
|
|
||||||
|
// aux-build:xcrate.rs
|
||||||
|
|
||||||
|
#![feature(extern_in_paths)]
|
||||||
|
|
||||||
|
use extern; //~ ERROR unresolved import `extern`
|
||||||
|
//~^ NOTE no `extern` in the root
|
||||||
|
use extern::*; //~ ERROR unresolved import `extern::*`
|
||||||
|
//~^ NOTE cannot glob-import all possible crates
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let s = extern::xcrate; //~ ERROR expected value, found module `extern::xcrate`
|
||||||
|
//~^ NOTE not a value
|
||||||
|
}
|
31
src/test/run-pass/rfc-2126-extern-absolute-paths/extern.rs
Normal file
31
src/test/run-pass/rfc-2126-extern-absolute-paths/extern.rs
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
// Copyright 2017 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.
|
||||||
|
|
||||||
|
// aux-build:xcrate.rs
|
||||||
|
|
||||||
|
#![feature(extern_in_paths)]
|
||||||
|
|
||||||
|
use extern::xcrate::Z;
|
||||||
|
|
||||||
|
fn f() {
|
||||||
|
use extern::xcrate;
|
||||||
|
use extern::xcrate as ycrate;
|
||||||
|
let s = xcrate::S;
|
||||||
|
assert_eq!(format!("{:?}", s), "S");
|
||||||
|
let z = ycrate::Z;
|
||||||
|
assert_eq!(format!("{:?}", z), "Z");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let s = extern::xcrate::S;
|
||||||
|
assert_eq!(format!("{:?}", s), "S");
|
||||||
|
let z = Z;
|
||||||
|
assert_eq!(format!("{:?}", z), "Z");
|
||||||
|
}
|
15
src/test/ui/feature-gate-extern_in_paths.rs
Normal file
15
src/test/ui/feature-gate-extern_in_paths.rs
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
// Copyright 2017 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.
|
||||||
|
|
||||||
|
struct S;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let _ = extern::std::vec::Vec::new(); //~ ERROR `extern` in paths is experimental
|
||||||
|
}
|
10
src/test/ui/feature-gate-extern_in_paths.stderr
Normal file
10
src/test/ui/feature-gate-extern_in_paths.stderr
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
error: `extern` in paths is experimental (see issue #44660)
|
||||||
|
--> $DIR/feature-gate-extern_in_paths.rs:14:13
|
||||||
|
|
|
||||||
|
14 | let _ = extern::std::vec::Vec::new(); //~ ERROR `extern` in paths is experimental
|
||||||
|
| ^^^^^^
|
||||||
|
|
|
||||||
|
= help: add #![feature(extern_in_paths)] to the crate attributes to enable
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue