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 4384 : UnsafeChecker::UnsafeChecker ()
34 4384 : : context (*Resolver::TypeCheckContext::get ()),
35 4384 : resolver (Resolver2_0::FinalizedNameResolutionContext::get ()),
36 8768 : mappings (Analysis::Mappings::get ())
37 4384 : {}
38 :
39 : void
40 4384 : UnsafeChecker::go (HIR::Crate &crate)
41 : {
42 22500 : for (auto &item : crate.get_items ())
43 18116 : item->accept_vis (*this);
44 4384 : }
45 :
46 : static void
47 790 : check_static_mut (HIR::Item *maybe_static, location_t locus)
48 : {
49 790 : if (maybe_static->get_hir_kind () == Node::BaseKind::VIS_ITEM)
50 : {
51 790 : auto item = static_cast<Item *> (maybe_static);
52 790 : 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 790 : }
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 30356 : UnsafeChecker::check_use_of_static (HirId node_id, location_t locus)
72 : {
73 30356 : if (unsafe_context.is_in_context ())
74 : return;
75 :
76 21767 : if (auto maybe_static_mut = mappings.lookup_hir_item (node_id))
77 790 : check_static_mut (*maybe_static_mut, locus);
78 :
79 21767 : 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 4587 : check_unsafe_call (HIR::Function *fn, location_t locus, const std::string &kind)
87 : {
88 4587 : 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 4587 : }
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 1054 : 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 1054 : if (maybe_fn->get_extern_kind () != ExternalItem::ExternKind::Function)
154 : return;
155 :
156 : // Some intrinsics are safe to call
157 2108 : if (parent_block->get_abi () == Rust::ABI::INTRINSIC
158 3160 : && is_safe_intrinsic (maybe_fn->get_item_name ().as_string ()))
159 : return;
160 :
161 1 : rust_error_at (locus,
162 : "call to extern function requires unsafe function or block");
163 : }
164 :
165 : void
166 12165 : UnsafeChecker::check_function_call (HirId node_id, location_t locus)
167 : {
168 12165 : if (unsafe_context.is_in_context ())
169 4853 : return;
170 :
171 7312 : auto maybe_fn = mappings.lookup_hir_item (node_id);
172 :
173 7312 : if (maybe_fn
174 7312 : && maybe_fn.value ()->get_item_kind () == Item::ItemKind::Function)
175 3043 : check_unsafe_call (static_cast<Function *> (*maybe_fn), locus, "function");
176 :
177 7312 : if (auto maybe_extern = mappings.lookup_hir_extern_item (node_id))
178 1054 : check_extern_call (static_cast<ExternalItem *> (maybe_extern->first),
179 2108 : *mappings.lookup_hir_extern_block (maybe_extern->second),
180 : locus);
181 : }
182 :
183 : static void
184 3043 : check_target_attr (HIR::Function *fn, location_t locus)
185 : {
186 3043 : if (std::any_of (fn->get_outer_attrs ().begin (),
187 3043 : fn->get_outer_attrs ().end (),
188 35 : [] (const AST::Attribute &attr) {
189 35 : 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 3043 : }
196 :
197 : void
198 12165 : UnsafeChecker::check_function_attr (HirId node_id, location_t locus)
199 : {
200 12165 : if (unsafe_context.is_in_context ())
201 4853 : return;
202 :
203 7312 : auto maybe_fn = mappings.lookup_hir_item (node_id);
204 :
205 7312 : if (maybe_fn
206 7312 : && maybe_fn.value ()->get_item_kind () == Item::ItemKind::Function)
207 3043 : 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 30356 : UnsafeChecker::visit (PathInExpression &path)
220 : {
221 30356 : NodeId ast_node_id = path.get_mappings ().get_nodeid ();
222 30356 : NodeId ref_node_id;
223 :
224 60712 : if (auto resolved
225 30356 : = resolver.lookup (ast_node_id, Resolver2_0::Namespace::Values,
226 30356 : Resolver2_0::Namespace::Types))
227 30356 : ref_node_id = resolved->id;
228 : else
229 0 : return;
230 :
231 30356 : if (auto definition_id = mappings.lookup_node_to_hir (ref_node_id))
232 : {
233 30356 : 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 19636 : UnsafeChecker::visit (LiteralExpr &)
267 19636 : {}
268 :
269 : void
270 2001 : UnsafeChecker::visit (BorrowExpr &expr)
271 : {
272 2001 : expr.get_expr ().accept_vis (*this);
273 2001 : }
274 :
275 : void
276 3912 : UnsafeChecker::visit (DereferenceExpr &expr)
277 : {
278 3912 : TyTy::BaseType *to_deref_type;
279 3912 : auto to_deref = expr.get_expr ().get_mappings ().get_hirid ();
280 :
281 3912 : rust_assert (context.lookup_type (to_deref, &to_deref_type));
282 :
283 3912 : if (to_deref_type->get_kind () == TyTy::TypeKind::POINTER
284 3912 : && !unsafe_context.is_in_context ())
285 2 : rust_error_at (expr.get_locus (), "dereference of raw pointer requires "
286 : "unsafe function or block");
287 3912 : }
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 3254 : UnsafeChecker::visit (ArithmeticOrLogicalExpr &expr)
303 : {
304 3254 : expr.get_lhs ().accept_vis (*this);
305 3254 : expr.get_rhs ().accept_vis (*this);
306 3254 : }
307 :
308 : void
309 3557 : UnsafeChecker::visit (ComparisonExpr &expr)
310 : {
311 3557 : expr.get_lhs ().accept_vis (*this);
312 3557 : expr.get_rhs ().accept_vis (*this);
313 3557 : }
314 :
315 : void
316 404 : UnsafeChecker::visit (LazyBooleanExpr &expr)
317 : {
318 404 : expr.get_lhs ().accept_vis (*this);
319 404 : expr.get_rhs ().accept_vis (*this);
320 404 : }
321 :
322 : void
323 5261 : UnsafeChecker::visit (TypeCastExpr &expr)
324 : {
325 5261 : expr.get_expr ().accept_vis (*this);
326 5261 : }
327 :
328 : void
329 2475 : UnsafeChecker::visit (AssignmentExpr &expr)
330 : {
331 2475 : expr.get_lhs ().accept_vis (*this);
332 2475 : expr.get_rhs ().accept_vis (*this);
333 2475 : }
334 :
335 : void
336 696 : UnsafeChecker::visit (CompoundAssignmentExpr &expr)
337 : {
338 696 : expr.get_lhs ().accept_vis (*this);
339 696 : expr.get_rhs ().accept_vis (*this);
340 696 : }
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 557 : UnsafeChecker::visit (TupleExpr &expr)
376 : {
377 1526 : for (auto &elem : expr.get_tuple_elems ())
378 969 : elem->accept_vis (*this);
379 557 : }
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 229 : UnsafeChecker::visit (StructExprFieldIdentifier &)
393 229 : {}
394 :
395 : void
396 2666 : UnsafeChecker::visit (StructExprFieldIdentifierValue &field)
397 : {
398 2666 : field.get_value ().accept_vis (*this);
399 2666 : }
400 :
401 : void
402 42 : UnsafeChecker::visit (StructExprFieldIndexValue &field)
403 : {
404 42 : field.get_value ().accept_vis (*this);
405 42 : }
406 :
407 : void
408 1352 : UnsafeChecker::visit (StructExprStructFields &expr)
409 : {
410 4289 : for (auto &field : expr.get_fields ())
411 2937 : field->accept_vis (*this);
412 1352 : }
413 :
414 : void
415 0 : UnsafeChecker::visit (StructExprStructBase &)
416 0 : {}
417 :
418 : void
419 12235 : UnsafeChecker::visit (CallExpr &expr)
420 : {
421 12235 : if (!expr.has_fnexpr ())
422 : return;
423 :
424 12235 : NodeId ast_node_id = expr.get_fnexpr ().get_mappings ().get_nodeid ();
425 12235 : NodeId ref_node_id;
426 :
427 12235 : if (auto resolved
428 12235 : = resolver.lookup (ast_node_id, Resolver2_0::Namespace::Values))
429 12165 : ref_node_id = resolved.value ();
430 : else
431 70 : return;
432 :
433 12165 : 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 12165 : check_function_call (*definition_id, expr.get_locus ());
441 12165 : check_function_attr (*definition_id, expr.get_locus ());
442 :
443 12165 : if (expr.has_params ())
444 23508 : for (auto &arg : expr.get_arguments ())
445 13789 : arg->accept_vis (*this);
446 : }
447 : else
448 : {
449 0 : rust_unreachable ();
450 : }
451 : }
452 :
453 : void
454 2896 : UnsafeChecker::visit (MethodCallExpr &expr)
455 : {
456 2896 : TyTy::BaseType *method_type;
457 2896 : context.lookup_type (expr.get_method_name ().get_mappings ().get_hirid (),
458 : &method_type);
459 2896 : if (!method_type || !method_type->is<TyTy::FnType> ())
460 0 : return;
461 :
462 2896 : 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 2896 : auto method = mappings.lookup_hir_implitem (fn.get_ref ());
468 2896 : 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 2896 : expr.get_receiver ().accept_vis (*this);
473 :
474 4823 : for (auto &arg : expr.get_arguments ())
475 1927 : arg->accept_vis (*this);
476 : }
477 :
478 : void
479 5645 : UnsafeChecker::visit (FieldAccessExpr &expr)
480 : {
481 5645 : expr.get_receiver_expr ().accept_vis (*this);
482 :
483 5645 : if (unsafe_context.is_in_context ())
484 575 : return;
485 :
486 5070 : TyTy::BaseType *receiver_ty;
487 5070 : auto ok = context.lookup_type (
488 5070 : expr.get_receiver_expr ().get_mappings ().get_hirid (), &receiver_ty);
489 5070 : rust_assert (ok);
490 :
491 5070 : if (receiver_ty->get_kind () == TyTy::TypeKind::ADT)
492 : {
493 1665 : auto maybe_union = static_cast<TyTy::ADTType *> (receiver_ty);
494 1665 : 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 22989 : UnsafeChecker::visit (BlockExpr &expr)
509 : {
510 47107 : for (auto &stmt : expr.get_statements ())
511 24118 : stmt->accept_vis (*this);
512 :
513 22989 : if (expr.has_expr ())
514 16346 : expr.get_final_expr ().accept_vis (*this);
515 22989 : }
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 22 : UnsafeChecker::visit (ContinueExpr &)
531 22 : {}
532 :
533 : void
534 97 : UnsafeChecker::visit (BreakExpr &expr)
535 : {
536 97 : if (expr.has_break_expr ())
537 19 : expr.get_expr ().accept_vis (*this);
538 97 : }
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 0 : UnsafeChecker::visit (RangeToInclExpr &expr)
565 : {
566 0 : expr.get_to_expr ().accept_vis (*this);
567 0 : }
568 :
569 : void
570 1 : UnsafeChecker::visit (BoxExpr &expr)
571 : {
572 1 : expr.get_expr ().accept_vis (*this);
573 1 : }
574 :
575 : void
576 540 : UnsafeChecker::visit (ReturnExpr &expr)
577 : {
578 540 : if (expr.has_return_expr ())
579 507 : expr.get_expr ().accept_vis (*this);
580 540 : }
581 :
582 : void
583 3691 : UnsafeChecker::visit (UnsafeBlockExpr &expr)
584 : {
585 3691 : unsafe_context.enter (expr.get_mappings ().get_hirid ());
586 :
587 3691 : expr.get_block_expr ().accept_vis (*this);
588 :
589 3691 : unsafe_context.exit ();
590 3691 : }
591 :
592 : void
593 136 : UnsafeChecker::visit (LoopExpr &expr)
594 : {
595 136 : expr.get_loop_block ().accept_vis (*this);
596 136 : }
597 :
598 : void
599 78 : UnsafeChecker::visit (WhileLoopExpr &expr)
600 : {
601 78 : expr.get_predicate_expr ().accept_vis (*this);
602 78 : expr.get_loop_block ().accept_vis (*this);
603 78 : }
604 :
605 : void
606 0 : UnsafeChecker::visit (WhileLetLoopExpr &expr)
607 : {
608 0 : expr.get_cond ().accept_vis (*this);
609 0 : expr.get_loop_block ().accept_vis (*this);
610 0 : }
611 :
612 : void
613 1246 : UnsafeChecker::visit (IfExpr &expr)
614 : {
615 1246 : expr.get_if_condition ().accept_vis (*this);
616 1246 : expr.get_if_block ().accept_vis (*this);
617 1246 : }
618 :
619 : void
620 1258 : UnsafeChecker::visit (IfExprConseqElse &expr)
621 : {
622 1258 : expr.get_if_condition ().accept_vis (*this);
623 1258 : expr.get_if_block ().accept_vis (*this);
624 1258 : expr.get_else_block ().accept_vis (*this);
625 1258 : }
626 :
627 : void
628 1077 : UnsafeChecker::visit (MatchExpr &expr)
629 : {
630 1077 : expr.get_scrutinee_expr ().accept_vis (*this);
631 :
632 3556 : for (auto &match_arm : expr.get_match_cases ())
633 2479 : match_arm.get_expr ().accept_vis (*this);
634 1077 : }
635 :
636 : void
637 0 : UnsafeChecker::visit (AwaitExpr &)
638 : {
639 : // TODO: Visit expression
640 0 : }
641 :
642 : void
643 0 : UnsafeChecker::visit (AsyncBlockExpr &)
644 : {
645 : // TODO: Visit block expression
646 0 : }
647 :
648 : void
649 27 : UnsafeChecker::visit (InlineAsm &expr)
650 : {
651 27 : if (unsafe_context.is_in_context ())
652 : return;
653 :
654 1 : rust_error_at (
655 1 : expr.get_locus (), ErrorCode::E0133,
656 : "use of inline assembly is unsafe and requires unsafe function or block");
657 : }
658 :
659 : void
660 2 : UnsafeChecker::visit (LlvmInlineAsm &expr)
661 : {
662 2 : if (unsafe_context.is_in_context ())
663 : return;
664 :
665 0 : rust_error_at (
666 0 : expr.get_locus (), ErrorCode::E0133,
667 : "use of inline assembly is unsafe and requires unsafe function or block");
668 : }
669 :
670 : void
671 15 : UnsafeChecker::visit (OffsetOf &expr)
672 : {
673 : // nothing to do, offset_of!() is safe
674 15 : }
675 :
676 : void
677 0 : UnsafeChecker::visit (TypeParam &)
678 0 : {}
679 :
680 : void
681 0 : UnsafeChecker::visit (ConstGenericParam &)
682 0 : {}
683 :
684 : void
685 0 : UnsafeChecker::visit (LifetimeWhereClauseItem &)
686 0 : {}
687 :
688 : void
689 0 : UnsafeChecker::visit (TypeBoundWhereClauseItem &)
690 0 : {}
691 :
692 : void
693 1163 : UnsafeChecker::visit (Module &module)
694 : {
695 4956 : for (auto &item : module.get_items ())
696 3793 : item->accept_vis (*this);
697 1163 : }
698 :
699 : void
700 0 : UnsafeChecker::visit (ExternCrate &)
701 0 : {}
702 :
703 : void
704 0 : UnsafeChecker::visit (UseTreeGlob &)
705 0 : {}
706 :
707 : void
708 0 : UnsafeChecker::visit (UseTreeList &)
709 0 : {}
710 :
711 : void
712 0 : UnsafeChecker::visit (UseTreeRebind &)
713 0 : {}
714 :
715 : void
716 0 : UnsafeChecker::visit (UseDeclaration &)
717 0 : {}
718 :
719 : void
720 13336 : UnsafeChecker::visit (Function &function)
721 : {
722 13336 : auto is_unsafe_fn = function.get_qualifiers ().is_unsafe ();
723 :
724 13336 : if (is_unsafe_fn)
725 457 : unsafe_context.enter (function.get_mappings ().get_hirid ());
726 :
727 13336 : function.get_definition ().accept_vis (*this);
728 :
729 13336 : if (is_unsafe_fn)
730 457 : unsafe_context.exit ();
731 13336 : }
732 :
733 : void
734 1236 : UnsafeChecker::visit (TypeAlias &)
735 : {
736 : // FIXME: What do we need to do to handle type aliasing? Is it possible to
737 : // have unsafe types? Type aliases on unsafe functions?
738 1236 : }
739 :
740 : void
741 1511 : UnsafeChecker::visit (StructStruct &)
742 1511 : {}
743 :
744 : void
745 936 : UnsafeChecker::visit (TupleStruct &)
746 936 : {}
747 :
748 : void
749 0 : UnsafeChecker::visit (EnumItem &)
750 0 : {}
751 :
752 : void
753 0 : UnsafeChecker::visit (EnumItemTuple &)
754 0 : {}
755 :
756 : void
757 0 : UnsafeChecker::visit (EnumItemStruct &)
758 0 : {}
759 :
760 : void
761 0 : UnsafeChecker::visit (EnumItemDiscriminant &)
762 0 : {}
763 :
764 : void
765 495 : UnsafeChecker::visit (Enum &)
766 495 : {}
767 :
768 : void
769 102 : UnsafeChecker::visit (Union &)
770 102 : {}
771 :
772 : void
773 518 : UnsafeChecker::visit (ConstantItem &const_item)
774 : {
775 518 : const_item.get_expr ().accept_vis (*this);
776 518 : }
777 :
778 : void
779 53 : UnsafeChecker::visit (StaticItem &static_item)
780 : {
781 53 : static_item.get_expr ().accept_vis (*this);
782 53 : }
783 :
784 : void
785 2520 : UnsafeChecker::visit (TraitItemFunc &item)
786 : {
787 2520 : if (item.has_definition ())
788 851 : item.get_block_expr ().accept_vis (*this);
789 2520 : }
790 :
791 : void
792 31 : UnsafeChecker::visit (TraitItemConst &item)
793 : {
794 31 : if (item.has_expr ())
795 7 : item.get_expr ().accept_vis (*this);
796 31 : }
797 :
798 : void
799 711 : UnsafeChecker::visit (TraitItemType &)
800 711 : {}
801 :
802 : void
803 3781 : UnsafeChecker::visit (Trait &trait)
804 : {
805 : // FIXME: Handle unsafe traits
806 7043 : for (auto &item : trait.get_trait_items ())
807 3262 : item->accept_vis (*this);
808 3781 : }
809 :
810 : void
811 5649 : UnsafeChecker::visit (ImplBlock &impl)
812 : {
813 5649 : bool safe = !impl.is_unsafe ();
814 : // Check for unsafe-only attributes on generics and lifetimes
815 5649 : if (safe)
816 6602 : for (auto &parm : impl.get_generic_params ())
817 : {
818 1020 : for (auto o_attr : parm->get_outer_attrs ())
819 : {
820 2 : rust_assert (!o_attr.is_inner_attribute ());
821 :
822 2 : Rust::AST::SimplePath path = o_attr.get_path ();
823 2 : if (path == Values::Attributes::MAY_DANGLE)
824 2 : rust_error_at (
825 : o_attr.get_locus (), ErrorCode::E0569,
826 : "use of %<may_dangle%> is unsafe and requires unsafe impl");
827 2 : }
828 : }
829 :
830 13800 : for (auto &item : impl.get_impl_items ())
831 8151 : item->accept_vis (*this);
832 5649 : }
833 :
834 : void
835 1 : UnsafeChecker::visit (ExternalStaticItem &)
836 1 : {}
837 :
838 : void
839 2546 : UnsafeChecker::visit (ExternalFunctionItem &)
840 2546 : {}
841 :
842 : void
843 0 : UnsafeChecker::visit (ExternalTypeItem &)
844 0 : {}
845 :
846 : void
847 1661 : UnsafeChecker::visit (ExternBlock &block)
848 : {
849 : // FIXME: Do we need to do this?
850 4208 : for (auto &item : block.get_extern_items ())
851 2547 : item->accept_vis (*this);
852 1661 : }
853 :
854 : void
855 0 : UnsafeChecker::visit (LiteralPattern &)
856 0 : {}
857 :
858 : void
859 0 : UnsafeChecker::visit (IdentifierPattern &)
860 0 : {}
861 :
862 : void
863 0 : UnsafeChecker::visit (WildcardPattern &)
864 0 : {}
865 :
866 : void
867 0 : UnsafeChecker::visit (RangePatternBoundLiteral &)
868 0 : {}
869 :
870 : void
871 0 : UnsafeChecker::visit (RangePatternBoundPath &)
872 0 : {}
873 :
874 : void
875 0 : UnsafeChecker::visit (RangePatternBoundQualPath &)
876 0 : {}
877 :
878 : void
879 0 : UnsafeChecker::visit (RangePattern &)
880 0 : {}
881 :
882 : void
883 0 : UnsafeChecker::visit (ReferencePattern &)
884 0 : {}
885 :
886 : void
887 0 : UnsafeChecker::visit (StructPatternFieldTuplePat &)
888 0 : {}
889 :
890 : void
891 0 : UnsafeChecker::visit (StructPatternFieldIdentPat &)
892 0 : {}
893 :
894 : void
895 0 : UnsafeChecker::visit (StructPatternFieldIdent &)
896 0 : {}
897 :
898 : void
899 0 : UnsafeChecker::visit (StructPattern &)
900 0 : {}
901 :
902 : void
903 0 : UnsafeChecker::visit (TupleStructItemsNoRest &)
904 0 : {}
905 :
906 : void
907 0 : UnsafeChecker::visit (TupleStructItemsHasRest &)
908 0 : {}
909 :
910 : void
911 0 : UnsafeChecker::visit (TupleStructPattern &)
912 0 : {}
913 :
914 : void
915 0 : UnsafeChecker::visit (TuplePatternItemsNoRest &)
916 0 : {}
917 :
918 : void
919 0 : UnsafeChecker::visit (TuplePatternItemsHasRest &)
920 0 : {}
921 :
922 : void
923 0 : UnsafeChecker::visit (TuplePattern &)
924 0 : {}
925 :
926 : void
927 0 : UnsafeChecker::visit (SlicePatternItemsNoRest &)
928 0 : {}
929 :
930 : void
931 0 : UnsafeChecker::visit (SlicePatternItemsHasRest &)
932 0 : {}
933 :
934 : void
935 0 : UnsafeChecker::visit (SlicePattern &)
936 0 : {}
937 :
938 : void
939 0 : UnsafeChecker::visit (AltPattern &)
940 0 : {}
941 :
942 : void
943 45 : UnsafeChecker::visit (EmptyStmt &)
944 45 : {}
945 :
946 : void
947 12791 : UnsafeChecker::visit (LetStmt &stmt)
948 : {
949 12791 : if (stmt.has_init_expr ())
950 11662 : stmt.get_init_expr ().accept_vis (*this);
951 12791 : }
952 :
953 : void
954 10901 : UnsafeChecker::visit (ExprStmt &stmt)
955 : {
956 10901 : stmt.get_expr ().accept_vis (*this);
957 10901 : }
958 :
959 : void
960 0 : UnsafeChecker::visit (TraitBound &)
961 0 : {}
962 :
963 : void
964 0 : UnsafeChecker::visit (ImplTraitType &)
965 0 : {}
966 :
967 : void
968 0 : UnsafeChecker::visit (TraitObjectType &)
969 0 : {}
970 :
971 : void
972 0 : UnsafeChecker::visit (ParenthesisedType &)
973 0 : {}
974 :
975 : void
976 0 : UnsafeChecker::visit (TupleType &)
977 0 : {}
978 :
979 : void
980 0 : UnsafeChecker::visit (NeverType &)
981 0 : {}
982 :
983 : void
984 0 : UnsafeChecker::visit (RawPointerType &)
985 0 : {}
986 :
987 : void
988 0 : UnsafeChecker::visit (ReferenceType &)
989 0 : {}
990 :
991 : void
992 0 : UnsafeChecker::visit (ArrayType &)
993 0 : {}
994 :
995 : void
996 0 : UnsafeChecker::visit (SliceType &)
997 0 : {}
998 :
999 : void
1000 0 : UnsafeChecker::visit (InferredType &)
1001 0 : {}
1002 :
1003 : void
1004 0 : UnsafeChecker::visit (BareFunctionType &)
1005 0 : {}
1006 :
1007 : } // namespace HIR
1008 : } // namespace Rust
|