Skip to content

Commit 6032412

Browse files
bors[bot]liushuyu
andauthored
Merge #1088
1088: rust-session-manager: better crate name handling logic r=philberty a=liushuyu - rust-session-manager: set and validate crate name properly - testsuite/rust: fix the testcases and add more testcases for testing crate name handling Co-authored-by: liushuyu <[email protected]>
2 parents 497ee70 + a125901 commit 6032412

11 files changed

+170
-11
lines changed

gcc/rust/rust-lang.cc

+1
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,7 @@ run_rust_tests ()
458458
simple_assert ();
459459
rust_cfg_parser_test ();
460460
rust_privacy_ctx_test ();
461+
rust_crate_name_validation_test ();
461462
}
462463
} // namespace selftest
463464

gcc/rust/rust-session-manager.cc

+127-6
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
#include "diagnostic.h"
3636
#include "input.h"
3737
#include "rust-target.h"
38+
#include "selftest.h"
3839

3940
extern bool
4041
saw_errors (void);
@@ -54,7 +55,65 @@ const char *kHIRDumpFile = "gccrs.hir.dump";
5455
const char *kHIRTypeResolutionDumpFile = "gccrs.type-resolution.dump";
5556
const char *kTargetOptionsDumpFile = "gccrs.target-options.dump";
5657

57-
const std::string kDefaultCrateName = "example";
58+
const std::string kDefaultCrateName = "rust_out";
59+
const size_t kMaxNameLength = 64;
60+
61+
static std::string
62+
infer_crate_name (const std::string &filename)
63+
{
64+
if (filename == "-")
65+
return kDefaultCrateName;
66+
67+
std::string crate = std::string (filename);
68+
size_t path_sep = crate.find_last_of (file_separator);
69+
70+
// find the base filename
71+
if (path_sep != std::string::npos)
72+
crate.erase (0, path_sep + 1);
73+
74+
// find the file stem name (remove file extension)
75+
size_t ext_position = crate.find_last_of ('.');
76+
if (ext_position != std::string::npos)
77+
crate.erase (ext_position);
78+
79+
// Replace all the '-' symbols with '_' per Rust rules
80+
for (auto &c : crate)
81+
{
82+
if (c == '-')
83+
c = '_';
84+
}
85+
return crate;
86+
}
87+
88+
/* Validate the crate name using the ASCII rules
89+
TODO: Support Unicode version of the rules */
90+
91+
static bool
92+
validate_crate_name (const std::string &crate_name, Error &error)
93+
{
94+
if (crate_name.empty ())
95+
{
96+
error = Error (Location (), "crate name cannot be empty");
97+
return false;
98+
}
99+
if (crate_name.length () > kMaxNameLength)
100+
{
101+
error = Error (Location (), "crate name cannot exceed %ld characters",
102+
kMaxNameLength);
103+
return false;
104+
}
105+
for (auto &c : crate_name)
106+
{
107+
if (!(ISALNUM (c) || c == '_'))
108+
{
109+
error = Error (Location (),
110+
"invalid character %<%c%> in crate name: %<%s%>", c,
111+
crate_name.c_str ());
112+
return false;
113+
}
114+
}
115+
return true;
116+
}
58117

59118
// Implicitly enable a target_feature (and recursively enable dependencies).
60119
void
@@ -311,10 +370,6 @@ Session::init ()
311370

312371
// setup backend to GCC GIMPLE
313372
backend = rust_get_backend ();
314-
315-
// set the default crate name if crate name was unset
316-
if (options.crate_name.empty ())
317-
options.set_crate_name (kDefaultCrateName);
318373
}
319374

