Skip to content

Commit 1b0bb49

Browse files
committed
Emit warning when there is no space between -o and arg
Signed-off-by: xizheyin <xizheyin@smail.nju.edu.cn>
1 parent 0d11be5 commit 1b0bb49

File tree

5 files changed

+146
-1
lines changed

5 files changed

+146
-1
lines changed

compiler/rustc_driver_impl/src/args.rs

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use std::{env, error, fmt, fs, io};
22

3-
use rustc_session::EarlyDiagCtxt;
3+
use rustc_session::{EarlyDiagCtxt, config};
44

55
/// Expands argfiles in command line arguments.
66
#[derive(Default)]
@@ -153,3 +153,40 @@ impl fmt::Display for Error {
153153
}
154154

155155
impl error::Error for Error {}
156+
157+
/// check if suspect is a confusables of any option or arg in rustc or fake_args
158+
pub(crate) fn check_confusables(suspect: &str, fake_args: &[&str]) -> Option<String> {
159+
let suspect = suspect.strip_prefix("-").unwrap_or(suspect);
160+
// Check if s1 starts with s2, ignoring hyphens vs underscores
161+
fn starts_with_ignoring_separators(s1: &str, s2: &str) -> bool {
162+
let normalized_s1 = s1.replace('-', "_");
163+
let normalized_s2 = s2.replace('-', "_");
164+
normalized_s1.starts_with(&normalized_s2)
165+
}
166+
167+
let optgroups = config::rustc_optgroups();
168+
for option in optgroups {
169+
let prefix = String::from("--");
170+
if starts_with_ignoring_separators(option.long_name(), suspect) {
171+
return Some(prefix + option.long_name());
172+
}
173+
}
174+
for option in config::CG_OPTIONS {
175+
let prefix = String::from("-C ");
176+
if starts_with_ignoring_separators(option.name(), suspect) {
177+
return Some(prefix + option.name());
178+
}
179+
}
180+
for option in config::Z_OPTIONS {
181+
let prefix = String::from("-Z ");
182+
if starts_with_ignoring_separators(option.name(), suspect) {
183+
return Some(prefix + option.name());
184+
}
185+
}
186+
for arg in fake_args {
187+
if starts_with_ignoring_separators(arg, suspect) {
188+
return Some("".to_string());
189+
}
190+
}
191+
None
192+
}

compiler/rustc_driver_impl/src/lib.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ mod signal_handler {
103103
pub(super) fn install() {}
104104
}
105105

106+
use crate::args::check_confusables;
106107
use crate::session_diagnostics::{
107108
CantEmitMIR, RLinkEmptyVersionNumber, RLinkEncodingVersionMismatch, RLinkRustcVersionMismatch,
108109
RLinkWrongFileType, RlinkCorruptFile, RlinkNotAFile, RlinkUnableToRead, UnstableFeatureUsage,
@@ -1237,6 +1238,26 @@ pub fn handle_options(early_dcx: &EarlyDiagCtxt, args: &[String]) -> Option<geto
12371238
return None;
12381239
}
12391240

1241+
// To avoid confusion, emit warning if no space
1242+
// between `-o` and arg, e.g.`-optimize`, `-out-dir`, is applied, see issue #142812
1243+
if let Some(name) = matches.opt_str("o")
1244+
&& let Some(suspect) = args.iter().find(|arg| arg.starts_with("-o") && *arg != "-o")
1245+
{
1246+
let confusables = ["optimize", "o0", "o1", "o2", "o3", "ofast", "og", "os", "oz"];
1247+
if let Some(confusable) = check_confusables(&suspect, &confusables) {
1248+
early_dcx.early_warn(
1249+
"option `-o` has no space between flag name and value, which can be confusing",
1250+
);
1251+
early_dcx.early_note(format!(
1252+
"option `-o {}` is applied instead of a flag named `o{}` to specify output filename `{}`",
1253+
name, name, name
1254+
));
1255+
if !confusable.is_empty() {
1256+
early_dcx.early_note(format!("Do you mean `{}`?", confusable));
1257+
}
1258+
}
1259+
}
1260+
12401261
Some(matches)
12411262
}
12421263

