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