Skip to content

rustc: Remove support for hyphens in crate names #23786

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Mar 28, 2015
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
rustc: Remove support for hyphens in crate names
This commit removes parser support for `extern crate "foo" as bar` as the
renamed crate is now required to be an identifier. Additionally this commit
enables hard errors on crate names that contain hyphens in them, they must now
solely contain alphanumeric characters or underscores.

If the crate name is inferred from the file name, however, the file name
`foo-bar.rs` will have the crate name inferred as `foo_bar`. If a binary is
being emitted it will have the name `foo-bar` and a library will have the name
`libfoo_bar.rlib`.

This commit is a breaking change for a number of reasons:

* Old syntax is being removed. This was previously only issuing warnings.
* The output for the compiler when input is received on stdin is now `rust_out`
  instead of `rust-out`.
* The crate name for a crate in the file `foo-bar.rs` is now `foo_bar` which can
  affect infrastructure such as logging.

[breaking-change]
  • Loading branch information
alexcrichton committed Mar 27, 2015
commit b24a3b82011c3b78573ace4ade3f99d7c4701a11
20 changes: 5 additions & 15 deletions src/librustc/metadata/creader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,24 +73,20 @@ struct CrateInfo {
}

pub fn validate_crate_name(sess: Option<&Session>, s: &str, sp: Option<Span>) {
let say = |s: &str, warn: bool| {
let say = |s: &str| {
match (sp, sess) {
(_, None) => panic!("{}", s),
(Some(sp), Some(sess)) if warn => sess.span_warn(sp, s),
(Some(sp), Some(sess)) => sess.span_err(sp, s),
(None, Some(sess)) if warn => sess.warn(s),
(None, Some(sess)) => sess.err(s),
}
};
if s.len() == 0 {
say("crate name must not be empty", false);
} else if s.contains("-") {
say(&format!("crate names soon cannot contain hyphens: {}", s), true);
say("crate name must not be empty");
}
for c in s.chars() {
if c.is_alphanumeric() { continue }
if c == '_' || c == '-' { continue }
say(&format!("invalid character `{}` in crate name: `{}`", c, s), false);
if c == '_' { continue }
say(&format!("invalid character `{}` in crate name: `{}`", c, s));
}
match sess {
Some(sess) => sess.abort_if_errors(),
Expand Down Expand Up @@ -306,13 +302,7 @@ impl<'a> CrateReader<'a> {
-> Option<ast::CrateNum> {
let mut ret = None;
self.sess.cstore.iter_crate_data(|cnum, data| {
// For now we do a "fuzzy match" on crate names by considering
// hyphens equal to underscores. This is purely meant to be a
// transitionary feature while we deprecate the quote syntax of
// `extern crate` statements.
if data.name != name.replace("-", "_") {
return
}
if data.name != name { return }

match hash {
Some(hash) if *hash == data.hash() => { ret = Some(cnum); return }
Expand Down
18 changes: 15 additions & 3 deletions src/librustc_trans/back/link.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,11 +159,19 @@ pub fn find_crate_name(sess: Option<&Session>,
}
if let Input::File(ref path) = *input {
if let Some(s) = path.file_stem().and_then(|s| s.to_str()) {
return validate(s.to_string(), None);
if s.starts_with("-") {
let msg = format!("crate names cannot start with a `-`, but \
`{}` has a leading hyphen", s);
if let Some(sess) = sess {
sess.err(&msg);
}
} else {
return validate(s.replace("-", "_"), None);
}
}
}

"rust-out".to_string()
"rust_out".to_string()
}

pub fn build_link_meta(sess: &Session, krate: &ast::Crate,
Expand Down Expand Up @@ -455,7 +463,11 @@ pub fn filename_for_input(sess: &Session,
}
config::CrateTypeExecutable => {
let suffix = &sess.target.target.options.exe_suffix;
out_filename.with_file_name(&format!("{}{}", libname, suffix))
if suffix.len() == 0 {
out_filename.to_path_buf()
} else {
out_filename.with_extension(&suffix[1..])
}
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustdoc/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ fn runtest(test: &str, cratename: &str, libs: SearchPaths,
// environment to ensure that the target loads the right libraries at
// runtime. It would be a sad day if the *host* libraries were loaded as a
// mistake.
let mut cmd = Command::new(&outdir.path().join("rust-out"));
let mut cmd = Command::new(&outdir.path().join("rust_out"));
let var = DynamicLibrary::envvar();
let newpath = {
let path = env::var_os(var).unwrap_or(OsString::new());
Expand Down
47 changes: 10 additions & 37 deletions src/libsyntax/parse/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4977,46 +4977,19 @@ impl<'a> Parser<'a> {
///
/// # Examples
///
/// extern crate url;
/// extern crate foo = "bar"; //deprecated
/// extern crate "bar" as foo;
/// extern crate foo;
/// extern crate bar as foo;
fn parse_item_extern_crate(&mut self,
lo: BytePos,
visibility: Visibility,
attrs: Vec<Attribute>)
lo: BytePos,
visibility: Visibility,
attrs: Vec<Attribute>)
-> P<Item> {

let (maybe_path, ident) = match self.token {
token::Ident(..) => {
let crate_name = self.parse_ident();
if self.eat_keyword(keywords::As) {
(Some(crate_name.name), self.parse_ident())
} else {
(None, crate_name)
}
},
token::Literal(token::Str_(..), suf) |
token::Literal(token::StrRaw(..), suf) => {
let sp = self.span;
self.expect_no_suffix(sp, "extern crate name", suf);
// forgo the internal suffix check of `parse_str` to
// avoid repeats (this unwrap will always succeed due
// to the restriction of the `match`)
let (s, _, _) = self.parse_optional_str().unwrap();
self.expect_keyword(keywords::As);
let the_ident = self.parse_ident();
self.obsolete(sp, ObsoleteSyntax::ExternCrateString);
let s = token::intern(&s);
(Some(s), the_ident)
},
_ => {
let span = self.span;
let token_str = self.this_token_to_string();
self.span_fatal(span,
&format!("expected extern crate name but \
found `{}`",
token_str));
}
let crate_name = self.parse_ident();
let (maybe_path, ident) = if self.eat_keyword(keywords::As) {
(Some(crate_name.name), self.parse_ident())
} else {
(None, crate_name)
};
self.expect(&token::Semi);

Expand Down
14 changes: 0 additions & 14 deletions src/test/compile-fail/bad-crate-id2.rs

This file was deleted.

6 changes: 6 additions & 0 deletions src/test/run-make/output-with-hyphens/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
-include ../tools.mk

all:
$(RUSTC) foo-bar.rs
[ -f $(TMPDIR)/$(call BIN,foo-bar) ]
[ -f $(TMPDIR)/libfoo_bar.rlib ]
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// 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.
//
Expand All @@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

extern crate "" as foo; //~ ERROR: crate name must not be empty
//~^ WARNING: obsolete syntax
#![crate_type = "lib"]
#![crate_type = "bin"]

fn main() {}