LCOV - code coverage report
Current view: top level - gcc/rust - rust-lang.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 79.0 % 119 94
Test Date: 2026-08-22 16:33:35 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        44847 : rust_add_target_info (const char *key, const char *value)
      84              : {
      85        89694 :   Rust::Session::get_instance ().options.target_data.insert_key_value_pair (
      86        89694 :     key, value);
      87        44847 : }
      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         4983 : 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         4983 :   build_common_tree_nodes (false);
     104              : 
     105              :   // Builds built-ins for middle-end after all front-end built-ins are already
     106              :   // instantiated
     107         4983 :   build_common_builtin_nodes ();
     108              : 
     109         4983 :   mpfr_set_default_prec (128);
     110              : 
     111         4983 :   using_eh_for_cleanups ();
     112              : 
     113              :   // initialise compiler session
     114         4983 :   Rust::Session::get_instance ().init ();
     115              : 
     116         4983 :   return true;
     117              : }
     118              : 
     119              : /* The option mask (something to do with options for specific frontends or
     120              :  * something). */
     121              : static unsigned int
     122        16142 : grs_langhook_option_lang_mask (void)
     123              : {
     124        16142 :   return CL_Rust;
     125              : }
     126              : 
     127              : /* Initialize the options structure. */
     128              : static void
     129         4984 : 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         4984 :   opts->x_flag_wrapv = 1;
     136              : 
     137              :   /* We need to warn on unused variables by default */
     138         4984 :   opts->x_warn_unused_variable = 1;
     139              :   /* Experimental lints under -frust-unused-check-2.0 warn by default */
     140         4984 :   opts->x_warn_unused = 1;
     141              :   /* For const variables too */
     142         4984 :   opts->x_warn_unused_const_variable = 1;
     143              :   /* And finally unused result for #[must_use] */
     144         4984 :   opts->x_warn_unused_result = 1;
     145              :   /* lets warn for infinite recursion*/
     146         4984 :   opts->x_warn_infinite_recursion = 1;
     147              :   /* Enable exception handling (aka `panic!` in Rust) */
     148         4984 :   opts->x_flag_exceptions = 1;
     149              : 
     150              :   // nothing yet - used by frontends to change specific options for the language
     151         4984 :   Rust::Session::get_instance ().init_options ();
     152         4984 : }
     153              : 
     154              : /* Main entry point for front-end, apparently. Finds input file names in global
     155              :  * vars in_fnames and num_in_fnames. From this, frontend can take over and do
     156              :  * actual parsing and initial compilation. This function must create a complete
     157              :  * parse tree in a global var, and then return.
     158              :  *
     159              :  * Some consider this the "start of compilation". */
     160              : static void
     161         4983 : grs_langhook_parse_file (void)
     162              : {
     163         4983 :   rust_debug ("Preparing to parse files. ");
     164              : 
     165         4983 :   Rust::Session::get_instance ().handle_input_files (num_in_fnames, in_fnames);
     166         4974 : }
     167              : 
     168              : /* Seems to get the exact type for a specific type - e.g. for scalar float with
     169              :  * 32-bit bitsize, it returns float, and for 64-bit bitsize, it returns double.
     170              :  * Used to map RTL nodes to machine modes or something like that. */
     171              : static tree
     172        39862 : grs_langhook_type_for_mode (machine_mode mode, int unsignedp)
     173              : {
     174              :   // TODO: change all this later to match rustc types
     175        39862 :   if (mode == QImode)
     176           45 :     return unsignedp ? unsigned_intQI_type_node : intQI_type_node;
     177              : 
     178        39817 :   if (mode == HImode)
     179            0 :     return unsignedp ? unsigned_intHI_type_node : intHI_type_node;
     180              : 
     181        39817 :   if (mode == SImode)
     182           47 :     return unsignedp ? unsigned_intSI_type_node : intSI_type_node;
     183              : 
     184        39770 :   if (mode == DImode)
     185         9850 :     return unsignedp ? unsigned_intDI_type_node : intDI_type_node;
     186              : 
     187        29920 :   if (mode == TYPE_MODE (intTI_type_node))
     188           22 :     return unsignedp ? unsigned_intTI_type_node : intTI_type_node;
     189              : 
     190        29898 :   if (mode == TYPE_MODE (float_type_node))
     191            0 :     return float_type_node;
     192              : 
     193        29898 :   if (mode == TYPE_MODE (double_type_node))
     194            0 :     return double_type_node;
     195              : 
     196        29898 :   if (mode == TYPE_MODE (long_double_type_node))
     197            0 :     return long_double_type_node;
     198              : 
     199        29898 :   if (COMPLEX_MODE_P (mode))
     200              :     {
     201        29898 :       if (mode == TYPE_MODE (complex_float_type_node))
     202         4983 :         return complex_float_type_node;
     203        24915 :       if (mode == TYPE_MODE (complex_double_type_node))
     204         4983 :         return complex_double_type_node;
     205        19932 :       if (mode == TYPE_MODE (complex_long_double_type_node))
     206         4983 :         return complex_long_double_type_node;
     207        14949 :       if (mode == TYPE_MODE (complex_integer_type_node) && !unsignedp)
     208            0 :         return complex_integer_type_node;
     209              :     }
     210              : 
     211              :   /* See (a) <https://github.com/Rust-GCC/gccrs/issues/1713>
     212              :      "Test failure on msp430-elfbare target", and
     213              :      (b) <https://gcc.gnu.org/PR46805>
     214              :      "ICE: SIGSEGV in optab_for_tree_code (optabs.c:407) with -O
     215              :      -fno-tree-scev-cprop -ftree-vectorize"
     216              :      -- we have to support "random" modes/types here.
     217              :      TODO Clean all this up (either locally, or preferably per PR46805:
     218              :      "Ideally we'd never use lang_hooks.types.type_for_mode (or _for_size) in
     219              :      the middle-end but had a pure middle-end based implementation".  */
     220        29898 :   for (size_t i = 0; i < NUM_INT_N_ENTS; i++)
     221        14949 :     if (int_n_enabled_p[i] && mode == int_n_data[i].m)
     222            0 :       return (unsignedp ? int_n_trees[i].unsigned_type
     223            0 :                         : int_n_trees[i].signed_type);
     224              : 
     225              :   /* rust_unreachable */
     226              :   return NULL;
     227              : }
     228              : 
     229              : // Record a builtin function. We just ignore builtin functions.
     230              : static tree
     231      2410790 : grs_langhook_builtin_function (tree decl ATTRIBUTE_UNUSED)
     232              : {
     233      2410790 :   return decl;
     234              : }
     235              : 
     236              : /* Return true if we are in the global binding level (which is never,
     237              :  * apparently). */
     238              : static bool
     239          394 : grs_langhook_global_bindings_p (void)
     240              : {
     241              :   // return current_function_decl == NULL_TREE;
     242              :   // rust_unreachable();
     243              :   // return true;
     244          394 :   return false;
     245              : }
     246              : 
     247              : /* Push a declaration into the current binding level.  We can't
     248              :    usefully implement this since we don't want to convert from tree
     249              :    back to one of our internal data structures.  I think the only way
     250              :    this is used is to record a decl which is to be returned by
     251              :    getdecls, and we could implement it for that purpose if
     252              :    necessary.  */
     253              : static tree
     254            0 : grs_langhook_pushdecl (tree decl ATTRIBUTE_UNUSED)
     255              : {
     256            0 :   rust_unreachable ();
     257              :   return NULL;
     258              : }
     259              : 
     260              : /* This hook is used to get the current list of declarations as trees.
     261              :    We don't support that; instead we use the write_globals hook.  This
     262              :    can't simply crash because it is called by -gstabs.  */
     263              : static tree
     264            0 : grs_langhook_getdecls (void)
     265              : {
     266              :   // rust_unreachable();
     267            0 :   return NULL;
     268              : }
     269              : 
     270              : // Handle Rust-specific options. Return false if nothing happened.
     271              : static bool
     272        45124 : grs_langhook_handle_option (
     273              :   size_t scode, const char *arg, HOST_WIDE_INT value, int kind ATTRIBUTE_UNUSED,
     274              :   location_t loc, const struct cl_option_handlers *handlers ATTRIBUTE_UNUSED)
     275              : {
     276              :   // Convert integer code to lang.opt enum codes with names.
     277        45124 :   enum opt_code code = (enum opt_code) scode;
     278              : 
     279              :   // Delegate to session manager
     280        45124 :   return Rust::Session::get_instance ().handle_option (code, arg, value, kind,
     281        45124 :                                                        loc, handlers);
     282              : }
     283              : 
     284              : /* Run after parsing options.  */
     285              : static bool
     286         4984 : grs_langhook_post_options (const char **pfilename ATTRIBUTE_UNUSED)
     287              : {
     288              :   // can be used to override other options if required
     289              : 
     290              :   // satisfies an assert in init_excess_precision in toplev.cc
     291         4984 :   if (flag_excess_precision /*_cmdline*/ == EXCESS_PRECISION_DEFAULT)
     292         4984 :     flag_excess_precision /*_cmdline*/ = EXCESS_PRECISION_STANDARD;
     293              : 
     294              :   /* Returning false means that the backend should be used.  */
     295         4984 :   return false;
     296              : }
     297              : 
     298              : /* Rust-specific gimplification. May need to gimplify e.g.
     299              :  * CALL_EXPR_STATIC_CHAIN */
     300              : static int
     301       695210 : grs_langhook_gimplify_expr (tree *expr_p ATTRIBUTE_UNUSED,
     302              :                             gimple_seq *pre_p ATTRIBUTE_UNUSED,
     303              :                             gimple_seq *post_p ATTRIBUTE_UNUSED)
     304              : {
     305       695210 :   if (TREE_CODE (*expr_p) == CALL_EXPR
     306       695210 :       && CALL_EXPR_STATIC_CHAIN (*expr_p) != NULL_TREE)
     307            0 :     gimplify_expr (&CALL_EXPR_STATIC_CHAIN (*expr_p), pre_p, post_p,
     308              :                    is_gimple_val, fb_rvalue);
     309       695210 :   return GS_UNHANDLED;
     310              : }
     311              : 
     312              : static tree
     313            2 : grs_langhook_eh_personality (void)
     314              : {
     315            2 :   static tree personality_decl;
     316            2 :   if (personality_decl == NULL_TREE)
     317              :     {
     318            2 :       personality_decl = build_personality_function ("gccrs");
     319            2 :       rust_preserve_from_gc (personality_decl);
     320              :     }
     321            2 :   return personality_decl;
     322              : }
     323              : 
     324              : tree
     325          208 : convert (tree type, tree expr)
     326              : {
     327          208 :   if (type == error_mark_node || expr == error_mark_node
     328          416 :       || TREE_TYPE (expr) == error_mark_node)
     329              :     return error_mark_node;
     330              : 
     331          208 :   if (type == TREE_TYPE (expr))
     332              :     return expr;
     333              : 
     334          208 :   if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (TREE_TYPE (expr)))
     335            0 :     return fold_convert (type, expr);
     336              : 
     337          208 :   switch (TREE_CODE (type))
     338              :     {
     339            0 :     case VOID_TYPE:
     340            0 :     case BOOLEAN_TYPE:
     341            0 :       return fold_convert (type, expr);
     342          104 :     case INTEGER_TYPE:
     343          104 :       return convert_to_integer (type, expr);
     344          104 :     case POINTER_TYPE:
     345          104 :       return convert_to_pointer (type, expr);
     346            0 :     case REAL_TYPE:
     347            0 :       return convert_to_real (type, expr);
     348            0 :     case COMPLEX_TYPE:
     349            0 :       return convert_to_complex (type, expr);
     350            0 :     default:
     351            0 :       break;
     352              :     }
     353              : 
     354            0 :   rust_unreachable ();
     355              : }
     356              : 
     357              : /* FIXME: This is a hack to preserve trees that we create from the
     358              :    garbage collector.  */
     359              : 
     360              : static GTY (()) tree rust_gc_root;
     361              : 
     362              : void
     363       149698 : rust_preserve_from_gc (tree t)
     364              : {
     365       149698 :   rust_gc_root = tree_cons (NULL_TREE, t, rust_gc_root);
     366       149698 : }
     367              : 
     368              : /* Convert an identifier for use in an error message.  */
     369              : 
     370              : const char *
     371            0 : rust_localize_identifier (const char *ident)
     372              : {
     373            0 :   return identifier_to_locale (ident);
     374              : }
     375              : 
     376              : extern const struct scoped_attribute_specs grs_langhook_gnu_attribute_table;
     377              : extern const struct scoped_attribute_specs grs_langhook_common_attribute_table;
     378              : 
     379              : const scoped_attribute_specs *const grs_langhook_attribute_table[] = {
     380              :   &grs_langhook_gnu_attribute_table,
     381              :   &grs_langhook_common_attribute_table,
     382              : };
     383              : 
     384              : /* The language hooks data structure. This is the main interface between the GCC
     385              :  * front-end and the GCC middle-end/back-end. A list of language hooks could be
     386              :  * found in <gcc>/langhooks.h
     387              :  */
     388              : #undef LANG_HOOKS_NAME
     389              : #undef LANG_HOOKS_INIT
     390              : #undef LANG_HOOKS_OPTION_LANG_MASK
     391              : #undef LANG_HOOKS_INIT_OPTIONS_STRUCT
     392              : #undef LANG_HOOKS_HANDLE_OPTION
     393              : #undef LANG_HOOKS_POST_OPTIONS
     394              : #undef LANG_HOOKS_PARSE_FILE
     395              : #undef LANG_HOOKS_TYPE_FOR_MODE
     396              : #undef LANG_HOOKS_BUILTIN_FUNCTION
     397              : #undef LANG_HOOKS_GLOBAL_BINDINGS_P
     398              : #undef LANG_HOOKS_PUSHDECL
     399              : #undef LANG_HOOKS_GETDECLS
     400              : #undef LANG_HOOKS_WRITE_GLOBALS
     401              : #undef LANG_HOOKS_GIMPLIFY_EXPR
     402              : #undef LANG_HOOKS_EH_PERSONALITY
     403              : #undef LANG_HOOKS_ATTRIBUTE_TABLE
     404              : 
     405              : #define LANG_HOOKS_NAME "GNU Rust"
     406              : #define LANG_HOOKS_INIT grs_langhook_init
     407              : #define LANG_HOOKS_OPTION_LANG_MASK grs_langhook_option_lang_mask
     408              : #define LANG_HOOKS_INIT_OPTIONS_STRUCT grs_langhook_init_options_struct
     409              : #define LANG_HOOKS_HANDLE_OPTION grs_langhook_handle_option
     410              : #define LANG_HOOKS_POST_OPTIONS grs_langhook_post_options
     411              : /* Main lang-hook, apparently. Finds input file names in global vars in_fnames
     412              :  * and num_in_fnames From this, frontend can take over and do actual parsing and
     413              :  * initial compilation.
     414              :  * This hook must create a complete parse tree in a global var, and then return.
     415              :  */
     416              : #define LANG_HOOKS_PARSE_FILE grs_langhook_parse_file
     417              : #define LANG_HOOKS_TYPE_FOR_MODE grs_langhook_type_for_mode
     418              : #define LANG_HOOKS_BUILTIN_FUNCTION grs_langhook_builtin_function
     419              : #define LANG_HOOKS_GLOBAL_BINDINGS_P grs_langhook_global_bindings_p
     420              : #define LANG_HOOKS_PUSHDECL grs_langhook_pushdecl
     421              : #define LANG_HOOKS_GETDECLS grs_langhook_getdecls
     422              : #define LANG_HOOKS_GIMPLIFY_EXPR grs_langhook_gimplify_expr
     423              : #define LANG_HOOKS_EH_PERSONALITY grs_langhook_eh_personality
     424              : 
     425              : #define LANG_HOOKS_ATTRIBUTE_TABLE grs_langhook_attribute_table
     426              : 
     427              : #if CHECKING_P
     428              : 
     429              : #undef LANG_HOOKS_RUN_LANG_SELFTESTS
     430              : #define LANG_HOOKS_RUN_LANG_SELFTESTS selftest::run_rust_tests
     431              : 
     432              : namespace selftest {
     433              : 
     434              : void
     435            1 : run_rust_tests ()
     436              : {
     437              :   // Call tests for the rust frontend here
     438            1 :   rust_input_source_test ();
     439            1 :   rust_nfc_qc_test ();
     440            1 :   rust_utf8_normalize_test ();
     441            1 :   rust_punycode_encode_test ();
     442            1 :   rust_cfg_parser_test ();
     443            1 :   rust_privacy_ctx_test ();
     444            1 :   rust_crate_name_validation_test ();
     445            1 : }
     446              : } // namespace selftest
     447              : 
     448              : #endif /* !CHECKING_P */
     449              : 
     450              : // Expands all LANG_HOOKS_x of GCC
     451              : struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER;
     452              : 
     453              : // These are for GCC's garbage collector to work properly or something
     454              : #include "gt-rust-rust-lang.h"
     455              : #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.