compiler/rustc_session/src/config.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1653,6 +1653,10 @@ impl RustcOptGroup {
16531653
OptionKind::FlagMulti => options.optflagmulti(short_name, long_name, desc),
16541654
};
16551655
}
1656+
1657+
pub fn long_name(&self) -> &str {
1658+
self.long_name
1659+
}
16561660
}
16571661

16581662
pub fn make_opt(
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
fn main() {}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
// This test is to check if the warning is emitted when no space
2+
// between `-o` and arg is applied, see issue #142812
3+
use run_make_support::rustc;
4+
5+
fn main() {
6+
// test fake args
7+
rustc()
8+
.input("main.rs")
9+
.arg("-optimize")
10+
.run()
11+
.assert_stderr_contains(
12+
"warning: option `-o` has no space between flag name and value, which can be confusing",
13+
)
14+
.assert_stderr_contains(
15+
"note: option `-o ptimize` is applied instead of a flag named `optimize`",
16+
)
17+
.assert_stderr_contains("to specify output filename `ptimize`");
18+
rustc()
19+
.input("main.rs")
20+
.arg("-o0")
21+
.run()
22+
.assert_stderr_contains(
23+
"warning: option `-o` has no space between flag name and value, which can be confusing",
24+
)
25+
.assert_stderr_contains("note: option `-o 0` is applied instead of a flag named `o0`")
26+
.assert_stderr_contains("to specify output filename `0`");
27+
rustc().input("main.rs").arg("-o1").run();
28+
// test real args by iter optgroups
29+
rustc()
30+
.input("main.rs")
31+
.arg("-out-dir")
32+
.run()
33+
.assert_stderr_contains(
34+
"warning: option `-o` has no space between flag name and value, which can be confusing",
35+
)
36+
.assert_stderr_contains(
37+
"note: option `-o ut-dir` is applied instead of a flag named `out-dir`",
38+
)
39+
.assert_stderr_contains("to specify output filename `ut-dir`")
40+
.assert_stderr_contains("Do you mean `--out-dir`?");
41+
// test real args by iter CG_OPTIONS
42+
rustc()
43+
.input("main.rs")
44+
.arg("-opt-level")
45+
.run()
46+
.assert_stderr_contains(
47+
"warning: option `-o` has no space between flag name and value, which can be confusing",
48+
)
49+
.assert_stderr_contains(
50+
"note: option `-o pt-level` is applied instead of a flag named `opt-level`",
51+
)
52+
.assert_stderr_contains("to specify output filename `pt-level`")
53+
.assert_stderr_contains("Do you mean `-C opt_level`?");
54+
rustc()
55+
.input("main.rs")
56+
.arg("-overflow-checks")
57+
.run()
58+
.assert_stderr_contains(
59+
"warning: option `-o` has no space between flag name and value, which can be confusing",
60+
)
61+
.assert_stderr_contains(
62+
"note: option `-o verflow-checks` is applied instead of a flag named `overflow-checks`",
63+
)
64+
.assert_stderr_contains("to specify output filename `verflow-checks`")
65+
.assert_stderr_contains("Do you mean `-C overflow_checks`?");
66+
// test real args by iter Z_OPTIONS
67+
rustc()
68+
.input("main.rs")
69+
.arg("-oom")
70+
.run()
71+
.assert_stderr_contains(
72+
"warning: option `-o` has no space between flag name and value, which can be confusing",
73+
)
74+
.assert_stderr_contains("note: option `-o om` is applied instead of a flag named `oom`")
75+
.assert_stderr_contains("to specify output filename `om`")
76+
.assert_stderr_contains("note: Do you mean `-Z oom`?");
77+
78+
// test no warning when there is space between `-o` and arg
79+
rustc().input("main.rs").arg("-o").arg("ptimize").run().assert_stderr_equals("");
80+
rustc().input("main.rs").arg("--out-dir").arg("xxx").run().assert_stderr_equals("");
81+
rustc().input("main.rs").arg("-o").arg("out-dir").run().assert_stderr_equals("");
82+
}

0 commit comments

Comments
 (0)