diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2022-02-17 10:58:07 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-02-17 10:58:07 +0000 |
commit | 752bf6c80a922e09edf5bcb53e15e08e83057a7f (patch) | |
tree | 0968dcfc9a8ccc858a5aa5531463cc50a713eab4 /gcc | |
parent | 6a6c21709314e72f2edb5539913a4b7ce7a1cb66 (diff) | |
parent | 766a9002a3d5fb6701de2d84ce689379811eabff (diff) | |
download | gcc-752bf6c80a922e09edf5bcb53e15e08e83057a7f.zip gcc-752bf6c80a922e09edf5bcb53e15e08e83057a7f.tar.gz gcc-752bf6c80a922e09edf5bcb53e15e08e83057a7f.tar.bz2 |
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 <arthur.cohen@embecosm.com>
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/rust/Make-lang.in | 1 | ||||
-rw-r--r-- | gcc/rust/parse/rust-cfg-parser.cc | 75 | ||||
-rw-r--r-- | gcc/rust/parse/rust-cfg-parser.h | 57 | ||||
-rw-r--r-- | gcc/rust/parse/rust-parse.cc | 1 | ||||
-rw-r--r-- | gcc/rust/rust-lang.cc | 2 | ||||
-rw-r--r-- | gcc/rust/rust-session-manager.cc | 86 | ||||
-rw-r--r-- | gcc/testsuite/rust/compile/cfg5.rs | 2 |
7 files changed, 147 insertions, 77 deletions
diff --git a/gcc/rust/Make-lang.in b/gcc/rust/Make-lang.in index 5d02f06..883e133 100644 --- a/gcc/rust/Make-lang.in +++ b/gcc/rust/Make-lang.in @@ -66,6 +66,7 @@ GRS_OBJS = \ rust/rust-gcc.o \ rust/rust-token.o \ rust/rust-lex.o \ + rust/rust-cfg-parser.o \ rust/rust-parse.o \ rust/rust-ast-full-test.o \ rust/rust-session-manager.o \ diff --git a/gcc/rust/parse/rust-cfg-parser.cc b/gcc/rust/parse/rust-cfg-parser.cc new file mode 100644 index 0000000..a6f34b6 --- /dev/null +++ b/gcc/rust/parse/rust-cfg-parser.cc @@ -0,0 +1,75 @@ +#include "rust-cfg-parser.h" +#include "selftest.h" + +namespace Rust { +bool +parse_cfg_option (const std::string &input, std::string &key, + std::string &value) +{ + key.clear (); + value.clear (); + + auto equal = input.find ('='); + + // If there is no equal sign, it means there is no value. Clean up the key + // and return + if (equal == std::string::npos) + { + key = input; + + // FIXME: Make sure key is a proper identifier + + return true; + } + + key = input.substr (0, equal); + + auto remaining_input = input.substr (equal + 1); + if (remaining_input[0] != '"' || remaining_input.back () != '"') + return false; + + // Remove the quotes around the value, by advancing one character + value = remaining_input.substr (1); + // And trimming the rightmost character. This is fine since we've already + // checked that both the first and last characters were quotes. + value.resize (value.size () - 1); + + // FIXME: We need to sanitize here and make sure that both key and value + // are proper identifiers + + return true; +} + +} // namespace Rust + +#if CHECKING_P + +namespace selftest { + +void +rust_cfg_parser_test (void) +{ + std::string key; + std::string value; + + ASSERT_TRUE (Rust::parse_cfg_option ("key-no-value", key, value)); + ASSERT_EQ (key, "key-no-value"); + ASSERT_TRUE (value.empty ()); + + ASSERT_TRUE (Rust::parse_cfg_option ("k=\"v\"", key, value)); + ASSERT_EQ (key, "k"); + ASSERT_EQ (value, "v"); + + // values should be between double quotes + ASSERT_FALSE (Rust::parse_cfg_option ("k=v", key, value)); + + // No value is an error if there is an equal sign + ASSERT_FALSE (Rust::parse_cfg_option ("k=", key, value)); + + // No key is an error + ASSERT_FALSE (Rust::parse_cfg_option ("=", key, value)); + ASSERT_FALSE (Rust::parse_cfg_option ("=value", key, value)); +} +} // namespace selftest + +#endif // CHECKING_P diff --git a/gcc/rust/parse/rust-cfg-parser.h b/gcc/rust/parse/rust-cfg-parser.h new file mode 100644 index 0000000..a4b860f --- /dev/null +++ b/gcc/rust/parse/rust-cfg-parser.h @@ -0,0 +1,57 @@ +/* This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. */ + +#ifndef RUST_CFG_PARSER_H +#define RUST_CFG_PARSER_H + +#include "config.h" +#include "system.h" +#include "coretypes.h" + +#include <string> + +namespace Rust { +/** + * Parse a `key` or `key="value"` pair given to the `-frust-cfg` compiler + * option. + * + * The format is as follows: + * + * -frust-cfg=<input> + * + * cfg_input: identifier | identifier '=' '"' identifier '"' + * + * @param input User input given to the -frust-cfg option + * @param key String in which to store the parsed `key`. + * @param value String in which to store the parsed `value` if it exists + * + * @return false if the given input was invalid, true otherwise + */ +bool +parse_cfg_option (const std::string &input, std::string &key, + std::string &value); +} // namespace Rust + +#if CHECKING_P + +namespace selftest { +extern void +rust_cfg_parser_test (void); +} // namespace selftest + +#endif // CHECKING_P + +#endif // RUST_CFG_PARSER_H diff --git a/gcc/rust/parse/rust-parse.cc b/gcc/rust/parse/rust-parse.cc index e78de51..f2c1301 100644 --- a/gcc/rust/parse/rust-parse.cc +++ b/gcc/rust/parse/rust-parse.cc @@ -118,5 +118,4 @@ extract_module_path (const AST::AttrVec &inner_attrs, return path; } - } // namespace Rust diff --git a/gcc/rust/rust-lang.cc b/gcc/rust/rust-lang.cc index fbab9b1..5ecd79b 100644 --- a/gcc/rust/rust-lang.cc +++ b/gcc/rust/rust-lang.cc @@ -33,6 +33,7 @@ #include "langhooks.h" #include "langhooks-def.h" #include "selftest.h" +#include "rust-cfg-parser.h" #include <mpfr.h> // note: header files must be in this order or else forward declarations don't @@ -453,6 +454,7 @@ run_rust_tests () { // Call tests for the rust frontend here simple_assert (); + rust_cfg_parser_test (); } } // namespace selftest diff --git a/gcc/rust/rust-session-manager.cc b/gcc/rust/rust-session-manager.cc index ea933d63..cd2c590 100644 --- a/gcc/rust/rust-session-manager.cc +++ b/gcc/rust/rust-session-manager.cc @@ -29,6 +29,7 @@ #include "rust-tycheck-dump.h" #include "rust-ast-resolve-unused.h" #include "rust-compile.h" +#include "rust-cfg-parser.h" #include "diagnostic.h" #include "input.h" @@ -382,87 +383,22 @@ Session::handle_cfg_option (const std::string &input) std::string key; std::string value; - enum pstate - { - KEY, - EQ, - VAL, - DONE, - ERROR - }; - - // FIXME - // we need to use the GCC self_test framework to unit-test this its - // likely got a bunch of bugs. This simple parser could be extracted to a - // helper function to be more easily unit-tested or it could be tested via - // checking what the target_options contain - bool expect_quote = false; - pstate s = KEY; - for (const auto &ch : input) + // Refactor this if needed + if (!parse_cfg_option (input, key, value)) { - if (ch == ' ') - { - if (!key.empty ()) - s = EQ; - else if (!value.empty ()) - s = DONE; - else - { - s = ERROR; - break; - } - } - else if (ch == '"') - { - expect_quote = !expect_quote; - } - else if (ch == '=') - { - if (key.empty ()) - { - s = ERROR; - break; - } - - s = VAL; - } - else - { - if (s == KEY) - key.push_back (ch); - else if (s == VAL) - value.push_back (ch); - else - { - s = ERROR; - break; - } - } - } - - if (key.empty () && value.empty ()) - s = ERROR; - - if (expect_quote) - s = ERROR; - - if (s == ERROR) - { - rust_error_at (Location (), - "invalid %<-frust-cfg=option%> expected %<key%> or " - "key=%<value%> got %<%s%>", - input.c_str ()); + rust_error_at ( + Location (), + "invalid argument to %<-frust-cfg%>: Accepted formats are " + "%<-frust-cfg=key%> or %<-frust-cfg=key=\"value\"%> (quoted)"); return false; } if (value.empty ()) - { - // rustc does not seem to error on dup key - options.target_data.insert_key (key); - return true; - } + // rustc does not seem to error on dup key + options.target_data.insert_key (key); + else + options.target_data.insert_key_value_pair (key, value); - options.target_data.insert_key_value_pair (key, value); return true; } diff --git a/gcc/testsuite/rust/compile/cfg5.rs b/gcc/testsuite/rust/compile/cfg5.rs index 927c497..1852efa 100644 --- a/gcc/testsuite/rust/compile/cfg5.rs +++ b/gcc/testsuite/rust/compile/cfg5.rs @@ -1,4 +1,4 @@ -// { dg-additional-options "-w -frust-cfg=A=B" } +// { dg-additional-options "-w -frust-cfg=A=\"B\"" } struct Foo; impl Foo { #[cfg(A = "B")] |