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