35
35
#include " diagnostic.h"
36
36
#include " input.h"
37
37
#include " rust-target.h"
38
+ #include " selftest.h"
38
39
39
40
extern bool
40
41
saw_errors (void );
@@ -55,9 +56,10 @@ const char *kHIRTypeResolutionDumpFile = "gccrs.type-resolution.dump";
55
56
const char *kTargetOptionsDumpFile = " gccrs.target-options.dump" ;
56
57
57
58
const std::string kDefaultCrateName = " rust_out" ;
59
+ const size_t kMaxNameLength = 64 ;
58
60
59
61
static std::string
60
- infer_crate_name (const std::string filename)
62
+ infer_crate_name (const std::string & filename)
61
63
{
62
64
if (filename == " -" )
63
65
return kDefaultCrateName ;
@@ -74,9 +76,42 @@ infer_crate_name (const std::string filename)
74
76
if (ext_position != std::string::npos)
75
77
crate.erase (ext_position);
76
78
79
+ // Replace all the '-' symbols with '_' per Rust rules
80
+ for (auto &c : crate)
81
+ {
82
+ if (c == ' -' )
83
+ c = ' _' ;
84
+ }
77
85
return crate;
78
86
}
79
87
88
+ bool
89
+ CompileOptions::validate_crate_name (const std::string &crate_name)
90
+ {
91
+ if (crate_name.empty ())
92
+ {
93
+ rust_error_at (Location (), " crate name cannot be empty" );
94
+ return false ;
95
+ }
96
+ if (crate_name.length () > kMaxNameLength )
97
+ {
98
+ rust_error_at (Location (), " crate name cannot exceed %ld characters" ,
99
+ kMaxNameLength );
100
+ return false ;
101
+ }
102
+ for (auto &c : crate_name)
103
+ {
104
+ if (!(ISALNUM (c) || c == ' _' ))
105
+ {
106
+ rust_error_at (Location (),
107
+ " invalid character %<%c%> in crate name: %<%s%>" , c,
108
+ crate_name.c_str ());
109
+ return false ;
110
+ }
111
+ }
112
+ return true ;
113
+ }
114
+
80
115
// Implicitly enable a target_feature (and recursively enable dependencies).
81
116
void
82
117
Session::implicitly_enable_feature (std::string feature_name)
@@ -496,21 +531,25 @@ Session::enable_dump (std::string arg)
496
531
void
497
532
Session::parse_files (int num_files, const char **files)
498
533
{
499
- rust_assert (num_files > 0 );
500
-
501
534
if (options.crate_name .empty ())
502
535
{
503
536
/* HACK: We use the first file to infer the crate name, which might be
504
537
* incorrect: since rustc only allows one file to be supplied in the
505
538
* command-line */
506
- auto crate_name = infer_crate_name (files[0 ]);
507
- rust_debug_loc (Location (), " inferred crate name: %s" ,
508
- crate_name.c_str ());
539
+ auto filename = " -" ;
540
+ if (num_files > 0 )
541
+ filename = files[0 ];
542
+
543
+ auto crate_name = infer_crate_name (filename);
544
+ rust_debug (" inferred crate name: %s" , crate_name.c_str ());
509
545
if (!options.set_crate_name (crate_name))
510
546
{
511
- rust_inform (Location (),
512
- " crate name inferred from the input file %<%s%>" ,
513
- files[0 ]);
547
+ // fake a linemapping so that we can show the filename
548
+ linemap->start_file (filename, 0 );
549
+ linemap->start_line (0 , 1 );
550
+ rust_inform (linemap->get_location (0 ),
551
+ " crate name inferred from this file" );
552
+ linemap->stop ();
514
553
return ;
515
554
}
516
555
}
@@ -1157,3 +1196,33 @@ TargetOptions::enable_implicit_feature_reqs (std::string feature)
1157
1196
* - code generation
1158
1197
* - link */
1159
1198
} // namespace Rust
1199
+
1200
+ #if CHECKING_P
1201
+ namespace selftest {
1202
+ void
1203
+ rust_crate_name_validation_test (void )
1204
+ {
1205
+ ASSERT_TRUE (Rust::CompileOptions::validate_crate_name (" example" ));
1206
+ ASSERT_TRUE (Rust::CompileOptions::validate_crate_name (" abcdefg_1234" ));
1207
+ ASSERT_TRUE (Rust::CompileOptions::validate_crate_name (" 1" ));
1208
+ // FIXME: The next test does not pass as of current implementation
1209
+ // ASSERT_TRUE (Rust::CompileOptions::validate_crate_name ("惊吓"));
1210
+ // NOTE: - is not allowed in the crate name ...
1211
+ /*
1212
+ ASSERT_FALSE (Rust::CompileOptions::validate_crate_name ("abcdefg-1234"));
1213
+ ASSERT_FALSE (Rust::CompileOptions::validate_crate_name ("a+b"));
1214
+ ASSERT_FALSE (Rust::CompileOptions::validate_crate_name ("/a+b/")); */
1215
+
1216
+ /* Tests for crate name inference */
1217
+ ASSERT_EQ (Rust::infer_crate_name (" c.rs" ), " c" );
1218
+ // NOTE: ... but - is allowed when in the filename
1219
+ ASSERT_EQ (Rust::infer_crate_name (" a-b.rs" ), " a_b" );
1220
+ ASSERT_EQ (Rust::infer_crate_name (" book.rs.txt" ), " book.rs" );
1221
+ #if defined(HAVE_DOS_BASED_FILE_SYSTEM)
1222
+ ASSERT_EQ (Rust::infer_crate_name (" a\\ c\\ a-b.rs" ), " a_b" );
1223
+ #else
1224
+ ASSERT_EQ (Rust::infer_crate_name (" a/c/a-b.rs" ), " a_b" );
1225
+ #endif
1226
+ }
1227
+ } // namespace selftest
1228
+ #endif // CHECKING_P
0 commit comments