Skip to content

Commit 49dcecd

Browse files
committed
frust-cfg: Use proper parser to parse key-value pairs
In order to conform to the rust reference, we must make sure that when parsing -frust-cfg key-value pairs, we actually parse a valid key and value. The key must be a valid identifier, while the value must be a valid identifier surrounded by double quotes
1 parent ede68b7 commit 49dcecd

File tree

2 files changed

+70
-35
lines changed

2 files changed

+70
-35
lines changed

gcc/rust/parse/rust-cfg-parser.cc

Lines changed: 69 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,55 @@
11
#include "rust-cfg-parser.h"
2+
#include "rust-lex.h"
3+
#include "rust-parse.h"
4+
#include "rust-session-manager.h"
25
#include "selftest.h"
36

47
namespace Rust {
58
bool
6-
parse_cfg_option (const std::string &input, std::string &key,
7-
std::string &value)
9+
parse_cfg_option (std::string &input, std::string &key, std::string &value)
810
{
911
key.clear ();
1012
value.clear ();
1113

12-
auto equal = input.find ('=');
14+
auto lexer = Lexer::lex_string (input);
15+
auto parser = Parser<Lexer> (std::move (lexer));
1316

14-
// If there is no equal sign, it means there is no value. Clean up the key
15-
// and return
16-
if (equal == std::string::npos)
17+
auto token = parser.peek_current_token ();
18+
if (token->get_id () != IDENTIFIER)
1719
{
18-
key = input;
19-
20-
// FIXME: Make sure key is a proper identifier
21-
22-
return true;
20+
return false;
2321
}
2422

25-
key = input.substr (0, equal);
26-
27-
auto remaining_input = input.substr (equal + 1);
28-
if (remaining_input[0] != '"' || remaining_input.back () != '"')
29-
return false;
30-
31-
// Remove the quotes around the value, by advancing one character
32-
value = remaining_input.substr (1);
33-
// And trimming the rightmost character. This is fine since we've already
34-
// checked that both the first and last characters were quotes.
35-
value.resize (value.size () - 1);
23+
key = token->get_str ();
3624

37-
// FIXME: We need to sanitize here and make sure that both key and value
38-
// are proper identifiers
25+
rust_assert (parser.skip_token (IDENTIFIER));
26+
token = parser.peek_current_token ();
3927

40-
return true;
28+
switch (token->get_id ())
29+
{
30+
case END_OF_FILE:
31+
// we're done parsing, we had a valid key, return happily
32+
return true;
33+
case EQUAL:
34+
// We have an equal sign: Skip the token and parse an identifier
35+
{
36+
rust_assert (parser.skip_token (EQUAL));
37+
38+
auto value_expr = parser.parse_literal_expr ();
39+
// We had an equal sign but no value, error out
40+
if (!value_expr)
41+
return false;
42+
43+
if (value_expr->get_lit_type () != AST::Literal::LitType::STRING)
44+
return false;
45+
46+
value = value_expr->get_literal ().as_string ();
47+
return true;
48+
}
49+
default:
50+
return false;
51+
}
4152
}
42-
4353
} // namespace Rust
4454

4555
#if CHECKING_P
@@ -52,23 +62,49 @@ rust_cfg_parser_test (void)
5262
std::string key;
5363
std::string value;
5464

55-
ASSERT_TRUE (Rust::parse_cfg_option ("key-no-value", key, value));
56-
ASSERT_EQ (key, "key-no-value");
65+
auto input = std::string ("key_no_value");
66+
67+
ASSERT_TRUE (Rust::parse_cfg_option (input, key, value));
68+
ASSERT_EQ (key, "key_no_value");
5769
ASSERT_TRUE (value.empty ());
5870

59-
ASSERT_TRUE (Rust::parse_cfg_option ("k=\"v\"", key, value));
71+
input = std::string ("k=\"v\"");
72+
73+
ASSERT_TRUE (Rust::parse_cfg_option (input, key, value));
6074
ASSERT_EQ (key, "k");
6175
ASSERT_EQ (value, "v");
6276

6377
// values should be between double quotes
64-
ASSERT_FALSE (Rust::parse_cfg_option ("k=v", key, value));
78+
input = std::string ("k=v");
79+
ASSERT_FALSE (Rust::parse_cfg_option (input, key, value));
6580

6681
// No value is an error if there is an equal sign
67-
ASSERT_FALSE (Rust::parse_cfg_option ("k=", key, value));
82+
input = std::string ("k=");
83+
ASSERT_FALSE (Rust::parse_cfg_option (input, key, value));
6884

6985
// No key is an error
70-
ASSERT_FALSE (Rust::parse_cfg_option ("=", key, value));
71-
ASSERT_FALSE (Rust::parse_cfg_option ("=value", key, value));
86+
input = std::string ("=");
87+
ASSERT_FALSE (Rust::parse_cfg_option (input, key, value));
88+
89+
input = std::string ("=value");
90+
ASSERT_FALSE (Rust::parse_cfg_option (input, key, value));
91+
92+
// values that are not string literals are an error
93+
input = std::string ("key=b\"a\"");
94+
ASSERT_FALSE (Rust::parse_cfg_option (input, key, value));
95+
96+
input = std::string ("key='v'");
97+
ASSERT_FALSE (Rust::parse_cfg_option (input, key, value));
98+
99+
input = std::string ("key=155");
100+
ASSERT_FALSE (Rust::parse_cfg_option (input, key, value));
101+
102+
input = std::string ("key=3.14");
103+
ASSERT_FALSE (Rust::parse_cfg_option (input, key, value));
104+
105+
// kebab case is not valid for an identifier
106+
input = std::string ("key-no-value");
107+
ASSERT_FALSE (Rust::parse_cfg_option (input, key, value));
72108
}
73109
} // namespace selftest
74110

gcc/rust/parse/rust-cfg-parser.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,7 @@ namespace Rust {
4141
* @return false if the given input was invalid, true otherwise
4242
*/
4343
bool
44-
parse_cfg_option (const std::string &input, std::string &key,
45-
std::string &value);
44+
parse_cfg_option (std::string &input, std::string &key, std::string &value);
4645
} // namespace Rust
4746

4847
#if CHECKING_P

0 commit comments

Comments
 (0)