Skip to content

Commit 26f5936

Browse files
authored
Rollup merge of #143719 - xizheyin:142812-1, r=jieyouxu
Emit warning when there is no space between `-o` and arg Closes #142812 `getopt` doesn't seem to have an API to check this, so we have to check the args manually. r? compiler
2 parents accf61d + af39c0c commit 26f5936

File tree

4 files changed

+147
-0
lines changed

4 files changed

+147
-0
lines changed

compiler/rustc_driver_impl/src/lib.rs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1237,9 +1237,55 @@ 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 high-value confusables, for example:
1269+
// - Long name of flags, e.g. `--out-dir` vs `-out-dir`
1270+
// - C compiler flag, e.g. `optimize`, `o0`, `o1`, `o2`, `o3`, `ofast`.
1271+
// - Codegen flags, e.g. `pt-level` of `-opt-level`.
1272+
if optgroups.iter().any(|option| eq_ignore_separators(option.long_name(), filename))
1273+
|| config::CG_OPTIONS.iter().any(|option| eq_ignore_separators(option.name(), filename))
1274+
|| fake_args.iter().any(|arg| eq_ignore_separators(arg, filename))
1275+
{
1276+
early_dcx.early_warn(
1277+
"option `-o` has no space between flag name and value, which can be confusing",
1278+
);
1279+
early_dcx.early_note(format!(
1280+
"output filename `-o {name}` is applied instead of a flag named `o{name}`"
1281+
));
1282+
early_dcx.early_help(format!(
1283+
"insert a space between `-o` and `{name}` if this is intentional: `-o {name}`"
1284+
));
1285+
}
1286+
}
1287+
}
1288+
12431289
fn parse_crate_attrs<'a>(sess: &'a Session) -> PResult<'a, ast::AttrVec> {
12441290
let mut parser = unwrap_or_emit_fatal(match &sess.io.input {
12451291
Input::File(file) => new_parser_from_file(&sess.psess, file, None),

compiler/rustc_session/src/config.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1708,6 +1708,11 @@ impl RustcOptGroup {
17081708
OptionKind::FlagMulti => options.optflagmulti(short_name, long_name, desc),
17091709
};
17101710
}
1711+
1712+
/// This is for diagnostics-only.
1713+
pub fn long_name(&self) -> &str {
1714+
self.long_name
1715+
}
17111716
}
17121717

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

0 commit comments

Comments
 (0)