Skip to content

Commit 752bf6c

Browse files
Merge #935
935: frust-cfg: Only allow double quoted values r=philberty a=CohenArthur Closes #910 This PR separates the `handle_cfg_option()` function in two, separating the parsing logic from the session logic. The parsing logic is able to be unit tested, and now only allows quoted values. What remains to be done is to only allow `key` and `value` to be proper rust identifiers. We need to figure out if we'd like to spawn a parser here and parse identifiers, or simply sanitize both strings to make sure they do not contain invalid characters. Co-authored-by: Arthur Cohen <[email protected]>
2 parents 6a6c217 + 766a900 commit 752bf6c

File tree

7 files changed

+147
-77
lines changed

7 files changed

+147
-77
lines changed

gcc/rust/Make-lang.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ GRS_OBJS = \
6666
rust/rust-gcc.o \
6767
rust/rust-token.o \
6868
rust/rust-lex.o \
69+
rust/rust-cfg-parser.o \
6970
rust/rust-parse.o \
7071
rust/rust-ast-full-test.o \
7172
rust/rust-session-manager.o \

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

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
#include "rust-cfg-parser.h"
2+
#include "selftest.h"
3+
4+
namespace Rust {
5+
bool
6+
parse_cfg_option (const std::string &input, std::string &key,
7+
std::string &value)
8+
{
9+
key.clear ();
10+
value.clear ();
11+
12+
auto equal = input.find ('=');
13+
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+
{
18+
key = input;
19+
20+
// FIXME: Make sure key is a proper identifier
21+
22+
return true;
23+
}
24+
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);
36+
37+
// FIXME: We need to sanitize here and make sure that both key and value
38+
// are proper identifiers
39+
40+
return true;
41+
}
42+
43+
} // namespace Rust
44+
45+
#if CHECKING_P
46+
47+
namespace selftest {
48+
49+
void
50+
rust_cfg_parser_test (void)
51+
{
52+
std::string key;
53+
std::string value;
54+
55+
ASSERT_TRUE (Rust::parse_cfg_option ("key-no-value", key, value));
56+
ASSERT_EQ (key, "key-no-value");
57+
ASSERT_TRUE (value.empty ());
58+
59+
ASSERT_TRUE (Rust::parse_cfg_option ("k=\"v\"", key, value));
60+
ASSERT_EQ (key, "k");
61+
ASSERT_EQ (value, "v");
62+
63+
// values should be between double quotes
64+
ASSERT_FALSE (Rust::parse_cfg_option ("k=v", key, value));
65+
66+
// No value is an error if there is an equal sign
67+
ASSERT_FALSE (Rust::parse_cfg_option ("k=", key, value));
68+
69+
// No key is an error
70+
ASSERT_FALSE (Rust::parse_cfg_option ("=", key, value));
71+
ASSERT_FALSE (Rust::parse_cfg_option ("=value", key, value));
72+
}
73+
} // namespace selftest
74+
75+
#endif // CHECKING_P

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

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/* This file is part of GCC.
2+
3+
GCC is free software; you can redistribute it and/or modify
4+
it under the terms of the GNU General Public License as published by
5+
the Free Software Foundation; either version 3, or (at your option)
6+
any later version.
7+
8+
GCC is distributed in the hope that it will be useful,
9+
but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+
GNU General Public License for more details.
12+
13+
You should have received a copy of the GNU General Public License
14+
along with GCC; see the file COPYING3. If not see
15+
<http://www.gnu.org/licenses/>. */
16+
17+
#ifndef RUST_CFG_PARSER_H
18+
#define RUST_CFG_PARSER_H
19+
20+
#include "config.h"
21+
#include "system.h"
22+
#include "coretypes.h"
23+
24+
#include <string>
25+
26+
namespace Rust {
27+
/**
28+
* Parse a `key` or `key="value"` pair given to the `-frust-cfg` compiler
29+
* option.
30+
*
31+
* The format is as follows:
32+
*
33+
* -frust-cfg=<input>
34+
*
35+
* cfg_input: identifier | identifier '=' '"' identifier '"'
36+
*
37+
* @param input User input given to the -frust-cfg option
38+
* @param key String in which to store the parsed `key`.
39+
* @param value String in which to store the parsed `value` if it exists
40+
*
41+
* @return false if the given input was invalid, true otherwise
42+
*/
43+
bool
44+
parse_cfg_option (const std::string &input, std::string &key,
45+
std::string &value);
46+
} // namespace Rust
47+
48+
#if CHECKING_P
49+
50+
namespace selftest {
51+
extern void
52+
rust_cfg_parser_test (void);
53+
} // namespace selftest
54+
55+
#endif // CHECKING_P
56+
57+
#endif // RUST_CFG_PARSER_H

