public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc/devel/rust/master] macros: Add env! macro
@ 2022-06-08 12:31 Thomas Schwinge
  0 siblings, 0 replies; only message in thread
From: Thomas Schwinge @ 2022-06-08 12:31 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:1e6e42769665288b3e2a12148ee9bacf057b2fe8

commit 1e6e42769665288b3e2a12148ee9bacf057b2fe8
Author: Ondřej Machota <ondrejmachota@gmail.com>
Date:   Tue Apr 12 20:48:30 2022 +0200

    macros: Add env! macro
    
    Signed-off-by: Ondřej Machota <ondrejmachota@gmail.com>

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<MacroInvocLexer> 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<AST::LiteralExpr> 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
+}


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2022-06-08 12:31 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-06-08 12:31 [gcc/devel/rust/master] macros: Add env! macro Thomas Schwinge

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).