Skip to content

Commit aadb571

Browse files
committed
Auto merge of #116001 - fmease:validate-crate-name-extern-cli-opt, r=est31
[breaking change] Validate crate name in `--extern` [MCP 650] Reject non-ASCII-identifier crate names passed to the CLI option `--extern` (`rustc`, `rustdoc`). Implements [MCP 650](rust-lang/compiler-team#650) (except that we only allow ASCII identifiers not arbitrary Rust identifiers). Fixes #113035. [As mentioned on Zulip](https://rust-lang.zulipchat.com/#narrow/stream/233931-t-compiler.2Fmajor-changes/topic/Disallow.20non-identifier-valid.20--extern.20cr.E2.80.A6.20compiler-team.23650/near/376826988), doing a crater run probably doesn't make sense since it wouldn't yield anything. Most users don't interact with `rustc` directly but only ever through Cargo which always passes a valid crate name to `--extern` when it invokes `rustc` and `rustdoc`. In any case, the user wouldn't be able to use such a crate name in the source code anyway. Note that I'm not using [`rustc_session::output::validate_crate_name`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_session/output/fn.validate_crate_name.html) (used for `--crate-name` and `#![crate_name]`) since the latter doesn't reject non-ASCII crate names and ones that start with a digit. As an aside, I've also thought about getting rid of `validate_crate_name` entirely in a separate PR (with another MCP) in favor of `is_ascii_ident` to reject more weird `--crate-name`s, `#![crate_name]`s and file names but I think that would lead to a lot of actual breakage, namely because of file names starting with a digit. In `tests/ui` 9 tests would be impacted for example. CC `@estebank` r? `@est31`
2 parents 959b2c7 + 8d81d5a commit aadb571

15 files changed

+60
-17
lines changed

Diff for: compiler/rustc_session/src/config.rs

+13
Original file line numberDiff line numberDiff line change
@@ -2475,6 +2475,19 @@ pub fn parse_externs(
24752475
Some((opts, name)) => (Some(opts), name.to_string()),
24762476
};
24772477

2478+
if !crate::utils::is_ascii_ident(&name) {
2479+
let mut error = handler.early_struct_error(format!(
2480+
"crate name `{name}` passed to `--extern` is not a valid ASCII identifier"
2481+
));
2482+
let adjusted_name = name.replace("-", "_");
2483+
if crate::utils::is_ascii_ident(&adjusted_name) {
2484+
error.help(format!(
2485+
"consider replacing the dashes with underscores: `{adjusted_name}`"
2486+
));
2487+
}
2488+
error.emit();
2489+
}
2490+
24782491
let path = path.map(|p| CanonicalizedPath::new(p));
24792492

24802493
let entry = externs.entry(name.to_owned());

Diff for: compiler/rustc_session/src/session.rs

+9
Original file line numberDiff line numberDiff line change
@@ -1724,6 +1724,15 @@ impl EarlyErrorHandler {
17241724
self.handler.struct_fatal(msg).emit()
17251725
}
17261726

1727+
#[allow(rustc::untranslatable_diagnostic)]
1728+
#[allow(rustc::diagnostic_outside_of_impl)]
1729+
pub(crate) fn early_struct_error(
1730+
&self,
1731+
msg: impl Into<DiagnosticMessage>,
1732+
) -> DiagnosticBuilder<'_, !> {
1733+
self.handler.struct_fatal(msg)
1734+
}
1735+
17271736
#[allow(rustc::untranslatable_diagnostic)]
17281737
#[allow(rustc::diagnostic_outside_of_impl)]
17291738
pub fn early_warn(&self, msg: impl Into<DiagnosticMessage>) {

Diff for: compiler/rustc_session/src/utils.rs

+9
Original file line numberDiff line numberDiff line change
@@ -158,3 +158,12 @@ pub fn extra_compiler_flags() -> Option<(Vec<String>, bool)> {
158158

159159
if !result.is_empty() { Some((result, excluded_cargo_defaults)) } else { None }
160160
}
161+
162+
pub(crate) fn is_ascii_ident(string: &str) -> bool {
163+
let mut chars = string.chars();
164+
if let Some(start) = chars.next() && (start.is_ascii_alphabetic() || start == '_') {
165+
chars.all(|char| char.is_ascii_alphanumeric() || char == '_')
166+
} else {
167+
false
168+
}
169+
}

Diff for: tests/run-make/incr-foreign-head-span/Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ INCR=$(TMPDIR)/incr
1515
all:
1616
cp first_crate.rs second_crate.rs $(TMPDIR)
1717
$(RUSTC) $(TMPDIR)/first_crate.rs -C incremental=$(INCR) --target $(TARGET) --crate-type lib
18-
$(RUSTC) $(TMPDIR)/second_crate.rs -C incremental=$(INCR) --target $(TARGET) --extern first-crate=$(TMPDIR) --crate-type lib
18+
$(RUSTC) $(TMPDIR)/second_crate.rs -C incremental=$(INCR) --target $(TARGET) --extern first_crate=$(TMPDIR)/libfirst_crate.rlib --crate-type lib
1919
rm $(TMPDIR)/first_crate.rs
2020
$(RUSTC) $(TMPDIR)/second_crate.rs -C incremental=$(INCR) --target $(TARGET) --cfg second_run --crate-type lib
2121

Diff for: tests/ui/extern-flag/invalid-crate-name-dashed.rs

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// compile-flags: --extern=my-awesome-library=libawesome.rlib
2+
// error-pattern: crate name `my-awesome-library` passed to `--extern` is not a valid ASCII identifier
3+
// error-pattern: consider replacing the dashes with underscores: `my_awesome_library`
4+
5+
// In a sense, this is a regression test for issue #113035. We no longer suggest
6+
// `pub use my-awesome-library::*;` (sic!) as we outright ban this crate name.
7+
8+
pub use my_awesome_library::*;
9+
10+
fn main() {}
+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
error: crate name `my-awesome-library` passed to `--extern` is not a valid ASCII identifier
2+
|
3+
= help: consider replacing the dashes with underscores: `my_awesome_library`
4+

Diff for: tests/ui/extern-flag/invalid-crate-name-non-ascii.rs

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// compile-flags: --extern čɍαţē=libnon_ascii.rlib
2+
// error-pattern: crate name `čɍαţē` passed to `--extern` is not a valid ASCII identifier
3+
4+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
error: crate name `čɍαţē` passed to `--extern` is not a valid ASCII identifier
2+

Diff for: tests/ui/extern-flag/invalid-crate-name.rs

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// compile-flags: --extern=?#1%$
2+
// error-pattern: crate name `?#1%$` passed to `--extern` is not a valid ASCII identifier
3+
4+
fn main() {}

Diff for: tests/ui/extern-flag/invalid-crate-name.stderr

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
error: crate name `?#1%$` passed to `--extern` is not a valid ASCII identifier
2+

Diff for: tests/ui/rfcs/rfc-2457-non-ascii-idents/crate_name_nonascii_forbidden-2.rs

-6
This file was deleted.

Diff for: tests/ui/rfcs/rfc-2457-non-ascii-idents/crate_name_nonascii_forbidden-2.stderr

-8
This file was deleted.

Diff for: tests/ui/rfcs/rfc-2457-non-ascii-idents/crate_name_nonascii_forbidden-1.stderr renamed to tests/ui/rfcs/rfc-2457-non-ascii-idents/crate_name_nonascii_forbidden.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error: cannot load a crate with a non-ascii name `ьаг`
2-
--> $DIR/crate_name_nonascii_forbidden-1.rs:1:1
2+
--> $DIR/crate_name_nonascii_forbidden.rs:1:1
33
|
44
LL | extern crate ьаг;
55
| ^^^^^^^^^^^^^^^^^

Diff for: tests/ui/rust-2018/trait-import-suggestions.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// edition:2018
22
// aux-build:trait-import-suggestions.rs
3-
// compile-flags:--extern trait-import-suggestions
3+
// compile-flags:--extern trait_import_suggestions
44

55
mod foo {
66
mod foobar {

0 commit comments

Comments
 (0)