gcc/rust/parse/rust-parse.cc

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,5 +118,4 @@ extract_module_path (const AST::AttrVec &inner_attrs,
118118

119119
return path;
120120
}
121-
122121
} // namespace Rust

gcc/rust/rust-lang.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include "langhooks.h"
3434
#include "langhooks-def.h"
3535
#include "selftest.h"
36+
#include "rust-cfg-parser.h"
3637

3738
#include <mpfr.h>
3839
// note: header files must be in this order or else forward declarations don't
@@ -453,6 +454,7 @@ run_rust_tests ()
453454
{
454455
// Call tests for the rust frontend here
455456
simple_assert ();
457+
rust_cfg_parser_test ();
456458
}
457459
} // namespace selftest
458460

gcc/rust/rust-session-manager.cc

Lines changed: 11 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include "rust-tycheck-dump.h"
3030
#include "rust-ast-resolve-unused.h"
3131
#include "rust-compile.h"
32+
#include "rust-cfg-parser.h"
3233

3334
#include "diagnostic.h"
3435
#include "input.h"
@@ -382,87 +383,22 @@ Session::handle_cfg_option (const std::string &input)
382383
std::string key;
383384
std::string value;
384385

385-
enum pstate
386-
{
387-
KEY,
388-
EQ,
389-
VAL,
390-
DONE,
391-
ERROR
392-
};
393-
394-
// FIXME
395-
// we need to use the GCC self_test framework to unit-test this its
396-
// likely got a bunch of bugs. This simple parser could be extracted to a
397-
// helper function to be more easily unit-tested or it could be tested via
398-
// checking what the target_options contain
399-
bool expect_quote = false;
400-
pstate s = KEY;
401-
for (const auto &ch : input)
386+
// Refactor this if needed
387+
if (!parse_cfg_option (input, key, value))
402388
{
403-
if (ch == ' ')
404-
{
405-
if (!key.empty ())
406-
s = EQ;
407-
else if (!value.empty ())
408-
s = DONE;
409-
else
410-
{
411-
s = ERROR;
412-
break;
413-
}
414-
}
415-
else if (ch == '"')
416-
{
417-
expect_quote = !expect_quote;
418-
}
419-
else if (ch == '=')
420-
{
421-
if (key.empty ())
422-
{
423-
s = ERROR;
424-
break;
425-
}
426-
427-
s = VAL;
428-
}
429-
else
430-
{
431-
if (s == KEY)
432-
key.push_back (ch);
433-
else if (s == VAL)
434-
value.push_back (ch);
435-
else
436-
{
437-
s = ERROR;
438-
break;
439-
}
440-
}
441-
}
442-
443-
if (key.empty () && value.empty ())
444-
s = ERROR;
445-
446-
if (expect_quote)
447-
s = ERROR;
448-
449-
if (s == ERROR)
450-
{
451-
rust_error_at (Location (),
452-
"invalid %<-frust-cfg=option%> expected %<key%> or "
453-
"key=%<value%> got %<%s%>",
454-
input.c_str ());
389+
rust_error_at (
390+
Location (),
391+
"invalid argument to %<-frust-cfg%>: Accepted formats are "
392+
"%<-frust-cfg=key%> or %<-frust-cfg=key=\"value\"%> (quoted)");
455393
return false;
456394
}
457395

458396
if (value.empty ())
459-
{
460-
// rustc does not seem to error on dup key
461-
options.target_data.insert_key (key);
462-
return true;
463-
}
397+
// rustc does not seem to error on dup key
398+
options.target_data.insert_key (key);
399+
else
400+
options.target_data.insert_key_value_pair (key, value);
464401

465-
options.target_data.insert_key_value_pair (key, value);
466402
return true;
467403
}
468404

gcc/testsuite/rust/compile/cfg5.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// { dg-additional-options "-w -frust-cfg=A=B" }
1+
// { dg-additional-options "-w -frust-cfg=A=\"B\"" }
22
struct Foo;
33
impl Foo {
44
#[cfg(A = "B")]

0 commit comments

Comments
 (0)