LCOV - code coverage report
Current view: top level - gcc/rust - rust-lang.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 79.2 % 120 95
Test Date: 2026-09-19 16:22:48 Functions: 83.3 % 18 15
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-system.h"
      20              : #include "rust-diagnostics.h"
      21              : #include "coretypes.h"
      22              : #include "target.h"
      23              : #include "tree.h"
      24              : #include "gimple-expr.h"
      25              : #include "diagnostic.h"
      26              : #include "opts.h"
      27              : #include "fold-const.h"
      28              : #include "gimplify.h"
      29              : #include "stor-layout.h"
      30              : #include "debug.h"
      31              : #include "convert.h"
      32              : #include "langhooks.h"
      33              : #include "langhooks-def.h"
      34              : #include "selftest.h"
      35              : #include "rust-cfg-parser.h"
      36              : #include "rust-privacy-ctx.h"
      37              : #include "rust-lex.h"
      38              : #include "optional.h"
      39              : #include "rust-unicode.h"
      40              : #include "rust-punycode.h"
      41              : #include "rust-builtins.h"
      42              : 
      43              : #include <mpfr.h>
      44              : // note: header files must be in this order or else forward declarations don't
      45              : // work properly. Kinda dumb system, but have to live with it. clang-format
      46              : // seems to mess it up
      47              : /* Order: config, system, coretypes, target, tree, gimple-expr, diagnostic,
      48              :  * opts, fold-const, gimplify, stor-layout, debug, convert, langhooks,
      49              :  * langhooks-def */
      50              : 
      51              : // FIXME: test saving intellisense
      52              : #include "options.h"
      53              : 
      54              : // version check to stop compiling if c++ isn't c++14 or higher
      55              : #if __cplusplus < 201402
      56              : #error                                                                         \
      57              :   "GCC Rust frontend requires C++14 or higher. You can compile the g++ frontend first and then compile the Rust frontend using that."
      58              : #endif
      59              : // TODO: is this best way to do it? Is it allowed? (should be)
      60              : 
      61              : /* General TODOs:
      62              :  *  - convert all copies of expensive-to-copy (deep copy) AST objects into
      63              :  * moves, if possible. Don't remove clone functionality - it may be required for
      64              :  * e.g. HIR conversion.
      65              :  */
      66              : 
      67              : #include "rust-session-manager.h"
      68              : #include "rust-tree.h"
      69              : 
      70              : // The resulting tree type.
      71              : union GTY ((
      72              :   desc ("TREE_CODE (&%h.generic) == IDENTIFIER_NODE"),
      73              :   chain_next (
      74              :     "CODE_CONTAINS_STRUCT (TREE_CODE (&%h.generic), "
      75              :     "TS_COMMON) ? ((union lang_tree_node *) TREE_CHAIN (&%h.generic)) : NULL")))
      76              :   lang_tree_node
      77              : {
      78              :   union tree_node GTY ((tag ("0"), desc ("tree_node_structure (&%h)"))) generic;
      79              :   struct lang_identifier GTY ((tag ("1"))) identifier;
      80              : };
      81              : 
      82              : // has to be in same compilation unit as session, so here for now
      83              : void
      84        46056 : rust_add_target_info (const char *key, const char *value)
      85              : {
      86        92112 :   Rust::Session::get_instance ().options.target_data.insert_key_value_pair (
      87        92112 :     key, value);
      88        46056 : }
      89              : 
      90              : /* Language hooks.  */
      91              : 
      92              : /* Initial lang hook called (possibly), used for initialisation.
      93              :  * Must call build_common_tree_nodes, set_sizetype, build_common_tree_nodes_2,
      94              :  * and build_common_builtin_nodes, as well as set global variable
      95              :  * void_list_node. Apparently called after option handling? */
      96              : static bool
      97         5117 : grs_langhook_init (void)
      98              : {
      99              :   /* Something to do with this:
     100              :    This allows the code in d-builtins.cc to not have to worry about
     101              :    converting (C signed char *) to (D char *) for string arguments of
     102              :    built-in functions. The parameter (signed_char = false) specifies
     103              :    whether char is signed.  */
     104         5117 :   build_common_tree_nodes (false);
     105              : 
     106              :   // Builds built-ins for middle-end after all front-end built-ins are already
     107              :   // instantiated
     108         5117 :   build_common_builtin_nodes ();
     109              : 
     110         5117 :   mpfr_set_default_prec (128);
     111              : 
     112         5117 :   using_eh_for_cleanups ();
     113              : 
     114              :   // initialise compiler session
     115         5117 :   Rust::Session::get_instance ().init ();
     116              : 
     117         5117 :   return true;
     118              : }
     119              : 
     120              : /* The option mask (something to do with options for specific frontends or
     121              :  * something). */
     122              : static unsigned int
     123        16739 : grs_langhook_option_lang_mask (void)
     124              : {
     125        16739 :   return CL_Rust;
     126              : }
     127              : 
     128              : /* Initialize the options structure. */
     129              : static void
     130         5118 : grs_langhook_init_options_struct (struct gcc_options *opts)
     131              : {
     132              :   /* Operations are always wrapping in Rust, even on signed integer. This is
     133              :    * useful for the low level wrapping_{add, sub, mul} intrinsics, not for
     134              :    * regular arithmetic operations which are checked for overflow anyway using
     135              :    * builtins */
     136         5118 :   opts->x_flag_wrapv = 1;
     137              : 
     138              :   /* We need to warn on unused variables by default */
     139         5118 :   opts->x_warn_unused_variable = 1;
     140              :   /* Experimental lints under -frust-unused-check-2.0 warn by default */
     141         5118 :   opts->x_warn_unused = 1;
     142              :   /* For const variables too */
     143         5118 :   opts->x_warn_unused_const_variable = 1;
     144              :   /* And finally unused result for #[must_use] */
     145         5118 :   opts->x_warn_unused_result = 1;
     146              :   /* lets warn for infinite recursion*/
     147         5118 :   opts->x_warn_infinite_recursion = 1;
     148              :   /* Enable exception handling (aka `panic!` in Rust) */
     149         5118 :   opts->x_flag_exceptions = 1;
     150              : 
     151              :   // nothing yet - used by frontends to change specific options for the language
     152         5118 :   Rust::Session::get_instance ().init_options ();
     153         5118 : }
     154              : 
     155              : /* Main entry point for front-end, apparently. Finds input file names in global
     156              :  * vars in_fnames and num_in_fnames. From this, frontend can take over and do
     157              :  * actual parsing and initial compilation. This function must create a complete
     158              :  * parse tree in a global var, and then return.
     159              :  *
     160              :  * Some consider this the "start of compilation". */
     161              : static void
     162         5117 : grs_langhook_parse_file (void)
     163              : {
     164         5117 :   rust_debug ("Preparing to parse files. ");
     165              : 
     166         5117 :   Rust::Session::get_instance ().handle_input_files (num_in_fnames, in_fnames);
     167         5099 : }
     168              : 
     169              : /* Seems to get the exact type for a specific type - e.g. for scalar float with
     170              :  * 32-bit bitsize, it returns float, and for 64-bit bitsize, it returns double.
     171              :  * Used to map RTL nodes to machine modes or something like that. */
     172              : static tree
     173        51453 : grs_langhook_type_for_mode (machine_mode mode, int unsignedp)
     174              : {
     175              :   // TODO: change all this later to match rustc types
     176        51453 :   if (mode == QImode)
     177           57 :     return unsignedp ? unsigned_intQI_type_node : intQI_type_node;
     178              : 
     179        51396 :   if (mode == HImode)
     180            0 :     return unsignedp ? unsigned_intHI_type_node : intHI_type_node;
     181              : 
     182        51396 :   if (mode == SImode)
     183           47 :     return unsignedp ? unsigned_intSI_type_node : intSI_type_node;
     184              : 
     185        51349 :   if (mode == DImode)
     186        20625 :     return unsignedp ? unsigned_intDI_type_node : intDI_type_node;
     187              : 
     188        30724 :   if (mode == TYPE_MODE (intTI_type_node))
     189           22 :     return unsignedp ? unsigned_intTI_type_node : intTI_type_node;
     190              : 
     191        30702 :   if (mode == TYPE_MODE (float_type_node))
     192            0 :     return float_type_node;
     193              : 
     194        30702 :   if (mode == TYPE_MODE (double_type_node))
     195            0 :     return double_type_node;
     196              : 
     197        30702 :   if (mode == TYPE_MODE (long_double_type_node))
     198            0 :     return long_double_type_node;
     199              : 
     200        30702 :   if (COMPLEX_MODE_P (mode))
     201              :     {
     202        30702 :       if (mode == TYPE_MODE (complex_float_type_node))
     203         5117 :         return complex_float_type_node;
     204        25585 :       if (mode == TYPE_MODE (complex_double_type_node))
     205         5117 :         return complex_double_type_node;
     206        20468 :       if (mode == TYPE_MODE (complex_long_double_type_node))
     207         5117 :         return complex_long_double_type_node;
     208        15351 :       if (mode == TYPE_MODE (complex_integer_type_node) && !unsignedp)
     209            0 :         return complex_integer_type_node;
     210              :     }
     211              : 
     212              :   /* See (a) <https://github.com/Rust-GCC/gccrs/issues/1713>
     213              :      "Test failure on msp430-elfbare target", and
     214              :      (b) <https://gcc.gnu.org/PR46805>
     215              :      "ICE: SIGSEGV in optab_for_tree_code (optabs.c:407) with -O
     216              :      -fno-tree-scev-cprop -ftree-vectorize"
     217              :      -- we have to support "random" modes/types here.
     218              :      TODO Clean all this up (either locally, or preferably per PR46805:
     219              :      "Ideally we'd never use lang_hooks.types.type_for_mode (or _for_size) in
     220              :      the middle-end but had a pure middle-end based implementation".  */
     221        30702 :   for (size_t i = 0; i < NUM_INT_N_ENTS; i++)
     222        15351 :     if (int_n_enabled_p[i] && mode == int_n_data[i].m)
     223            0 :       return (unsignedp ? int_n_trees[i].unsigned_type
     224            0 :                         : int_n_trees[i].signed_type);
     225              : 
     226              :   /* rust_unreachable */
     227              :   return NULL;
     228              : }
     229              : 
     230              : // Record a builtin function.
     231              : static tree
     232     26633985 : grs_langhook_builtin_function (tree decl)
     233              : {
     234     26633985 :   Rust::Compile::BuiltinsContext::get ().register_builtin (decl);
     235     26633985 :   return decl;
     236              : }
     237              : 
     238              : /* Return true if we are in the global binding level (which is never,
     239              :  * apparently). */
     240              : static bool
     241          486 : grs_langhook_global_bindings_p (void)
     242              : {
     243              :   // return current_function_decl == NULL_TREE;
     244              :   // rust_unreachable();
     245              :   // return true;
     246          486 :   return false;
     247              : }
     248              : 
     249              : /* Push a declaration into the current binding level.  We can't
     250              :    usefully implement this since we don't want to convert from tree
     251              :    back to one of our internal data structures.  I think the only way
     252              :    this is used is to record a decl which is to be returned by
     253              :    getdecls, and we could implement it for that purpose if
     254              :    necessary.  */
     255              : static tree
     256            0 : grs_langhook_pushdecl (tree decl ATTRIBUTE_UNUSED)
     257              : {
     258              :   // rust_unreachable ();
     259            0 :   return NULL;
     260              : }
     261              : 
     262              : /* This hook is used to get the current list of declarations as trees.
     263              :    We don't support that; instead we use the write_globals hook.  This
     264              :    can't simply crash because it is called by -gstabs.  */
     265              : static tree
     266            0 : grs_langhook_getdecls (void)
     267              : {
     268              :   // rust_unreachable();
     269            0 :   return NULL;
     270              : }
     271              : 
     272              : // Handle Rust-specific options. Return false if nothing happened.
     273              : static bool
     274        46351 : grs_langhook_handle_option (
     275              :   size_t scode, const char *arg, HOST_WIDE_INT value, int kind ATTRIBUTE_UNUSED,
     276              :   location_t loc, const struct cl_option_handlers *handlers ATTRIBUTE_UNUSED)
     277              : {
     278              :   // Convert integer code to lang.opt enum codes with names.
     279        46351 :   enum opt_code code = (enum opt_code) scode;
     280              : 
     281              :   // Delegate to session manager
     282        46351 :   return Rust::Session::get_instance ().handle_option (code, arg, value, kind,
     283        46351 :                                                        loc, handlers);
     284              : }
     285              : 
     286              : /* Run after parsing options.  */
     287              : static bool
     288         5118 : grs_langhook_post_options (const char **pfilename ATTRIBUTE_UNUSED)
     289              : {
     290              :   // can be used to override other options if required
     291              : 
     292              :   // satisfies an assert in init_excess_precision in toplev.cc
     293         5118 :   if (flag_excess_precision /*_cmdline*/ == EXCESS_PRECISION_DEFAULT)
     294         5118 :     flag_excess_precision /*_cmdline*/ = EXCESS_PRECISION_STANDARD;
     295              : 
     296              :   /* Returning false means that the backend should be used.  */
     297         5118 :   return false;
     298              : }
     299              : 
     300              : /* Rust-specific gimplification. May need to gimplify e.g.
     301              :  * CALL_EXPR_STATIC_CHAIN */
     302              : static int
     303       733127 : grs_langhook_gimplify_expr (tree *expr_p ATTRIBUTE_UNUSED,
     304              :                             gimple_seq *pre_p ATTRIBUTE_UNUSED,
     305              :                             gimple_seq *post_p ATTRIBUTE_UNUSED)
     306              : {
     307       733127 :   if (TREE_CODE (*expr_p) == CALL_EXPR
     308       733127 :       && CALL_EXPR_STATIC_CHAIN (*expr_p) != NULL_TREE)
     309            0 :     gimplify_expr (&CALL_EXPR_STATIC_CHAIN (*expr_p), pre_p, post_p,
     310              :                    is_gimple_val, fb_rvalue);
     311       733127 :   return GS_UNHANDLED;
     312              : }
     313              : 
     314              : static tree
     315            2 : grs_langhook_eh_personality (void)
     316              : {
     317            2 :   static tree personality_decl;
     318            2 :   if (personality_decl == NULL_TREE)
     319              :     {
     320            2 :       personality_decl = build_personality_function ("gccrs");
     321            2 :       rust_preserve_from_gc (personality_decl);
     322              :     }
     323            2 :   return personality_decl;
     324              : }
     325              : 
     326              : tree
     327          216 : convert (tree type, tree expr)
     328              : {
     329          216 :   if (type == error_mark_node || expr == error_mark_node
     330          432 :       || TREE_TYPE (expr) == error_mark_node)
     331              :     return error_mark_node;
     332              : 
     333          216 :   if (type == TREE_TYPE (expr))
     334              :     return expr;
     335              : 
     336          216 :   if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (TREE_TYPE (expr)))
     337            0 :     return fold_convert (type, expr);
     338              : 
     339          216 :   switch (TREE_CODE (type))
     340              :     {
     341            0 :     case VOID_TYPE:
     342            0 :     case BOOLEAN_TYPE:
     343            0 :       return fold_convert (type, expr);
     344          111 :     case INTEGER_TYPE:
     345          111 :       return convert_to_integer (type, expr);
     346          105 :     case POINTER_TYPE:
     347          105 :       return convert_to_pointer (type, expr);
     348            0 :     case REAL_TYPE:
     349            0 :       return convert_to_real (type, expr);
     350            0 :     case COMPLEX_TYPE:
     351            0 :       return convert_to_complex (type, expr);
     352            0 :     default:
     353            0 :       break;
     354              :     }
     355              : 
     356            0 :   rust_unreachable ();
     357              : }
     358              : 
     359              : /* FIXME: This is a hack to preserve trees that we create from the
     360              :    garbage collector.  */
     361              : 
     362              : static GTY (()) tree rust_gc_root;
     363              : 
     364              : void
     365       157570 : rust_preserve_from_gc (tree t)
     366              : {
     367       157570 :   rust_gc_root = tree_cons (NULL_TREE, t, rust_gc_root);
     368       157570 : }
     369              : 
     370              : /* Convert an identifier for use in an error message.  */
     371              : 
     372              : const char *
     373            0 : rust_localize_identifier (const char *ident)
     374              : {
     375            0 :   return identifier_to_locale (ident);
     376              : }
     377              : 
     378              : extern const struct scoped_attribute_specs grs_langhook_gnu_attribute_table;
     379              : extern const struct scoped_attribute_specs grs_langhook_common_attribute_table;
     380              : 
     381              : const scoped_attribute_specs *const grs_langhook_attribute_table[] = {
     382              :   &grs_langhook_gnu_attribute_table,
     383              :   &grs_langhook_common_attribute_table,
     384              : };
     385              : 
     386              : /* The language hooks data structure. This is the main interface between the GCC
     387              :  * front-end and the GCC middle-end/back-end. A list of language hooks could be
     388              :  * found in <gcc>/langhooks.h
     389              :  */
     390              : #undef LANG_HOOKS_NAME
     391              : #undef LANG_HOOKS_INIT
     392              : #undef LANG_HOOKS_OPTION_LANG_MASK
     393              : #undef LANG_HOOKS_INIT_OPTIONS_STRUCT
     394              : #undef LANG_HOOKS_HANDLE_OPTION
     395              : #undef LANG_HOOKS_POST_OPTIONS
     396              : #undef LANG_HOOKS_PARSE_FILE
     397              : #undef LANG_HOOKS_TYPE_FOR_MODE
     398              : #undef LANG_HOOKS_BUILTIN_FUNCTION
     399              : #undef LANG_HOOKS_GLOBAL_BINDINGS_P
     400              : #undef LANG_HOOKS_PUSHDECL
     401              : #undef LANG_HOOKS_GETDECLS
     402              : #undef LANG_HOOKS_WRITE_GLOBALS
     403              : #undef LANG_HOOKS_GIMPLIFY_EXPR
     404              : #undef LANG_HOOKS_EH_PERSONALITY
     405              : #undef LANG_HOOKS_ATTRIBUTE_TABLE
     406              : 
     407              : #define LANG_HOOKS_NAME "GNU Rust"
     408              : #define LANG_HOOKS_INIT grs_langhook_init
     409              : #define LANG_HOOKS_OPTION_LANG_MASK grs_langhook_option_lang_mask
     410              : #define LANG_HOOKS_INIT_OPTIONS_STRUCT grs_langhook_init_options_struct
     411              : #define LANG_HOOKS_HANDLE_OPTION grs_langhook_handle_option
     412              : #define LANG_HOOKS_POST_OPTIONS grs_langhook_post_options
     413              : /* Main lang-hook, apparently. Finds input file names in global vars in_fnames
     414              :  * and num_in_fnames From this, frontend can take over and do actual parsing and
     415              :  * initial compilation.
     416              :  * This hook must create a complete parse tree in a global var, and then return.
     417              :  */
     418              : #define LANG_HOOKS_PARSE_FILE grs_langhook_parse_file
     419              : #define LANG_HOOKS_TYPE_FOR_MODE grs_langhook_type_for_mode
     420              : #define LANG_HOOKS_BUILTIN_FUNCTION grs_langhook_builtin_function
     421              : #define LANG_HOOKS_GLOBAL_BINDINGS_P grs_langhook_global_bindings_p
     422              : #define LANG_HOOKS_PUSHDECL grs_langhook_pushdecl
     423              : #define LANG_HOOKS_GETDECLS grs_langhook_getdecls
     424              : #define LANG_HOOKS_GIMPLIFY_EXPR grs_langhook_gimplify_expr
     425              : #define LANG_HOOKS_EH_PERSONALITY grs_langhook_eh_personality
     426              : 
     427              : #define LANG_HOOKS_ATTRIBUTE_TABLE grs_langhook_attribute_table
     428              : 
     429              : #if CHECKING_P
     430              : 
     431              : #undef LANG_HOOKS_RUN_LANG_SELFTESTS
     432              : #define LANG_HOOKS_RUN_LANG_SELFTESTS selftest::run_rust_tests
     433              : 
     434              : namespace selftest {
     435              : 
     436              : void
     437            1 : run_rust_tests ()
     438              : {
     439              :   // Call tests for the rust frontend here
     440            1 :   rust_input_source_test ();
     441            1 :   rust_nfc_qc_test ();
     442            1 :   rust_utf8_normalize_test ();
     443            1 :   rust_punycode_encode_test ();
     444            1 :   rust_cfg_parser_test ();
     445            1 :   rust_privacy_ctx_test ();
     446            1 :   rust_crate_name_validation_test ();
     447            1 : }
     448              : } // namespace selftest
     449              : 
     450              : #endif /* !CHECKING_P */
     451              : 
     452              : // Expands all LANG_HOOKS_x of GCC
     453              : struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER;
     454              : 
     455              : // These are for GCC's garbage collector to work properly or something
     456              : #include "gt-rust-rust-lang.h"
     457              : #include "gtype-rust.h"
        

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.