gccrs: Add unsafe checks for Rust

The UnsafeChecker visitor verifies that unsafe actions are only performed
in unsafe contexts. Otherwise, an error should be reported to the user and
the compilation pipeline should be halted. These contexts, which include
unsafe blocks or unsafe functions, are allowed to perform more actions
than regular safe Rust code. These actions currently include:

- Dereferencing raw pointers
- Calls to unsafe functions
- Use of inline assembly
- Use of mutable static
- Use of extern static
- Access to a union's field
- Call to functions with #[target(feature)] attribute
- Initializing type with rustc_layout_scalar_valid_range attribute
- Mutation of layout constrained field
- Borrow of layout constrained field

	gcc/rust/
	* checks/errors/rust-unsafe-checker.cc: New.
	* checks/errors/rust-unsafe-checker.h: New.
This commit is contained in:
Arthur Cohen 2022-08-23 16:31:17 +01:00
parent 06688fe40a
commit b1b35204d8
2 changed files with 1154 additions and 0 deletions

View file

@ -0,0 +1,963 @@
// Copyright (C) 2020-2022 Free Software Foundation, Inc.
// This file is part of GCC.
// GCC is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 3, or (at your option) any later
// version.
// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
// You should have received a copy of the GNU General Public License
// along with GCC; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
#include "rust-unsafe-checker.h"
#include "rust-hir.h"
#include "rust-hir-expr.h"
#include "rust-hir-stmt.h"
#include "rust-hir-item.h"
namespace Rust {
namespace HIR {
UnsafeChecker::UnsafeChecker ()
: context (*Resolver::TypeCheckContext::get ()),
resolver (*Resolver::Resolver::get ()),
mappings (*Analysis::Mappings::get ())
{}
void
UnsafeChecker::go (HIR::Crate &crate)
{
for (auto &item : crate.items)
item->accept_vis (*this);
}
static void
check_static_mut (HIR::Item *maybe_static, Location locus)
{
if (maybe_static->get_hir_kind () == Node::BaseKind::VIS_ITEM)
{
auto item = static_cast<Item *> (maybe_static);
if (item->get_item_kind () == Item::ItemKind::Static)
{
auto static_item = static_cast<StaticItem *> (item);
if (static_item->is_mut ())
rust_error_at (
locus, "use of mutable static requires unsafe function or block");
}
}
}
static void
check_extern_static (HIR::ExternalItem *maybe_static, Location locus)
{
if (maybe_static->get_extern_kind () == ExternalItem::ExternKind::Static)
rust_error_at (locus,
"use of extern static requires unsafe function or block");
}
void
UnsafeChecker::check_use_of_static (HirId node_id, Location locus)
{
if (unsafe_context.is_in_context ())
return;
auto maybe_static_mut = mappings.lookup_hir_item (node_id);
HirId extern_block;
auto maybe_extern_static
= mappings.lookup_hir_extern_item (node_id, &extern_block);
if (maybe_static_mut)
check_static_mut (maybe_static_mut, locus);
if (maybe_extern_static)
check_extern_static (static_cast<ExternalItem *> (maybe_extern_static),
locus);
}
static void
check_unsafe_call (HIR::Function *fn, Location locus, const std::string &kind)
{
if (fn->get_qualifiers ().is_unsafe ())
rust_error_at (locus, "call to unsafe %s requires unsafe function or block",
kind.c_str ());
}
static bool
is_safe_intrinsic (const std::string &fn_name)
{
static const std::unordered_set<std::string> safe_intrinsics = {
"abort",
"size_of",
"min_align_of",
"needs_drop",
"caller_location",
"add_with_overflow",
"sub_with_overflow",
"mul_with_overflow",
"wrapping_add",
"wrapping_sub",
"wrapping_mul",
"saturating_add",
"saturating_sub",
"rotate_left",
"rotate_right",
"ctpop",
"ctlz",
"cttz",
"bswap",
"bitreverse",
"discriminant_value",
"type_id",
"likely",
"unlikely",
"ptr_guaranteed_eq",
"ptr_guaranteed_ne",
"minnumf32",
"minnumf64",
"maxnumf32",
"rustc_peek",
"maxnumf64",
"type_name",
"forget",
"black_box",
"variant_count",
};
return safe_intrinsics.find (fn_name) != safe_intrinsics.end ();
}
static void
check_extern_call (HIR::ExternalItem *maybe_fn, HIR::ExternBlock *parent_block,
Location locus)
{
// We have multiple operations to perform here
// 1. Is the item an actual function we're calling
// 2. Is the block it's defined in an FFI block or an `extern crate` block
//
// It is not unsafe to call into other crates, so items defined in an `extern
// crate` must be callable without being in an unsafe context. On the other
// hand, any function defined in a block with a specific ABI (even `extern
// "Rust"` blocks) is unsafe to call
if (maybe_fn->get_extern_kind () != ExternalItem::ExternKind::Function)
return;
// Some intrinsics are safe to call
if (parent_block->get_abi () == Rust::ABI::INTRINSIC
&& is_safe_intrinsic (maybe_fn->get_item_name ()))
return;
rust_error_at (locus,
"call to extern function requires unsafe function or block");
}
void
UnsafeChecker::check_function_call (HirId node_id, Location locus)
{
if (unsafe_context.is_in_context ())
return;
HirId parent_extern_block;
auto maybe_fn = mappings.lookup_hir_item (node_id);
auto maybe_extern
= mappings.lookup_hir_extern_item (node_id, &parent_extern_block);
if (maybe_fn && maybe_fn->get_item_kind () == Item::ItemKind::Function)
check_unsafe_call (static_cast<Function *> (maybe_fn), locus, "function");
if (maybe_extern)
check_extern_call (static_cast<ExternalItem *> (maybe_extern),
mappings.lookup_hir_extern_block (parent_extern_block),
locus);
}
void
UnsafeChecker::visit (Lifetime &lifetime)
{}
void
UnsafeChecker::visit (LifetimeParam &lifetime_param)
{}
void
UnsafeChecker::visit (PathInExpression &path)
{
NodeId ast_node_id = path.get_mappings ().get_nodeid ();
NodeId ref_node_id;
HirId definition_id;
if (!resolver.lookup_resolved_name (ast_node_id, &ref_node_id))
return;
rust_assert (mappings.lookup_node_to_hir (ref_node_id, &definition_id));
check_use_of_static (definition_id, path.get_locus ());
}
void
UnsafeChecker::visit (TypePathSegment &segment)
{}
void
UnsafeChecker::visit (TypePathSegmentGeneric &segment)
{}
void
UnsafeChecker::visit (TypePathSegmentFunction &segment)
{}
void
UnsafeChecker::visit (TypePath &path)
{}
void
UnsafeChecker::visit (QualifiedPathInExpression &path)
{}
void
UnsafeChecker::visit (QualifiedPathInType &path)
{}
void
UnsafeChecker::visit (LiteralExpr &expr)
{}
void
UnsafeChecker::visit (BorrowExpr &expr)
{
expr.get_expr ()->accept_vis (*this);
}
void
UnsafeChecker::visit (DereferenceExpr &expr)
{
TyTy::BaseType *to_deref_type;
auto to_deref = expr.get_expr ()->get_mappings ().get_hirid ();
rust_assert (context.lookup_type (to_deref, &to_deref_type));
if (to_deref_type->get_kind () == TyTy::TypeKind::POINTER
&& !unsafe_context.is_in_context ())
rust_error_at (expr.get_locus (), "dereference of raw pointer requires "
"unsafe function or block");
}
void
UnsafeChecker::visit (ErrorPropagationExpr &expr)
{
expr.get_expr ()->accept_vis (*this);
}
void
UnsafeChecker::visit (NegationExpr &expr)
{
expr.get_expr ()->accept_vis (*this);
}
void
UnsafeChecker::visit (ArithmeticOrLogicalExpr &expr)
{
expr.get_lhs ()->accept_vis (*this);
expr.get_rhs ()->accept_vis (*this);
}
void
UnsafeChecker::visit (ComparisonExpr &expr)
{
expr.get_lhs ()->accept_vis (*this);
expr.get_rhs ()->accept_vis (*this);
}
void
UnsafeChecker::visit (LazyBooleanExpr &expr)
{
expr.get_lhs ()->accept_vis (*this);
expr.get_rhs ()->accept_vis (*this);
}
void
UnsafeChecker::visit (TypeCastExpr &expr)
{
expr.get_expr ()->accept_vis (*this);
}
void
UnsafeChecker::visit (AssignmentExpr &expr)
{
expr.get_lhs ()->accept_vis (*this);
expr.get_rhs ()->accept_vis (*this);
}
void
UnsafeChecker::visit (CompoundAssignmentExpr &expr)
{
expr.get_left_expr ()->accept_vis (*this);
expr.get_right_expr ()->accept_vis (*this);
}
void
UnsafeChecker::visit (GroupedExpr &expr)
{
expr.get_expr_in_parens ()->accept_vis (*this);
}
void
UnsafeChecker::visit (ArrayElemsValues &elems)
{
for (auto &elem : elems.get_values ())
elem->accept_vis (*this);
}
void
UnsafeChecker::visit (ArrayElemsCopied &elems)
{
elems.get_elem_to_copy ()->accept_vis (*this);
}
void
UnsafeChecker::visit (ArrayExpr &expr)
{
expr.get_internal_elements ()->accept_vis (*this);
}
void
UnsafeChecker::visit (ArrayIndexExpr &expr)
{
expr.get_array_expr ()->accept_vis (*this);
expr.get_index_expr ()->accept_vis (*this);
}
void
UnsafeChecker::visit (TupleExpr &expr)
{
for (auto &elem : expr.get_tuple_elems ())
elem->accept_vis (*this);
}
void
UnsafeChecker::visit (TupleIndexExpr &expr)
{
expr.get_tuple_expr ()->accept_vis (*this);
}
void
UnsafeChecker::visit (StructExprStruct &expr)
{}
void
UnsafeChecker::visit (StructExprFieldIdentifier &field)
{}
void
UnsafeChecker::visit (StructExprFieldIdentifierValue &field)
{
field.get_value ()->accept_vis (*this);
}
void
UnsafeChecker::visit (StructExprFieldIndexValue &field)
{
field.get_value ()->accept_vis (*this);
}
void
UnsafeChecker::visit (StructExprStructFields &expr)
{
for (auto &field : expr.get_fields ())
field->accept_vis (*this);
}
void
UnsafeChecker::visit (StructExprStructBase &expr)
{}
void
UnsafeChecker::visit (CallExpr &expr)
{
auto fn = expr.get_fnexpr ();
if (!fn)
return;
NodeId ast_node_id = fn->get_mappings ().get_nodeid ();
NodeId ref_node_id;
HirId definition_id;
// There are no unsafe types, and functions are defined in the name resolver.
// If we can't find the name, then we're dealing with a type and should return
// early.
if (!resolver.lookup_resolved_name (ast_node_id, &ref_node_id))
return;
rust_assert (mappings.lookup_node_to_hir (ref_node_id, &definition_id));
// At this point we have the function's HIR Id. There are two checks we
// must perform:
// 1. The function is an unsafe one
// 2. The function is an extern one
check_function_call (definition_id, expr.get_locus ());
if (expr.has_params ())
for (auto &arg : expr.get_arguments ())
arg->accept_vis (*this);
}
void
UnsafeChecker::visit (MethodCallExpr &expr)
{
TyTy::BaseType *method_type;
context.lookup_type (expr.get_method_name ().get_mappings ().get_hirid (),
&method_type);
auto fn = *static_cast<TyTy::FnType *> (method_type);
auto method = mappings.lookup_hir_implitem (fn.get_ref (), nullptr);
if (!unsafe_context.is_in_context () && method)
check_unsafe_call (static_cast<Function *> (method), expr.get_locus (),
"method");
expr.get_receiver ()->accept_vis (*this);
for (auto &arg : expr.get_arguments ())
arg->accept_vis (*this);
}
void
UnsafeChecker::visit (FieldAccessExpr &expr)
{
expr.get_receiver_expr ()->accept_vis (*this);
if (unsafe_context.is_in_context ())
return;
TyTy::BaseType *receiver_ty;
auto ok = context.lookup_type (
expr.get_receiver_expr ()->get_mappings ().get_hirid (), &receiver_ty);
rust_assert (ok);
if (receiver_ty->get_kind () == TyTy::TypeKind::ADT)
{
auto maybe_union = static_cast<TyTy::ADTType *> (receiver_ty);
if (maybe_union->is_union ())
rust_error_at (
expr.get_locus (),
"access to union field requires unsafe function or block");
}
}
void
UnsafeChecker::visit (ClosureExprInner &expr)
{}
void
UnsafeChecker::visit (BlockExpr &expr)
{
for (auto &stmt : expr.get_statements ())
stmt->accept_vis (*this);
if (expr.has_expr ())
expr.get_final_expr ()->accept_vis (*this);
}
void
UnsafeChecker::visit (ClosureExprInnerTyped &expr)
{}
void
UnsafeChecker::visit (ContinueExpr &expr)
{}
void
UnsafeChecker::visit (BreakExpr &expr)
{
if (expr.has_break_expr ())
expr.get_expr ()->accept_vis (*this);
}
void
UnsafeChecker::visit (RangeFromToExpr &expr)
{
expr.get_from_expr ()->accept_vis (*this);
expr.get_to_expr ()->accept_vis (*this);
}
void
UnsafeChecker::visit (RangeFromExpr &expr)
{
expr.get_from_expr ()->accept_vis (*this);
}
void
UnsafeChecker::visit (RangeToExpr &expr)
{
expr.get_to_expr ()->accept_vis (*this);
}
void
UnsafeChecker::visit (RangeFullExpr &expr)
{}
void
UnsafeChecker::visit (RangeFromToInclExpr &expr)
{
expr.get_from_expr ()->accept_vis (*this);
expr.get_to_expr ()->accept_vis (*this);
}
void
UnsafeChecker::visit (RangeToInclExpr &expr)
{
expr.get_to_expr ()->accept_vis (*this);
}
void
UnsafeChecker::visit (ReturnExpr &expr)
{
if (expr.has_return_expr ())
expr.get_expr ()->accept_vis (*this);
}
void
UnsafeChecker::visit (UnsafeBlockExpr &expr)
{
unsafe_context.enter (expr.get_mappings ().get_hirid ());
expr.get_block_expr ()->accept_vis (*this);
unsafe_context.exit ();
}
void
UnsafeChecker::visit (LoopExpr &expr)
{
expr.get_loop_block ()->accept_vis (*this);
}
void
UnsafeChecker::visit (WhileLoopExpr &expr)
{
expr.get_predicate_expr ()->accept_vis (*this);
expr.get_loop_block ()->accept_vis (*this);
}
void
UnsafeChecker::visit (WhileLetLoopExpr &expr)
{
expr.get_cond ()->accept_vis (*this);
expr.get_loop_block ()->accept_vis (*this);
}
void
UnsafeChecker::visit (ForLoopExpr &expr)
{
expr.get_iterator_expr ()->accept_vis (*this);
expr.get_loop_block ()->accept_vis (*this);
}
void
UnsafeChecker::visit (IfExpr &expr)
{
expr.get_if_condition ()->accept_vis (*this);
expr.get_if_block ()->accept_vis (*this);
}
void
UnsafeChecker::visit (IfExprConseqElse &expr)
{
expr.get_if_condition ()->accept_vis (*this);
expr.get_if_block ()->accept_vis (*this);
expr.get_else_block ()->accept_vis (*this);
}
void
UnsafeChecker::visit (IfExprConseqIf &expr)
{
expr.get_if_condition ()->accept_vis (*this);
expr.get_if_block ()->accept_vis (*this);
expr.get_conseq_if_expr ()->accept_vis (*this);
}
void
UnsafeChecker::visit (IfExprConseqIfLet &expr)
{
expr.get_if_condition ()->accept_vis (*this);
expr.get_if_block ()->accept_vis (*this);
// TODO: Visit conseq if let expression
}
void
UnsafeChecker::visit (IfLetExpr &expr)
{
expr.get_scrutinee_expr ()->accept_vis (*this);
expr.get_if_block ()->accept_vis (*this);
}
void
UnsafeChecker::visit (IfLetExprConseqElse &expr)
{
expr.get_scrutinee_expr ()->accept_vis (*this);
expr.get_if_block ()->accept_vis (*this);
// TODO: Visit else expression
}
void
UnsafeChecker::visit (IfLetExprConseqIf &expr)
{
expr.get_scrutinee_expr ()->accept_vis (*this);
expr.get_if_block ()->accept_vis (*this);
}
void
UnsafeChecker::visit (IfLetExprConseqIfLet &expr)
{
expr.get_scrutinee_expr ()->accept_vis (*this);
expr.get_if_block ()->accept_vis (*this);
// TODO: Visit conseq if let expression
}
void
UnsafeChecker::visit (MatchExpr &expr)
{
expr.get_scrutinee_expr ()->accept_vis (*this);
for (auto &match_arm : expr.get_match_cases ())
match_arm.get_expr ()->accept_vis (*this);
}
void
UnsafeChecker::visit (AwaitExpr &expr)
{
// TODO: Visit expression
}
void
UnsafeChecker::visit (AsyncBlockExpr &expr)
{
// TODO: Visit block expression
}
void
UnsafeChecker::visit (TypeParam &param)
{}
void
UnsafeChecker::visit (ConstGenericParam &param)
{}
void
UnsafeChecker::visit (LifetimeWhereClauseItem &item)
{}
void
UnsafeChecker::visit (TypeBoundWhereClauseItem &item)
{}
void
UnsafeChecker::visit (Module &module)
{
for (auto &item : module.get_items ())
item->accept_vis (*this);
}
void
UnsafeChecker::visit (ExternCrate &crate)
{}
void
UnsafeChecker::visit (UseTreeGlob &use_tree)
{}
void
UnsafeChecker::visit (UseTreeList &use_tree)
{}
void
UnsafeChecker::visit (UseTreeRebind &use_tree)
{}
void
UnsafeChecker::visit (UseDeclaration &use_decl)
{}
void
UnsafeChecker::visit (Function &function)
{
auto is_unsafe_fn = function.get_qualifiers ().is_unsafe ();
if (is_unsafe_fn)
unsafe_context.enter (function.get_mappings ().get_hirid ());
function.get_definition ()->accept_vis (*this);
if (is_unsafe_fn)
unsafe_context.exit ();
}
void
UnsafeChecker::visit (TypeAlias &type_alias)
{
// FIXME: What do we need to do to handle type aliasing? Is it possible to
// have unsafe types? Type aliases on unsafe functions?
}
void
UnsafeChecker::visit (StructStruct &struct_item)
{}
void
UnsafeChecker::visit (TupleStruct &tuple_struct)
{}
void
UnsafeChecker::visit (EnumItem &item)
{}
void
UnsafeChecker::visit (EnumItemTuple &item)
{}
void
UnsafeChecker::visit (EnumItemStruct &item)
{}
void
UnsafeChecker::visit (EnumItemDiscriminant &item)
{}
void
UnsafeChecker::visit (Enum &enum_item)
{}
void
UnsafeChecker::visit (Union &union_item)
{}
void
UnsafeChecker::visit (ConstantItem &const_item)
{
const_item.get_expr ()->accept_vis (*this);
}
void
UnsafeChecker::visit (StaticItem &static_item)
{
static_item.get_expr ()->accept_vis (*this);
}
void
UnsafeChecker::visit (TraitItemFunc &item)
{
if (item.has_block_defined ())
item.get_block_expr ()->accept_vis (*this);
}
void
UnsafeChecker::visit (TraitItemConst &item)
{
if (item.has_expr ())
item.get_expr ()->accept_vis (*this);
}
void
UnsafeChecker::visit (TraitItemType &item)
{}
void
UnsafeChecker::visit (Trait &trait)
{
// FIXME: Handle unsafe traits
for (auto &item : trait.get_trait_items ())
item->accept_vis (*this);
}
void
UnsafeChecker::visit (ImplBlock &impl)
{
// FIXME: Handle unsafe impls
for (auto &item : impl.get_impl_items ())
item->accept_vis (*this);
}
void
UnsafeChecker::visit (ExternalStaticItem &item)
{}
void
UnsafeChecker::visit (ExternalFunctionItem &item)
{}
void
UnsafeChecker::visit (ExternBlock &block)
{
// FIXME: Do we need to do this?
for (auto &item : block.get_extern_items ())
item->accept_vis (*this);
}
void
UnsafeChecker::visit (LiteralPattern &pattern)
{}
void
UnsafeChecker::visit (IdentifierPattern &pattern)
{}
void
UnsafeChecker::visit (WildcardPattern &pattern)
{}
void
UnsafeChecker::visit (RangePatternBoundLiteral &bound)
{}
void
UnsafeChecker::visit (RangePatternBoundPath &bound)
{}
void
UnsafeChecker::visit (RangePatternBoundQualPath &bound)
{}
void
UnsafeChecker::visit (RangePattern &pattern)
{}
void
UnsafeChecker::visit (ReferencePattern &pattern)
{}
void
UnsafeChecker::visit (StructPatternFieldTuplePat &field)
{}
void
UnsafeChecker::visit (StructPatternFieldIdentPat &field)
{}
void
UnsafeChecker::visit (StructPatternFieldIdent &field)
{}
void
UnsafeChecker::visit (StructPattern &pattern)
{}
void
UnsafeChecker::visit (TupleStructItemsNoRange &tuple_items)
{}
void
UnsafeChecker::visit (TupleStructItemsRange &tuple_items)
{}
void
UnsafeChecker::visit (TupleStructPattern &pattern)
{}
void
UnsafeChecker::visit (TuplePatternItemsMultiple &tuple_items)
{}
void
UnsafeChecker::visit (TuplePatternItemsRanged &tuple_items)
{}
void
UnsafeChecker::visit (TuplePattern &pattern)
{}
void
UnsafeChecker::visit (GroupedPattern &pattern)
{}
void
UnsafeChecker::visit (SlicePattern &pattern)
{}
void
UnsafeChecker::visit (EmptyStmt &stmt)
{}
void
UnsafeChecker::visit (LetStmt &stmt)
{
if (stmt.has_init_expr ())
stmt.get_init_expr ()->accept_vis (*this);
}
void
UnsafeChecker::visit (ExprStmtWithoutBlock &stmt)
{
stmt.get_expr ()->accept_vis (*this);
}
void
UnsafeChecker::visit (ExprStmtWithBlock &stmt)
{
stmt.get_expr ()->accept_vis (*this);
}
void
UnsafeChecker::visit (TraitBound &bound)
{}
void
UnsafeChecker::visit (ImplTraitType &type)
{}
void
UnsafeChecker::visit (TraitObjectType &type)
{}
void
UnsafeChecker::visit (ParenthesisedType &type)
{}
void
UnsafeChecker::visit (ImplTraitTypeOneBound &type)
{}
void
UnsafeChecker::visit (TupleType &type)
{}
void
UnsafeChecker::visit (NeverType &type)
{}
void
UnsafeChecker::visit (RawPointerType &type)
{}
void
UnsafeChecker::visit (ReferenceType &type)
{}
void
UnsafeChecker::visit (ArrayType &type)
{}
void
UnsafeChecker::visit (SliceType &type)
{}
void
UnsafeChecker::visit (InferredType &type)
{}
void
UnsafeChecker::visit (BareFunctionType &type)
{}
} // namespace HIR
} // namespace Rust

