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