diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2022-07-27 12:32:38 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-07-27 12:32:38 +0000 |
commit | d94d5b1ea23220d423fd40bd00cadb0e6ede751f (patch) | |
tree | 9a6292e682c843b6ee7c3f65f23e6f74fd6c0dca /gcc | |
parent | dec7ee4c5e703422ecb9bc94417645d66af7eaae (diff) | |
parent | 961468ed824a7b49f10ed597ba9dcc98177125ca (diff) | |
download | gcc-d94d5b1ea23220d423fd40bd00cadb0e6ede751f.zip gcc-d94d5b1ea23220d423fd40bd00cadb0e6ede751f.tar.gz gcc-d94d5b1ea23220d423fd40bd00cadb0e6ede751f.tar.bz2 |
Merge #1410
1410: unsafe: Add UnsafeCheck visitor r=CohenArthur a=CohenArthur
This visitor takes care of checking for unsafe expressions in safe
contexts. This first iteration reports the dereferencing of raw
pointers.
Co-authored-by: Arthur Cohen <arthur.cohen@embecosm.com>
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/rust/Make-lang.in | 1 | ||||
-rw-r--r-- | gcc/rust/checks/errors/rust-unsafe-checker.cc | 779 | ||||
-rw-r--r-- | gcc/rust/checks/errors/rust-unsafe-checker.h | 193 | ||||
-rw-r--r-- | gcc/rust/hir/tree/rust-hir-expr.h | 2 | ||||
-rw-r--r-- | gcc/rust/hir/tree/rust-hir-item.h | 1 | ||||
-rw-r--r-- | gcc/rust/rust-session-manager.cc | 9 | ||||
-rw-r--r-- | gcc/testsuite/rust/compile/unsafe4.rs | 29 | ||||
-rw-r--r-- | gcc/testsuite/rust/compile/unsafe5.rs | 4 |
8 files changed, 1017 insertions, 1 deletions
diff --git a/gcc/rust/Make-lang.in b/gcc/rust/Make-lang.in index d340e36..1ae9bd7 100644 --- a/gcc/rust/Make-lang.in +++ b/gcc/rust/Make-lang.in @@ -123,6 +123,7 @@ GRS_OBJS = \ rust/rust-lint-marklive.o \ rust/rust-lint-unused-var.o \ rust/rust-hir-type-check-path.o \ + rust/rust-unsafe-checker.o \ rust/rust-compile-intrinsic.o \ rust/rust-compile-pattern.o \ rust/rust-compile-fnparam.o \ diff --git a/gcc/rust/checks/errors/rust-unsafe-checker.cc b/gcc/rust/checks/errors/rust-unsafe-checker.cc new file mode 100644 index 0000000..def3cc1 --- /dev/null +++ b/gcc/rust/checks/errors/rust-unsafe-checker.cc @@ -0,0 +1,779 @@ +// 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 ()) +{} + +void +UnsafeChecker::go (HIR::Crate &crate) +{ + for (auto &item : crate.items) + item->accept_vis (*this); +} + +void +UnsafeChecker::push_unsafe (HirId id) +{ + unsafe_contexts.emplace_back (id); +} + +HirId +UnsafeChecker::pop_unsafe () +{ + rust_assert (!unsafe_contexts.empty ()); + + auto last = unsafe_contexts.back (); + unsafe_contexts.pop_back (); + + return last; +} + +bool +UnsafeChecker::is_unsafe_context () +{ + return !unsafe_contexts.empty (); +} + +void +UnsafeChecker::visit (IdentifierExpr &ident_expr) +{} + +void +UnsafeChecker::visit (Lifetime &lifetime) +{} + +void +UnsafeChecker::visit (LifetimeParam &lifetime_param) +{} + +void +UnsafeChecker::visit (PathInExpression &path) +{} + +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 + && !is_unsafe_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) +{} + +void +UnsafeChecker::visit (MethodCallExpr &expr) +{} + +void +UnsafeChecker::visit (FieldAccessExpr &expr) +{ + // FIXME: If the receiver is an union, we need to be in an unsafe context to + // access it. Make sure to check. + + expr.get_receiver_expr ()->accept_vis (*this); +} + +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) +{ + push_unsafe (expr.get_mappings ().get_hirid ()); + + expr.get_block_expr ()->accept_vis (*this); + + pop_unsafe (); +} + +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 ¶m) +{} + +void +UnsafeChecker::visit (ConstGenericParam ¶m) +{} + +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) + push_unsafe (function.get_mappings ().get_hirid ()); + + function.get_definition ()->accept_vis (*this); + + if (is_unsafe_fn) + pop_unsafe (); +} + +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 diff --git a/gcc/rust/checks/errors/rust-unsafe-checker.h b/gcc/rust/checks/errors/rust-unsafe-checker.h new file mode 100644 index 0000000..3c81707 --- /dev/null +++ b/gcc/rust/checks/errors/rust-unsafe-checker.h @@ -0,0 +1,193 @@ +// 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-hir-type-check.h" + +namespace Rust { +namespace HIR { +class UnsafeChecker : public HIRFullVisitor +{ +public: + UnsafeChecker (); + + void go (HIR::Crate &crate); + +private: + /* Stack of unsafe contexts */ + std::vector<HirId> unsafe_contexts; + + /** + * Add an unsafe context to the stack. To call when entering unsafe blocks + */ + void push_unsafe (HirId id); + + /** + * Remove an unsafe context from the stack. Call this when exiting unsafe + * blocks + */ + HirId pop_unsafe (); + + /** + * Are we currently in an unsafe context or not + */ + bool is_unsafe_context (); + + Resolver::TypeCheckContext &context; + + virtual void visit (IdentifierExpr &ident_expr) override; + 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 ¶m) override; + virtual void visit (ConstGenericParam ¶m) 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 */ diff --git a/gcc/rust/hir/tree/rust-hir-expr.h b/gcc/rust/hir/tree/rust-hir-expr.h index c695412..327a9ac 100644 --- a/gcc/rust/hir/tree/rust-hir-expr.h +++ b/gcc/rust/hir/tree/rust-hir-expr.h @@ -2716,6 +2716,8 @@ public: void accept_vis (HIRFullVisitor &vis) override; void accept_vis (HIRExpressionVisitor &vis) override; + std::unique_ptr<Expr> &get_to_expr () { return to; }; + protected: /* Use covariance to implement clone function as returning this object rather * than base */ diff --git a/gcc/rust/hir/tree/rust-hir-item.h b/gcc/rust/hir/tree/rust-hir-item.h index 1fcecb8..0d41bd0 100644 --- a/gcc/rust/hir/tree/rust-hir-item.h +++ b/gcc/rust/hir/tree/rust-hir-item.h @@ -502,6 +502,7 @@ public: AsyncConstStatus get_status () const { return const_status; } bool is_const () const { return const_status == AsyncConstStatus::CONST_FN; } + bool is_unsafe () const { return unsafety == Unsafety::Unsafe; } ABI get_abi () const { return abi; } }; diff --git a/gcc/rust/rust-session-manager.cc b/gcc/rust/rust-session-manager.cc index 1ef6765..6a2c1b6 100644 --- a/gcc/rust/rust-session-manager.cc +++ b/gcc/rust/rust-session-manager.cc @@ -17,6 +17,7 @@ // <http://www.gnu.org/licenses/>. #include "rust-session-manager.h" +#include "rust-unsafe-checker.h" #include "rust-diagnostics.h" #include "rust-lex.h" #include "rust-parse.h" @@ -789,8 +790,14 @@ Session::parse_file (const char *filename) if (saw_errors ()) return; - // privacy pass + // Various HIR error passes. The privacy pass happens before the unsafe checks Privacy::Resolver::resolve (hir); + if (saw_errors ()) + return; + + HIR::UnsafeChecker ().go (hir); + if (saw_errors ()) + return; // do compile to gcc generic Compile::Context ctx (backend); diff --git a/gcc/testsuite/rust/compile/unsafe4.rs b/gcc/testsuite/rust/compile/unsafe4.rs new file mode 100644 index 0000000..7d1356b --- /dev/null +++ b/gcc/testsuite/rust/compile/unsafe4.rs @@ -0,0 +1,29 @@ +fn foo() -> i32 { + let a = 15; + let p_a = &a as *const i32; + + unsafe { *p_a } +} + +unsafe fn bar() -> i32 { + let a = 15; + let p_a = &a as *const i32; + + *p_a +} + +fn baz() -> i32 { + let a = 15; + let p_a = &a as *const i32; + + *p_a // { dg-error "dereference of raw pointer" } +} + +unsafe fn qux() -> i32 { + let a = 15; + let p_a = &a as *const i32; + + unsafe {} + + *p_a +} diff --git a/gcc/testsuite/rust/compile/unsafe5.rs b/gcc/testsuite/rust/compile/unsafe5.rs new file mode 100644 index 0000000..35990f6 --- /dev/null +++ b/gcc/testsuite/rust/compile/unsafe5.rs @@ -0,0 +1,4 @@ +fn main() { + let b = 15; + let c = *(&b as *const i32); // { dg-error "dereference of raw pointer" } +} |