From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 1643) id CA7C3386DC6B; Wed, 8 Jun 2022 12:31:26 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org CA7C3386DC6B MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Content-Type: text/plain; charset="utf-8" From: Thomas Schwinge To: gcc-cvs@gcc.gnu.org Subject: [gcc/devel/rust/master] macros: Add env! macro X-Act-Checkin: gcc X-Git-Author: =?utf-8?q?Ond=C5=99ej_Machota?= X-Git-Refname: refs/heads/devel/rust/master X-Git-Oldrev: e9ab95c088060ab27d3665879cd1ae0b6cbdc912 X-Git-Newrev: 1e6e42769665288b3e2a12148ee9bacf057b2fe8 Message-Id: <20220608123126.CA7C3386DC6B@sourceware.org> Date: Wed, 8 Jun 2022 12:31:26 +0000 (GMT) X-BeenThere: gcc-cvs@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-cvs mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 08 Jun 2022 12:31:26 -0000 https://gcc.gnu.org/g:1e6e42769665288b3e2a12148ee9bacf057b2fe8 commit 1e6e42769665288b3e2a12148ee9bacf057b2fe8 Author: Ondřej Machota Date: Tue Apr 12 20:48:30 2022 +0200 macros: Add env! macro Signed-off-by: Ondřej Machota Diff: --- gcc/rust/expand/rust-macro-builtins.cc | 70 ++++++++++++++++++++++ gcc/rust/expand/rust-macro-builtins.h | 3 + gcc/rust/util/rust-hir-map.cc | 1 + gcc/testsuite/rust/compile/builtin_macro_env.rs | 19 ++++++ .../rust/execute/torture/builtin_macro_env.rs | 26 ++++++++ 5 files changed, 119 insertions(+) diff --git a/gcc/rust/expand/rust-macro-builtins.cc b/gcc/rust/expand/rust-macro-builtins.cc index 1f41545ba38..d0f73024ca9 100644 --- a/gcc/rust/expand/rust-macro-builtins.cc +++ b/gcc/rust/expand/rust-macro-builtins.cc @@ -306,4 +306,74 @@ MacroBuiltin::concat (Location invoc_locus, AST::MacroInvocData &invoc) return AST::ASTFragment ({node}); } +/* Expand builtin macro env!(), which inspects an environment variable at + compile time. */ + +AST::ASTFragment +MacroBuiltin::env (Location invoc_locus, AST::MacroInvocData &invoc) +{ + auto invoc_token_tree = invoc.get_delim_tok_tree (); + MacroInvocLexer lex (invoc_token_tree.to_token_stream ()); + Parser parser (std::move (lex)); + + auto last_token_id = macro_end_token (invoc_token_tree, parser); + + if (parser.peek_current_token ()->get_id () != STRING_LITERAL) + { + if (parser.peek_current_token ()->get_id () == last_token_id) + rust_error_at (invoc_locus, "env! takes 1 or 2 arguments"); + else + rust_error_at (parser.peek_current_token ()->get_locus (), + "argument must be a string literal"); + return AST::ASTFragment::create_error (); + } + + auto lit_expr = parser.parse_literal_expr (); + auto comma_skipped = parser.maybe_skip_token (COMMA); + + std::unique_ptr error_expr = nullptr; + + if (parser.peek_current_token ()->get_id () != last_token_id) + { + if (!comma_skipped) + { + rust_error_at (parser.peek_current_token ()->get_locus (), + "expected token: %<,%>"); + return AST::ASTFragment::create_error (); + } + if (parser.peek_current_token ()->get_id () != STRING_LITERAL) + { + rust_error_at (parser.peek_current_token ()->get_locus (), + "argument must be a string literal"); + return AST::ASTFragment::create_error (); + } + + error_expr = parser.parse_literal_expr (); + parser.maybe_skip_token (COMMA); + } + + if (parser.peek_current_token ()->get_id () != last_token_id) + { + rust_error_at (invoc_locus, "env! takes 1 or 2 arguments"); + return AST::ASTFragment::create_error (); + } + + parser.skip_token (last_token_id); + + auto env_value = getenv (lit_expr->as_string ().c_str ()); + + if (env_value == nullptr) + { + if (error_expr == nullptr) + rust_error_at (invoc_locus, "environment variable %qs not defined", + lit_expr->as_string ().c_str ()); + else + rust_error_at (invoc_locus, "%s", error_expr->as_string ().c_str ()); + return AST::ASTFragment::create_error (); + } + + auto node = AST::SingleASTNode (make_string (invoc_locus, env_value)); + return AST::ASTFragment ({node}); +} + } // namespace Rust diff --git a/gcc/rust/expand/rust-macro-builtins.h b/gcc/rust/expand/rust-macro-builtins.h index 3f4bf37edbc..047181146c1 100644 --- a/gcc/rust/expand/rust-macro-builtins.h +++ b/gcc/rust/expand/rust-macro-builtins.h @@ -89,6 +89,9 @@ public: static AST::ASTFragment concat (Location invoc_locus, AST::MacroInvocData &invoc); + + static AST::ASTFragment env (Location invoc_locus, + AST::MacroInvocData &invoc); }; } // namespace Rust diff --git a/gcc/rust/util/rust-hir-map.cc b/gcc/rust/util/rust-hir-map.cc index 7bacc4c0f01..23b78efcf07 100644 --- a/gcc/rust/util/rust-hir-map.cc +++ b/gcc/rust/util/rust-hir-map.cc @@ -755,6 +755,7 @@ Mappings::insert_macro_def (AST::MacroRulesDefinition *macro) {"include_str", MacroBuiltin::include_str}, {"compile_error", MacroBuiltin::compile_error}, {"concat", MacroBuiltin::concat}, + {"env", MacroBuiltin::env}, }; auto builtin = builtin_macros.find (macro->get_rule_name ()); diff --git a/gcc/testsuite/rust/compile/builtin_macro_env.rs b/gcc/testsuite/rust/compile/builtin_macro_env.rs new file mode 100644 index 00000000000..8c50a7d8901 --- /dev/null +++ b/gcc/testsuite/rust/compile/builtin_macro_env.rs @@ -0,0 +1,19 @@ +macro_rules! env { + () => {{}}; +} + +fn main () { + let message = "error message"; + env! (message); // { dg-error "argument must be a string literal" "" } + env! (); // { dg-error "env! takes 1 or 2 arguments" "" } + env! (,); // { dg-error "argument must be a string literal" "" } + env! (1); // { dg-error "argument must be a string literal" "" } + env! ("NOT_DEFINED"); // { dg-error "environment variable 'NOT_DEFINED' not defined" "" } + env! ("NOT_DEFINED",); // { dg-error "environment variable 'NOT_DEFINED' not defined" "" } + env! ("NOT_DEFINED", 1); // { dg-error "argument must be a string literal" "" } + env! ("NOT_DEFINED", "two", "three"); // { dg-error "env! takes 1 or 2 arguments" "" } + env! ("NOT_DEFINED" "expected error message"); // { dg-error "expected token: ','" "" } + env! ("NOT_DEFINED", "expected error message"); // { dg-error "expected error message" "" } + env! ("NOT_DEFINED", "expected error message",); // { dg-error "expected error message" "" } + env! (1, "two"); // { dg-error "argument must be a string literal" "" } +} diff --git a/gcc/testsuite/rust/execute/torture/builtin_macro_env.rs b/gcc/testsuite/rust/execute/torture/builtin_macro_env.rs new file mode 100644 index 00000000000..ab6f139075c --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/builtin_macro_env.rs @@ -0,0 +1,26 @@ +// { dg-output "VALUE\nVALUE\n" } +// { dg-set-compiler-env-var ENV_MACRO_TEST "VALUE" } + +macro_rules! env { + () => {{}}; +} + +extern "C" { + fn printf(fmt: *const i8, ...); +} + +fn print(s: &str) { + printf("%s\n" as *const str as *const i8, s as *const str as *const i8); +} + +fn main() -> i32 { + let val0 = env!("ENV_MACRO_TEST"); + + print(val0); + + let val1 = env!("ENV_MACRO_TEST",); + + print(val1); + + 0 +}