LCOV - code coverage report
Current view: top level - gcc/rust/expand - rust-macro-builtins-utility.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 92.4 % 249 230
Test Date: 2026-08-22 16:33:35 Functions: 100.0 % 7 7
Legend: Lines:     hit not hit

            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-fmt.h"
      20              : #include "rust-ast-builder.h"
      21              : #include "rust-macro-builtins.h"
      22              : #include "rust-macro-builtins-helpers.h"
      23              : #include "rust-session-manager.h"
      24              : #include "rust-stmt.h"
      25              : 
      26              : namespace Rust {
      27              : 
      28              : /* Expand builtin macro compile_error!("error"), which forces a compile error
      29              :    during the compile time. */
      30              : tl::optional<AST::Fragment>
      31            5 : MacroBuiltin::compile_error_handler (location_t invoc_locus,
      32              :                                      AST::MacroInvocData &invoc,
      33              :                                      AST::InvocKind semicolon)
      34              : {
      35            5 :   auto lit_expr
      36              :     = parse_single_string_literal (BuiltinMacro::CompileError,
      37              :                                    invoc.get_delim_tok_tree (), invoc_locus,
      38            5 :                                    invoc.get_expander ());
      39            5 :   if (lit_expr == nullptr)
      40            6 :     return AST::Fragment::create_error ();
      41              : 
      42            2 :   rust_assert (lit_expr->is_literal ());
      43              : 
      44            2 :   std::string error_string = lit_expr->as_string ();
      45            2 :   rust_error_at (invoc_locus, "%s", error_string.c_str ());
      46              : 
      47            4 :   return AST::Fragment::create_error ();
      48            5 : }
      49              : 
      50              : /* Expand builtin macro concat!(), which joins all the literal parameters
      51              :    into a string with no delimiter. */
      52              : 
      53              : // This is a weird one. We want to do something where, if something cannot be
      54              : // expanded yet (i.e. macro invocation?) we return the whole MacroInvocation
      55              : // node again but expanded as much as possible.
      56              : // Is that possible? How do we do that?
      57              : //
      58              : // Let's take a few examples:
      59              : //
      60              : // 1. concat!(1, 2, true);
      61              : // 2. concat!(a!(), 2, true);
      62              : // 3. concat!(concat!(1, false), 2, true);
      63              : // 4. concat!(concat!(1, a!()), 2, true);
      64              : //
      65              : // 1. We simply want to return the new fragment: "12true"
      66              : // 2. We want to return `concat!(a_expanded, 2, true)` as a fragment
      67              : // 3. We want to return `concat!(1, false, 2, true)`
      68              : // 4. We want to return `concat!(concat!(1, a_expanded), 2, true);
      69              : //
      70              : // How do we do that?
      71              : //
      72              : // For each (un)expanded fragment: we check if it is expanded fully
      73              : //
      74              : // 1. What is expanded fully?
      75              : // 2. How to check?
      76              : //
      77              : // If it is expanded fully and not a literal, then we error out.
      78              : // Otherwise we simply emplace it back and keep going.
      79              : //
      80              : // In the second case, we must mark that this concat invocation still has some
      81              : // expansion to do: This allows us to return a `MacroInvocation { ... }` as an
      82              : // AST fragment, instead of a completed string.
      83              : //
      84              : // This means that we must change all the `try_expand_many_*` APIs and so on to
      85              : // return some sort of index or way to signify that we might want to reuse some
      86              : // bits and pieces of the original token tree.
      87              : //
      88              : // Now, before that: How do we resolve the names used in a builtin macro
      89              : // invocation?
      90              : // Do we split the two passes of parsing the token tree and then expanding it?
      91              : // Can we do that easily?
      92              : tl::optional<AST::Fragment>
      93          660 : MacroBuiltin::concat_handler (location_t invoc_locus,
      94              :                               AST::MacroInvocData &invoc,
      95              :                               AST::InvocKind semicolon)
      96              : {
      97          660 :   auto invoc_token_tree = invoc.get_delim_tok_tree ();
      98          660 :   MacroInvocLexer lex (invoc_token_tree.to_token_stream ());
      99          660 :   Parser<MacroInvocLexer> parser (lex);
     100              : 
     101          660 :   auto str = std::string ();
     102          660 :   bool has_error = false;
     103              : 
     104          660 :   auto last_token_id = macro_end_token (invoc_token_tree, parser);
     105              : 
     106          660 :   auto start = lex.get_offs ();
     107              :   /* NOTE: concat! could accept no argument, so we don't have any checks here */
     108          660 :   auto expanded_expr = try_expand_many_expr (parser, last_token_id,
     109          660 :                                              invoc.get_expander (), has_error);
     110          660 :   auto end = lex.get_offs ();
     111              : 
     112          660 :   auto tokens = lex.get_token_slice (start, end);
     113              : 
     114          660 :   auto pending_invocations = check_for_eager_invocations (expanded_expr);
     115          660 :   if (!pending_invocations.empty ())
     116          608 :     return make_eager_builtin_invocation (BuiltinMacro::Concat, invoc_locus,
     117          304 :                                           invoc.get_delim_tok_tree (),
     118          304 :                                           std::move (pending_invocations));
     119              : 
     120         2305 :   for (auto &expr : expanded_expr)
     121              :     {
     122         1949 :       if (!expr->is_literal ()
     123         1949 :           && expr->get_expr_kind () != AST::Expr::Kind::MacroInvocation)
     124              :         {
     125            2 :           has_error = true;
     126            2 :           rust_error_at (expr->get_locus (), "expected a literal");
     127              :           // diagnostics copied from rustc
     128            2 :           rust_inform (expr->get_locus (),
     129              :                        "only literals (like %<\"foo\"%>, %<42%> and "
     130              :                        "%<3.14%>) can be passed to %<concat!()%>");
     131            2 :           continue;
     132              :         }
     133         1947 :       auto *literal = static_cast<AST::LiteralExpr *> (expr.get ());
     134         1947 :       if (literal->get_lit_type () == AST::Literal::BYTE
     135         1947 :           || literal->get_lit_type () == AST::Literal::BYTE_STRING)
     136              :         {
     137            0 :           has_error = true;
     138            0 :           rust_error_at (expr->get_locus (),
     139              :                          "cannot concatenate a byte string literal");
     140            0 :           continue;
     141              :         }
     142         3894 :       str += literal->as_string ();
     143              :     }
     144              : 
     145          356 :   parser.skip_token (last_token_id);
     146              : 
     147          356 :   if (has_error)
     148            8 :     return AST::Fragment::create_error ();
     149              : 
     150          704 :   auto node = AST::SingleASTNode (make_string (invoc_locus, str));
     151          704 :   auto str_tok = make_token (Token::make_string (invoc_locus, std::move (str)));
     152              : 
     153         1056 :   return AST::Fragment ({node}, std::move (str_tok));
     154          660 : }
     155              : 
     156              : /* Expand builtin macro env!(), which inspects an environment variable at
     157              :    compile time. */
     158              : tl::optional<AST::Fragment>
     159           32 : MacroBuiltin::env_handler (location_t invoc_locus, AST::MacroInvocData &invoc,
     160              :                            AST::InvocKind semicolon)
     161              : {
     162           32 :   auto invoc_token_tree = invoc.get_delim_tok_tree ();
     163           32 :   MacroInvocLexer lex (invoc_token_tree.to_token_stream ());
     164           32 :   Parser<MacroInvocLexer> parser (lex);
     165              : 
     166           32 :   auto last_token_id = macro_end_token (invoc_token_tree, parser);
     167           32 :   std::unique_ptr<AST::LiteralExpr> error_expr = nullptr;
     168           32 :   std::unique_ptr<AST::LiteralExpr> lit_expr = nullptr;
     169           32 :   bool has_error = false;
     170              : 
     171           32 :   auto start = lex.get_offs ();
     172           32 :   auto expanded_expr = try_expand_many_expr (parser, last_token_id,
     173           32 :                                              invoc.get_expander (), has_error);
     174           32 :   auto end = lex.get_offs ();
     175              : 
     176           32 :   auto tokens = lex.get_token_slice (start, end);
     177              : 
     178           32 :   if (has_error)
     179            4 :     return AST::Fragment::create_error ();
     180              : 
     181           30 :   auto pending = check_for_eager_invocations (expanded_expr);
     182           30 :   if (!pending.empty ())
     183            6 :     return make_eager_builtin_invocation (BuiltinMacro::Env, invoc_locus,
     184              :                                           invoc_token_tree,
     185            3 :                                           std::move (pending));
     186              : 
     187           27 :   if (expanded_expr.size () < 1 || expanded_expr.size () > 2)
     188              :     {
     189            2 :       rust_error_at (invoc_locus, "env! takes 1 or 2 arguments");
     190            4 :       return AST::Fragment::create_error ();
     191              :     }
     192           25 :   if (expanded_expr.size () > 0)
     193              :     {
     194           50 :       if (!(lit_expr
     195           25 :             = try_extract_string_literal_from_fragment (invoc_locus,
     196           50 :                                                         expanded_expr[0])))
     197              :         {
     198            6 :           return AST::Fragment::create_error ();
     199              :         }
     200              :     }
     201           22 :   if (expanded_expr.size () > 1)
     202              :     {
     203            5 :       if (!(error_expr
     204            5 :             = try_extract_string_literal_from_fragment (invoc_locus,
     205           10 :                                                         expanded_expr[1])))
     206              :         {
     207            2 :           return AST::Fragment::create_error ();
     208              :         }
     209              :     }
     210              : 
     211           21 :   parser.skip_token (last_token_id);
     212              : 
     213           21 :   auto env_value = getenv (lit_expr->as_string ().c_str ());
     214              : 
     215           21 :   if (env_value == nullptr)
     216              :     {
     217            7 :       if (error_expr == nullptr)
     218            3 :         rust_error_at (invoc_locus, "environment variable %qs not defined",
     219            6 :                        lit_expr->as_string ().c_str ());
     220              :       else
     221            4 :         rust_error_at (invoc_locus, "%s", error_expr->as_string ().c_str ());
     222           14 :       return AST::Fragment::create_error ();
     223              :     }
     224              : 
     225           14 :   auto node = AST::SingleASTNode (make_string (invoc_locus, env_value));
     226           14 :   auto tok
     227           28 :     = make_token (Token::make_string (invoc_locus, std::move (env_value)));
     228              : 
     229           42 :   return AST::Fragment ({node}, std::move (tok));
     230           32 : }
     231              : 
     232              : /* Expand builtin macro option_env!(), which inspects an environment variable at
     233              :    compile time. */
     234              : tl::optional<AST::Fragment>
     235           25 : MacroBuiltin::option_env_handler (location_t invoc_locus,
     236              :                                   AST::MacroInvocData &invoc,
     237              :                                   AST::InvocKind semicolon)
     238              : {
     239           25 :   auto invoc_token_tree = invoc.get_delim_tok_tree ();
     240           25 :   MacroInvocLexer lex (invoc_token_tree.to_token_stream ());
     241           25 :   Parser<MacroInvocLexer> parser (lex);
     242              : 
     243           25 :   auto last_token_id = macro_end_token (invoc_token_tree, parser);
     244           25 :   std::unique_ptr<AST::LiteralExpr> lit_expr = nullptr;
     245           25 :   bool has_error = false;
     246              : 
     247           25 :   auto start = lex.get_offs ();
     248           25 :   auto expanded_expr = try_expand_many_expr (parser, last_token_id,
     249           25 :                                              invoc.get_expander (), has_error);
     250           25 :   auto end = lex.get_offs ();
     251              : 
     252           25 :   auto tokens = lex.get_token_slice (start, end);
     253              : 
     254           25 :   if (has_error)
     255            0 :     return AST::Fragment::create_error ();
     256              : 
     257           25 :   auto pending = check_for_eager_invocations (expanded_expr);
     258           25 :   if (!pending.empty ())
     259           14 :     return make_eager_builtin_invocation (BuiltinMacro::OptionEnv, invoc_locus,
     260              :                                           invoc_token_tree,
     261            7 :                                           std::move (pending));
     262              : 
     263           18 :   if (expanded_expr.size () != 1)
     264              :     {
     265            1 :       rust_error_at (invoc_locus, "%<option_env!%> takes 1 argument");
     266            2 :       return AST::Fragment::create_error ();
     267              :     }
     268              : 
     269           17 :   if (expanded_expr.size () > 0)
     270           34 :     if (!(lit_expr
     271           17 :           = try_extract_string_literal_from_fragment (invoc_locus,
     272           34 :                                                       expanded_expr[0])))
     273            2 :       return AST::Fragment::create_error ();
     274              : 
     275           16 :   parser.skip_token (last_token_id);
     276              : 
     277           16 :   auto env_value = getenv (lit_expr->as_string ().c_str ());
     278           16 :   AST::Builder b (invoc_locus, AST::Builder::Source::Any);
     279              : 
     280           16 :   if (env_value == nullptr)
     281              :     {
     282            1 :       auto none_expr = std::unique_ptr<AST::Expr> (
     283              :         new AST::PathInExpression (LangItem::Kind::OPTION_NONE, {},
     284            1 :                                    invoc_locus));
     285              : 
     286            1 :       auto node = AST::SingleASTNode (std::move (none_expr));
     287            1 :       std::vector<AST::SingleASTNode> nodes;
     288            1 :       nodes.push_back (node);
     289              : 
     290            2 :       return AST::Fragment (nodes, std::vector<std::unique_ptr<AST::Token>> ());
     291            1 :     }
     292           15 :   std::vector<std::unique_ptr<AST::Expr>> args;
     293           15 :   args.push_back (b.literal_string (env_value));
     294              : 
     295           15 :   std::unique_ptr<AST::Expr> some_expr
     296           15 :     = b.call (std::unique_ptr<AST::Expr> (
     297              :                 new AST::PathInExpression (LangItem::Kind::OPTION_SOME, {},
     298           30 :                                            invoc_locus)),
     299           15 :               std::move (args));
     300              : 
     301           15 :   auto node = AST::SingleASTNode (std::move (some_expr));
     302              : 
     303           15 :   std::vector<AST::SingleASTNode> nodes;
     304           15 :   nodes.push_back (node);
     305              : 
     306           30 :   return AST::Fragment (nodes, std::vector<std::unique_ptr<AST::Token>> ());
     307           25 : }
     308              : 
     309              : tl::optional<AST::Fragment>
     310          132 : MacroBuiltin::cfg_handler (location_t invoc_locus, AST::MacroInvocData &invoc,
     311              :                            AST::InvocKind semicolon)
     312              : {
     313              :   // only parse if not already parsed
     314          132 :   if (!invoc.is_parsed ())
     315              :     {
     316          132 :       std::unique_ptr<AST::AttrInputMetaItemContainer> converted_input (
     317          132 :         invoc.get_delim_tok_tree ().parse_to_meta_item ());
     318              : 
     319          132 :       if (converted_input == nullptr)
     320              :         {
     321            0 :           rust_debug ("DEBUG: failed to parse macro to meta item");
     322              :           // TODO: do something now? is this an actual error?
     323              :         }
     324              :       else
     325              :         {
     326          132 :           std::vector<std::unique_ptr<AST::MetaItemInner>> meta_items (
     327          132 :             std::move (converted_input->get_items ()));
     328          132 :           invoc.set_meta_item_output (std::move (meta_items));
     329          132 :         }
     330          132 :     }
     331              : 
     332              :   /* TODO: assuming that cfg! macros can only have one meta item inner, like cfg
     333              :    * attributes */
     334          132 :   if (invoc.get_meta_items ().size () != 1)
     335            0 :     return AST::Fragment::create_error ();
     336              : 
     337          132 :   bool result = invoc.get_meta_items ()[0]->check_cfg_predicate (
     338          132 :     Session::get_instance ());
     339          132 :   auto literal_exp = AST::SingleASTNode (std::unique_ptr<AST::Expr> (
     340          132 :     new AST::LiteralExpr (result ? "true" : "false", AST::Literal::BOOL,
     341          396 :                           PrimitiveCoreType::CORETYPE_BOOL, {}, invoc_locus)));
     342          132 :   auto tok = make_token (
     343          237 :     Token::make (result ? TRUE_LITERAL : FALSE_LITERAL, invoc_locus));
     344              : 
     345          396 :   return AST::Fragment ({literal_exp}, std::move (tok));
     346          132 : }
     347              : 
     348              : tl::optional<AST::Fragment>
     349           29 : MacroBuiltin::cfg_select_handler (location_t invoc_locus,
     350              :                                   AST::MacroInvocData &invoc,
     351              :                                   AST::InvocKind semicolon)
     352              : {
     353           29 :   auto invoc_token_tree = invoc.get_delim_tok_tree ();
     354           29 :   MacroInvocLexer lex (invoc_token_tree.to_token_stream ());
     355              : 
     356           29 :   Parser<MacroInvocLexer> parser (lex);
     357              : 
     358           29 :   if (!parser.skip_token (LEFT_CURLY))
     359              :     {
     360            0 :       rust_error_at (invoc_locus, "expected %<(%> in %<cfg_select!%>");
     361            0 :       return AST::Fragment::create_error ();
     362              :     }
     363              : 
     364           29 :   std::vector<AST::SingleASTNode> matched_body_nodes;
     365           29 :   std::vector<std::unique_ptr<AST::Token>> matched_body_tokens;
     366           29 :   bool has_match = false;
     367              : 
     368           29 :   while (lex.peek_token ()->get_id () != RIGHT_CURLY
     369          204 :          && lex.peek_token ()->get_id () != END_OF_FILE)
     370              :     {
     371          102 :       if (lex.peek_token ()->get_id () == UNDERSCORE)
     372              :         {
     373              :           // wildcard predicate
     374           22 :           lex.skip_token (); // consume '_'
     375           22 :           has_match = true;
     376              :         }
     377              :       else
     378              :         {
     379           29 :           size_t pred_start = lex.get_offs ();
     380              : 
     381              :           // parse the predicate (until =>)
     382         2212 :           while (lex.peek_token ()->get_id () != MATCH_ARROW)
     383              :             {
     384         2154 :               if (lex.peek_token ()->get_id () == END_OF_FILE)
     385              :                 {
     386            0 :                   rust_error_at (invoc_locus,
     387              :                                  "unterminated %<cfg_select!%>arm");
     388            0 :                   return AST::Fragment::create_error ();
     389              :                 }
     390         1077 :               lex.skip_token ();
     391              :             }
     392              : 
     393           29 :           size_t pred_end = lex.get_offs ();
     394              : 
     395           29 :           std::vector<const_TokenPtr> synth;
     396           29 :           synth.emplace_back (Token::make (LEFT_PAREN, invoc_locus));
     397           29 :           auto pred_tokens = lex.get_token_slice (pred_start, pred_end);
     398         1106 :           for (auto &t : pred_tokens)
     399         2154 :             synth.emplace_back (t->get_tok_ptr ());
     400           29 :           synth.emplace_back (Token::make (RIGHT_PAREN, invoc_locus));
     401              : 
     402           29 :           AST::AttributeParser attr_parser (std::move (synth));
     403           29 :           auto items = attr_parser.parse_meta_item_seq ();
     404           29 :           if (items.size () != 1)
     405              :             {
     406            0 :               rust_error_at (invoc_locus,
     407              :                              "  %<cfg_select!%> arm predicate must "
     408              :                              "be a single cfg expression");
     409            0 :               return AST::Fragment::create_error ();
     410              :             }
     411              : 
     412           29 :           bool result
     413           29 :             = items[0]->check_cfg_predicate (Session::get_instance ());
     414           29 :           if (result)
     415              :             has_match = true;
     416           29 :         }
     417              : 
     418           51 :       if (!parser.skip_token (MATCH_ARROW))
     419              :         {
     420            0 :           rust_error_at (lex.peek_token ()->get_locus (),
     421              :                          "expected %<=>%> in %<cfg_select!%> arm");
     422            0 :           return AST::Fragment::create_error ();
     423              :         }
     424              : 
     425              :       // parse the body (after =>)
     426              :       // always parse the body regardless of whether has_match is set, so lex
     427              :       // will be at the next predicate in the next loop
     428           51 :       size_t body_start = lex.get_offs ();
     429           51 :       auto block_res = parser.parse_block_expr ();
     430           51 :       if (has_match)
     431              :         {
     432           29 :           size_t body_end = lex.get_offs ();
     433           29 :           if (!block_res)
     434              :             {
     435            0 :               rust_error_at (lex.peek_token ()->get_locus (),
     436              :                              "failed to parse %<cfg_select!%> arm body");
     437            0 :               return AST::Fragment::create_error ();
     438              :             }
     439              : 
     440           29 :           auto block = std::move (*block_res);
     441           44 :           for (auto &stmt : block->get_statements ())
     442              :             {
     443           15 :               if (stmt->get_stmt_kind () == AST::Stmt::Kind::Item)
     444              :                 {
     445           15 :                   AST::Stmt *raw = stmt.release ();
     446           15 :                   matched_body_nodes.emplace_back (std::unique_ptr<AST::Item> (
     447           15 :                     static_cast<AST::Item *> (raw)));
     448              :                 }
     449              :               else
     450              :                 {
     451            0 :                   matched_body_nodes.emplace_back (std::move (stmt));
     452              :                 }
     453              :             }
     454           29 :           if (block->has_tail_expr ())
     455              :             {
     456           14 :               auto tail = block->take_tail_expr ();
     457           14 :               matched_body_nodes.emplace_back (AST::SingleASTNode (
     458           28 :                 std::make_unique<AST::ExprStmt> (std::move (tail), invoc_locus,
     459           14 :                                                  false)));
     460           14 :             }
     461              : 
     462           29 :           matched_body_tokens = lex.get_token_slice (body_start, body_end);
     463           29 :           break;
     464           29 :         }
     465              : 
     466           22 :       parser.maybe_skip_token (COMMA);
     467           51 :     }
     468              : 
     469           29 :   if (!has_match)
     470              :     {
     471            0 :       rust_error_at (
     472              :         invoc_locus,
     473              :         "no %<cfg_select!%> arm matched and no %<_%> arm was provided");
     474            0 :       return AST::Fragment::create_error ();
     475              :     }
     476              : 
     477           29 :   return AST::Fragment (std::move (matched_body_nodes),
     478           58 :                         std::move (matched_body_tokens));
     479           29 : }
     480              : 
     481              : tl::optional<AST::Fragment>
     482          696 : MacroBuiltin::stringify_handler (location_t invoc_locus,
     483              :                                  AST::MacroInvocData &invoc,
     484              :                                  AST::InvocKind semicolon)
     485              : {
     486          696 :   std::string content;
     487          696 :   auto invoc_token_tree = invoc.get_delim_tok_tree ();
     488          696 :   auto tokens = invoc_token_tree.to_token_stream ();
     489              : 
     490              :   // Tokens stream includes the first and last delimiter
     491              :   // which we need to skip.
     492         1433 :   for (auto token = tokens.cbegin () + 1; token < tokens.cend () - 1; token++)
     493              :     {
     494              :       // Rust stringify format has no garantees but the reference compiler
     495              :       // removes spaces before some tokens depending on the lexer's behavior,
     496              :       // let's mimick some of those behaviors.
     497          737 :       auto token_id = (*token)->get_id ();
     498          737 :       if (token_id != RIGHT_PAREN && token_id != EXCLAM
     499          737 :           && token != tokens.cbegin () + 1)
     500              :         {
     501           25 :           content.push_back (' ');
     502              :         }
     503         1474 :       content += (*token)->as_string ();
     504              :     }
     505              : 
     506         1392 :   auto node = AST::SingleASTNode (make_string (invoc_locus, content));
     507          696 :   auto token
     508         1392 :     = make_token (Token::make_string (invoc_locus, std::move (content)));
     509         2088 :   return AST::Fragment ({node}, std::move (token));
     510          696 : }
     511              : 
     512              : } // namespace Rust
        

Generated by: LCOV version 2.4-beta

LCOV profile is generated on x86_64 machine using following configure options: configure --disable-bootstrap --enable-coverage=opt --enable-languages=c,c++,fortran,go,jit,lto,rust,m2 --enable-host-shared. GCC test suite is run with the built compiler.