320375
/* Initialise default options. Actually called before handle_option, unlike init
@@ -347,7 +402,16 @@ Session::handle_option (
347402
case OPT_frust_crate_:
348403
// set the crate name
349404
if (arg != nullptr)
350-
ret = options.set_crate_name (arg);
405+
{
406+
auto error = Error (Location (), std::string ());
407+
if ((ret = validate_crate_name (arg, error)))
408+
options.set_crate_name (arg);
409+
else
410+
{
411+
rust_assert (!error.message.empty ());
412+
error.emit_error ();
413+
}
414+
}
351415
else
352416
ret = false;
353417
break;
@@ -479,6 +543,32 @@ Session::enable_dump (std::string arg)
479543
void
480544
Session::parse_files (int num_files, const char **files)
481545
{
546+
if (options.crate_name.empty ())
547+
{
548+
/* HACK: We use the first file to infer the crate name, which might be
549+
* incorrect: since rustc only allows one file to be supplied in the
550+
* command-line */
551+
auto filename = "-";
552+
if (num_files > 0)
553+
filename = files[0];
554+
555+
auto crate_name = infer_crate_name (filename);
556+
Error error ((Location ()), std::string ());
557+
rust_debug ("inferred crate name: %s", crate_name.c_str ());
558+
if (!validate_crate_name (crate_name, error))
559+
{
560+
// fake a linemapping so that we can show the filename
561+
linemap->start_file (filename, 0);
562+
linemap->start_line (0, 1);
563+
error.emit_error ();
564+
rust_inform (linemap->get_location (0),
565+
"crate name inferred from this file");
566+
linemap->stop ();
567+
return;
568+
}
569+
options.set_crate_name (crate_name);
570+
}
571+
482572
auto mappings = Analysis::Mappings::get ();
483573
CrateNum crate_num = mappings->setup_crate_mappings (options.crate_name);
484574
mappings->set_current_crate (crate_num);
@@ -1121,3 +1211,34 @@ TargetOptions::enable_implicit_feature_reqs (std::string feature)
11211211
* - code generation
11221212
* - link */
11231213
} // namespace Rust
1214+
1215+
#if CHECKING_P
1216+
namespace selftest {
1217+
void
1218+
rust_crate_name_validation_test (void)
1219+
{
1220+
auto error = Rust::Error (Location (), std::string ());
1221+
ASSERT_TRUE (Rust::validate_crate_name ("example", error));
1222+
ASSERT_TRUE (Rust::validate_crate_name ("abcdefg_1234", error));
1223+
ASSERT_TRUE (Rust::validate_crate_name ("1", error));
1224+
// FIXME: The next test does not pass as of current implementation
1225+
// ASSERT_TRUE (Rust::CompileOptions::validate_crate_name ("惊吓"));
1226+
// NOTE: - is not allowed in the crate name ...
1227+
1228+
ASSERT_FALSE (Rust::validate_crate_name ("abcdefg-1234", error));
1229+
ASSERT_FALSE (Rust::validate_crate_name ("a+b", error));
1230+
ASSERT_FALSE (Rust::validate_crate_name ("/a+b/", error));
1231+
1232+
/* Tests for crate name inference */
1233+
ASSERT_EQ (Rust::infer_crate_name ("c.rs"), "c");
1234+
// NOTE: ... but - is allowed when in the filename
1235+
ASSERT_EQ (Rust::infer_crate_name ("a-b.rs"), "a_b");
1236+
ASSERT_EQ (Rust::infer_crate_name ("book.rs.txt"), "book.rs");
1237+
#if defined(HAVE_DOS_BASED_FILE_SYSTEM)
1238+
ASSERT_EQ (Rust::infer_crate_name ("a\\c\\a-b.rs"), "a_b");
1239+
#else
1240+
ASSERT_EQ (Rust::infer_crate_name ("a/c/a-b.rs"), "a_b");
1241+
#endif
1242+
}
1243+
} // namespace selftest
1244+
#endif // CHECKING_P

gcc/rust/rust-session-manager.h

+11-3
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222

2323
#include "rust-linemap.h"
2424
#include "rust-backend.h"
25+
#include "safe-ctype.h"
2526

2627
#include "config.h"
2728
#include "rust-system.h"
@@ -212,11 +213,11 @@ struct CompileOptions
212213
enable_dump_option (DumpOption::TYPE_RESOLUTION_DUMP);
213214
}
214215

215-
bool set_crate_name (std::string name)
216+
void set_crate_name (std::string name)
216217
{
217-
// TODO: validate the crate name?
218+
rust_assert (!name.empty ());
219+
218220
crate_name = std::move (name);
219-
return true;
220221
}
221222

222223
void set_edition (int raw_edition)
@@ -304,4 +305,11 @@ struct Session
304305
};
305306
} // namespace Rust
306307

308+
#if CHECKING_P
309+
namespace selftest {
310+
extern void
311+
rust_crate_name_validation_test (void);
312+
}
313+
#endif // CHECKING_P
314+
307315
#endif
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// { dg-additional-options "-frust-crate=bad+name" }
2+
// { dg-excess-errors "invalid crate name: ...." }
3+
// { dg-excess-errors "unrecognized command-line option ...." }
4+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// { dg-additional-options "-fdump-tree-gimple -frust-crate=good_name" }
2+
pub fn does_nothing() {}
3+
fn main() {
4+
does_nothing()
5+
}
6+
// { dg-final { scan-tree-dump-times {good_name::does_nothing} 2 gimple } }
7+
// { dg-final { scan-tree-dump-times {good_name::main} 1 gimple } }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
// { dg-excess-errors "invalid crate name: ...." }
2+
// { dg-bogus "unrecognized command-line option ...." }
3+
fn main() {}

gcc/testsuite/rust/compile/canonical_paths1.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// { dg-additional-options "-w -fdump-tree-gimple" }
1+
// { dg-additional-options "-w -fdump-tree-gimple -frust-crate=example" }
22
struct Foo(i32);
33

44
trait TR {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// { dg-additional-options "-fdump-tree-gimple" }
2+
pub fn does_nothing() {}
3+
fn main() {
4+
does_nothing()
5+
}
6+
// { dg-final { scan-tree-dump-times {infer_crate_name::does_nothing} 2 gimple } }
7+
// { dg-final { scan-tree-dump-times {infer_crate_name::main} 1 gimple } }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// { dg-additional-options "-frust-crate=fancy_crate_name -fdump-tree-gimple" }
2+
pub fn does_nothing() {}
3+
fn main() {
4+
does_nothing()
5+
}
6+
// { dg-final { scan-tree-dump-times {fancy_crate_name::does_nothing} 2 gimple } }
7+
// { dg-final { scan-tree-dump-times {fancy_crate_name::main} 1 gimple } }

gcc/testsuite/rust/compile/torture/struct_decl.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// { dg-additional-options -fdump-tree-gimple }
1+
// { dg-additional-options "-fdump-tree-gimple -frust-crate=example" }
22

33
struct Foo {
44
a: u16,

gcc/testsuite/rust/compile/traits9.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
// { dg-additional-options -frust-crate=example }
12
struct Foo(i32);
23
trait Bar {
34
fn baz(&self);

0 commit comments

Comments
 (0)