diff options
author | Liam Naddell <liamnprg@gmail.com> | 2025-01-30 20:51:21 -0500 |
---|---|---|
committer | CohenArthur <arthur.cohen@embecosm.com> | 2025-01-31 15:44:25 +0000 |
commit | 761d424d2a7af38aacad9ffd5b5132fcf286ac2e (patch) | |
tree | 01cc83831b41d9365a22fc2b0b1540dbfb82d7fe /gcc/rust | |
parent | 51a2da3d567dfbc70e9407276dfabc0b963ad420 (diff) | |
download | gcc-761d424d2a7af38aacad9ffd5b5132fcf286ac2e.zip gcc-761d424d2a7af38aacad9ffd5b5132fcf286ac2e.tar.gz gcc-761d424d2a7af38aacad9ffd5b5132fcf286ac2e.tar.bz2 |
Add option_env! support
gcc/rust/ChangeLog:
* expand/rust-macro-builtins-utility.cc: Add macro expansion for
option_env with eager expansion
* expand/rust-macro-builtins.cc: Add option_env to builtin list
* expand/rust-macro-builtins.h: Add option_env handler to header
file
* resolve/rust-late-name-resolver-2.0.cc: Prevent NR2.0 from
recursing into lang-item segments
gcc/testsuite/ChangeLog:
* rust/compile/macros/builtin/option_env1.rs: Add success case for option_env
* rust/compile/macros/builtin/option_env2.rs: Add failure case for option_env
* rust/execute/torture/builtin_macro_option_env.rs: Add
execution case for option_env
Diffstat (limited to 'gcc/rust')
-rw-r--r-- | gcc/rust/expand/rust-macro-builtins-utility.cc | 78 | ||||
-rw-r--r-- | gcc/rust/expand/rust-macro-builtins.cc | 2 | ||||
-rw-r--r-- | gcc/rust/expand/rust-macro-builtins.h | 4 | ||||
-rw-r--r-- | gcc/rust/resolve/rust-late-name-resolver-2.0.cc | 2 |
4 files changed, 85 insertions, 1 deletions
diff --git a/gcc/rust/expand/rust-macro-builtins-utility.cc b/gcc/rust/expand/rust-macro-builtins-utility.cc index ff64879..28829a1 100644 --- a/gcc/rust/expand/rust-macro-builtins-utility.cc +++ b/gcc/rust/expand/rust-macro-builtins-utility.cc @@ -17,6 +17,7 @@ // <http://www.gnu.org/licenses/>. #include "rust-fmt.h" +#include "rust-ast-builder.h" #include "rust-macro-builtins.h" #include "rust-macro-builtins-helpers.h" @@ -226,6 +227,83 @@ MacroBuiltin::env_handler (location_t invoc_locus, AST::MacroInvocData &invoc, return AST::Fragment ({node}, std::move (tok)); } +/* Expand builtin macro option_env!(), which inspects an environment variable at + compile time. */ +tl::optional<AST::Fragment> +MacroBuiltin::option_env_handler (location_t invoc_locus, + AST::MacroInvocData &invoc, + AST::InvocKind semicolon) +{ + auto invoc_token_tree = invoc.get_delim_tok_tree (); + MacroInvocLexer lex (invoc_token_tree.to_token_stream ()); + Parser<MacroInvocLexer> parser (lex); + + auto last_token_id = macro_end_token (invoc_token_tree, parser); + std::unique_ptr<AST::LiteralExpr> lit_expr = nullptr; + bool has_error = false; + + auto start = lex.get_offs (); + auto expanded_expr = try_expand_many_expr (parser, last_token_id, + invoc.get_expander (), has_error); + auto end = lex.get_offs (); + + auto tokens = lex.get_token_slice (start, end); + + if (has_error) + return AST::Fragment::create_error (); + + auto pending = check_for_eager_invocations (expanded_expr); + if (!pending.empty ()) + return make_eager_builtin_invocation (BuiltinMacro::OptionEnv, invoc_locus, + invoc_token_tree, + std::move (pending)); + + if (expanded_expr.size () != 1) + { + rust_error_at (invoc_locus, "%<option_env!%> takes 1 argument"); + return AST::Fragment::create_error (); + } + + if (expanded_expr.size () > 0) + if (!(lit_expr + = try_extract_string_literal_from_fragment (invoc_locus, + expanded_expr[0]))) + return AST::Fragment::create_error (); + + parser.skip_token (last_token_id); + + auto env_value = getenv (lit_expr->as_string ().c_str ()); + AST::Builder b (invoc_locus); + + if (env_value == nullptr) + { + auto none_expr = std::unique_ptr<AST::Expr> ( + new AST::PathInExpression (LangItem::Kind::OPTION_NONE, {}, + invoc_locus)); + + auto node = AST::SingleASTNode (std::move (none_expr)); + std::vector<AST::SingleASTNode> nodes; + nodes.push_back (node); + + return AST::Fragment (nodes, std::vector<std::unique_ptr<AST::Token>> ()); + } + std::vector<std::unique_ptr<AST::Expr>> args; + args.push_back (b.literal_string (env_value)); + + std::unique_ptr<AST::Expr> some_expr + = b.call (std::unique_ptr<AST::Expr> ( + new AST::PathInExpression (LangItem::Kind::OPTION_SOME, {}, + invoc_locus)), + std::move (args)); + + auto node = AST::SingleASTNode (std::move (some_expr)); + + std::vector<AST::SingleASTNode> nodes; + nodes.push_back (node); + + return AST::Fragment (nodes, std::vector<std::unique_ptr<AST::Token>> ()); +} + tl::optional<AST::Fragment> MacroBuiltin::cfg_handler (location_t invoc_locus, AST::MacroInvocData &invoc, AST::InvocKind semicolon) diff --git a/gcc/rust/expand/rust-macro-builtins.cc b/gcc/rust/expand/rust-macro-builtins.cc index 07a1f3c..59b8f6a 100644 --- a/gcc/rust/expand/rust-macro-builtins.cc +++ b/gcc/rust/expand/rust-macro-builtins.cc @@ -120,8 +120,8 @@ std::unordered_map<std::string, AST::MacroTranscriberFunc> {"format_args_nl", format_args_maker (AST::FormatArgs::Newline::Yes)}, {"asm", inline_asm_maker (AST::AsmKind::Inline)}, {"global_asm", inline_asm_maker (AST::AsmKind::Global)}, + {"option_env", MacroBuiltin::option_env_handler}, /* Unimplemented macro builtins */ - {"option_env", MacroBuiltin::sorry}, {"concat_idents", MacroBuiltin::sorry}, {"module_path", MacroBuiltin::sorry}, {"log_syntax", MacroBuiltin::sorry}, diff --git a/gcc/rust/expand/rust-macro-builtins.h b/gcc/rust/expand/rust-macro-builtins.h index b0c4a64..1d17b43 100644 --- a/gcc/rust/expand/rust-macro-builtins.h +++ b/gcc/rust/expand/rust-macro-builtins.h @@ -159,6 +159,10 @@ public: AST::MacroInvocData &invoc, AST::InvocKind semicolon); + static tl::optional<AST::Fragment> + option_env_handler (location_t invoc_locus, AST::MacroInvocData &invoc, + AST::InvocKind semicolon); + static tl::optional<AST::Fragment> cfg_handler (location_t invoc_locus, AST::MacroInvocData &invoc, AST::InvocKind semicolon); diff --git a/gcc/rust/resolve/rust-late-name-resolver-2.0.cc b/gcc/rust/resolve/rust-late-name-resolver-2.0.cc index b0364d1..ec20e9a 100644 --- a/gcc/rust/resolve/rust-late-name-resolver-2.0.cc +++ b/gcc/rust/resolve/rust-late-name-resolver-2.0.cc @@ -254,6 +254,8 @@ Late::visit (AST::PathInExpression &expr) // TODO: How do we have a nice error with `can't capture dynamic environment // in a function item` error here? // do we emit it in `get<Namespace::Labels>`? + if (expr.is_lang_item ()) + return; auto resolved = ctx.values.resolve_path (expr.get_segments ()).or_else ([&] () { |