Line data Source code
1 : // Copyright (C) 2020-2026 Free Software Foundation, Inc.
2 :
3 : // This file is part of GCC.
4 :
5 : // GCC is free software; you can redistribute it and/or modify it under
6 : // the terms of the GNU General Public License as published by the Free
7 : // Software Foundation; either version 3, or (at your option) any later
8 : // version.
9 :
10 : // GCC is distributed in the hope that it will be useful, but WITHOUT ANY
11 : // WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 : // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 : // for more details.
14 :
15 : // You should have received a copy of the GNU General Public License
16 : // along with GCC; see the file COPYING3. If not see
17 : // <http://www.gnu.org/licenses/>.
18 :
19 : #include "rust-ast-fragment.h"
20 : #include "rust-macro-builtins.h"
21 : #include "rust-macro-builtins-helpers.h"
22 : #include "rust-ast-builder.h"
23 : #include "optional.h"
24 : #include "rust-ast-collector.h"
25 :
26 : namespace Rust {
27 : tl::optional<AST::Fragment>
28 1 : MacroBuiltin::assert_handler (location_t invoc_locus,
29 : AST::MacroInvocData &invoc,
30 : AST::InvocKind semicolon)
31 : {
32 1 : rust_debug ("assert!() called");
33 1 : auto tt = invoc.get_delim_tok_tree ();
34 1 : MacroInvocLexer lex (tt.to_token_stream ());
35 1 : Parser<MacroInvocLexer> parser (lex);
36 :
37 1 : auto last_token_id = macro_end_token (tt, parser);
38 1 : bool has_error = false;
39 :
40 1 : auto expanded_expr = try_expand_many_expr (parser, last_token_id,
41 1 : invoc.get_expander (), has_error);
42 1 : if (expanded_expr.size () < 1)
43 : {
44 0 : rust_error_at (invoc_locus,
45 : "macro requires a boolean expression as an argument");
46 0 : return AST::Fragment::create_error ();
47 : }
48 1 : auto expr_to_assert = std::move (expanded_expr[0]);
49 1 : expanded_expr.erase (expanded_expr.begin ());
50 :
51 1 : if (expanded_expr.size () > 1)
52 : {
53 0 : rust_sorry_at (
54 : invoc_locus,
55 : "The second form of assert with a message is not supported yet");
56 :
57 0 : return AST::Fragment::create_error ();
58 : }
59 :
60 1 : auto pending_invocations = check_for_eager_invocations (expanded_expr);
61 1 : if (!pending_invocations.empty ())
62 0 : return make_eager_builtin_invocation (BuiltinMacro::Assert, invoc_locus,
63 0 : invoc.get_delim_tok_tree (),
64 0 : std::move (pending_invocations));
65 :
66 1 : AST::Builder b (invoc_locus);
67 :
68 1 : std::vector<std::unique_ptr<AST::TokenTree>> panic_tree;
69 1 : const_TokenPtr open = Token::make (TokenId::LEFT_PAREN, invoc_locus);
70 1 : panic_tree.push_back (std::make_unique<AST::Token> (std::move (open)));
71 :
72 1 : const_TokenPtr close = Token::make (TokenId::RIGHT_PAREN, invoc_locus);
73 1 : panic_tree.push_back (std::make_unique<AST::Token> (std::move (close)));
74 :
75 1 : auto panic = AST::MacroInvocation::Regular (
76 3 : AST::MacroInvocData (AST::SimplePath (Identifier ("panic")),
77 2 : AST::DelimTokenTree (AST::DelimType::PARENS,
78 : std::move (panic_tree),
79 3 : invoc_locus)),
80 1 : {} /* outer attributes */, invoc_locus, true /* semicoloned */);
81 2 : auto stmt = b.statementify (std::move (panic));
82 1 : std::vector<std::unique_ptr<AST::Stmt>> stmts;
83 1 : stmts.push_back (std::move (stmt));
84 1 : auto block = b.block (std::move (stmts));
85 1 : auto negated_condition = std::unique_ptr<AST::NegationExpr> (
86 : new AST::NegationExpr (std::move (expr_to_assert),
87 1 : AST::NegationExpr::ExprType::NOT, {}, invoc_locus));
88 :
89 1 : auto if_expr = std::make_unique<AST::IfExpr> (
90 : std::move (negated_condition) /* condition*/, std::move (block),
91 1 : std::vector<AST::Attribute>{}, invoc_locus);
92 :
93 1 : auto node = AST::SingleASTNode (std::move (if_expr));
94 :
95 1 : AST::TokenCollector collector;
96 1 : collector.visit (node);
97 1 : std::vector<std::unique_ptr<AST::Token>> tokens;
98 12 : for (auto &&token : collector.collect_tokens ())
99 12 : tokens.push_back (std::make_unique<AST::Token> (token));
100 :
101 3 : return AST::Fragment ({node}, std::move (tokens));
102 :
103 : return AST::Fragment::create_error ();
104 1 : }
105 : } // namespace Rust
|