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