View file

@ -0,0 +1,191 @@
// Copyright (C) 2020-2022 Free Software Foundation, Inc.
// This file is part of GCC.
// GCC is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 3, or (at your option) any later
// version.
// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
// You should have received a copy of the GNU General Public License
// along with GCC; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
#ifndef RUST_UNSAFE_CHECKER_H
#define RUST_UNSAFE_CHECKER_H
#include "rust-hir-visitor.h"
#include "rust-name-resolver.h"
#include "rust-hir-type-check.h"
#include "rust-stacked-contexts.h"
namespace Rust {
namespace HIR {
class UnsafeChecker : public HIRFullVisitor
{
public:
UnsafeChecker ();
void go (HIR::Crate &crate);
private:
/**
* Check if a mutable static or external static item is used outside of an
* unsafe context
*/
void check_use_of_static (HirId node_id, Location locus);
/**
* Check if a call to an unsafe or external function is outside of an unsafe
* context
*/
void check_function_call (HirId node_id, Location locus);
StackedContexts<HirId> unsafe_context;
Resolver::TypeCheckContext &context;
Resolver::Resolver &resolver;
Analysis::Mappings &mappings;
virtual void visit (Lifetime &lifetime) override;
virtual void visit (LifetimeParam &lifetime_param) override;
virtual void visit (PathInExpression &path) override;
virtual void visit (TypePathSegment &segment) override;
virtual void visit (TypePathSegmentGeneric &segment) override;
virtual void visit (TypePathSegmentFunction &segment) override;
virtual void visit (TypePath &path) override;
virtual void visit (QualifiedPathInExpression &path) override;
virtual void visit (QualifiedPathInType &path) override;
virtual void visit (LiteralExpr &expr) override;
virtual void visit (BorrowExpr &expr) override;
virtual void visit (DereferenceExpr &expr) override;
virtual void visit (ErrorPropagationExpr &expr) override;
virtual void visit (NegationExpr &expr) override;
virtual void visit (ArithmeticOrLogicalExpr &expr) override;
virtual void visit (ComparisonExpr &expr) override;
virtual void visit (LazyBooleanExpr &expr) override;
virtual void visit (TypeCastExpr &expr) override;
virtual void visit (AssignmentExpr &expr) override;
virtual void visit (CompoundAssignmentExpr &expr) override;
virtual void visit (GroupedExpr &expr) override;
virtual void visit (ArrayElemsValues &elems) override;
virtual void visit (ArrayElemsCopied &elems) override;
virtual void visit (ArrayExpr &expr) override;
virtual void visit (ArrayIndexExpr &expr) override;
virtual void visit (TupleExpr &expr) override;
virtual void visit (TupleIndexExpr &expr) override;
virtual void visit (StructExprStruct &expr) override;
virtual void visit (StructExprFieldIdentifier &field) override;
virtual void visit (StructExprFieldIdentifierValue &field) override;
virtual void visit (StructExprFieldIndexValue &field) override;
virtual void visit (StructExprStructFields &expr) override;
virtual void visit (StructExprStructBase &expr) override;
virtual void visit (CallExpr &expr) override;
virtual void visit (MethodCallExpr &expr) override;
virtual void visit (FieldAccessExpr &expr) override;
virtual void visit (ClosureExprInner &expr) override;
virtual void visit (BlockExpr &expr) override;
virtual void visit (ClosureExprInnerTyped &expr) override;
virtual void visit (ContinueExpr &expr) override;
virtual void visit (BreakExpr &expr) override;
virtual void visit (RangeFromToExpr &expr) override;
virtual void visit (RangeFromExpr &expr) override;
virtual void visit (RangeToExpr &expr) override;
virtual void visit (RangeFullExpr &expr) override;
virtual void visit (RangeFromToInclExpr &expr) override;
virtual void visit (RangeToInclExpr &expr) override;
virtual void visit (ReturnExpr &expr) override;
virtual void visit (UnsafeBlockExpr &expr) override;
virtual void visit (LoopExpr &expr) override;
virtual void visit (WhileLoopExpr &expr) override;
virtual void visit (WhileLetLoopExpr &expr) override;
virtual void visit (ForLoopExpr &expr) override;
virtual void visit (IfExpr &expr) override;
virtual void visit (IfExprConseqElse &expr) override;
virtual void visit (IfExprConseqIf &expr) override;
virtual void visit (IfExprConseqIfLet &expr) override;
virtual void visit (IfLetExpr &expr) override;
virtual void visit (IfLetExprConseqElse &expr) override;
virtual void visit (IfLetExprConseqIf &expr) override;
virtual void visit (IfLetExprConseqIfLet &expr) override;
virtual void visit (MatchExpr &expr) override;
virtual void visit (AwaitExpr &expr) override;
virtual void visit (AsyncBlockExpr &expr) override;
virtual void visit (TypeParam &param) override;
virtual void visit (ConstGenericParam &param) override;
virtual void visit (LifetimeWhereClauseItem &item) override;
virtual void visit (TypeBoundWhereClauseItem &item) override;
virtual void visit (Module &module) override;
virtual void visit (ExternCrate &crate) override;
virtual void visit (UseTreeGlob &use_tree) override;
virtual void visit (UseTreeList &use_tree) override;
virtual void visit (UseTreeRebind &use_tree) override;
virtual void visit (UseDeclaration &use_decl) override;
virtual void visit (Function &function) override;
virtual void visit (TypeAlias &type_alias) override;
virtual void visit (StructStruct &struct_item) override;
virtual void visit (TupleStruct &tuple_struct) override;
virtual void visit (EnumItem &item) override;
virtual void visit (EnumItemTuple &item) override;
virtual void visit (EnumItemStruct &item) override;
virtual void visit (EnumItemDiscriminant &item) override;
virtual void visit (Enum &enum_item) override;
virtual void visit (Union &union_item) override;
virtual void visit (ConstantItem &const_item) override;
virtual void visit (StaticItem &static_item) override;
virtual void visit (TraitItemFunc &item) override;
virtual void visit (TraitItemConst &item) override;
virtual void visit (TraitItemType &item) override;
virtual void visit (Trait &trait) override;
virtual void visit (ImplBlock &impl) override;
virtual void visit (ExternalStaticItem &item) override;
virtual void visit (ExternalFunctionItem &item) override;
virtual void visit (ExternBlock &block) override;
virtual void visit (LiteralPattern &pattern) override;
virtual void visit (IdentifierPattern &pattern) override;
virtual void visit (WildcardPattern &pattern) override;
virtual void visit (RangePatternBoundLiteral &bound) override;
virtual void visit (RangePatternBoundPath &bound) override;
virtual void visit (RangePatternBoundQualPath &bound) override;
virtual void visit (RangePattern &pattern) override;
virtual void visit (ReferencePattern &pattern) override;
virtual void visit (StructPatternFieldTuplePat &field) override;
virtual void visit (StructPatternFieldIdentPat &field) override;
virtual void visit (StructPatternFieldIdent &field) override;
virtual void visit (StructPattern &pattern) override;
virtual void visit (TupleStructItemsNoRange &tuple_items) override;
virtual void visit (TupleStructItemsRange &tuple_items) override;
virtual void visit (TupleStructPattern &pattern) override;
virtual void visit (TuplePatternItemsMultiple &tuple_items) override;
virtual void visit (TuplePatternItemsRanged &tuple_items) override;
virtual void visit (TuplePattern &pattern) override;
virtual void visit (GroupedPattern &pattern) override;
virtual void visit (SlicePattern &pattern) override;
virtual void visit (EmptyStmt &stmt) override;
virtual void visit (LetStmt &stmt) override;
virtual void visit (ExprStmtWithoutBlock &stmt) override;
virtual void visit (ExprStmtWithBlock &stmt) override;
virtual void visit (TraitBound &bound) override;
virtual void visit (ImplTraitType &type) override;
virtual void visit (TraitObjectType &type) override;
virtual void visit (ParenthesisedType &type) override;
virtual void visit (ImplTraitTypeOneBound &type) override;
virtual void visit (TupleType &type) override;
virtual void visit (NeverType &type) override;
virtual void visit (RawPointerType &type) override;
virtual void visit (ReferenceType &type) override;
virtual void visit (ArrayType &type) override;
virtual void visit (SliceType &type) override;
virtual void visit (InferredType &type) override;
virtual void visit (BareFunctionType &type) override;
};
} // namespace HIR
} // namespace Rust
#endif /* !RUST_UNSAFE_CHECKER_H */