diff options
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/rust/Make-lang.in | 1 | ||||
-rw-r--r-- | gcc/rust/checks/errors/rust-const-checker.cc | 803 | ||||
-rw-r--r-- | gcc/rust/checks/errors/rust-const-checker.h | 183 | ||||
-rw-r--r-- | gcc/rust/checks/errors/rust-unsafe-checker.cc | 113 | ||||
-rw-r--r-- | gcc/rust/checks/errors/rust-unsafe-checker.h | 24 | ||||
-rw-r--r-- | gcc/rust/hir/rust-ast-lower-expr.h | 18 | ||||
-rw-r--r-- | gcc/rust/hir/tree/rust-hir-expr.h | 20 | ||||
-rw-r--r-- | gcc/rust/hir/tree/rust-hir-item.h | 37 | ||||
-rw-r--r-- | gcc/rust/hir/tree/rust-hir.h | 20 | ||||
-rw-r--r-- | gcc/rust/rust-session-manager.cc | 5 | ||||
-rw-r--r-- | gcc/rust/util/rust-stacked-contexts.h | 86 | ||||
-rw-r--r-- | gcc/testsuite/rust/compile/const1.rs | 6 | ||||
-rw-r--r-- | gcc/testsuite/rust/compile/const2.rs | 7 | ||||
-rw-r--r-- | gcc/testsuite/rust/compile/const3.rs | 7 | ||||
-rw-r--r-- | gcc/testsuite/rust/compile/unsafe1.rs | 14 | ||||
-rw-r--r-- | gcc/testsuite/rust/compile/unsafe2.rs | 16 | ||||
-rw-r--r-- | gcc/testsuite/rust/compile/unsafe3.rs | 10 | ||||
-rw-r--r-- | gcc/testsuite/rust/compile/unsafe9.rs | 10 |
18 files changed, 1329 insertions, 51 deletions
diff --git a/gcc/rust/Make-lang.in b/gcc/rust/Make-lang.in index 1ae9bd7..78c3d0f 100644 --- a/gcc/rust/Make-lang.in +++ b/gcc/rust/Make-lang.in @@ -120,6 +120,7 @@ GRS_OBJS = \ rust/rust-hir-type-check-base.o \ rust/rust-autoderef.o \ rust/rust-substitution-mapper.o \ + rust/rust-const-checker.o \ rust/rust-lint-marklive.o \ rust/rust-lint-unused-var.o \ rust/rust-hir-type-check-path.o \ diff --git a/gcc/rust/checks/errors/rust-const-checker.cc b/gcc/rust/checks/errors/rust-const-checker.cc new file mode 100644 index 0000000..bb6ae10 --- /dev/null +++ b/gcc/rust/checks/errors/rust-const-checker.cc @@ -0,0 +1,803 @@ +// 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-const-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 { + +ConstChecker::ConstChecker () + : resolver (*Resolver::Resolver::get ()), + mappings (*Analysis::Mappings::get ()) +{} + +void +ConstChecker::go (HIR::Crate &crate) +{ + for (auto &item : crate.items) + item->accept_vis (*this); +} + +void +ConstChecker::visit (IdentifierExpr &ident_expr) +{} + +void +ConstChecker::visit (Lifetime &lifetime) +{} + +void +ConstChecker::visit (LifetimeParam &lifetime_param) +{} + +void +ConstChecker::visit (PathInExpression &path) +{} + +void +ConstChecker::visit (TypePathSegment &segment) +{} + +void +ConstChecker::visit (TypePathSegmentGeneric &segment) +{} + +void +ConstChecker::visit (TypePathSegmentFunction &segment) +{} + +void +ConstChecker::visit (TypePath &path) +{} + +void +ConstChecker::visit (QualifiedPathInExpression &path) +{} + +void +ConstChecker::visit (QualifiedPathInType &path) +{} + +void +ConstChecker::visit (LiteralExpr &expr) +{} + +void +ConstChecker::visit (BorrowExpr &expr) +{ + expr.get_expr ()->accept_vis (*this); +} + +void +ConstChecker::visit (DereferenceExpr &expr) +{ + expr.get_expr ()->accept_vis (*this); +} + +void +ConstChecker::visit (ErrorPropagationExpr &expr) +{ + expr.get_expr ()->accept_vis (*this); +} + +void +ConstChecker::visit (NegationExpr &expr) +{ + expr.get_expr ()->accept_vis (*this); +} + +void +ConstChecker::visit (ArithmeticOrLogicalExpr &expr) +{ + expr.get_lhs ()->accept_vis (*this); + expr.get_rhs ()->accept_vis (*this); +} + +void +ConstChecker::visit (ComparisonExpr &expr) +{ + expr.get_lhs ()->accept_vis (*this); + expr.get_rhs ()->accept_vis (*this); +} + +void +ConstChecker::visit (LazyBooleanExpr &expr) +{ + expr.get_lhs ()->accept_vis (*this); + expr.get_rhs ()->accept_vis (*this); +} + +void +ConstChecker::visit (TypeCastExpr &expr) +{ + expr.get_expr ()->accept_vis (*this); +} + +void +ConstChecker::visit (AssignmentExpr &expr) +{ + expr.get_lhs ()->accept_vis (*this); + expr.get_rhs ()->accept_vis (*this); +} + +void +ConstChecker::visit (CompoundAssignmentExpr &expr) +{ + expr.get_left_expr ()->accept_vis (*this); + expr.get_right_expr ()->accept_vis (*this); +} + +void +ConstChecker::visit (GroupedExpr &expr) +{ + expr.get_expr_in_parens ()->accept_vis (*this); +} + +void +ConstChecker::visit (ArrayElemsValues &elems) +{ + for (auto &elem : elems.get_values ()) + elem->accept_vis (*this); +} + +void +ConstChecker::visit (ArrayElemsCopied &elems) +{ + elems.get_elem_to_copy ()->accept_vis (*this); + + const_context.enter (elems.get_mappings ().get_hirid ()); + + elems.get_num_copies_expr ()->accept_vis (*this); + + const_context.exit (); +} + +void +ConstChecker::visit (ArrayExpr &expr) +{ + expr.get_internal_elements ()->accept_vis (*this); +} + +void +ConstChecker::visit (ArrayIndexExpr &expr) +{ + expr.get_array_expr ()->accept_vis (*this); + expr.get_index_expr ()->accept_vis (*this); +} + +void +ConstChecker::visit (TupleExpr &expr) +{ + for (auto &elem : expr.get_tuple_elems ()) + elem->accept_vis (*this); +} + +void +ConstChecker::visit (TupleIndexExpr &expr) +{ + expr.get_tuple_expr ()->accept_vis (*this); +} + +void +ConstChecker::visit (StructExprStruct &expr) +{} + +void +ConstChecker::visit (StructExprFieldIdentifier &field) +{} + +void +ConstChecker::visit (StructExprFieldIdentifierValue &field) +{ + field.get_value ()->accept_vis (*this); +} + +void +ConstChecker::visit (StructExprFieldIndexValue &field) +{ + field.get_value ()->accept_vis (*this); +} + +void +ConstChecker::visit (StructExprStructFields &expr) +{ + for (auto &field : expr.get_fields ()) + field->accept_vis (*this); +} + +void +ConstChecker::visit (StructExprStructBase &expr) +{} + +void +ConstChecker::check_function_call (HirId fn_id, Location locus) +{ + if (!const_context.is_in_context ()) + return; + + auto maybe_fn = mappings.lookup_hir_item (fn_id); + if (!maybe_fn || maybe_fn->get_item_kind () != Item::ItemKind::Function) + return; + + auto fn = static_cast<Function *> (maybe_fn); + if (!fn->get_qualifiers ().is_const ()) + rust_error_at (locus, "only functions marked as %<const%> are allowed to " + "be called from constant contexts"); +} + +void +ConstChecker::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; + + // We don't care about types here + 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_function_call (definition_id, expr.get_locus ()); + + for (auto &arg : expr.get_arguments ()) + arg->accept_vis (*this); +} + +void +ConstChecker::visit (MethodCallExpr &expr) +{ + expr.get_receiver ()->accept_vis (*this); + + for (auto &arg : expr.get_arguments ()) + arg->accept_vis (*this); +} + +void +ConstChecker::visit (FieldAccessExpr &expr) +{ + expr.get_receiver_expr ()->accept_vis (*this); +} + +void +ConstChecker::visit (ClosureExprInner &expr) +{} + +void +ConstChecker::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 +ConstChecker::visit (ClosureExprInnerTyped &expr) +{} + +void +ConstChecker::visit (ContinueExpr &expr) +{} + +void +ConstChecker::visit (BreakExpr &expr) +{ + if (expr.has_break_expr ()) + expr.get_expr ()->accept_vis (*this); +} + +void +ConstChecker::visit (RangeFromToExpr &expr) +{ + expr.get_from_expr ()->accept_vis (*this); + expr.get_to_expr ()->accept_vis (*this); +} + +void +ConstChecker::visit (RangeFromExpr &expr) +{ + expr.get_from_expr ()->accept_vis (*this); +} + +void +ConstChecker::visit (RangeToExpr &expr) +{ + expr.get_to_expr ()->accept_vis (*this); +} + +void +ConstChecker::visit (RangeFullExpr &expr) +{} + +void +ConstChecker::visit (RangeFromToInclExpr &expr) +{ + expr.get_from_expr ()->accept_vis (*this); + expr.get_to_expr ()->accept_vis (*this); +} + +void +ConstChecker::visit (RangeToInclExpr &expr) +{ + // FIXME: Visit to_expr +} + +void +ConstChecker::visit (ReturnExpr &expr) +{ + if (expr.has_return_expr ()) + expr.get_expr ()->accept_vis (*this); +} + +void +ConstChecker::visit (UnsafeBlockExpr &expr) +{ + expr.get_block_expr ()->accept_vis (*this); +} + +void +ConstChecker::visit (LoopExpr &expr) +{ + expr.get_loop_block ()->accept_vis (*this); +} + +void +ConstChecker::visit (WhileLoopExpr &expr) +{ + expr.get_predicate_expr ()->accept_vis (*this); + expr.get_loop_block ()->accept_vis (*this); +} + +void +ConstChecker::visit (WhileLetLoopExpr &expr) +{ + expr.get_cond ()->accept_vis (*this); + expr.get_loop_block ()->accept_vis (*this); +} + +void +ConstChecker::visit (ForLoopExpr &expr) +{ + expr.get_iterator_expr ()->accept_vis (*this); + expr.get_loop_block ()->accept_vis (*this); +} + +void +ConstChecker::visit (IfExpr &expr) +{ + expr.get_if_condition ()->accept_vis (*this); + expr.get_if_block ()->accept_vis (*this); +} + +void +ConstChecker::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 +ConstChecker::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 +ConstChecker::visit (IfExprConseqIfLet &expr) +{ + expr.get_if_condition ()->accept_vis (*this); + expr.get_if_block ()->accept_vis (*this); + + // TODO: Visit conseq if let expression +} + +void +ConstChecker::visit (IfLetExpr &expr) +{ + expr.get_scrutinee_expr ()->accept_vis (*this); + expr.get_if_block ()->accept_vis (*this); +} + +void +ConstChecker::visit (IfLetExprConseqElse &expr) +{ + expr.get_scrutinee_expr ()->accept_vis (*this); + expr.get_if_block ()->accept_vis (*this); + + // TODO: Visit else expression +} + +void +ConstChecker::visit (IfLetExprConseqIf &expr) +{ + expr.get_scrutinee_expr ()->accept_vis (*this); + expr.get_if_block ()->accept_vis (*this); +} + +void +ConstChecker::visit (IfLetExprConseqIfLet &expr) +{ + expr.get_scrutinee_expr ()->accept_vis (*this); + expr.get_if_block ()->accept_vis (*this); + + // TODO: Visit conseq if let expression +} + +void +ConstChecker::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 +ConstChecker::visit (AwaitExpr &expr) +{ + // TODO: Visit expression +} + +void +ConstChecker::visit (AsyncBlockExpr &expr) +{ + // TODO: Visit block expression +} + +void +ConstChecker::visit (TypeParam ¶m) +{} + +void +ConstChecker::visit (ConstGenericParam ¶m) +{} + +void +ConstChecker::visit (LifetimeWhereClauseItem &item) +{} + +void +ConstChecker::visit (TypeBoundWhereClauseItem &item) +{} + +void +ConstChecker::visit (Module &module) +{ + for (auto &item : module.get_items ()) + item->accept_vis (*this); +} + +void +ConstChecker::visit (ExternCrate &crate) +{} + +void +ConstChecker::visit (UseTreeGlob &use_tree) +{} + +void +ConstChecker::visit (UseTreeList &use_tree) +{} + +void +ConstChecker::visit (UseTreeRebind &use_tree) +{} + +void +ConstChecker::visit (UseDeclaration &use_decl) +{} + +void +ConstChecker::visit (Function &function) +{ + auto const_fn = function.get_qualifiers ().is_const (); + if (const_fn) + const_context.enter (function.get_mappings ().get_hirid ()); + + function.get_definition ()->accept_vis (*this); + + if (const_fn) + const_context.exit (); +} + +void +ConstChecker::visit (TypeAlias &type_alias) +{} + +void +ConstChecker::visit (StructStruct &struct_item) +{} + +void +ConstChecker::visit (TupleStruct &tuple_struct) +{} + +void +ConstChecker::visit (EnumItem &item) +{} + +void +ConstChecker::visit (EnumItemTuple &item) +{} + +void +ConstChecker::visit (EnumItemStruct &item) +{} + +void +ConstChecker::visit (EnumItemDiscriminant &item) +{ + const_context.enter (item.get_mappings ().get_hirid ()); + + item.get_discriminant_expression ()->accept_vis (*this); + + const_context.exit (); +} + +void +ConstChecker::visit (Enum &enum_item) +{} + +void +ConstChecker::visit (Union &union_item) +{} + +void +ConstChecker::visit (ConstantItem &const_item) +{ + const_context.enter (const_item.get_mappings ().get_hirid ()); + + const_item.get_expr ()->accept_vis (*this); + + const_context.exit (); +} + +void +ConstChecker::visit (StaticItem &static_item) +{ + const_context.enter (static_item.get_mappings ().get_hirid ()); + + static_item.get_expr ()->accept_vis (*this); + + const_context.exit (); +} + +void +ConstChecker::visit (TraitItemFunc &item) +{ + if (item.has_block_defined ()) + item.get_block_expr ()->accept_vis (*this); +} + +void +ConstChecker::visit (TraitItemConst &item) +{ + if (item.has_expr ()) + item.get_expr ()->accept_vis (*this); +} + +void +ConstChecker::visit (TraitItemType &item) +{} + +void +ConstChecker::visit (Trait &trait) +{ + for (auto &item : trait.get_trait_items ()) + item->accept_vis (*this); +} + +void +ConstChecker::visit (ImplBlock &impl) +{ + for (auto &item : impl.get_impl_items ()) + item->accept_vis (*this); +} + +void +ConstChecker::visit (ExternalStaticItem &item) +{} + +void +ConstChecker::visit (ExternalFunctionItem &item) +{} + +void +ConstChecker::visit (ExternBlock &block) +{ + // FIXME: Do we need to do this? + for (auto &item : block.get_extern_items ()) + item->accept_vis (*this); +} + +void +ConstChecker::visit (LiteralPattern &pattern) +{} + +void +ConstChecker::visit (IdentifierPattern &pattern) +{} + +void +ConstChecker::visit (WildcardPattern &pattern) +{} + +void +ConstChecker::visit (RangePatternBoundLiteral &bound) +{} + +void +ConstChecker::visit (RangePatternBoundPath &bound) +{} + +void +ConstChecker::visit (RangePatternBoundQualPath &bound) +{} + +void +ConstChecker::visit (RangePattern &pattern) +{} + +void +ConstChecker::visit (ReferencePattern &pattern) +{} + +void +ConstChecker::visit (StructPatternFieldTuplePat &field) +{} + +void +ConstChecker::visit (StructPatternFieldIdentPat &field) +{} + +void +ConstChecker::visit (StructPatternFieldIdent &field) +{} + +void +ConstChecker::visit (StructPattern &pattern) +{} + +void +ConstChecker::visit (TupleStructItemsNoRange &tuple_items) +{} + +void +ConstChecker::visit (TupleStructItemsRange &tuple_items) +{} + +void +ConstChecker::visit (TupleStructPattern &pattern) +{} + +void +ConstChecker::visit (TuplePatternItemsMultiple &tuple_items) +{} + +void +ConstChecker::visit (TuplePatternItemsRanged &tuple_items) +{} + +void +ConstChecker::visit (TuplePattern &pattern) +{} + +void +ConstChecker::visit (GroupedPattern &pattern) +{} + +void +ConstChecker::visit (SlicePattern &pattern) +{} + +void +ConstChecker::visit (EmptyStmt &stmt) +{} + +void +ConstChecker::visit (LetStmt &stmt) +{ + if (stmt.has_init_expr ()) + stmt.get_init_expr ()->accept_vis (*this); +} + +void +ConstChecker::visit (ExprStmtWithoutBlock &stmt) +{ + stmt.get_expr ()->accept_vis (*this); +} + +void +ConstChecker::visit (ExprStmtWithBlock &stmt) +{ + stmt.get_expr ()->accept_vis (*this); +} + +void +ConstChecker::visit (TraitBound &bound) +{} + +void +ConstChecker::visit (ImplTraitType &type) +{} + +void +ConstChecker::visit (TraitObjectType &type) +{} + +void +ConstChecker::visit (ParenthesisedType &type) +{} + +void +ConstChecker::visit (ImplTraitTypeOneBound &type) +{} + +void +ConstChecker::visit (TupleType &type) +{} + +void +ConstChecker::visit (NeverType &type) +{} + +void +ConstChecker::visit (RawPointerType &type) +{} + +void +ConstChecker::visit (ReferenceType &type) +{} + +void +ConstChecker::visit (ArrayType &type) +{ + const_context.enter (type.get_mappings ().get_hirid ()); + + type.get_size_expr ()->accept_vis (*this); + + const_context.exit (); +} + +void +ConstChecker::visit (SliceType &type) +{} + +void +ConstChecker::visit (InferredType &type) +{} + +void +ConstChecker::visit (BareFunctionType &type) +{} + +} // namespace HIR +} // namespace Rust diff --git a/gcc/rust/checks/errors/rust-const-checker.h b/gcc/rust/checks/errors/rust-const-checker.h new file mode 100644 index 0000000..a474fc8 --- /dev/null +++ b/gcc/rust/checks/errors/rust-const-checker.h @@ -0,0 +1,183 @@ +// 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_CONST_CHECKER_H +#define RUST_CONST_CHECKER_H + +#include "rust-hir-visitor.h" +#include "rust-hir-type-check.h" +#include "rust-stacked-contexts.h" +#include "rust-name-resolver.h" + +namespace Rust { +namespace HIR { +class ConstChecker : public HIRFullVisitor +{ +public: + ConstChecker (); + + void go (HIR::Crate &crate); + +private: + /** + * Check that only const functions are called in const contexts + */ + void check_function_call (HirId fn_id, Location locus); + + StackedContexts<HirId> const_context; + Resolver::Resolver &resolver; + Analysis::Mappings &mappings; + + 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_CONST_CHECKER_H */ diff --git a/gcc/rust/checks/errors/rust-unsafe-checker.cc b/gcc/rust/checks/errors/rust-unsafe-checker.cc index def3cc1..0d1e0e9 100644 --- a/gcc/rust/checks/errors/rust-unsafe-checker.cc +++ b/gcc/rust/checks/errors/rust-unsafe-checker.cc @@ -25,7 +25,10 @@ namespace Rust { namespace HIR { -UnsafeChecker::UnsafeChecker () : context (*Resolver::TypeCheckContext::get ()) +UnsafeChecker::UnsafeChecker () + : context (*Resolver::TypeCheckContext::get ()), + resolver (*Resolver::Resolver::get ()), + mappings (*Analysis::Mappings::get ()) {} void @@ -35,32 +38,61 @@ UnsafeChecker::go (HIR::Crate &crate) item->accept_vis (*this); } -void -UnsafeChecker::push_unsafe (HirId id) +static void +check_static_mut (HIR::Item *maybe_static, Location locus) { - unsafe_contexts.emplace_back (id); + 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"); + } + } } -HirId -UnsafeChecker::pop_unsafe () +static void +check_extern_static (HIR::ExternalItem *maybe_static, Location locus) { - rust_assert (!unsafe_contexts.empty ()); - - auto last = unsafe_contexts.back (); - unsafe_contexts.pop_back (); - - return last; + if (maybe_static->get_extern_kind () == ExternalItem::ExternKind::Static) + rust_error_at (locus, + "use of extern static requires unsafe function or block"); } -bool -UnsafeChecker::is_unsafe_context () +void +UnsafeChecker::check_use_of_static (HirId node_id, Location locus) { - return !unsafe_contexts.empty (); + if (unsafe_context.is_in_context ()) + return; + + auto maybe_static_mut = mappings.lookup_hir_item (node_id); + auto maybe_extern_static = mappings.lookup_hir_extern_item (node_id); + + 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); } void UnsafeChecker::visit (IdentifierExpr &ident_expr) -{} +{ + NodeId ast_node_id = ident_expr.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, ident_expr.get_locus ()); +} void UnsafeChecker::visit (Lifetime &lifetime) @@ -72,7 +104,18 @@ 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) @@ -117,7 +160,7 @@ UnsafeChecker::visit (DereferenceExpr &expr) rust_assert (context.lookup_type (to_deref, &to_deref_type)); if (to_deref_type->get_kind () == TyTy::TypeKind::POINTER - && !is_unsafe_context ()) + && !unsafe_context.is_in_context ()) rust_error_at (expr.get_locus (), "dereference of raw pointer requires " "unsafe function or block"); } @@ -253,7 +296,11 @@ UnsafeChecker::visit (StructExprStructBase &expr) void UnsafeChecker::visit (CallExpr &expr) -{} +{ + if (expr.has_params ()) + for (auto &arg : expr.get_arguments ()) + arg->accept_vis (*this); +} void UnsafeChecker::visit (MethodCallExpr &expr) @@ -262,10 +309,24 @@ 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); + + 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 @@ -343,11 +404,11 @@ UnsafeChecker::visit (ReturnExpr &expr) void UnsafeChecker::visit (UnsafeBlockExpr &expr) { - push_unsafe (expr.get_mappings ().get_hirid ()); + unsafe_context.enter (expr.get_mappings ().get_hirid ()); expr.get_block_expr ()->accept_vis (*this); - pop_unsafe (); + unsafe_context.exit (); } void @@ -511,12 +572,12 @@ UnsafeChecker::visit (Function &function) auto is_unsafe_fn = function.get_qualifiers ().is_unsafe (); if (is_unsafe_fn) - push_unsafe (function.get_mappings ().get_hirid ()); + unsafe_context.enter (function.get_mappings ().get_hirid ()); function.get_definition ()->accept_vis (*this); if (is_unsafe_fn) - pop_unsafe (); + unsafe_context.exit (); } void diff --git a/gcc/rust/checks/errors/rust-unsafe-checker.h b/gcc/rust/checks/errors/rust-unsafe-checker.h index 3c81707..b9d06ef 100644 --- a/gcc/rust/checks/errors/rust-unsafe-checker.h +++ b/gcc/rust/checks/errors/rust-unsafe-checker.h @@ -20,7 +20,9 @@ #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 { @@ -32,26 +34,16 @@ public: 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 + * Check if a mutable static or external static item is used outside of an + * unsafe context */ - bool is_unsafe_context (); + void check_use_of_static (HirId node_id, Location locus); + StackedContexts<HirId> unsafe_context; Resolver::TypeCheckContext &context; + Resolver::Resolver &resolver; + Analysis::Mappings &mappings; virtual void visit (IdentifierExpr &ident_expr) override; virtual void visit (Lifetime &lifetime) override; diff --git a/gcc/rust/hir/rust-ast-lower-expr.h b/gcc/rust/hir/rust-ast-lower-expr.h index 166a44b..b420a4d 100644 --- a/gcc/rust/hir/rust-ast-lower-expr.h +++ b/gcc/rust/hir/rust-ast-lower-expr.h @@ -307,7 +307,14 @@ public: elements.push_back (std::unique_ptr<HIR::Expr> (translated_elem)); } - translated_array_elems = new HIR::ArrayElemsValues (std::move (elements)); + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (mappings->get_current_crate (), + elems.get_node_id (), + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + + translated_array_elems + = new HIR::ArrayElemsValues (mapping, std::move (elements)); } void visit (AST::ArrayElemsCopied &elems) override @@ -317,8 +324,15 @@ public: HIR::Expr *num_copies = ASTLoweringExpr::translate (elems.get_num_copies ().get ()); + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (mappings->get_current_crate (), + elems.get_node_id (), + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + translated_array_elems - = new HIR::ArrayElemsCopied (std::unique_ptr<HIR::Expr> (element), + = new HIR::ArrayElemsCopied (mapping, + std::unique_ptr<HIR::Expr> (element), std::unique_ptr<HIR::Expr> (num_copies)); } diff --git a/gcc/rust/hir/tree/rust-hir-expr.h b/gcc/rust/hir/tree/rust-hir-expr.h index 327a9ac..d16ac92 100644 --- a/gcc/rust/hir/tree/rust-hir-expr.h +++ b/gcc/rust/hir/tree/rust-hir-expr.h @@ -849,6 +849,8 @@ public: COPIED, }; + ArrayElems (Analysis::NodeMapping mappings) : mappings (mappings){}; + virtual ~ArrayElems () {} // Unique pointer custom clone ArrayElems function @@ -863,9 +865,13 @@ public: virtual ArrayExprType get_array_expr_type () const = 0; + Analysis::NodeMapping &get_mappings () { return mappings; } + protected: // pure virtual clone implementation virtual ArrayElems *clone_array_elems_impl () const = 0; + + Analysis::NodeMapping mappings; }; // Value array elements @@ -876,12 +882,13 @@ class ArrayElemsValues : public ArrayElems // TODO: should this store location data? public: - ArrayElemsValues (std::vector<std::unique_ptr<Expr> > elems) - : values (std::move (elems)) + ArrayElemsValues (Analysis::NodeMapping mappings, + std::vector<std::unique_ptr<Expr> > elems) + : ArrayElems (mappings), values (std::move (elems)) {} // copy constructor with vector clone - ArrayElemsValues (ArrayElemsValues const &other) + ArrayElemsValues (ArrayElemsValues const &other) : ArrayElems (other) { values.reserve (other.values.size ()); for (const auto &e : other.values) @@ -930,15 +937,16 @@ class ArrayElemsCopied : public ArrayElems public: // Constructor requires pointers for polymorphism - ArrayElemsCopied (std::unique_ptr<Expr> copied_elem, + ArrayElemsCopied (Analysis::NodeMapping mappings, + std::unique_ptr<Expr> copied_elem, std::unique_ptr<Expr> copy_amount) - : elem_to_copy (std::move (copied_elem)), + : ArrayElems (mappings), elem_to_copy (std::move (copied_elem)), num_copies (std::move (copy_amount)) {} // Copy constructor required due to unique_ptr - uses custom clone ArrayElemsCopied (ArrayElemsCopied const &other) - : elem_to_copy (other.elem_to_copy->clone_expr ()), + : ArrayElems (other), elem_to_copy (other.elem_to_copy->clone_expr ()), num_copies (other.num_copies->clone_expr ()) {} diff --git a/gcc/rust/hir/tree/rust-hir-item.h b/gcc/rust/hir/tree/rust-hir-item.h index 0d41bd0..394b04f 100644 --- a/gcc/rust/hir/tree/rust-hir-item.h +++ b/gcc/rust/hir/tree/rust-hir-item.h @@ -723,6 +723,8 @@ public: Location get_locus () const override final { return locus; } + ItemKind get_item_kind () const override { return ItemKind::Module; } + protected: /* Use covariance to implement clone function as returning this object * rather than base */ @@ -773,6 +775,8 @@ public: Location get_locus () const override final { return locus; } + ItemKind get_item_kind () const override { return ItemKind::ExternCrate; } + void accept_vis (HIRFullVisitor &vis) override; void accept_vis (HIRStmtVisitor &vis) override; void accept_vis (HIRVisItemVisitor &vis) override; @@ -1039,6 +1043,7 @@ public: UseDeclaration &operator= (UseDeclaration &&other) = default; Location get_locus () const override final { return locus; } + ItemKind get_item_kind () const override { return ItemKind::UseDeclaration; } void accept_vis (HIRFullVisitor &vis) override; void accept_vis (HIRStmtVisitor &vis) override; @@ -1094,6 +1099,8 @@ public: return ImplItem::ImplItemType::FUNCTION; } + ItemKind get_item_kind () const override { return ItemKind::Function; } + // Mega-constructor with all possible fields Function (Analysis::NodeMapping mappings, Identifier function_name, FunctionQualifiers qualifiers, @@ -1329,6 +1336,8 @@ public: Identifier get_new_type_name () const { return new_type_name; } + ItemKind get_item_kind () const override { return ItemKind::TypeAlias; } + Analysis::NodeMapping get_impl_mappings () const override { return get_mappings (); @@ -1373,6 +1382,7 @@ public: bool has_where_clause () const { return !where_clause.is_empty (); } Location get_locus () const override final { return locus; } + ItemKind get_item_kind () const override { return ItemKind::Struct; } std::vector<std::unique_ptr<GenericParam>> &get_generic_params () { @@ -1709,6 +1719,8 @@ public: Identifier get_identifier () const { return variant_name; } + ItemKind get_item_kind () const override { return ItemKind::EnumItem; } + protected: EnumItem *clone_item_impl () const override { return new EnumItem (*this); } }; @@ -1930,6 +1942,7 @@ public: void accept_vis (HIRVisItemVisitor &vis) override; Identifier get_identifier () const { return enum_name; } + ItemKind get_item_kind () const override { return ItemKind::Enum; } std::vector<std::unique_ptr<GenericParam>> &get_generic_params () { @@ -2037,6 +2050,8 @@ public: WhereClause &get_where_clause () { return where_clause; } + ItemKind get_item_kind () const override { return ItemKind::Union; } + protected: /* Use covariance to implement clone function as returning this object * rather than base */ @@ -2111,6 +2126,8 @@ public: return ImplItem::ImplItemType::CONSTANT; } + ItemKind get_item_kind () const override { return ItemKind::Constant; } + protected: /* Use covariance to implement clone function as returning this object * rather than base */ @@ -2188,6 +2205,8 @@ public: Type *get_type () { return type.get (); } + ItemKind get_item_kind () const override { return ItemKind::Static; } + protected: StaticItem *clone_item_impl () const override { @@ -2677,6 +2696,8 @@ public: return type_param_bounds; } + ItemKind get_item_kind () const override { return ItemKind::Trait; } + protected: /* Use covariance to implement clone function as returning this object * rather than base */ @@ -2797,6 +2818,8 @@ public: WhereClause &get_where_clause () { return where_clause; } + ItemKind get_item_kind () const override { return ItemKind::Impl; } + protected: ImplBlock *clone_item_impl () const override { return new ImplBlock (*this); } }; @@ -2811,10 +2834,18 @@ class ExternalItem : public Node Location locus; public: + enum class ExternKind + { + Static, + Function, + }; + virtual ~ExternalItem () {} BaseKind get_hir_kind () override final { return EXTERNAL; } + virtual ExternKind get_extern_kind () = 0; + // Returns whether item has outer attributes. bool has_outer_attrs () const { return !outer_attrs.empty (); } @@ -2921,6 +2952,8 @@ public: std::unique_ptr<Type> &get_item_type () { return item_type; } + ExternKind get_extern_kind () override { return ExternKind::Static; } + protected: /* Use covariance to implement clone function as returning this object * rather than base */ @@ -3072,6 +3105,8 @@ public: bool is_variadic () const { return has_variadics; } + ExternKind get_extern_kind () override { return ExternKind::Function; } + protected: /* Use covariance to implement clone function as returning this object * rather than base */ @@ -3149,6 +3184,8 @@ public: return extern_items; } + ItemKind get_item_kind () const override { return ItemKind::ExternBlock; } + protected: /* Use covariance to implement clone function as returning this object * rather than base */ diff --git a/gcc/rust/hir/tree/rust-hir.h b/gcc/rust/hir/tree/rust-hir.h index 58f4db2..c2f6fef 100644 --- a/gcc/rust/hir/tree/rust-hir.h +++ b/gcc/rust/hir/tree/rust-hir.h @@ -175,6 +175,26 @@ class Item : public Stmt // TODO: should outer attrs be defined here or in each derived class? public: + enum class ItemKind + { + Static, + Constant, + TypeAlias, + Function, + UseDeclaration, + ExternBlock, + ExternCrate, + Struct, + Union, + Enum, + EnumItem, // FIXME: ARTHUR: Do we need that? + Trait, + Impl, + Module, + }; + + virtual ItemKind get_item_kind () const = 0; + // Unique pointer custom clone function std::unique_ptr<Item> clone_item () const { diff --git a/gcc/rust/rust-session-manager.cc b/gcc/rust/rust-session-manager.cc index 6a2c1b6..e3c211e 100644 --- a/gcc/rust/rust-session-manager.cc +++ b/gcc/rust/rust-session-manager.cc @@ -17,8 +17,8 @@ // <http://www.gnu.org/licenses/>. #include "rust-session-manager.h" -#include "rust-unsafe-checker.h" #include "rust-diagnostics.h" +#include "rust-unsafe-checker.h" #include "rust-lex.h" #include "rust-parse.h" #include "rust-macro-expand.h" @@ -26,6 +26,7 @@ #include "rust-ast-lower.h" #include "rust-hir-type-check.h" #include "rust-privacy-check.h" +#include "rust-const-checker.h" #include "rust-tycheck-dump.h" #include "rust-compile.h" #include "rust-cfg-parser.h" @@ -796,6 +797,8 @@ Session::parse_file (const char *filename) return; HIR::UnsafeChecker ().go (hir); + HIR::ConstChecker ().go (hir); + if (saw_errors ()) return; diff --git a/gcc/rust/util/rust-stacked-contexts.h b/gcc/rust/util/rust-stacked-contexts.h new file mode 100644 index 0000000..c34eb90 --- /dev/null +++ b/gcc/rust/util/rust-stacked-contexts.h @@ -0,0 +1,86 @@ +// 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_CONTEXT_STACK_H +#define RUST_CONTEXT_STACK_H + +#include "rust-system.h" + +namespace Rust { + +/** + * Context stack util class. This class is useful for situations where you can + * enter the same kind of context multiple times. For example, when dealing with + * unsafe contexts, you might be tempted to simply keep a boolean value. + * + * ```rust + * let a = 15; + * unsafe { // we set the boolean to true + * // Now unsafe operations are allowed! + * let b = *(&a as *const i32); + * let c = std::mem::transmute<i32, f32>(b); // Urgh! + * } // we set it to false + * ``` + * + * However, since the language allows nested unsafe blocks, you may run into + * this situation: + * + * ```rust + * unsafe { // we set the boolean to true + * unsafe { // we set the boolean to true + * } // we set it to false + * + * // Now unsafe operations are forbidden again, the boolean is false + * let f = std::mem::transmute<i32, f32>(15); // Error! + * } // we set it to false + * ``` + */ +template <typename T> class StackedContexts +{ +public: + /** + * Enter a special context + */ + void enter (T value) { stack.emplace_back (value); } + + /** + * Exit a special context + */ + T exit () + { + rust_assert (!stack.empty ()); + + auto last = stack.back (); + stack.pop_back (); + + return last; + } + + /** + * Are we currently inside of a special context? + */ + bool is_in_context () const { return !stack.empty (); } + +private: + /* Actual data */ + std::vector<T> stack; +}; + +} // namespace Rust + +#endif /* !RUST_CONTEXT_STACK_H */ diff --git a/gcc/testsuite/rust/compile/const1.rs b/gcc/testsuite/rust/compile/const1.rs new file mode 100644 index 0000000..5f19c67 --- /dev/null +++ b/gcc/testsuite/rust/compile/const1.rs @@ -0,0 +1,6 @@ +fn bar() {} + +const fn foo() { + bar(); // { dg-error "only functions marked as .const. are allowed to be called from constant contexts" } +} + diff --git a/gcc/testsuite/rust/compile/const2.rs b/gcc/testsuite/rust/compile/const2.rs new file mode 100644 index 0000000..17b6de5 --- /dev/null +++ b/gcc/testsuite/rust/compile/const2.rs @@ -0,0 +1,7 @@ +// { dg-additional-options "-w" } + +const fn foo() { + const fn bar() {} + + bar(); +} diff --git a/gcc/testsuite/rust/compile/const3.rs b/gcc/testsuite/rust/compile/const3.rs new file mode 100644 index 0000000..22dc3d3 --- /dev/null +++ b/gcc/testsuite/rust/compile/const3.rs @@ -0,0 +1,7 @@ +fn size() -> usize { + 15 +} + +fn main() { + let a = [15; size()]; // { dg-error "only functions marked as .const. are allowed to be called from constant contexts" } +} diff --git a/gcc/testsuite/rust/compile/unsafe1.rs b/gcc/testsuite/rust/compile/unsafe1.rs new file mode 100644 index 0000000..9cd3f6b --- /dev/null +++ b/gcc/testsuite/rust/compile/unsafe1.rs @@ -0,0 +1,14 @@ +fn foo(_a: &i32) {} +fn bar(_a: i32) {} + +static mut a: i32 = 15; + +fn main() { + foo(&a); // { dg-error "use of mutable static" } + bar(a); // { dg-error "use of mutable static" } + + unsafe { + foo(&a); + bar(a); + } +} diff --git a/gcc/testsuite/rust/compile/unsafe2.rs b/gcc/testsuite/rust/compile/unsafe2.rs new file mode 100644 index 0000000..e03e4bc --- /dev/null +++ b/gcc/testsuite/rust/compile/unsafe2.rs @@ -0,0 +1,16 @@ +fn foo(_a: &i32) {} +fn bar(_a: i32) {} + +mod inner { + pub static mut a: i32 = 15; +} + +fn main() { + foo(&inner::a); // { dg-error "use of mutable static" } + bar(inner::a); // { dg-error "use of mutable static" } + + unsafe { + foo(&inner::a); + bar(inner::a); + } +} diff --git a/gcc/testsuite/rust/compile/unsafe3.rs b/gcc/testsuite/rust/compile/unsafe3.rs new file mode 100644 index 0000000..56aec76 --- /dev/null +++ b/gcc/testsuite/rust/compile/unsafe3.rs @@ -0,0 +1,10 @@ +extern "C" { + static VALUE: char; +} + +fn main() { + let _ = VALUE; // { dg-error "use of extern static" } + unsafe { + let _ = VALUE; + } +} diff --git a/gcc/testsuite/rust/compile/unsafe9.rs b/gcc/testsuite/rust/compile/unsafe9.rs new file mode 100644 index 0000000..fb46c8f --- /dev/null +++ b/gcc/testsuite/rust/compile/unsafe9.rs @@ -0,0 +1,10 @@ +union U { + a: i32, + b: f32, + c: u8, +} + +fn main() { + let u = U { a: 14 }; + let _ = u.a; // { dg-error "access to union" } +} |