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-03-28 14:25:54 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        41868 : rust_add_target_info (const char *key, const char *value)
      84              : {
      85        83736 :   Rust::Session::get_instance ().options.target_data.insert_key_value_pair (
      86        83736 :     key, value);
      87        41868 : }
      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         4652 : 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         4652 :   build_common_tree_nodes (false);
     104              : 
     105              :   // Builds built-ins for middle-end after all front-end built-ins are already
     106              :   // instantiated
     107         4652 :   build_common_builtin_nodes ();
     108              : 
     109         4652 :   mpfr_set_default_prec (128);
     110              : 
     111         4652 :   using_eh_for_cleanups ();
     112              : 
     113              :   // initialise compiler session
     114         4652 :   Rust::Session::get_instance ().init ();
     115              : 
     116         4652 :   return true;
     117              : }
     118              : 
     119              : /* The option mask (something to do with options for specific frontends or
     120              :  * something). */
     121              : static unsigned int
     122        15305 : grs_langhook_option_lang_mask (void)
     123              : {
     124        15305 :   return CL_Rust;
     125              : }
     126              : 
     127              : /* Initialize the options structure. */
     128              : static void
     129         4653 : 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         4653 :   opts->x_flag_wrapv = 1;
     136              : 
     137              :   /* We need to warn on unused variables by default */
     138         4653 :   opts->x_warn_unused_variable = 1;
     139              :   /* For const variables too */
     140         4653 :   opts->x_warn_unused_const_variable = 1;
     141              :   /* And finally unused result for #[must_use] */
     142         4653 :   opts->x_warn_unused_result = 1;
     143              :   /* lets warn for infinite recursion*/
     144         4653 :   opts->x_warn_infinite_recursion = 1;
     145              :   /* Enable exception handling (aka `panic!` in Rust) */
     146         4653 :   opts->x_flag_exceptions = 1;
     147              : 
     148              :   // nothing yet - used by frontends to change specific options for the language
     149         4653 :   Rust::Session::get_instance ().init_options ();
     150         4653 : }
     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         4652 : grs_langhook_parse_file (void)
     160              : {
     161         4652 :   rust_debug ("Preparing to parse files. ");
     162              : 
     163         4652 :   Rust::Session::get_instance ().handle_input_files (num_in_fnames, in_fnames);
     164         4650 : }
     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        36732 : grs_langhook_type_for_mode (machine_mode mode, int unsignedp)
     171              : {
     172              :   // TODO: change all this later to match rustc types
     173        36732 :   if (mode == QImode)
     174            0 :     return unsignedp ? unsigned_intQI_type_node : intQI_type_node;
     175              : 
     176        36732 :   if (mode == HImode)
     177            0 :     return unsignedp ? unsigned_intHI_type_node : intHI_type_node;
     178              : 
     179        36732 :   if (mode == SImode)
     180           24 :     return unsignedp ? unsigned_intSI_type_node : intSI_type_node;
     181              : 
     182        36708 :   if (mode == DImode)
     183         8774 :     return unsignedp ? unsigned_intDI_type_node : intDI_type_node;
     184              : 
     185        27934 :   if (mode == TYPE_MODE (intTI_type_node))
     186           22 :     return unsignedp ? unsigned_intTI_type_node : intTI_type_node;
     187              : 
     188        27912 :   if (mode == TYPE_MODE (float_type_node))
     189            0 :     return float_type_node;
     190              : 
     191        27912 :   if (mode == TYPE_MODE (double_type_node))
     192            0 :     return double_type_node;
     193              : 
     194        27912 :   if (mode == TYPE_MODE (long_double_type_node))
     195            0 :     return long_double_type_node;
     196              : 
     197        27912 :   if (COMPLEX_MODE_P (mode))
     198              :     {
     199        27912 :       if (mode == TYPE_MODE (complex_float_type_node))
     200         4652 :         return complex_float_type_node;
     201        23260 :       if (mode == TYPE_MODE (complex_double_type_node))
     202         4652 :         return complex_double_type_node;
     203        18608 :       if (mode == TYPE_MODE (complex_long_double_type_node))
     204         4652 :         return complex_long_double_type_node;
     205        13956 :       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        27912 :   for (size_t i = 0; i < NUM_INT_N_ENTS; i++)
     219        13956 :     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      2131006 : grs_langhook_builtin_function (tree decl ATTRIBUTE_UNUSED)
     230              : {
     231      2131006 :   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        42065 : grs_langhook_handle_option (
     271              :   size_t scode, const char *arg, HOST_WIDE_INT value, int kind ATTRIBUTE_UNUSED,
     272              :   location_t loc, const struct cl_option_handlers *handlers ATTRIBUTE_UNUSED)
     273              : {
     274              :   // Convert integer code to lang.opt enum codes with names.
     275        42065 :   enum opt_code code = (enum opt_code) scode;
     276              : 
     277              :   // Delegate to session manager
     278        42065 :   return Rust::Session::get_instance ().handle_option (code, arg, value, kind,
     279        42065 :                                                        loc, handlers);
     280              : }
     281              : 
     282              : /* Run after parsing options.  */
     283              : static bool
     284         4653 : grs_langhook_post_options (const char **pfilename ATTRIBUTE_UNUSED)
     285              : {
     286              :   // can be used to override other options if required
     287              : 
     288              :   // satisfies an assert in init_excess_precision in toplev.cc
     289         4653 :   if (flag_excess_precision /*_cmdline*/ == EXCESS_PRECISION_DEFAULT)
     290         4653 :     flag_excess_precision /*_cmdline*/ = EXCESS_PRECISION_STANDARD;
     291              : 
     292              :   /* Returning false means that the backend should be used.  */
     293         4653 :   return false;
     294              : }
     295              : 
     296              : /* Rust-specific gimplification. May need to gimplify e.g.
     297              :  * CALL_EXPR_STATIC_CHAIN */
     298              : static int
     299       590974 : grs_langhook_gimplify_expr (tree *expr_p ATTRIBUTE_UNUSED,
     300              :                             gimple_seq *pre_p ATTRIBUTE_UNUSED,
     301              :                             gimple_seq *post_p ATTRIBUTE_UNUSED)
     302              : {
     303       590974 :   if (TREE_CODE (*expr_p) == CALL_EXPR
     304       590974 :       && CALL_EXPR_STATIC_CHAIN (*expr_p) != NULL_TREE)
     305            0 :     gimplify_expr (&CALL_EXPR_STATIC_CHAIN (*expr_p), pre_p, post_p,
     306              :                    is_gimple_val, fb_rvalue);
     307       590974 :   return GS_UNHANDLED;
     308              : }
     309              : 
     310              : static tree
     311            2 : grs_langhook_eh_personality (void)
     312              : {
     313            2 :   static tree personality_decl;
     314            2 :   if (personality_decl == NULL_TREE)
     315              :     {
     316            2 :       personality_decl = build_personality_function ("gccrs");
     317            2 :       rust_preserve_from_gc (personality_decl);
     318              :     }
     319            2 :   return personality_decl;
     320              : }
     321              : 
     322              : tree
     323          208 : convert (tree type, tree expr)
     324              : {
     325          208 :   if (type == error_mark_node || expr == error_mark_node
     326          416 :       || TREE_TYPE (expr) == error_mark_node)
     327              :     return error_mark_node;
     328              : 
     329          208 :   if (type == TREE_TYPE (expr))
     330              :     return expr;
     331              : 
     332          208 :   if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (TREE_TYPE (expr)))
     333            0 :     return fold_convert (type, expr);
     334              : 
     335          208 :   switch (TREE_CODE (type))
     336              :     {
     337            0 :     case VOID_TYPE:
     338            0 :     case BOOLEAN_TYPE:
     339            0 :       return fold_convert (type, expr);
     340          104 :     case INTEGER_TYPE:
     341          104 :       return convert_to_integer (type, expr);
     342          104 :     case POINTER_TYPE:
     343          104 :       return convert_to_pointer (type, expr);
     344            0 :     case REAL_TYPE:
     345            0 :       return convert_to_real (type, expr);
     346            0 :     case COMPLEX_TYPE:
     347            0 :       return convert_to_complex (type, expr);
     348            0 :     default:
     349            0 :       break;
     350              :     }
     351              : 
     352            0 :   rust_unreachable ();
     353              : }
     354              : 
     355              : /* FIXME: This is a hack to preserve trees that we create from the
     356              :    garbage collector.  */
     357              : 
     358              : static GTY (()) tree rust_gc_root;
     359              : 
     360              : void
     361       140497 : rust_preserve_from_gc (tree t)
     362              : {
     363       140497 :   rust_gc_root = tree_cons (NULL_TREE, t, rust_gc_root);
     364       140497 : }
     365              : 
     366              : /* Convert an identifier for use in an error message.  */
     367              : 
     368              : const char *
     369            0 : rust_localize_identifier (const char *ident)
     370              : {
     371            0 :   return identifier_to_locale (ident);
     372              : }
     373              : 
     374              : extern const struct scoped_attribute_specs grs_langhook_gnu_attribute_table;
     375              : extern const struct scoped_attribute_specs grs_langhook_common_attribute_table;
     376              : 
     377              : const scoped_attribute_specs *const grs_langhook_attribute_table[] = {
     378              :   &grs_langhook_gnu_attribute_table,
     379              :   &grs_langhook_common_attribute_table,
     380              : };
     381              : 
     382              : /* The language hooks data structure. This is the main interface between the GCC
     383              :  * front-end and the GCC middle-end/back-end. A list of language hooks could be
     384              :  * found in <gcc>/langhooks.h
     385              :  */
     386              : #undef LANG_HOOKS_NAME
     387              : #undef LANG_HOOKS_INIT
     388              : #undef LANG_HOOKS_OPTION_LANG_MASK
     389              : #undef LANG_HOOKS_INIT_OPTIONS_STRUCT
     390              : #undef LANG_HOOKS_HANDLE_OPTION
     391              : #undef LANG_HOOKS_POST_OPTIONS
     392              : #undef LANG_HOOKS_PARSE_FILE
     393              : #undef LANG_HOOKS_TYPE_FOR_MODE
     394              : #undef LANG_HOOKS_BUILTIN_FUNCTION
     395              : #undef LANG_HOOKS_GLOBAL_BINDINGS_P
     396              : #undef LANG_HOOKS_PUSHDECL
     397              : #undef LANG_HOOKS_GETDECLS
     398              : #undef LANG_HOOKS_WRITE_GLOBALS
     399              : #undef LANG_HOOKS_GIMPLIFY_EXPR
     400              : #undef LANG_HOOKS_EH_PERSONALITY
     401              : #undef LANG_HOOKS_ATTRIBUTE_TABLE
     402              : 
     403              : #define LANG_HOOKS_NAME "GNU Rust"
     404              : #define LANG_HOOKS_INIT grs_langhook_init
     405              : #define LANG_HOOKS_OPTION_LANG_MASK grs_langhook_option_lang_mask
     406              : #define LANG_HOOKS_INIT_OPTIONS_STRUCT grs_langhook_init_options_struct
     407              : #define LANG_HOOKS_HANDLE_OPTION grs_langhook_handle_option
     408              : #define LANG_HOOKS_POST_OPTIONS grs_langhook_post_options
     409              : /* Main lang-hook, apparently. Finds input file names in global vars in_fnames
     410              :  * and num_in_fnames From this, frontend can take over and do actual parsing and
     411              :  * initial compilation.
     412              :  * This hook must create a complete parse tree in a global var, and then return.
     413              :  */
     414              : #define LANG_HOOKS_PARSE_FILE grs_langhook_parse_file
     415              : #define LANG_HOOKS_TYPE_FOR_MODE grs_langhook_type_for_mode
     416              : #define LANG_HOOKS_BUILTIN_FUNCTION grs_langhook_builtin_function
     417              : #define LANG_HOOKS_GLOBAL_BINDINGS_P grs_langhook_global_bindings_p
     418              : #define LANG_HOOKS_PUSHDECL grs_langhook_pushdecl
     419              : #define LANG_HOOKS_GETDECLS grs_langhook_getdecls
     420              : #define LANG_HOOKS_GIMPLIFY_EXPR grs_langhook_gimplify_expr
     421              : #define LANG_HOOKS_EH_PERSONALITY grs_langhook_eh_personality
     422              : 
     423              : #define LANG_HOOKS_ATTRIBUTE_TABLE grs_langhook_attribute_table
     424              : 
     425              : #if CHECKING_P
     426              : 
     427              : #undef LANG_HOOKS_RUN_LANG_SELFTESTS
     428              : #define LANG_HOOKS_RUN_LANG_SELFTESTS selftest::run_rust_tests
     429              : 
     430              : namespace selftest {
     431              : 
     432              : void
     433            1 : run_rust_tests ()
     434              : {
     435              :   // Call tests for the rust frontend here
     436            1 :   rust_input_source_test ();
     437            1 :   rust_nfc_qc_test ();
     438            1 :   rust_utf8_normalize_test ();
     439            1 :   rust_punycode_encode_test ();
     440            1 :   rust_cfg_parser_test ();
     441            1 :   rust_privacy_ctx_test ();
     442            1 :   rust_crate_name_validation_test ();
     443            1 : }
     444              : } // namespace selftest
     445              : 
     446              : #endif /* !CHECKING_P */
     447              : 
     448              : // Expands all LANG_HOOKS_x of GCC
     449              : struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER;
     450              : 
     451              : // These are for GCC's garbage collector to work properly or something
     452              : #include "gt-rust-rust-lang.h"
     453              : #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.