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