Skip to content

Commit afea9de

Browse files
committed
Emit warning when there is no space between -o and confusing arg
Signed-off-by: xizheyin <[email protected]>
1 parent 0d11be5 commit afea9de

File tree

4 files changed

+143
-0
lines changed

4 files changed

+143
-0
lines changed

compiler/rustc_driver_impl/src/lib.rs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1237,9 +1237,54 @@ pub fn handle_options(early_dcx: &EarlyDiagCtxt, args: &[String]) -> Option<geto
12371237
return None;
12381238
}
12391239

1240+
warn_on_confusing_output_filename_flag(early_dcx, &matches, args);
1241+
12401242
Some(matches)
12411243
}
12421244

1245+
/// Warn if `-o` is used without a space between the flag name and the value
1246+
/// and the value is a high-value confusables,
1247+
/// e.g. `-optimize` instead of `-o optimize`, see issue #142812.
1248+
fn warn_on_confusing_output_filename_flag(
1249+
early_dcx: &EarlyDiagCtxt,
1250+
matches: &getopts::Matches,
1251+
args: &[String],
1252+
) {
1253+
fn eq_ignore_separators(s1: &str, s2: &str) -> bool {
1254+
let s1 = s1.replace('-', "_");
1255+
let s2 = s2.replace('-', "_");
1256+
s1 == s2
1257+
}
1258+
1259+
if let Some(name) = matches.opt_str("o")
1260+
&& let Some(suspect) = args.iter().find(|arg| arg.starts_with("-o") && *arg != "-o")
1261+
{
1262+
let filename = suspect.strip_prefix("-").unwrap_or(suspect);
1263+
let optgroups = config::rustc_optgroups();
1264+
let fake_args = ["optimize", "o0", "o1", "o2", "o3", "ofast", "og", "os", "oz"];
1265+
1266+
// Check if provided filename might be confusing in conjunction with `-o` flag,
1267+
// i.e. consider `-o{filename}` such as `-optimize` with `filename` being `ptimize`.
1268+
// There are also other high-value confusables except for rustc options, for example:
1269+
// - C compiler flag, e.g. "optimize", "o0", "o1", "o2", "o3", "ofast".
1270+
// - Codegen flags, e.g. "pt-level" of -opt-level.
1271+
if optgroups.iter().any(|option| eq_ignore_separators(option.long_name(), filename))
1272+
|| config::CG_OPTIONS.iter().any(|option| eq_ignore_separators(option.name(), filename))
1273+
|| fake_args.iter().any(|arg| eq_ignore_separators(arg, filename))
1274+
{
1275+
early_dcx.early_warn(
1276+
"option `-o` has no space between flag name and value, which can be confusing",
1277+
);
1278+
early_dcx.early_note(format!(
1279+
"output filename `-o {name}` is applied instead of a flag named `o{name}`"
1280+
));
1281+
early_dcx.early_help(format!(
1282+
"insert a space between `-o` and `{name}` if this is intentional: `-o {name}`"
1283+
));
1284+
}
1285+
}
1286+
}
1287+
12431288
fn parse_crate_attrs<'a>(sess: &'a Session) -> PResult<'a, ast::AttrVec> {
12441289
let mut parser = unwrap_or_emit_fatal(match &sess.io.input {
12451290
Input::File(file) => new_parser_from_file(&sess.psess, file, None),

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: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
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: output filename `-o ptimize` is applied instead of a flag named `optimize`",
16+
);
17+
rustc()
18+
.input("main.rs")
19+
.arg("-o0")
20+
.run()
21+
.assert_stderr_contains(
22+
"warning: option `-o` has no space between flag name and value, which can be confusing",
23+
)
24+
.assert_stderr_contains(
25+
"note: output filename `-o 0` is applied instead of a flag named `o0`",
26+
);
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: output filename `-o ut-dir` is applied instead of a flag named `out-dir`",
38+
)
39+
.assert_stderr_contains(
40+
"help: insert a space between `-o` and `ut-dir` if this is intentional: `-o ut-dir`",
41+
);
42+
// test real args by iter CG_OPTIONS
43+
rustc()
44+
.input("main.rs")
45+
.arg("-opt_level")
46+
.run()
47+
.assert_stderr_contains(
48+
"warning: option `-o` has no space between flag name and value, which can be confusing",
49+
)
50+
.assert_stderr_contains(
51+
"note: output filename `-o pt_level` is applied instead of a flag named `opt_level`",
52+
)
53+
.assert_stderr_contains(
54+
"help: insert a space between `-o` and `pt_level` if this is intentional: `-o pt_level`"
55+
);
56+
// separater in-sensitive
57+
rustc()
58+
.input("main.rs")
59+
.arg("-opt-level")
60+
.run()
61+
.assert_stderr_contains(
62+
"warning: option `-o` has no space between flag name and value, which can be confusing",
63+
)
64+
.assert_stderr_contains(
65+
"note: output filename `-o pt-level` is applied instead of a flag named `opt-level`",
66+
)
67+
.assert_stderr_contains(
68+
"help: insert a space between `-o` and `pt-level` if this is intentional: `-o pt-level`"
69+
);
70+
rustc()
71+
.input("main.rs")
72+
.arg("-overflow-checks")
73+
.run()
74+
.assert_stderr_contains(
75+
"warning: option `-o` has no space between flag name and value, which can be confusing",
76+
)
77+
.assert_stderr_contains(
78+
"note: output filename `-o verflow-checks` \
79+
is applied instead of a flag named `overflow-checks`",
80+
)
81+
.assert_stderr_contains(
82+
"help: insert a space between `-o` and `verflow-checks` \
83+
if this is intentional: `-o verflow-checks`",
84+
);
85+
86+
// No warning for Z_OPTIONS
87+
rustc().input("main.rs").arg("-oom").run().assert_stderr_equals("");
88+
89+
// test no warning when there is space between `-o` and arg
90+
rustc().input("main.rs").arg("-o").arg("ptimize").run().assert_stderr_equals("");
91+
rustc().input("main.rs").arg("--out-dir").arg("xxx").run().assert_stderr_equals("");
92+
rustc().input("main.rs").arg("-o").arg("out-dir").run().assert_stderr_equals("");
93+
}

0 commit comments

Comments
 (0)