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