aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2022-04-14 06:56:37 +0000
committerGitHub <noreply@github.com>2022-04-14 06:56:37 +0000
commit73e017f7cb8423cbd3ab1a8424d59f2ced81eb97 (patch)
treef751ad4d9a6a539657adc7e62052056db0dc276b
parent60324125c3dbfd2f1551ec41dcfd4322ca80d6fa (diff)
parent1e6e42769665288b3e2a12148ee9bacf057b2fe8 (diff)
downloadgcc-73e017f7cb8423cbd3ab1a8424d59f2ced81eb97.zip
gcc-73e017f7cb8423cbd3ab1a8424d59f2ced81eb97.tar.gz
gcc-73e017f7cb8423cbd3ab1a8424d59f2ced81eb97.tar.bz2
Merge #1113
1113: macros: Add env! macro r=CohenArthur a=omachota Added the `env!()` macro and relevant test cases Fixes: #977 Signed-off-by: Ondřej Machota <ondrejmachota@gmail.com> Co-authored-by: Ondřej Machota <ondrejmachota@gmail.com>
-rw-r--r--gcc/rust/expand/rust-macro-builtins.cc70
-rw-r--r--gcc/rust/expand/rust-macro-builtins.h3
-rw-r--r--gcc/rust/util/rust-hir-map.cc1
-rw-r--r--gcc/testsuite/rust/compile/builtin_macro_env.rs19
-rw-r--r--gcc/testsuite/rust/execute/torture/builtin_macro_env.rs26
5 files changed, 119 insertions, 0 deletions
diff --git a/gcc/rust/expand/rust-macro-builtins.cc b/gcc/rust/expand/rust-macro-builtins.cc
index 1f41545..d0f7302 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 3f4bf37..0471811 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 7bacc4c..23b78ef 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 0000000..8c50a7d
--- /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 0000000..ab6f139
--- /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
+}