LCOV - code coverage report
Current view: top level - gcc/rust/checks/errors - rust-unsafe-checker.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 71.6 % 479 343
Test Date: 2026-02-28 14:20:25 Functions: 56.0 % 141 79
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-unsafe-checker.h"
      20              : #include "rust-hir.h"
      21              : #include "rust-hir-expr.h"
      22              : #include "rust-hir-stmt.h"
      23              : #include "rust-hir-item.h"
      24              : #include "rust-attribute-values.h"
      25              : #include "rust-system.h"
      26              : #include "rust-immutable-name-resolution-context.h"
      27              : 
      28              : // for flag_name_resolution_2_0
      29              : #include "options.h"
      30              : 
      31              : namespace Rust {
      32              : namespace HIR {
      33              : 
      34         4110 : UnsafeChecker::UnsafeChecker ()
      35         4110 :   : context (*Resolver::TypeCheckContext::get ()),
      36         4110 :     resolver (*Resolver::Resolver::get ()),
      37         8220 :     mappings (Analysis::Mappings::get ())
      38         4110 : {}
      39              : 
      40              : void
      41         4110 : UnsafeChecker::go (HIR::Crate &crate)
      42              : {
      43        21116 :   for (auto &item : crate.get_items ())
      44        17006 :     item->accept_vis (*this);
      45         4110 : }
      46              : 
      47              : static void
      48          759 : check_static_mut (HIR::Item *maybe_static, location_t locus)
      49              : {
      50          759 :   if (maybe_static->get_hir_kind () == Node::BaseKind::VIS_ITEM)
      51              :     {
      52          759 :       auto item = static_cast<Item *> (maybe_static);
      53          759 :       if (item->get_item_kind () == Item::ItemKind::Static)
      54              :         {
      55           22 :           auto static_item = static_cast<StaticItem *> (item);
      56           22 :           if (static_item->is_mut ())
      57            4 :             rust_error_at (
      58              :               locus, "use of mutable static requires unsafe function or block");
      59              :         }
      60              :     }
      61          759 : }
      62              : 
      63              : static void
      64            1 : check_extern_static (HIR::ExternalItem *maybe_static, location_t locus)
      65              : {
      66            1 :   if (maybe_static->get_extern_kind () == ExternalItem::ExternKind::Static)
      67            1 :     rust_error_at (locus,
      68              :                    "use of extern static requires unsafe function or block");
      69            1 : }
      70              : 
      71              : void
      72        29853 : UnsafeChecker::check_use_of_static (HirId node_id, location_t locus)
      73              : {
      74        29853 :   if (unsafe_context.is_in_context ())
      75              :     return;
      76              : 
      77        21454 :   if (auto maybe_static_mut = mappings.lookup_hir_item (node_id))
      78          759 :     check_static_mut (*maybe_static_mut, locus);
      79              : 
      80        21454 :   if (auto maybe_extern_static = mappings.lookup_hir_extern_item (node_id))
      81            2 :     check_extern_static (static_cast<ExternalItem *> (
      82            1 :                            maybe_extern_static->first),
      83              :                          locus);
      84              : }
      85              : 
      86              : static void
      87         4504 : check_unsafe_call (HIR::Function *fn, location_t locus, const std::string &kind)
      88              : {
      89         4504 :   if (fn->get_qualifiers ().is_unsafe ())
      90            4 :     rust_error_at (locus, ErrorCode::E0133,
      91              :                    "call to unsafe %s requires unsafe function or block",
      92              :                    kind.c_str ());
      93         4504 : }
      94              : 
      95              : static bool
      96          202 : is_safe_intrinsic (const std::string &fn_name)
      97              : {
      98          202 :   static const std::unordered_set<std::string> safe_intrinsics = {
      99              :     "abort",
     100              :     "size_of",
     101              :     "min_align_of",
     102              :     "needs_drop",
     103              :     "caller_location",
     104              :     "add_with_overflow",
     105              :     "sub_with_overflow",
     106              :     "mul_with_overflow",
     107              :     "wrapping_add",
     108              :     "wrapping_sub",
     109              :     "wrapping_mul",
     110              :     "saturating_add",
     111              :     "saturating_sub",
     112              :     "rotate_left",
     113              :     "rotate_right",
     114              :     "ctpop",
     115              :     "ctlz",
     116              :     "cttz",
     117              :     "bswap",
     118              :     "bitreverse",
     119              :     "discriminant_value",
     120              :     "type_id",
     121              :     "likely",
     122              :     "unlikely",
     123              :     "ptr_guaranteed_eq",
     124              :     "ptr_guaranteed_ne",
     125              :     "minnumf32",
     126              :     "minnumf64",
     127              :     "maxnumf32",
     128              :     "rustc_peek",
     129              :     "maxnumf64",
     130              :     "type_name",
     131              :     "forget",
     132              :     "black_box",
     133              :     "variant_count",
     134          202 :   };
     135              : 
     136          202 :   return safe_intrinsics.find (fn_name) != safe_intrinsics.end ();
     137              : }
     138              : 
     139              : static void
     140          211 : check_extern_call (HIR::ExternalItem *maybe_fn, HIR::ExternBlock *parent_block,
     141              :                    location_t locus)
     142              : {
     143              :   // We have multiple operations to perform here
     144              :   //     1. Is the item an actual function we're calling
     145              :   //     2. Is the block it's defined in an FFI block or an `extern crate` block
     146              :   //
     147              :   // It is not unsafe to call into other crates, so items defined in an `extern
     148              :   // crate` must be callable without being in an unsafe context. On the other
     149              :   // hand, any function defined in a block with a specific ABI (even `extern
     150              :   // "Rust"` blocks) is unsafe to call
     151              : 
     152          211 :   if (maybe_fn->get_extern_kind () != ExternalItem::ExternKind::Function)
     153              :     return;
     154              : 
     155              :   // Some intrinsics are safe to call
     156          422 :   if (parent_block->get_abi () == Rust::ABI::INTRINSIC
     157          615 :       && is_safe_intrinsic (maybe_fn->get_item_name ().as_string ()))
     158              :     return;
     159              : 
     160            9 :   rust_error_at (locus,
     161              :                  "call to extern function requires unsafe function or block");
     162              : }
     163              : 
     164              : void
     165        10581 : UnsafeChecker::check_function_call (HirId node_id, location_t locus)
     166              : {
     167        10581 :   if (unsafe_context.is_in_context ())
     168         4161 :     return;
     169              : 
     170         6420 :   auto maybe_fn = mappings.lookup_hir_item (node_id);
     171              : 
     172         6420 :   if (maybe_fn
     173         6420 :       && maybe_fn.value ()->get_item_kind () == Item::ItemKind::Function)
     174         2955 :     check_unsafe_call (static_cast<Function *> (*maybe_fn), locus, "function");
     175              : 
     176         6420 :   if (auto maybe_extern = mappings.lookup_hir_extern_item (node_id))
     177          211 :     check_extern_call (static_cast<ExternalItem *> (maybe_extern->first),
     178          422 :                        *mappings.lookup_hir_extern_block (maybe_extern->second),
     179              :                        locus);
     180              : }
     181              : 
     182              : static void
     183         2955 : check_target_attr (HIR::Function *fn, location_t locus)
     184              : {
     185         2955 :   if (std::any_of (fn->get_outer_attrs ().begin (),
     186         2955 :                    fn->get_outer_attrs ().end (),
     187           35 :                    [] (const AST::Attribute &attr) {
     188           70 :                      return attr.get_path ().as_string ()
     189           35 :                             == Values::Attributes::TARGET_FEATURE;
     190              :                    }))
     191            1 :     rust_error_at (locus,
     192              :                    "call to function with %<#[target_feature]%> requires "
     193              :                    "unsafe function or block");
     194         2955 : }
     195              : 
     196              : void
     197        10581 : UnsafeChecker::check_function_attr (HirId node_id, location_t locus)
     198              : {
     199        10581 :   if (unsafe_context.is_in_context ())
     200         4161 :     return;
     201              : 
     202         6420 :   auto maybe_fn = mappings.lookup_hir_item (node_id);
     203              : 
     204         6420 :   if (maybe_fn
     205         6420 :       && maybe_fn.value ()->get_item_kind () == Item::ItemKind::Function)
     206         2955 :     check_target_attr (static_cast<Function *> (*maybe_fn), locus);
     207              : }
     208              : 
     209              : void
     210            0 : UnsafeChecker::visit (Lifetime &)
     211            0 : {}
     212              : 
     213              : void
     214            0 : UnsafeChecker::visit (LifetimeParam &)
     215            0 : {}
     216              : 
     217              : void
     218        29853 : UnsafeChecker::visit (PathInExpression &path)
     219              : {
     220        29853 :   NodeId ast_node_id = path.get_mappings ().get_nodeid ();
     221        29853 :   NodeId ref_node_id;
     222              : 
     223        29853 :   if (flag_name_resolution_2_0)
     224              :     {
     225        29853 :       auto &nr_ctx
     226        29853 :         = Resolver2_0::ImmutableNameResolutionContext::get ().resolver ();
     227              : 
     228        29853 :       auto resolved = nr_ctx.lookup (ast_node_id);
     229              : 
     230        29853 :       if (!resolved.has_value ())
     231            0 :         return;
     232              : 
     233        29853 :       ref_node_id = resolved.value ();
     234              :     }
     235              :   else
     236              :     {
     237            0 :       if (!resolver.lookup_resolved_name (ast_node_id, &ref_node_id))
     238              :         return;
     239              :     }
     240              : 
     241        29853 :   if (auto definition_id = mappings.lookup_node_to_hir (ref_node_id))
     242              :     {
     243        29853 :       check_use_of_static (*definition_id, path.get_locus ());
     244              :     }
     245              :   else
     246              :     {
     247            0 :       rust_unreachable ();
     248              :     }
     249              : }
     250              : 
     251              : void
     252            0 : UnsafeChecker::visit (TypePathSegment &)
     253            0 : {}
     254              : 
     255              : void
     256            0 : UnsafeChecker::visit (TypePathSegmentGeneric &)
     257            0 : {}
     258              : 
     259              : void
     260            0 : UnsafeChecker::visit (TypePathSegmentFunction &)
     261            0 : {}
     262              : 
     263              : void
     264            0 : UnsafeChecker::visit (TypePath &)
     265            0 : {}
     266              : 
     267              : void
     268           15 : UnsafeChecker::visit (QualifiedPathInExpression &)
     269           15 : {}
     270              : 
     271              : void
     272            0 : UnsafeChecker::visit (QualifiedPathInType &)
     273            0 : {}
     274              : 
     275              : void
     276        17364 : UnsafeChecker::visit (LiteralExpr &)
     277        17364 : {}
     278              : 
     279              : void
     280         1926 : UnsafeChecker::visit (BorrowExpr &expr)
     281              : {
     282         1926 :   expr.get_expr ().accept_vis (*this);
     283         1926 : }
     284              : 
     285              : void
     286         3898 : UnsafeChecker::visit (DereferenceExpr &expr)
     287              : {
     288         3898 :   TyTy::BaseType *to_deref_type;
     289         3898 :   auto to_deref = expr.get_expr ().get_mappings ().get_hirid ();
     290              : 
     291         3898 :   rust_assert (context.lookup_type (to_deref, &to_deref_type));
     292              : 
     293         3898 :   if (to_deref_type->get_kind () == TyTy::TypeKind::POINTER
     294         3898 :       && !unsafe_context.is_in_context ())
     295            2 :     rust_error_at (expr.get_locus (), "dereference of raw pointer requires "
     296              :                                       "unsafe function or block");
     297         3898 : }
     298              : 
     299              : void
     300            0 : UnsafeChecker::visit (ErrorPropagationExpr &expr)
     301              : {
     302            0 :   expr.get_expr ().accept_vis (*this);
     303            0 : }
     304              : 
     305              : void
     306          428 : UnsafeChecker::visit (NegationExpr &expr)
     307              : {
     308          428 :   expr.get_expr ().accept_vis (*this);
     309          428 : }
     310              : 
     311              : void
     312         3206 : UnsafeChecker::visit (ArithmeticOrLogicalExpr &expr)
     313              : {
     314         3206 :   expr.get_lhs ().accept_vis (*this);
     315         3206 :   expr.get_rhs ().accept_vis (*this);
     316         3206 : }
     317              : 
     318              : void
     319         2697 : UnsafeChecker::visit (ComparisonExpr &expr)
     320              : {
     321         2697 :   expr.get_lhs ().accept_vis (*this);
     322         2697 :   expr.get_rhs ().accept_vis (*this);
     323         2697 : }
     324              : 
     325              : void
     326          384 : UnsafeChecker::visit (LazyBooleanExpr &expr)
     327              : {
     328          384 :   expr.get_lhs ().accept_vis (*this);
     329          384 :   expr.get_rhs ().accept_vis (*this);
     330          384 : }
     331              : 
     332              : void
     333         5083 : UnsafeChecker::visit (TypeCastExpr &expr)
     334              : {
     335         5083 :   expr.get_expr ().accept_vis (*this);
     336         5083 : }
     337              : 
     338              : void
     339         2465 : UnsafeChecker::visit (AssignmentExpr &expr)
     340              : {
     341         2465 :   expr.get_lhs ().accept_vis (*this);
     342         2465 :   expr.get_rhs ().accept_vis (*this);
     343         2465 : }
     344              : 
     345              : void
     346          673 : UnsafeChecker::visit (CompoundAssignmentExpr &expr)
     347              : {
     348          673 :   expr.get_lhs ().accept_vis (*this);
     349          673 :   expr.get_rhs ().accept_vis (*this);
     350          673 : }
     351              : 
     352              : void
     353          286 : UnsafeChecker::visit (GroupedExpr &expr)
     354              : {
     355          286 :   expr.get_expr_in_parens ().accept_vis (*this);
     356          286 : }
     357              : 
     358              : void
     359          283 : UnsafeChecker::visit (ArrayElemsValues &elems)
     360              : {
     361         1699 :   for (auto &elem : elems.get_values ())
     362         1416 :     elem->accept_vis (*this);
     363          283 : }
     364              : 
     365              : void
     366          113 : UnsafeChecker::visit (ArrayElemsCopied &elems)
     367              : {
     368          113 :   elems.get_elem_to_copy ().accept_vis (*this);
     369          113 : }
     370              : 
     371              : void
     372          396 : UnsafeChecker::visit (ArrayExpr &expr)
     373              : {
     374          396 :   expr.get_internal_elements ().accept_vis (*this);
     375          396 : }
     376              : 
     377              : void
     378          239 : UnsafeChecker::visit (ArrayIndexExpr &expr)
     379              : {
     380          239 :   expr.get_array_expr ().accept_vis (*this);
     381          239 :   expr.get_index_expr ().accept_vis (*this);
     382          239 : }
     383              : 
     384              : void
     385          539 : UnsafeChecker::visit (TupleExpr &expr)
     386              : {
     387         1475 :   for (auto &elem : expr.get_tuple_elems ())
     388          936 :     elem->accept_vis (*this);
     389          539 : }
     390              : 
     391              : void
     392          884 : UnsafeChecker::visit (TupleIndexExpr &expr)
     393              : {
     394          884 :   expr.get_tuple_expr ().accept_vis (*this);
     395          884 : }
     396              : 
     397              : void
     398           79 : UnsafeChecker::visit (StructExprStruct &)
     399           79 : {}
     400              : 
     401              : void
     402          215 : UnsafeChecker::visit (StructExprFieldIdentifier &)
     403          215 : {}
     404              : 
     405              : void
     406         2604 : UnsafeChecker::visit (StructExprFieldIdentifierValue &field)
     407              : {
     408         2604 :   field.get_value ().accept_vis (*this);
     409         2604 : }
     410              : 
     411              : void
     412           42 : UnsafeChecker::visit (StructExprFieldIndexValue &field)
     413              : {
     414           42 :   field.get_value ().accept_vis (*this);
     415           42 : }
     416              : 
     417              : void
     418         1296 : UnsafeChecker::visit (StructExprStructFields &expr)
     419              : {
     420         4157 :   for (auto &field : expr.get_fields ())
     421         2861 :     field->accept_vis (*this);
     422         1296 : }
     423              : 
     424              : void
     425            0 : UnsafeChecker::visit (StructExprStructBase &)
     426            0 : {}
     427              : 
     428              : void
     429        10595 : UnsafeChecker::visit (CallExpr &expr)
     430              : {
     431        10595 :   if (!expr.has_fnexpr ())
     432           14 :     return;
     433              : 
     434        10595 :   NodeId ast_node_id = expr.get_fnexpr ().get_mappings ().get_nodeid ();
     435        10595 :   NodeId ref_node_id;
     436              : 
     437              :   // There are no unsafe types, and functions are defined in the name resolver.
     438              :   // If we can't find the name, then we're dealing with a type and should return
     439              :   // early.
     440        10595 :   if (flag_name_resolution_2_0)
     441              :     {
     442        10595 :       auto &nr_ctx
     443        10595 :         = Resolver2_0::ImmutableNameResolutionContext::get ().resolver ();
     444              : 
     445        10595 :       auto resolved = nr_ctx.lookup (ast_node_id);
     446              : 
     447        10595 :       if (!resolved.has_value ())
     448           14 :         return;
     449              : 
     450        10581 :       ref_node_id = resolved.value ();
     451              :     }
     452              :   else
     453              :     {
     454            0 :       if (!resolver.lookup_resolved_name (ast_node_id, &ref_node_id))
     455              :         return;
     456              :     }
     457              : 
     458        10581 :   if (auto definition_id = mappings.lookup_node_to_hir (ref_node_id))
     459              :     {
     460              :       // At this point we have the function's HIR Id. There are three checks we
     461              :       // must perform:
     462              :       //     1. The function is an unsafe one
     463              :       //     2. The function is an extern one
     464              :       //     3. The function is marked with a target_feature attribute
     465        10581 :       check_function_call (*definition_id, expr.get_locus ());
     466        10581 :       check_function_attr (*definition_id, expr.get_locus ());
     467              : 
     468        10581 :       if (expr.has_params ())
     469        21885 :         for (auto &arg : expr.get_arguments ())
     470        12973 :           arg->accept_vis (*this);
     471              :     }
     472              :   else
     473              :     {
     474            0 :       rust_unreachable ();
     475              :     }
     476              : }
     477              : 
     478              : void
     479         2819 : UnsafeChecker::visit (MethodCallExpr &expr)
     480              : {
     481         2819 :   TyTy::BaseType *method_type;
     482         2819 :   context.lookup_type (expr.get_method_name ().get_mappings ().get_hirid (),
     483              :                        &method_type);
     484         2819 :   if (!method_type || !method_type->is<TyTy::FnType> ())
     485            0 :     return;
     486              : 
     487         2819 :   auto &fn = static_cast<TyTy::FnType &> (*method_type);
     488              : 
     489              :   // FIXME
     490              :   // should probably use the defid lookup instead
     491              :   // tl::optional<HIR::Item *> lookup_defid (DefId id);
     492         2819 :   auto method = mappings.lookup_hir_implitem (fn.get_ref ());
     493         2819 :   if (!unsafe_context.is_in_context () && method)
     494         1549 :     check_unsafe_call (static_cast<Function *> (method->first),
     495         3098 :                        expr.get_locus (), "method");
     496              : 
     497         2819 :   expr.get_receiver ().accept_vis (*this);
     498              : 
     499         4722 :   for (auto &arg : expr.get_arguments ())
     500         1903 :     arg->accept_vis (*this);
     501              : }
     502              : 
     503              : void
     504         5523 : UnsafeChecker::visit (FieldAccessExpr &expr)
     505              : {
     506         5523 :   expr.get_receiver_expr ().accept_vis (*this);
     507              : 
     508         5523 :   if (unsafe_context.is_in_context ())
     509          523 :     return;
     510              : 
     511         5000 :   TyTy::BaseType *receiver_ty;
     512         5000 :   auto ok = context.lookup_type (
     513         5000 :     expr.get_receiver_expr ().get_mappings ().get_hirid (), &receiver_ty);
     514         5000 :   rust_assert (ok);
     515              : 
     516         5000 :   if (receiver_ty->get_kind () == TyTy::TypeKind::ADT)
     517              :     {
     518         1640 :       auto maybe_union = static_cast<TyTy::ADTType *> (receiver_ty);
     519         1640 :       if (maybe_union->is_union ())
     520            1 :         rust_error_at (
     521              :           expr.get_locus (),
     522              :           "access to union field requires unsafe function or block");
     523              :     }
     524              : }
     525              : 
     526              : void
     527           53 : UnsafeChecker::visit (ClosureExpr &expr)
     528              : {
     529           53 :   expr.get_expr ().accept_vis (*this);
     530           53 : }
     531              : 
     532              : void
     533        21455 : UnsafeChecker::visit (BlockExpr &expr)
     534              : {
     535        43450 :   for (auto &stmt : expr.get_statements ())
     536        21995 :     stmt->accept_vis (*this);
     537              : 
     538        21455 :   if (expr.has_expr ())
     539        15785 :     expr.get_final_expr ().accept_vis (*this);
     540        21455 : }
     541              : 
     542              : void
     543           15 : UnsafeChecker::visit (AnonConst &expr)
     544              : {
     545           15 :   expr.get_inner_expr ().accept_vis (*this);
     546           15 : }
     547              : 
     548              : void
     549           15 : UnsafeChecker::visit (ConstBlock &expr)
     550              : {
     551           15 :   expr.get_const_expr ().accept_vis (*this);
     552           15 : }
     553              : 
     554              : void
     555           13 : UnsafeChecker::visit (ContinueExpr &)
     556           13 : {}
     557              : 
     558              : void
     559           79 : UnsafeChecker::visit (BreakExpr &expr)
     560              : {
     561           79 :   if (expr.has_break_expr ())
     562           15 :     expr.get_expr ().accept_vis (*this);
     563           79 : }
     564              : 
     565              : void
     566           66 : UnsafeChecker::visit (RangeFromToExpr &expr)
     567              : {
     568           66 :   expr.get_from_expr ().accept_vis (*this);
     569           66 :   expr.get_to_expr ().accept_vis (*this);
     570           66 : }
     571              : 
     572              : void
     573            7 : UnsafeChecker::visit (RangeFromExpr &expr)
     574              : {
     575            7 :   expr.get_from_expr ().accept_vis (*this);
     576            7 : }
     577              : 
     578              : void
     579            7 : UnsafeChecker::visit (RangeToExpr &expr)
     580              : {
     581            7 :   expr.get_to_expr ().accept_vis (*this);
     582            7 : }
     583              : 
     584              : void
     585            0 : UnsafeChecker::visit (RangeFullExpr &)
     586            0 : {}
     587              : 
     588              : void
     589            7 : UnsafeChecker::visit (RangeFromToInclExpr &expr)
     590              : {
     591            7 :   expr.get_from_expr ().accept_vis (*this);
     592            7 :   expr.get_to_expr ().accept_vis (*this);
     593            7 : }
     594              : 
     595              : void
     596            0 : UnsafeChecker::visit (RangeToInclExpr &expr)
     597              : {
     598            0 :   expr.get_to_expr ().accept_vis (*this);
     599            0 : }
     600              : 
     601              : void
     602          515 : UnsafeChecker::visit (ReturnExpr &expr)
     603              : {
     604          515 :   if (expr.has_return_expr ())
     605          484 :     expr.get_expr ().accept_vis (*this);
     606          515 : }
     607              : 
     608              : void
     609         3513 : UnsafeChecker::visit (UnsafeBlockExpr &expr)
     610              : {
     611         3513 :   unsafe_context.enter (expr.get_mappings ().get_hirid ());
     612              : 
     613         3513 :   expr.get_block_expr ().accept_vis (*this);
     614              : 
     615         3513 :   unsafe_context.exit ();
     616         3513 : }
     617              : 
     618              : void
     619          124 : UnsafeChecker::visit (LoopExpr &expr)
     620              : {
     621          124 :   expr.get_loop_block ().accept_vis (*this);
     622          124 : }
     623              : 
     624              : void
     625           71 : UnsafeChecker::visit (WhileLoopExpr &expr)
     626              : {
     627           71 :   expr.get_predicate_expr ().accept_vis (*this);
     628           71 :   expr.get_loop_block ().accept_vis (*this);
     629           71 : }
     630              : 
     631              : void
     632            0 : UnsafeChecker::visit (WhileLetLoopExpr &expr)
     633              : {
     634            0 :   expr.get_cond ().accept_vis (*this);
     635            0 :   expr.get_loop_block ().accept_vis (*this);
     636            0 : }
     637              : 
     638              : void
     639          464 : UnsafeChecker::visit (IfExpr &expr)
     640              : {
     641          464 :   expr.get_if_condition ().accept_vis (*this);
     642          464 :   expr.get_if_block ().accept_vis (*this);
     643          464 : }
     644              : 
     645              : void
     646         1201 : UnsafeChecker::visit (IfExprConseqElse &expr)
     647              : {
     648         1201 :   expr.get_if_condition ().accept_vis (*this);
     649         1201 :   expr.get_if_block ().accept_vis (*this);
     650         1201 :   expr.get_else_block ().accept_vis (*this);
     651         1201 : }
     652              : 
     653              : void
     654         1063 : UnsafeChecker::visit (MatchExpr &expr)
     655              : {
     656         1063 :   expr.get_scrutinee_expr ().accept_vis (*this);
     657              : 
     658         3512 :   for (auto &match_arm : expr.get_match_cases ())
     659         2449 :     match_arm.get_expr ().accept_vis (*this);
     660         1063 : }
     661              : 
     662              : void
     663            0 : UnsafeChecker::visit (AwaitExpr &)
     664              : {
     665              :   // TODO: Visit expression
     666            0 : }
     667              : 
     668              : void
     669            0 : UnsafeChecker::visit (AsyncBlockExpr &)
     670              : {
     671              :   // TODO: Visit block expression
     672            0 : }
     673              : 
     674              : void
     675           27 : UnsafeChecker::visit (InlineAsm &expr)
     676              : {
     677           27 :   if (unsafe_context.is_in_context ())
     678              :     return;
     679              : 
     680            1 :   rust_error_at (
     681            1 :     expr.get_locus (), ErrorCode::E0133,
     682              :     "use of inline assembly is unsafe and requires unsafe function or block");
     683              : }
     684              : 
     685              : void
     686            2 : UnsafeChecker::visit (LlvmInlineAsm &expr)
     687              : {
     688            2 :   if (unsafe_context.is_in_context ())
     689              :     return;
     690              : 
     691            0 :   rust_error_at (
     692            0 :     expr.get_locus (), ErrorCode::E0133,
     693              :     "use of inline assembly is unsafe and requires unsafe function or block");
     694              : }
     695              : 
     696              : void
     697           15 : UnsafeChecker::visit (OffsetOf &expr)
     698              : {
     699              :   // nothing to do, offset_of!() is safe
     700           15 : }
     701              : 
     702              : void
     703            0 : UnsafeChecker::visit (TypeParam &)
     704            0 : {}
     705              : 
     706              : void
     707            0 : UnsafeChecker::visit (ConstGenericParam &)
     708            0 : {}
     709              : 
     710              : void
     711            0 : UnsafeChecker::visit (LifetimeWhereClauseItem &)
     712            0 : {}
     713              : 
     714              : void
     715            0 : UnsafeChecker::visit (TypeBoundWhereClauseItem &)
     716            0 : {}
     717              : 
     718              : void
     719         1176 : UnsafeChecker::visit (Module &module)
     720              : {
     721         5060 :   for (auto &item : module.get_items ())
     722         3884 :     item->accept_vis (*this);
     723         1176 : }
     724              : 
     725              : void
     726            0 : UnsafeChecker::visit (ExternCrate &)
     727            0 : {}
     728              : 
     729              : void
     730            0 : UnsafeChecker::visit (UseTreeGlob &)
     731            0 : {}
     732              : 
     733              : void
     734            0 : UnsafeChecker::visit (UseTreeList &)
     735            0 : {}
     736              : 
     737              : void
     738            0 : UnsafeChecker::visit (UseTreeRebind &)
     739            0 : {}
     740              : 
     741              : void
     742            0 : UnsafeChecker::visit (UseDeclaration &)
     743            0 : {}
     744              : 
     745              : void
     746        12879 : UnsafeChecker::visit (Function &function)
     747              : {
     748        12879 :   auto is_unsafe_fn = function.get_qualifiers ().is_unsafe ();
     749              : 
     750        12879 :   if (is_unsafe_fn)
     751          437 :     unsafe_context.enter (function.get_mappings ().get_hirid ());
     752              : 
     753        12879 :   function.get_definition ().accept_vis (*this);
     754              : 
     755        12879 :   if (is_unsafe_fn)
     756          437 :     unsafe_context.exit ();
     757        12879 : }
     758              : 
     759              : void
     760         1212 : UnsafeChecker::visit (TypeAlias &)
     761              : {
     762              :   // FIXME: What do we need to do to handle type aliasing? Is it possible to
     763              :   // have unsafe types? Type aliases on unsafe functions?
     764         1212 : }
     765              : 
     766              : void
     767         1434 : UnsafeChecker::visit (StructStruct &)
     768         1434 : {}
     769              : 
     770              : void
     771          929 : UnsafeChecker::visit (TupleStruct &)
     772          929 : {}
     773              : 
     774              : void
     775            0 : UnsafeChecker::visit (EnumItem &)
     776            0 : {}
     777              : 
     778              : void
     779            0 : UnsafeChecker::visit (EnumItemTuple &)
     780            0 : {}
     781              : 
     782              : void
     783            0 : UnsafeChecker::visit (EnumItemStruct &)
     784            0 : {}
     785              : 
     786              : void
     787            0 : UnsafeChecker::visit (EnumItemDiscriminant &)
     788            0 : {}
     789              : 
     790              : void
     791          482 : UnsafeChecker::visit (Enum &)
     792          482 : {}
     793              : 
     794              : void
     795           97 : UnsafeChecker::visit (Union &)
     796           97 : {}
     797              : 
     798              : void
     799          505 : UnsafeChecker::visit (ConstantItem &const_item)
     800              : {
     801          505 :   const_item.get_expr ().accept_vis (*this);
     802          505 : }
     803              : 
     804              : void
     805           52 : UnsafeChecker::visit (StaticItem &static_item)
     806              : {
     807           52 :   static_item.get_expr ().accept_vis (*this);
     808           52 : }
     809              : 
     810              : void
     811         2472 : UnsafeChecker::visit (TraitItemFunc &item)
     812              : {
     813         2472 :   if (item.has_definition ())
     814          847 :     item.get_block_expr ().accept_vis (*this);
     815         2472 : }
     816              : 
     817              : void
     818           31 : UnsafeChecker::visit (TraitItemConst &item)
     819              : {
     820           31 :   if (item.has_expr ())
     821            7 :     item.get_expr ().accept_vis (*this);
     822           31 : }
     823              : 
     824              : void
     825          709 : UnsafeChecker::visit (TraitItemType &)
     826          709 : {}
     827              : 
     828              : void
     829         3535 : UnsafeChecker::visit (Trait &trait)
     830              : {
     831              :   // FIXME: Handle unsafe traits
     832         6747 :   for (auto &item : trait.get_trait_items ())
     833         3212 :     item->accept_vis (*this);
     834         3535 : }
     835              : 
     836              : void
     837         5541 : UnsafeChecker::visit (ImplBlock &impl)
     838              : {
     839         5541 :   bool safe = !impl.is_unsafe ();
     840              :   // Check for unsafe-only attributes on generics and lifetimes
     841         5541 :   if (safe)
     842         6473 :     for (auto &parm : impl.get_generic_params ())
     843              :       {
     844          999 :         for (auto o_attr : parm->get_outer_attrs ())
     845              :           {
     846            2 :             rust_assert (!o_attr.is_inner_attribute ());
     847              : 
     848            2 :             Rust::AST::SimplePath path = o_attr.get_path ();
     849            2 :             if (path == Values::Attributes::MAY_DANGLE)
     850            2 :               rust_error_at (
     851              :                 o_attr.get_locus (), ErrorCode::E0569,
     852              :                 "use of %<may_dangle%> is unsafe and requires unsafe impl");
     853            4 :           }
     854              :       }
     855              : 
     856        13572 :   for (auto &item : impl.get_impl_items ())
     857         8031 :     item->accept_vis (*this);
     858         5541 : }
     859              : 
     860              : void
     861            1 : UnsafeChecker::visit (ExternalStaticItem &)
     862            1 : {}
     863              : 
     864              : void
     865         2200 : UnsafeChecker::visit (ExternalFunctionItem &)
     866         2200 : {}
     867              : 
     868              : void
     869            0 : UnsafeChecker::visit (ExternalTypeItem &)
     870            0 : {}
     871              : 
     872              : void
     873         1456 : UnsafeChecker::visit (ExternBlock &block)
     874              : {
     875              :   // FIXME: Do we need to do this?
     876         3657 :   for (auto &item : block.get_extern_items ())
     877         2201 :     item->accept_vis (*this);
     878         1456 : }
     879              : 
     880              : void
     881            0 : UnsafeChecker::visit (LiteralPattern &)
     882            0 : {}
     883              : 
     884              : void
     885            0 : UnsafeChecker::visit (IdentifierPattern &)
     886            0 : {}
     887              : 
     888              : void
     889            0 : UnsafeChecker::visit (WildcardPattern &)
     890            0 : {}
     891              : 
     892              : void
     893            0 : UnsafeChecker::visit (RangePatternBoundLiteral &)
     894            0 : {}
     895              : 
     896              : void
     897            0 : UnsafeChecker::visit (RangePatternBoundPath &)
     898            0 : {}
     899              : 
     900              : void
     901            0 : UnsafeChecker::visit (RangePatternBoundQualPath &)
     902            0 : {}
     903              : 
     904              : void
     905            0 : UnsafeChecker::visit (RangePattern &)
     906            0 : {}
     907              : 
     908              : void
     909            0 : UnsafeChecker::visit (ReferencePattern &)
     910            0 : {}
     911              : 
     912              : void
     913            0 : UnsafeChecker::visit (StructPatternFieldTuplePat &)
     914            0 : {}
     915              : 
     916              : void
     917            0 : UnsafeChecker::visit (StructPatternFieldIdentPat &)
     918            0 : {}
     919              : 
     920              : void
     921            0 : UnsafeChecker::visit (StructPatternFieldIdent &)
     922            0 : {}
     923              : 
     924              : void
     925            0 : UnsafeChecker::visit (StructPattern &)
     926            0 : {}
     927              : 
     928              : void
     929            0 : UnsafeChecker::visit (TupleStructItemsNoRest &)
     930            0 : {}
     931              : 
     932              : void
     933            0 : UnsafeChecker::visit (TupleStructItemsHasRest &)
     934            0 : {}
     935              : 
     936              : void
     937            0 : UnsafeChecker::visit (TupleStructPattern &)
     938            0 : {}
     939              : 
     940              : void
     941            0 : UnsafeChecker::visit (TuplePatternItemsNoRest &)
     942            0 : {}
     943              : 
     944              : void
     945            0 : UnsafeChecker::visit (TuplePatternItemsHasRest &)
     946            0 : {}
     947              : 
     948              : void
     949            0 : UnsafeChecker::visit (TuplePattern &)
     950            0 : {}
     951              : 
     952              : void
     953            0 : UnsafeChecker::visit (SlicePatternItemsNoRest &)
     954            0 : {}
     955              : 
     956              : void
     957            0 : UnsafeChecker::visit (SlicePatternItemsHasRest &)
     958            0 : {}
     959              : 
     960              : void
     961            0 : UnsafeChecker::visit (SlicePattern &)
     962            0 : {}
     963              : 
     964              : void
     965            0 : UnsafeChecker::visit (AltPattern &)
     966            0 : {}
     967              : 
     968              : void
     969           45 : UnsafeChecker::visit (EmptyStmt &)
     970           45 : {}
     971              : 
     972              : void
     973        12433 : UnsafeChecker::visit (LetStmt &stmt)
     974              : {
     975        12433 :   if (stmt.has_init_expr ())
     976        11317 :     stmt.get_init_expr ().accept_vis (*this);
     977        12433 : }
     978              : 
     979              : void
     980         9140 : UnsafeChecker::visit (ExprStmt &stmt)
     981              : {
     982         9140 :   stmt.get_expr ().accept_vis (*this);
     983         9140 : }
     984              : 
     985              : void
     986            0 : UnsafeChecker::visit (TraitBound &)
     987            0 : {}
     988              : 
     989              : void
     990            0 : UnsafeChecker::visit (ImplTraitType &)
     991            0 : {}
     992              : 
     993              : void
     994            0 : UnsafeChecker::visit (TraitObjectType &)
     995            0 : {}
     996              : 
     997              : void
     998            0 : UnsafeChecker::visit (ParenthesisedType &)
     999            0 : {}
    1000              : 
    1001              : void
    1002            0 : UnsafeChecker::visit (TupleType &)
    1003            0 : {}
    1004              : 
    1005              : void
    1006            0 : UnsafeChecker::visit (NeverType &)
    1007            0 : {}
    1008              : 
    1009              : void
    1010            0 : UnsafeChecker::visit (RawPointerType &)
    1011            0 : {}
    1012              : 
    1013              : void
    1014            0 : UnsafeChecker::visit (ReferenceType &)
    1015            0 : {}
    1016              : 
    1017              : void
    1018            0 : UnsafeChecker::visit (ArrayType &)
    1019            0 : {}
    1020              : 
    1021              : void
    1022            0 : UnsafeChecker::visit (SliceType &)
    1023            0 : {}
    1024              : 
    1025              : void
    1026            0 : UnsafeChecker::visit (InferredType &)
    1027            0 : {}
    1028              : 
    1029              : void
    1030            0 : UnsafeChecker::visit (BareFunctionType &)
    1031            0 : {}
    1032              : 
    1033              : } // namespace HIR
    1034              : } // namespace Rust
        

Generated by: LCOV version 2.4-beta

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