diff --git a/.gitignore b/.gitignore index 7150fc3b29ca..f044fe16b5f6 100644 --- a/.gitignore +++ b/.gitignore @@ -71,6 +71,3 @@ stamp-* /gmp* /isl* /gettext* - -# ADDITIONS from GCCRS front-end -libgrust/*/target/ diff --git a/gcc/rust/Make-lang.in b/gcc/rust/Make-lang.in index 835e113aee2c..c7846892d895 100644 --- a/gcc/rust/Make-lang.in +++ b/gcc/rust/Make-lang.in @@ -81,6 +81,7 @@ GRS_OBJS = \ rust/rust-ast-dump.o \ rust/rust-ast-collector.o \ rust/rust-ast-visitor.o \ + rust/rust-hir-visitor.o \ rust/rust-hir-dump.o \ rust/rust-session-manager.o \ rust/rust-compile.o \ @@ -92,14 +93,15 @@ GRS_OBJS = \ rust/rust-cfg-strip.o \ rust/rust-expand-visitor.o \ rust/rust-ast-builder.o \ - rust/rust-ast-builder-type.o \ rust/rust-derive.o \ + rust/rust-derive-cmp-common.o \ rust/rust-derive-clone.o \ rust/rust-derive-copy.o \ rust/rust-derive-debug.o \ rust/rust-derive-default.o \ rust/rust-derive-partial-eq.o \ rust/rust-derive-eq.o \ + rust/rust-derive-ord.o \ rust/rust-derive-hash.o \ rust/rust-proc-macro.o \ rust/rust-macro-invoc-lexer.o \ @@ -123,7 +125,6 @@ GRS_OBJS = \ rust/rust-keyword-values.o \ rust/rust-abi.o \ rust/rust-token-converter.o \ - rust/rust-macro.o \ rust/rust-ast-lower.o \ rust/rust-ast-lower-base.o \ rust/rust-ast-lower-pattern.o \ @@ -237,11 +238,13 @@ GRS_OBJS = \ rust/rust-punycode.o \ rust/rust-unwrap-segment.o \ rust/rust-edition.o \ + rust/rust-ggc.o \ rust/rust-expand-format-args.o \ rust/rust-lang-item.o \ rust/rust-collect-lang-items.o \ rust/rust-desugar-for-loops.o \ rust/rust-desugar-question-mark.o \ + rust/rust-desugar-apit.o \ $(END) # removed object files from here diff --git a/gcc/rust/ast/rust-ast-builder-type.cc b/gcc/rust/ast/rust-ast-builder-type.cc deleted file mode 100644 index 13126b440571..000000000000 --- a/gcc/rust/ast/rust-ast-builder-type.cc +++ /dev/null @@ -1,163 +0,0 @@ -// Copyright (C) 2020-2024 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 -// . - -#include "rust-ast-builder-type.h" -#include "rust-ast-builder.h" -#include "rust-ast-full.h" -#include "rust-common.h" - -namespace Rust { -namespace AST { - -ASTTypeBuilder::ASTTypeBuilder () : translated (nullptr) {} - -Type * -ASTTypeBuilder::build (Type &type) -{ - ASTTypeBuilder builder; - type.accept_vis (builder); - rust_assert (builder.translated != nullptr); - return builder.translated; -} - -void -ASTTypeBuilder::visit (BareFunctionType &fntype) -{ - /* TODO */ -} - -void -ASTTypeBuilder::visit (TupleType &tuple) -{ - std::vector > elems; - for (auto &elem : tuple.get_elems ()) - { - Type *t = ASTTypeBuilder::build (*elem.get ()); - std::unique_ptr ty (t); - elems.push_back (std::move (ty)); - } - translated = new TupleType (std::move (elems), tuple.get_locus ()); -} - -void -ASTTypeBuilder::visit (TypePath &path) -{ - std::vector > segments; - for (auto &seg : path.get_segments ()) - { - switch (seg->get_type ()) - { - case TypePathSegment::REG: { - const TypePathSegment &segment - = (const TypePathSegment &) (*seg.get ()); - TypePathSegment *s - = new TypePathSegment (segment.get_ident_segment (), - segment.get_separating_scope_resolution (), - segment.get_locus ()); - std::unique_ptr sg (s); - segments.push_back (std::move (sg)); - } - break; - - case TypePathSegment::GENERIC: { - TypePathSegmentGeneric &generic - = (TypePathSegmentGeneric &) (*seg.get ()); - - GenericArgs args - = Builder::new_generic_args (generic.get_generic_args ()); - TypePathSegmentGeneric *s - = new TypePathSegmentGeneric (generic.get_ident_segment (), false, - std::move (args), - generic.get_locus ()); - std::unique_ptr sg (s); - segments.push_back (std::move (sg)); - } - break; - - case TypePathSegment::FUNCTION: { - rust_unreachable (); - // TODO - // const TypePathSegmentFunction &fn - // = (const TypePathSegmentFunction &) (*seg.get ()); - } - break; - } - } - - translated = new TypePath (std::move (segments), path.get_locus (), - path.has_opening_scope_resolution_op ()); -} - -void -ASTTypeBuilder::visit (QualifiedPathInType &path) -{ - /* TODO */ -} - -void -ASTTypeBuilder::visit (ArrayType &type) -{ - /* TODO */ -} - -void -ASTTypeBuilder::visit (ReferenceType &type) -{ - /* TODO */ -} - -void -ASTTypeBuilder::visit (RawPointerType &type) -{ - /* TODO */ -} - -void -ASTTypeBuilder::visit (SliceType &type) -{ - Type *t = ASTTypeBuilder::build (type.get_elem_type ()); - std::unique_ptr ty (t); - translated = new SliceType (std::move (ty), type.get_locus ()); -} - -void -ASTTypeBuilder::visit (InferredType &type) -{ - translated = new InferredType (type.get_locus ()); -} - -void -ASTTypeBuilder::visit (NeverType &type) -{ - translated = new NeverType (type.get_locus ()); -} - -void -ASTTypeBuilder::visit (TraitObjectTypeOneBound &type) -{ - /* TODO */ -} - -void -ASTTypeBuilder::visit (TraitObjectType &type) -{ - /* TODO */ -} - -} // namespace AST -} // namespace Rust diff --git a/gcc/rust/ast/rust-ast-builder-type.h b/gcc/rust/ast/rust-ast-builder-type.h deleted file mode 100644 index b67ae3b553ff..000000000000 --- a/gcc/rust/ast/rust-ast-builder-type.h +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (C) 2020-2024 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 -// . - -#ifndef RUST_AST_BUILDER_TYPE -#define RUST_AST_BUILDER_TYPE - -#include "rust-ast-visitor.h" - -namespace Rust { -namespace AST { - -class ASTTypeBuilder : public DefaultASTVisitor -{ -protected: - using DefaultASTVisitor::visit; - -public: - static Type *build (Type &type); - - void visit (BareFunctionType &fntype) override; - void visit (TupleType &tuple) override; - void visit (TypePath &path) override; - void visit (QualifiedPathInType &path) override; - void visit (ArrayType &type) override; - void visit (ReferenceType &type) override; - void visit (RawPointerType &type) override; - void visit (SliceType &type) override; - void visit (InferredType &type) override; - void visit (NeverType &type) override; - void visit (TraitObjectTypeOneBound &type) override; - void visit (TraitObjectType &type) override; - -private: - ASTTypeBuilder (); - - Type *translated; -}; - -} // namespace AST -} // namespace Rust - -#endif // RUST_AST_BUILDER_TYPE diff --git a/gcc/rust/ast/rust-ast-builder.cc b/gcc/rust/ast/rust-ast-builder.cc index 08c52b155c44..ed10ce7f9a18 100644 --- a/gcc/rust/ast/rust-ast-builder.cc +++ b/gcc/rust/ast/rust-ast-builder.cc @@ -18,7 +18,6 @@ #include "rust-ast-builder.h" #include "optional.h" -#include "rust-ast-builder-type.h" #include "rust-ast.h" #include "rust-common.h" #include "rust-expr.h" @@ -29,7 +28,6 @@ #include "rust-pattern.h" #include "rust-system.h" #include "rust-token.h" -#include namespace Rust { namespace AST { @@ -331,6 +329,12 @@ Builder::block () const return block (std::move (stmts)); } +std::unique_ptr +Builder::block (std::unique_ptr &&tail_expr) const +{ + return block (tl::nullopt, std::move (tail_expr)); +} + std::unique_ptr Builder::block (std::vector> &&stmts, std::unique_ptr &&tail_expr) const @@ -442,6 +446,14 @@ Builder::field_access (std::unique_ptr &&instance, new FieldAccessExpr (std::move (instance), field, {}, loc)); } +std::unique_ptr +Builder::struct_pattern_ident_pattern (std::string field_name, + std::unique_ptr &&pattern) +{ + return std::make_unique ( + field_name, std::move (pattern), std::vector (), loc); +} + std::unique_ptr Builder::wildcard () const { @@ -482,9 +494,14 @@ MatchCase Builder::match_case (std::unique_ptr &&pattern, std::unique_ptr &&expr) { - return MatchCase (match_arm (std::move (pattern)), std::move (expr)); + return match_case (match_arm (std::move (pattern)), std::move (expr)); } +MatchCase +Builder::match_case (MatchArm &&arm, std::unique_ptr &&expr) +{ + return MatchCase (std::move (arm), std::move (expr)); +} std::unique_ptr Builder::loop (std::vector> &&stmts) { @@ -523,11 +540,14 @@ Builder::generic_type_param ( std::vector ()); } -std::unique_ptr -Builder::new_type (Type &type) +std::unique_ptr +Builder::discriminant_value (std::string binding_name, std::string instance) { - Type *t = ASTTypeBuilder::build (type); - return std::unique_ptr (t); + auto intrinsic = ptrify ( + path_in_expression ({"core", "intrinsics", "discriminant_value"}, true)); + + return let (identifier_pattern (binding_name), nullptr, + call (std::move (intrinsic), identifier (instance))); } std::unique_ptr @@ -546,6 +566,16 @@ Builder::new_lifetime_param (LifetimeParam ¶m) return std::unique_ptr (p); } +std::unique_ptr +Builder::new_const_param (ConstGenericParam ¶m) const +{ + return std::make_unique (param.get_name (), + param.get_type ().clone_type (), + param.get_default_value (), + param.get_outer_attrs (), + param.get_locus ()); +} + std::unique_ptr Builder::new_type_param ( TypeParam ¶m, std::vector> extra_bounds) @@ -557,7 +587,7 @@ Builder::new_type_param ( std::unique_ptr type = nullptr; if (param.has_type ()) - type = new_type (param.get_type ()); + type = param.get_type ().reconstruct (); for (auto &&extra_bound : extra_bounds) type_param_bounds.emplace_back (std::move (extra_bound)); @@ -566,7 +596,8 @@ Builder::new_type_param ( { switch (b->get_bound_type ()) { - case TypeParamBound::TypeParamBoundType::TRAIT: { + case TypeParamBound::TypeParamBoundType::TRAIT: + { const TraitBound &tb = (const TraitBound &) *b.get (); const TypePath &path = tb.get_type_path (); @@ -591,7 +622,8 @@ Builder::new_type_param ( { switch (seg->get_type ()) { - case TypePathSegment::REG: { + case TypePathSegment::REG: + { const TypePathSegment &segment = (const TypePathSegment &) (*seg.get ()); TypePathSegment *s = new TypePathSegment ( @@ -603,7 +635,8 @@ Builder::new_type_param ( } break; - case TypePathSegment::GENERIC: { + case TypePathSegment::GENERIC: + { TypePathSegmentGeneric &generic = (TypePathSegmentGeneric &) (*seg.get ()); @@ -617,7 +650,8 @@ Builder::new_type_param ( } break; - case TypePathSegment::FUNCTION: { + case TypePathSegment::FUNCTION: + { rust_unreachable (); // TODO // const TypePathSegmentFunction &fn @@ -639,7 +673,8 @@ Builder::new_type_param ( } break; - case TypeParamBound::TypeParamBoundType::LIFETIME: { + case TypeParamBound::TypeParamBoundType::LIFETIME: + { const Lifetime &l = (const Lifetime &) *b.get (); auto bl = new Lifetime (l.get_lifetime_type (), @@ -682,7 +717,7 @@ Builder::new_generic_args (GenericArgs &args) for (auto &binding : args.get_binding_args ()) { Type &t = *binding.get_type_ptr ().get (); - std::unique_ptr ty = new_type (t); + std::unique_ptr ty = t.reconstruct (); GenericArgsBinding b (binding.get_identifier (), std::move (ty), binding.get_locus ()); binding_args.push_back (std::move (b)); @@ -690,19 +725,25 @@ Builder::new_generic_args (GenericArgs &args) for (auto &arg : args.get_generic_args ()) { + tl::optional new_arg = tl::nullopt; + switch (arg.get_kind ()) { - case GenericArg::Kind::Type: { - std::unique_ptr ty = new_type (arg.get_type ()); - GenericArg arg = GenericArg::create_type (std::move (ty)); - } + case GenericArg::Kind::Type: + new_arg = GenericArg::create_type (arg.get_type ().reconstruct ()); break; - - default: - // FIXME - rust_unreachable (); + case GenericArg::Kind::Either: + new_arg + = GenericArg::create_ambiguous (arg.get_path (), arg.get_locus ()); + break; + case GenericArg::Kind::Const: + new_arg + = GenericArg::create_const (arg.get_expression ().clone_expr ()); + // FIXME: Use `reconstruct()` here, not `clone_expr()` break; } + + generic_args.emplace_back (*new_arg); } return GenericArgs (std::move (lifetime_args), std::move (generic_args), diff --git a/gcc/rust/ast/rust-ast-builder.h b/gcc/rust/ast/rust-ast-builder.h index 41ce118e7714..843bab896c74 100644 --- a/gcc/rust/ast/rust-ast-builder.h +++ b/gcc/rust/ast/rust-ast-builder.h @@ -24,6 +24,7 @@ #include "rust-ast.h" #include "rust-item.h" #include "rust-operators.h" +#include namespace Rust { namespace AST { @@ -51,6 +52,19 @@ vec (std::unique_ptr &&t1, std::unique_ptr &&t2) return v; } +template +std::vector> +vec (std::unique_ptr &&t1, std::unique_ptr &&t2, std::unique_ptr &&t3) +{ + auto v = std::vector> (); + + v.emplace_back (std::move (t1)); + v.emplace_back (std::move (t2)); + v.emplace_back (std::move (t3)); + + return v; +} + /* Pointer-ify something */ template static std::unique_ptr @@ -117,6 +131,9 @@ class Builder /* Create an empty block */ std::unique_ptr block () const; + /* Create a block with just a tail expression */ + std::unique_ptr block (std::unique_ptr &&tail_expr) const; + /* Create an early return expression with an optional expression */ std::unique_ptr return_expr (std::unique_ptr &&to_return = nullptr); @@ -254,6 +271,10 @@ class Builder std::unique_ptr field_access (std::unique_ptr &&instance, std::string field) const; + std::unique_ptr + struct_pattern_ident_pattern (std::string field_name, + std::unique_ptr &&pattern); + /* Create a wildcard pattern (`_`) */ std::unique_ptr wildcard () const; /* Create a reference pattern (`&pattern`) */ @@ -268,6 +289,7 @@ class Builder MatchArm match_arm (std::unique_ptr &&pattern); MatchCase match_case (std::unique_ptr &&pattern, std::unique_ptr &&expr); + MatchCase match_case (MatchArm &&arm, std::unique_ptr &&expr); /* Create a loop expression */ std::unique_ptr loop (std::vector> &&stmts); @@ -285,11 +307,20 @@ class Builder std::vector> &&bounds, std::unique_ptr &&type = nullptr); - static std::unique_ptr new_type (Type &type); + /** + * Create a let statement with the discriminant value of a given enum + * instance. This helper exists since it is a common operation in a lot of the + * derive implementations, and it sucks to repeat all the steps every time. + */ + std::unique_ptr discriminant_value (std::string binding_name, + std::string instance = "self"); static std::unique_ptr new_lifetime_param (LifetimeParam ¶m); + std::unique_ptr + new_const_param (ConstGenericParam ¶m) const; + static std::unique_ptr new_type_param ( TypeParam ¶m, std::vector> extra_trait_bounds = {}); @@ -298,11 +329,13 @@ class Builder static GenericArgs new_generic_args (GenericArgs &args); -private: - /** - * Location of the generated AST nodes - */ + /* Location of the generated AST nodes */ location_t loc; + +private: + /* Some constexpr helpers for some of the builders */ + static constexpr std::initializer_list discriminant_value_path + = {"core", "intrinsics", "discriminant_value"}; }; } // namespace AST diff --git a/gcc/rust/ast/rust-ast-collector.cc b/gcc/rust/ast/rust-ast-collector.cc index c850e965cf4d..4fe246d7a3ad 100644 --- a/gcc/rust/ast/rust-ast-collector.cc +++ b/gcc/rust/ast/rust-ast-collector.cc @@ -154,20 +154,24 @@ TokenCollector::visit (Attribute &attrib) { switch (attrib.get_attr_input ().get_attr_input_type ()) { - case AST::AttrInput::AttrInputType::LITERAL: { + case AST::AttrInput::AttrInputType::LITERAL: + { visit (static_cast (attrib.get_attr_input ())); break; } - case AST::AttrInput::AttrInputType::MACRO: { + case AST::AttrInput::AttrInputType::MACRO: + { visit (static_cast (attrib.get_attr_input ())); break; } - case AST::AttrInput::AttrInputType::META_ITEM: { + case AST::AttrInput::AttrInputType::META_ITEM: + { visit (static_cast ( attrib.get_attr_input ())); break; } - case AST::AttrInput::AttrInputType::TOKEN_TREE: { + case AST::AttrInput::AttrInputType::TOKEN_TREE: + { visit (static_cast (attrib.get_attr_input ())); break; } @@ -634,7 +638,8 @@ TokenCollector::visit (GenericArg &arg) case GenericArg::Kind::Type: visit (arg.get_type ()); break; - case GenericArg::Kind::Either: { + case GenericArg::Kind::Either: + { auto path = arg.get_path (); push (Rust::Token::make_identifier (UNDEF_LOCATION, std::move (path))); } @@ -789,7 +794,8 @@ TokenCollector::visit (Literal &lit, location_t locus) push (Rust::Token::make_float (locus, std::move (value), lit.get_type_hint ())); break; - case Literal::LitType::BOOL: { + case Literal::LitType::BOOL: + { if (value == Values::Keywords::FALSE_LITERAL) push (Rust::Token::make (FALSE_LITERAL, locus)); else if (value == Values::Keywords::TRUE_LITERAL) @@ -864,7 +870,8 @@ TokenCollector::visit (BorrowExpr &expr) push (Rust::Token::make (MUT, UNDEF_LOCATION)); } - visit (expr.get_borrowed_expr ()); + if (expr.has_borrow_expr ()) + visit (expr.get_borrowed_expr ()); } void @@ -1263,13 +1270,29 @@ TokenCollector::visit (BlockExpr &expr) newline (); } +void +TokenCollector::visit (AnonConst &expr) +{ + visit (expr.get_inner_expr ()); +} + +void +TokenCollector::visit (ConstBlock &expr) +{ + push (Rust::Token::make (CONST, expr.get_locus ())); + + // The inner expression is already a block expr, so we don't need to add + // curlies + visit (expr.get_const_expr ()); +} + void TokenCollector::visit (ClosureExprInnerTyped &expr) { visit_closure_common (expr); push (Rust::Token::make (RETURN_TYPE, expr.get_locus ())); visit (expr.get_return_type ()); - visit (expr.get_definition_block ()); + visit (expr.get_definition_expr ()); } void @@ -1348,6 +1371,13 @@ TokenCollector::visit (ReturnExpr &expr) visit (expr.get_returned_expr ()); } +void +TokenCollector::visit (TryExpr &expr) +{ + push (Rust::Token::make (TRY, expr.get_locus ())); + visit (expr.get_block_expr ()); +} + void TokenCollector::visit (UnsafeBlockExpr &expr) { @@ -1518,7 +1548,95 @@ TokenCollector::visit (AsyncBlockExpr &expr) void TokenCollector::visit (InlineAsm &expr) -{} +{ + push (Rust::Token::make_identifier (expr.get_locus (), "asm")); + push (Rust::Token::make (EXCLAM, expr.get_locus ())); + push (Rust::Token::make (LEFT_PAREN, expr.get_locus ())); + + for (auto &template_str : expr.get_template_strs ()) + push (Rust::Token::make_string (template_str.get_locus (), + std::move (template_str.symbol))); + + push (Rust::Token::make (COLON, expr.get_locus ())); + + for (auto &operand : expr.get_operands ()) + { + using RegisterType = AST::InlineAsmOperand::RegisterType; + switch (operand.get_register_type ()) + { + case RegisterType::In: + { + visit (operand.get_in ().expr); + break; + } + case RegisterType::Out: + { + visit (operand.get_out ().expr); + break; + } + case RegisterType::InOut: + { + visit (operand.get_in_out ().expr); + break; + } + case RegisterType::SplitInOut: + { + auto split = operand.get_split_in_out (); + visit (split.in_expr); + visit (split.out_expr); + break; + } + case RegisterType::Const: + { + visit (operand.get_const ().anon_const.get_inner_expr ()); + break; + } + case RegisterType::Sym: + { + visit (operand.get_sym ().expr); + break; + } + case RegisterType::Label: + { + visit (operand.get_label ().expr); + break; + } + } + push (Rust::Token::make (COMMA, expr.get_locus ())); + } + push (Rust::Token::make (COLON, expr.get_locus ())); + + for (auto &clobber : expr.get_clobber_abi ()) + { + push (Rust::Token::make_string (expr.get_locus (), + std::move (clobber.symbol))); + push (Rust::Token::make (COMMA, expr.get_locus ())); + } + push (Rust::Token::make (COLON, expr.get_locus ())); + + for (auto it = expr.named_args.begin (); it != expr.named_args.end (); ++it) + { + auto &arg = *it; + push ( + Rust::Token::make_identifier (expr.get_locus (), arg.first.c_str ())); + push (Rust::Token::make (EQUAL, expr.get_locus ())); + push (Rust::Token::make_identifier (expr.get_locus (), + std::to_string (arg.second))); + + push (Rust::Token::make (COMMA, expr.get_locus ())); + } + + push (Rust::Token::make (COLON, expr.get_locus ())); + + for (auto &option : expr.get_options ()) + { + push (Rust::Token::make_identifier ( + expr.get_locus (), InlineAsm::option_to_string (option).c_str ())); + push (Rust::Token::make (COMMA, expr.get_locus ())); + } + + push (Rust::Token::make (RIGHT_PAREN, expr.get_locus ())); +} void TokenCollector::visit (LlvmInlineAsm &expr) @@ -1695,7 +1813,8 @@ TokenCollector::visit (UseTreeGlob &use_tree) { switch (use_tree.get_glob_type ()) { - case UseTreeGlob::PathType::PATH_PREFIXED: { + case UseTreeGlob::PathType::PATH_PREFIXED: + { auto path = use_tree.get_path (); visit (path); push (Rust::Token::make (SCOPE_RESOLUTION, UNDEF_LOCATION)); @@ -1715,7 +1834,8 @@ TokenCollector::visit (UseTreeList &use_tree) { switch (use_tree.get_path_type ()) { - case UseTreeList::PathType::PATH_PREFIXED: { + case UseTreeList::PathType::PATH_PREFIXED: + { auto path = use_tree.get_path (); visit (path); push (Rust::Token::make (SCOPE_RESOLUTION, UNDEF_LOCATION)); @@ -1743,7 +1863,8 @@ TokenCollector::visit (UseTreeRebind &use_tree) visit (path); switch (use_tree.get_new_bind_type ()) { - case UseTreeRebind::NewBindType::IDENTIFIER: { + case UseTreeRebind::NewBindType::IDENTIFIER: + { push (Rust::Token::make (AS, UNDEF_LOCATION)); auto id = use_tree.get_identifier ().as_string (); push ( @@ -1964,8 +2085,7 @@ TokenCollector::visit (ConstantItem &item) } else { - auto id = item.get_identifier (); - push (Rust::Token::make_identifier (UNDEF_LOCATION, std::move (id))); + push (Rust::Token::make_identifier (item.get_identifier ())); } push (Rust::Token::make (COLON, UNDEF_LOCATION)); visit (item.get_type ()); @@ -2370,10 +2490,10 @@ TokenCollector::visit (IdentifierPattern &pattern) auto id = pattern.get_ident ().as_string (); push (Rust::Token::make_identifier (UNDEF_LOCATION, std::move (id))); - if (pattern.has_pattern_to_bind ()) + if (pattern.has_subpattern ()) { push (Rust::Token::make (PATTERN_BIND, UNDEF_LOCATION)); - visit (pattern.get_pattern_to_bind ()); + visit (pattern.get_subpattern ()); } } diff --git a/gcc/rust/ast/rust-ast-collector.h b/gcc/rust/ast/rust-ast-collector.h index f45e3cc51aee..e8af5878a2cd 100644 --- a/gcc/rust/ast/rust-ast-collector.h +++ b/gcc/rust/ast/rust-ast-collector.h @@ -277,6 +277,8 @@ class TokenCollector : public ASTVisitor void visit (ClosureParam ¶m); void visit (ClosureExprInner &expr); void visit (BlockExpr &expr); + void visit (AnonConst &expr); + void visit (ConstBlock &expr); void visit (ClosureExprInnerTyped &expr); void visit (ContinueExpr &expr); void visit (BreakExpr &expr); @@ -287,6 +289,7 @@ class TokenCollector : public ASTVisitor void visit (RangeFromToInclExpr &expr); void visit (RangeToInclExpr &expr); void visit (ReturnExpr &expr); + void visit (TryExpr &expr); void visit (BoxExpr &expr); void visit (UnsafeBlockExpr &expr); void visit (LoopExpr &expr); diff --git a/gcc/rust/ast/rust-ast-dump.h b/gcc/rust/ast/rust-ast-dump.h index 02c99b7ae1ec..0c3875e28233 100644 --- a/gcc/rust/ast/rust-ast-dump.h +++ b/gcc/rust/ast/rust-ast-dump.h @@ -49,7 +49,8 @@ class Dump { switch (item.get_kind ()) { - case AST::CollectItem::Kind::Token: { + case AST::CollectItem::Kind::Token: + { TokenPtr current = item.get_token (); if (require_spacing (previous, current)) stream << " "; @@ -90,7 +91,6 @@ class Dump } // namespace Rust // In the global namespace to make it easier to call from debugger -void -debug (Rust::AST::Visitable &v); +void debug (Rust::AST::Visitable &v); #endif // !RUST_AST_DUMP_H diff --git a/gcc/rust/ast/rust-ast-formatting.h b/gcc/rust/ast/rust-ast-formatting.h index 3dfabbcccc60..aace93f7fae8 100644 --- a/gcc/rust/ast/rust-ast-formatting.h +++ b/gcc/rust/ast/rust-ast-formatting.h @@ -35,23 +35,18 @@ enum AttrMode INNER }; -std::string -indent_spaces (enum indent_mode mode); +std::string indent_spaces (enum indent_mode mode); // Gets a string in a certain delim type. -std::string -get_string_in_delims (std::string str_input, DelimType delim_type); +std::string get_string_in_delims (std::string str_input, DelimType delim_type); -std::string -get_mode_dump_desc (AttrMode mode); +std::string get_mode_dump_desc (AttrMode mode); // Adds lines below adding attributes -std::string -append_attributes (std::vector attrs, AttrMode mode); +std::string append_attributes (std::vector attrs, AttrMode mode); // Removes the beginning and end quotes of a quoted string. -std::string -unquote_string (std::string input); +std::string unquote_string (std::string input); } // namespace AST } // namespace Rust diff --git a/gcc/rust/ast/rust-ast-full-decls.h b/gcc/rust/ast/rust-ast-full-decls.h index 9359248aabd5..eb1f3ea890c7 100644 --- a/gcc/rust/ast/rust-ast-full-decls.h +++ b/gcc/rust/ast/rust-ast-full-decls.h @@ -115,6 +115,8 @@ struct ClosureParam; class ClosureExpr; class ClosureExprInner; class BlockExpr; +class AnonConst; +class ConstBlock; class ClosureExprInnerTyped; class ContinueExpr; class BreakExpr; @@ -126,6 +128,7 @@ class RangeFullExpr; class RangeFromToInclExpr; class RangeToInclExpr; class ReturnExpr; +class TryExpr; class UnsafeBlockExpr; class LoopLabel; class BaseLoopExpr; @@ -146,7 +149,6 @@ class MatchExpr; class AwaitExpr; class AsyncBlockExpr; enum class InlineAsmOption; -struct AnonConst; struct InlineAsmRegOrRegClass; class InlineAsmOperand; struct InlineAsmPlaceHolder; diff --git a/gcc/rust/ast/rust-ast-visitor.cc b/gcc/rust/ast/rust-ast-visitor.cc index b6833f69314e..32d5d32e43fe 100644 --- a/gcc/rust/ast/rust-ast-visitor.cc +++ b/gcc/rust/ast/rust-ast-visitor.cc @@ -455,6 +455,19 @@ DefaultASTVisitor::visit (AST::BlockExpr &expr) visit (expr.get_tail_expr ()); } +void +DefaultASTVisitor::visit (AST::ConstBlock &expr) +{ + visit (expr.get_const_expr ()); +} + +void +DefaultASTVisitor::visit (AST::AnonConst &expr) +{ + if (!expr.is_deferred ()) + visit (expr.get_inner_expr ()); +} + void DefaultASTVisitor::visit (AST::ClosureExprInnerTyped &expr) { @@ -462,7 +475,7 @@ DefaultASTVisitor::visit (AST::ClosureExprInnerTyped &expr) for (auto ¶m : expr.get_params ()) visit (param); visit (expr.get_return_type ()); - visit (expr.get_definition_block ()); + visit (expr.get_definition_expr ()); } void @@ -537,6 +550,13 @@ DefaultASTVisitor::visit (AST::ReturnExpr &expr) visit (expr.get_returned_expr ()); } +void +DefaultASTVisitor::visit (AST::TryExpr &expr) +{ + visit_outer_attrs (expr); + visit (expr.get_block_expr ()); +} + void DefaultASTVisitor::visit (AST::BoxExpr &expr) { @@ -582,7 +602,10 @@ DefaultASTVisitor::visit (AST::WhileLetLoopExpr &expr) visit_outer_attrs (expr); for (auto &pattern : expr.get_patterns ()) visit (pattern); - visit (expr.get_loop_label ()); + + if (expr.has_loop_label ()) + visit (expr.get_loop_label ()); + visit (expr.get_scrutinee_expr ()); visit (expr.get_loop_block ()); } @@ -680,33 +703,40 @@ DefaultASTVisitor::visit (AST::InlineAsm &expr) { switch (operand.get_register_type ()) { - case RegisterType::In: { + case RegisterType::In: + { visit (operand.get_in ().expr); break; } - case RegisterType::Out: { + case RegisterType::Out: + { visit (operand.get_out ().expr); break; } - case RegisterType::InOut: { + case RegisterType::InOut: + { visit (operand.get_in_out ().expr); break; } - case RegisterType::SplitInOut: { + case RegisterType::SplitInOut: + { auto split = operand.get_split_in_out (); visit (split.in_expr); visit (split.out_expr); break; } - case RegisterType::Const: { - visit (operand.get_const ().anon_const.expr); + case RegisterType::Const: + { + visit (operand.get_const ().anon_const.get_inner_expr ()); break; } - case RegisterType::Sym: { + case RegisterType::Sym: + { visit (operand.get_sym ().expr); break; } - case RegisterType::Label: { + case RegisterType::Label: + { visit (operand.get_label ().expr); break; } @@ -755,7 +785,8 @@ DefaultASTVisitor::visit (AST::TypeBoundWhereClauseItem &item) void DefaultASTVisitor::visit (AST::Visibility &vis) { - visit (vis.get_path ()); + if (vis.has_path ()) + visit (vis.get_path ()); } void @@ -922,7 +953,7 @@ DefaultASTVisitor::visit (AST::EnumItem &item) void DefaultASTVisitor::visit (AST::EnumItemTuple &item) { - visit (reinterpret_cast (item)); + DefaultASTVisitor::visit (static_cast (item)); for (auto &field : item.get_tuple_fields ()) visit (field); } @@ -930,7 +961,7 @@ DefaultASTVisitor::visit (AST::EnumItemTuple &item) void DefaultASTVisitor::visit (AST::EnumItemStruct &item) { - visit (reinterpret_cast (item)); + DefaultASTVisitor::visit (static_cast (item)); for (auto &field : item.get_struct_fields ()) visit (field); } @@ -938,7 +969,7 @@ DefaultASTVisitor::visit (AST::EnumItemStruct &item) void DefaultASTVisitor::visit (AST::EnumItemDiscriminant &item) { - visit (reinterpret_cast (item)); + DefaultASTVisitor::visit (static_cast (item)); visit (item.get_expr ()); } @@ -1179,8 +1210,8 @@ DefaultASTVisitor::visit (AST::LiteralPattern &pattern) void DefaultASTVisitor::visit (AST::IdentifierPattern &pattern) { - if (pattern.has_pattern_to_bind ()) - visit (pattern.get_pattern_to_bind ()); + if (pattern.has_subpattern ()) + visit (pattern.get_subpattern ()); } void diff --git a/gcc/rust/ast/rust-ast-visitor.h b/gcc/rust/ast/rust-ast-visitor.h index b1fc50465a1a..6111b0548edc 100644 --- a/gcc/rust/ast/rust-ast-visitor.h +++ b/gcc/rust/ast/rust-ast-visitor.h @@ -104,6 +104,8 @@ class ASTVisitor virtual void visit (FieldAccessExpr &expr) = 0; virtual void visit (ClosureExprInner &expr) = 0; virtual void visit (BlockExpr &expr) = 0; + virtual void visit (AnonConst &expr) = 0; + virtual void visit (ConstBlock &expr) = 0; virtual void visit (ClosureExprInnerTyped &expr) = 0; virtual void visit (ContinueExpr &expr) = 0; virtual void visit (BreakExpr &expr) = 0; @@ -114,6 +116,7 @@ class ASTVisitor virtual void visit (RangeFromToInclExpr &expr) = 0; virtual void visit (RangeToInclExpr &expr) = 0; virtual void visit (ReturnExpr &expr) = 0; + virtual void visit (TryExpr &expr) = 0; virtual void visit (BoxExpr &expr) = 0; virtual void visit (UnsafeBlockExpr &expr) = 0; virtual void visit (LoopExpr &expr) = 0; @@ -293,6 +296,8 @@ class DefaultASTVisitor : public ASTVisitor virtual void visit (AST::FieldAccessExpr &expr) override; virtual void visit (AST::ClosureExprInner &expr) override; virtual void visit (AST::BlockExpr &expr) override; + virtual void visit (AST::AnonConst &expr) override; + virtual void visit (AST::ConstBlock &expr) override; virtual void visit (AST::ClosureExprInnerTyped &expr) override; virtual void visit (AST::ContinueExpr &expr) override; virtual void visit (AST::BreakExpr &expr) override; @@ -303,6 +308,7 @@ class DefaultASTVisitor : public ASTVisitor virtual void visit (AST::RangeFromToInclExpr &expr) override; virtual void visit (AST::RangeToInclExpr &expr) override; virtual void visit (AST::ReturnExpr &expr) override; + virtual void visit (AST::TryExpr &expr) override; virtual void visit (AST::BoxExpr &expr) override; virtual void visit (AST::UnsafeBlockExpr &expr) override; virtual void visit (AST::LoopExpr &expr) override; diff --git a/gcc/rust/ast/rust-ast.cc b/gcc/rust/ast/rust-ast.cc index 4e82be420fe1..2b7ee5cb8bf0 100644 --- a/gcc/rust/ast/rust-ast.cc +++ b/gcc/rust/ast/rust-ast.cc @@ -33,6 +33,7 @@ along with GCC; see the file COPYING3. If not see #include "rust-operators.h" #include "rust-dir-owner.h" #include "rust-attribute-values.h" +#include "rust-macro-invoc-lexer.h" /* Compilation unit used for various AST-related functions that would make * the headers too long if they were defined inline and don't receive any @@ -249,27 +250,31 @@ Attribute::get_traits_to_derive () auto &input = get_attr_input (); switch (input.get_attr_input_type ()) { - case AST::AttrInput::META_ITEM: { + case AST::AttrInput::META_ITEM: + { auto &meta = static_cast (input); for (auto ¤t : meta.get_items ()) { // HACK: Find a better way to achieve the downcast. switch (current->get_kind ()) { - case AST::MetaItemInner::Kind::MetaItem: { + case AST::MetaItemInner::Kind::MetaItem: + { // Let raw pointer go out of scope without freeing, it doesn't // own the data anyway auto meta_item = static_cast (current.get ()); switch (meta_item->get_item_kind ()) { - case AST::MetaItem::ItemKind::Path: { + case AST::MetaItem::ItemKind::Path: + { auto path = static_cast (meta_item); result.push_back (path->get_path ()); } break; - case AST::MetaItem::ItemKind::Word: { + case AST::MetaItem::ItemKind::Word: + { auto word = static_cast (meta_item); // Convert current word to path current = std::make_unique ( @@ -620,7 +625,7 @@ ConstantItem::as_string () const { std::string str = VisItem::as_string (); - str += "const " + identifier; + str += "const " + identifier.as_string (); // DEBUG: null pointer check if (type == nullptr) @@ -782,7 +787,8 @@ UseTreeGlob::as_string () const return "*"; case GLOBAL: return "::*"; - case PATH_PREFIXED: { + case PATH_PREFIXED: + { std::string path_str = path.as_string (); return path_str + "::*"; } @@ -805,7 +811,8 @@ UseTreeList::as_string () const case GLOBAL: path_str = "::{"; break; - case PATH_PREFIXED: { + case PATH_PREFIXED: + { path_str = path.as_string () + "::{"; break; } @@ -1271,6 +1278,25 @@ BlockExpr::as_string () const return str; } +std::string +AnonConst::as_string () const +{ + std::string str = "AnonConst: "; + + if (kind == AnonConst::Kind::DeferredInference) + str += "_"; + else + str += expr.value ()->as_string (); + + return str; +} + +std::string +ConstBlock::as_string () const +{ + return "ConstBlock: " + expr.as_string (); +} + std::string TraitImpl::as_string () const { @@ -1618,6 +1644,19 @@ ReturnExpr::as_string () const return str; } +std::string +TryExpr::as_string () const +{ + /* TODO: find way to incorporate outer attrs - may have to represent in + * different style (i.e. something more like BorrowExpr: \n outer attrs) */ + + std::string str ("try "); + + str += block_expr->as_string (); + + return str; +} + std::string RangeToExpr::as_string () const { @@ -2714,7 +2753,7 @@ ImplTraitTypeOneBound::as_string () const { std::string str ("ImplTraitTypeOneBound: \n TraitBound: "); - return str + trait_bound.as_string (); + return str + trait_bound->as_string (); } std::string @@ -2736,7 +2775,7 @@ std::string ArrayType::as_string () const { // TODO: rewrite to work with non-linearisable types and exprs - return "[" + elem_type->as_string () + "; " + size->as_string () + "]"; + return "[" + elem_type->as_string () + "; " + size.as_string () + "]"; } std::string @@ -3477,6 +3516,17 @@ DelimTokenTree::parse_to_meta_item () const return new AttrInputMetaItemContainer (std::move (meta_items)); } +AttributeParser::AttributeParser ( + std::vector> token_stream, int stream_start_pos) + : lexer (new MacroInvocLexer (std::move (token_stream))), + parser (new Parser (*lexer)) +{ + if (stream_start_pos) + lexer->skip_token (stream_start_pos - 1); +} + +AttributeParser::~AttributeParser () {} + std::unique_ptr AttributeParser::parse_meta_item_inner () { @@ -3518,7 +3568,7 @@ AttributeParser::parse_meta_item_inner () return parse_path_meta_item (); } - auto ident = peek_token ()->as_string (); + auto ident = peek_token ()->get_str (); auto ident_locus = peek_token ()->get_locus (); if (is_end_meta_item_tok (peek_token (1)->get_id ())) @@ -3535,17 +3585,14 @@ AttributeParser::parse_meta_item_inner () && is_end_meta_item_tok (peek_token (3)->get_id ())) { // meta name value str syntax - auto &value_tok = peek_token (2); - auto value = value_tok->as_string (); + const_TokenPtr value_tok = peek_token (2); + auto value = value_tok->get_str (); auto locus = value_tok->get_locus (); skip_token (2); - // remove the quotes from the string value - std::string raw_value = unquote_string (std::move (value)); - return std::unique_ptr ( - new MetaNameValueStr (ident, ident_locus, std::move (raw_value), + new MetaNameValueStr (ident, ident_locus, std::move (value), locus)); } else @@ -3653,14 +3700,16 @@ AttributeParser::parse_path_meta_item () switch (peek_token ()->get_id ()) { - case LEFT_PAREN: { + case LEFT_PAREN: + { std::vector> meta_items = parse_meta_item_seq (); return std::unique_ptr ( new MetaItemSeq (std::move (path), std::move (meta_items))); } - case EQUAL: { + case EQUAL: + { skip_token (); location_t locus = peek_token ()->get_locus (); @@ -3695,7 +3744,6 @@ AttributeParser::parse_path_meta_item () std::vector> AttributeParser::parse_meta_item_seq () { - int vec_length = token_stream.size (); std::vector> meta_items; if (peek_token ()->get_id () != LEFT_PAREN) @@ -3706,7 +3754,8 @@ AttributeParser::parse_meta_item_seq () } skip_token (); - while (stream_pos < vec_length && peek_token ()->get_id () != RIGHT_PAREN) + while (peek_token ()->get_id () != END_OF_FILE + && peek_token ()->get_id () != RIGHT_PAREN) { std::unique_ptr inner = parse_meta_item_inner (); if (inner == nullptr) @@ -3755,33 +3804,32 @@ DelimTokenTree::to_token_stream () const Literal AttributeParser::parse_literal () { - const std::unique_ptr &tok = peek_token (); + const_TokenPtr tok = peek_token (); switch (tok->get_id ()) { case CHAR_LITERAL: skip_token (); - return Literal (tok->as_string (), Literal::CHAR, tok->get_type_hint ()); + return Literal (tok->get_str (), Literal::CHAR, tok->get_type_hint ()); case STRING_LITERAL: skip_token (); - return Literal (tok->as_string (), Literal::STRING, - tok->get_type_hint ()); + return Literal (tok->get_str (), Literal::STRING, tok->get_type_hint ()); case BYTE_CHAR_LITERAL: skip_token (); - return Literal (tok->as_string (), Literal::BYTE, tok->get_type_hint ()); + return Literal (tok->get_str (), Literal::BYTE, tok->get_type_hint ()); case BYTE_STRING_LITERAL: skip_token (); - return Literal (tok->as_string (), Literal::BYTE_STRING, + return Literal (tok->get_str (), Literal::BYTE_STRING, tok->get_type_hint ()); case RAW_STRING_LITERAL: skip_token (); - return Literal (tok->as_string (), Literal::RAW_STRING, + return Literal (tok->get_str (), Literal::RAW_STRING, tok->get_type_hint ()); case INT_LITERAL: skip_token (); - return Literal (tok->as_string (), Literal::INT, tok->get_type_hint ()); + return Literal (tok->get_str (), Literal::INT, tok->get_type_hint ()); case FLOAT_LITERAL: skip_token (); - return Literal (tok->as_string (), Literal::FLOAT, tok->get_type_hint ()); + return Literal (tok->get_str (), Literal::FLOAT, tok->get_type_hint ()); case TRUE_LITERAL: skip_token (); return Literal ("true", Literal::BOOL, tok->get_type_hint ()); @@ -3839,12 +3887,12 @@ AttributeParser::parse_simple_path () SimplePathSegment AttributeParser::parse_simple_path_segment () { - const std::unique_ptr &tok = peek_token (); + const_TokenPtr tok = peek_token (); switch (tok->get_id ()) { case IDENTIFIER: skip_token (); - return SimplePathSegment (tok->as_string (), tok->get_locus ()); + return SimplePathSegment (tok->get_str (), tok->get_locus ()); case SUPER: skip_token (); return SimplePathSegment ("super", tok->get_locus ()); @@ -3878,6 +3926,18 @@ AttributeParser::parse_meta_item_lit () new MetaItemLitExpr (std::move (lit_expr))); } +const_TokenPtr +AttributeParser::peek_token (int i) +{ + return lexer->peek_token (i); +} + +void +AttributeParser::skip_token (int i) +{ + lexer->skip_token (i); +} + bool AttrInputMetaItemContainer::check_cfg_predicate (const Session &session) const { @@ -4512,6 +4572,18 @@ BlockExpr::accept_vis (ASTVisitor &vis) vis.visit (*this); } +void +AnonConst::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +ConstBlock::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + void ClosureExprInnerTyped::accept_vis (ASTVisitor &vis) { @@ -4572,6 +4644,12 @@ ReturnExpr::accept_vis (ASTVisitor &vis) vis.visit (*this); } +void +TryExpr::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + void UnsafeBlockExpr::accept_vis (ASTVisitor &vis) { @@ -5047,7 +5125,8 @@ FormatArgs::get_outer_attrs () rust_unreachable (); } -void FormatArgs::set_outer_attrs (std::vector) +void +FormatArgs::set_outer_attrs (std::vector) { rust_unreachable (); } diff --git a/gcc/rust/ast/rust-ast.h b/gcc/rust/ast/rust-ast.h index aa6ad5066aa1..0d853e744c76 100644 --- a/gcc/rust/ast/rust-ast.h +++ b/gcc/rust/ast/rust-ast.h @@ -62,13 +62,14 @@ class Identifier return ident == other.ident; } + operator const std::string & () const { return ident; } + private: std::string ident; location_t loc; }; -std::ostream & -operator<< (std::ostream &os, Identifier const &i); +std::ostream &operator<< (std::ostream &os, Identifier const &i); namespace AST { // foward decl: ast visitor @@ -82,6 +83,38 @@ class Visitable virtual void accept_vis (ASTVisitor &vis) = 0; }; +/** + * Base function for reconstructing and asserting that the new NodeId is + * different from the old NodeId. It then wraps the given pointer into a unique + * pointer and returns it. + */ +template +std::unique_ptr +reconstruct_base (const T *instance) +{ + auto *reconstructed = instance->reconstruct_impl (); + + rust_assert (reconstructed->get_node_id () != instance->get_node_id ()); + + return std::unique_ptr (reconstructed); +} + +/** + * Reconstruct multiple items in a vector + */ +template +std::vector> +reconstruct_vec (const std::vector> &to_reconstruct) +{ + std::vector> reconstructed; + reconstructed.reserve (to_reconstruct.size ()); + + for (const auto &elt : to_reconstruct) + reconstructed.emplace_back (std::unique_ptr (elt->reconstruct_impl ())); + + return reconstructed; +} + // Delimiter types - used in macros and whatever. enum DelimType { @@ -403,15 +436,15 @@ class SimplePath public: // Constructor - SimplePath (std::vector path_segments, - bool has_opening_scope_resolution = false, - location_t locus = UNDEF_LOCATION) + explicit SimplePath (std::vector path_segments, + bool has_opening_scope_resolution = false, + location_t locus = UNDEF_LOCATION) : opening_scope_resolution (has_opening_scope_resolution), segments (std::move (path_segments)), locus (locus), node_id (Analysis::Mappings::get ().get_next_node_id ()) {} - SimplePath (Identifier ident) + explicit SimplePath (Identifier ident) : opening_scope_resolution (false), segments ({SimplePathSegment (ident.as_string (), ident.get_locus ())}), locus (ident.get_locus ()), @@ -1256,6 +1289,8 @@ class Expr : public Visitable FieldAccess, Closure, Block, + ConstExpr, + ConstBlock, Continue, Break, Range, @@ -1477,6 +1512,10 @@ class Type : public Visitable return std::unique_ptr (clone_type_impl ()); } + // Similar to `clone_type`, but generates a new instance of the node with a + // different NodeId + std::unique_ptr reconstruct () const { return reconstruct_base (this); } + // virtual destructor virtual ~Type () {} @@ -1495,11 +1534,13 @@ class Type : public Visitable virtual location_t get_locus () const = 0; NodeId get_node_id () const { return node_id; } + virtual Type *reconstruct_impl () const = 0; protected: Type () : node_id (Analysis::Mappings::get ().get_next_node_id ()) {} + Type (NodeId node_id) : node_id (node_id) {} - // Clone function implementation as pure virtual method + // Clone and reconstruct function implementations as pure virtual methods virtual Type *clone_type_impl () const = 0; NodeId node_id; @@ -1515,6 +1556,13 @@ class TypeNoBounds : public Type return std::unique_ptr (clone_type_no_bounds_impl ()); } + std::unique_ptr reconstruct () const + { + return reconstruct_base (this); + } + + virtual TypeNoBounds *reconstruct_impl () const override = 0; + protected: // Clone function implementation as pure virtual method virtual TypeNoBounds *clone_type_no_bounds_impl () const = 0; @@ -1549,6 +1597,11 @@ class TypeParamBound : public Visitable return std::unique_ptr (clone_type_param_bound_impl ()); } + std::unique_ptr reconstruct () const + { + return reconstruct_base (this); + } + virtual std::string as_string () const = 0; NodeId get_node_id () const { return node_id; } @@ -1557,10 +1610,14 @@ class TypeParamBound : public Visitable virtual TypeParamBoundType get_bound_type () const = 0; + virtual TypeParamBound *reconstruct_impl () const = 0; + protected: // Clone function implementation as pure virtual method virtual TypeParamBound *clone_type_param_bound_impl () const = 0; + TypeParamBound () : node_id (Analysis::Mappings::get ().get_next_node_id ()) + {} TypeParamBound (NodeId node_id) : node_id (node_id) {} NodeId node_id; @@ -1622,6 +1679,10 @@ class Lifetime : public TypeParamBound { return new Lifetime (node_id, lifetime_type, lifetime_name, locus); } + Lifetime *reconstruct_impl () const override + { + return new Lifetime (lifetime_type, lifetime_name, locus); + } }; /* Base generic parameter in AST. Abstract - can be represented by a Lifetime diff --git a/gcc/rust/ast/rust-collect-lang-items.cc b/gcc/rust/ast/rust-collect-lang-items.cc index cd6be7fbeb9c..306c6f747e2b 100644 --- a/gcc/rust/ast/rust-collect-lang-items.cc +++ b/gcc/rust/ast/rust-collect-lang-items.cc @@ -109,5 +109,29 @@ CollectLangItems::visit (AST::EnumItem &item) DefaultASTVisitor::visit (item); } +void +CollectLangItems::visit (AST::EnumItemTuple &item) +{ + maybe_add_lang_item (item); + + DefaultASTVisitor::visit (item); +} + +void +CollectLangItems::visit (AST::EnumItemStruct &item) +{ + maybe_add_lang_item (item); + + DefaultASTVisitor::visit (item); +} + +void +CollectLangItems::visit (AST::EnumItemDiscriminant &item) +{ + maybe_add_lang_item (item); + + DefaultASTVisitor::visit (item); +} + } // namespace AST } // namespace Rust diff --git a/gcc/rust/ast/rust-collect-lang-items.h b/gcc/rust/ast/rust-collect-lang-items.h index ddb34a914ed7..ddc7b51313bd 100644 --- a/gcc/rust/ast/rust-collect-lang-items.h +++ b/gcc/rust/ast/rust-collect-lang-items.h @@ -50,6 +50,9 @@ class CollectLangItems : public DefaultASTVisitor void visit (AST::Function &item) override; void visit (AST::StructStruct &item) override; void visit (AST::EnumItem &item) override; + void visit (AST::EnumItemTuple &item) override; + void visit (AST::EnumItemStruct &item) override; + void visit (AST::EnumItemDiscriminant &item) override; private: template void maybe_add_lang_item (const T &item); diff --git a/gcc/rust/ast/rust-cond-compilation.h b/gcc/rust/ast/rust-cond-compilation.h index 610b9046f455..56a5646704a8 100644 --- a/gcc/rust/ast/rust-cond-compilation.h +++ b/gcc/rust/ast/rust-cond-compilation.h @@ -42,8 +42,8 @@ class ConfigurationPredicate protected: // Clone function impl to be overriden in base classes - virtual ConfigurationPredicate * - clone_configuration_predicate_impl () const = 0; + virtual ConfigurationPredicate *clone_configuration_predicate_impl () const + = 0; }; // A configuration option - true if option is set, false if option is not set. diff --git a/gcc/rust/ast/rust-desugar-apit.cc b/gcc/rust/ast/rust-desugar-apit.cc new file mode 100644 index 000000000000..bca14eef1eab --- /dev/null +++ b/gcc/rust/ast/rust-desugar-apit.cc @@ -0,0 +1,522 @@ +// Copyright (C) 2025 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 +// . + +#include "rust-desugar-apit.h" +#include "rust-ast.h" +#include "rust-type.h" + +namespace Rust { +namespace AST { + +class DesugarApitType : public DefaultASTVisitor +{ + using DefaultASTVisitor::visit; + +public: + static std::pair>> + Desugar (AST::Type &type) + { + DesugarApitType visitor (&type); + type.accept_vis (visitor); + rust_assert (visitor.translated != nullptr); + return std::make_pair (visitor.translated, + std::move (visitor.implicit_generic_params)); + } + + // Generate a unique impl trait parameter name + static Identifier get_impl_name () + { + static size_t counter = 0; + return Identifier ("Impl_" + std::to_string (counter++)); + } + + // these can hold other types + void visit (AST::TupleType &tuple) override + { + for (auto &elem : tuple.get_elems ()) + { + auto &type = *elem.get (); + auto desugar = Desugar (type); + auto tt = desugar.first; + + auto &implicit_generics = desugar.second; + if (implicit_generics.empty ()) + continue; + + if (tt != elem.get ()) + elem = std::unique_ptr (tt); + + for (auto &implicit_generic : implicit_generics) + implicit_generic_params.push_back (std::move (implicit_generic)); + } + } + + void visit (AST::ArrayType &type) override + { + auto &element_type = type.get_element_type (); + auto desugar = Desugar (*element_type); + auto tt = desugar.first; + + auto &implicit_generics = desugar.second; + if (implicit_generics.empty ()) + return; + + if (tt != element_type.get ()) + element_type = std::unique_ptr (tt); + + for (auto &implicit_generic : implicit_generics) + implicit_generic_params.push_back (std::move (implicit_generic)); + } + + void visit (AST::ReferenceType &type) override + { + // Get a reference to the current type for in-place modification + auto &referenced_type = type.get_type_referenced (); + auto desugar = Desugar (referenced_type); + auto tt = desugar.first; + + auto &implicit_generics = desugar.second; + if (implicit_generics.empty ()) + return; + + // Update the reference type's contents rather than creating a new one + if (&referenced_type != tt) + { + std::unique_ptr new_type_no_bounds ( + static_cast (tt)); + type.get_type_ptr () = std::move (new_type_no_bounds); + } + + // Collect all the implicit generic parameters we found + for (auto &implicit_generic : implicit_generics) + implicit_generic_params.push_back (std::move (implicit_generic)); + } + + void visit (AST::RawPointerType &type) override + { + auto &pointed_type = type.get_type_pointed_to (); + auto desugar = Desugar (pointed_type); + auto tt = desugar.first; + + auto &implicit_generics = desugar.second; + if (implicit_generics.empty ()) + return; + + // Update the pointer's inner type directly using the new accessor + if (&pointed_type != tt) + { + std::unique_ptr new_type_no_bounds ( + static_cast (tt)); + type.get_type_ptr () = std::move (new_type_no_bounds); + } + + // Collect all the implicit generic parameters we found + for (auto &implicit_generic : implicit_generics) + implicit_generic_params.push_back (std::move (implicit_generic)); + } + + void visit (AST::SliceType &type) override + { + auto &element_type = type.get_elem_type (); + auto desugar = Desugar (element_type); + auto tt = desugar.first; + + auto &implicit_generics = desugar.second; + if (implicit_generics.empty ()) + return; + + if (&element_type != tt) + { + std::unique_ptr new_elem_type (tt); + type.get_elem_type_ptr () = std::move (new_elem_type); + } + + // Collect all the implicit generic parameters we found + for (auto &implicit_generic : implicit_generics) + implicit_generic_params.push_back (std::move (implicit_generic)); + } + + void visit (AST::ParenthesisedType &type) override + { + auto &inner_type_ptr = type.get_type_in_parens (); + auto desugar = Desugar (*inner_type_ptr); + auto tt = desugar.first; + + auto &implicit_generics = desugar.second; + if (implicit_generics.empty ()) + return; + + if (inner_type_ptr.get () != tt) + { + std::unique_ptr new_inner_type (tt); + inner_type_ptr = std::move (new_inner_type); + } + + // Collect all the implicit generic parameters we found + for (auto &implicit_generic : implicit_generics) + implicit_generic_params.push_back (std::move (implicit_generic)); + } + + // this is where the desugar happens + void visit (AST::ImplTraitType &type) override + { + // Generate a unique name using the static method + auto ident = get_impl_name (); + + // Create a type path for the new generic parameter + // Create a SimplePathSegment with the identifier string + auto simple_seg = SimplePathSegment (ident.as_string (), type.get_locus ()); + // Create a vector of SimplePathSegments for SimplePath constructor + std::vector simple_segs = {simple_seg}; + // Create a SimplePath + auto simple_path = SimplePath (simple_segs, false, type.get_locus ()); + + // Convert to TypePath by creating path segments + std::vector> segments; + segments.push_back (std::unique_ptr (new TypePathSegment ( + PathIdentSegment (ident.as_string (), type.get_locus ()), false, + type.get_locus ()))); + + // Create TypePath from segments + auto type_path + = new TypePath (std::move (segments), type.get_locus (), false); + + // Convert bounds from impl trait to generic parameter bounds + std::vector> bounds; + for (auto &bound : type.get_type_param_bounds ()) + bounds.push_back (bound->clone_type_param_bound ()); + + // Create the new generic parameter + auto generic_param = std::unique_ptr ( + new TypeParam (ident, type.get_locus (), std::move (bounds), nullptr, {}, + true /*from impl trait*/)); + + // Store the generic parameter to be added to the function signature + implicit_generic_params.push_back (std::move (generic_param)); + + // Replace impl trait with the new type parameter + translated = type_path; + } + + void visit (AST::ImplTraitTypeOneBound &type) override + { + // Generate a unique name using the static method + auto ident = get_impl_name (); + + // Create a type path for the new generic parameter + // Create a SimplePathSegment with the identifier string + auto simple_seg = SimplePathSegment (ident.as_string (), type.get_locus ()); + // Create a vector of SimplePathSegments for SimplePath constructor + std::vector simple_segs = {simple_seg}; + // Create a SimplePath + auto simple_path = SimplePath (simple_segs, false, type.get_locus ()); + + // Convert to TypePath by creating path segments + std::vector> segments; + segments.push_back (std::unique_ptr (new TypePathSegment ( + PathIdentSegment (ident.as_string (), type.get_locus ()), false, + type.get_locus ()))); + + // Create TypePath from segments + auto type_path + = new TypePath (std::move (segments), type.get_locus (), false); + + // Convert the bound to a generic parameter bound + std::vector> bounds; + bounds.push_back (std::move (type.get_trait_bound ())); + + // Create the new generic parameter + auto generic_param = std::unique_ptr ( + new TypeParam (ident, type.get_locus (), std::move (bounds), nullptr, {}, + true /*from impl trait*/)); + + // Store the generic parameter to be added to the function signature + implicit_generic_params.push_back (std::move (generic_param)); + + // Replace impl trait with the new type parameter + translated = type_path; + } + +private: + DesugarApitType (AST::Type *base) + : translated (base), implicit_generic_params () + {} + + AST::Type *translated; + std::vector> implicit_generic_params; +}; + +// --------- + +class ApitBoundProcessor +{ +public: + ApitBoundProcessor ( + WhereClause &where_clause, + std::vector> &generic_params) + : where_clause (where_clause), generic_params (generic_params) + {} + + void go (std::vector> &implicit_generics) + { + // some desugars are more complex so imagine this case + // + // pub fn foo(_value: impl Bar) -> i32 { + // 15 + // } + // + // this needs to become: + // + // pub fn foo(_value: T) -> i32 + // where + // T: Bar, + // U: Foo, + // { + // 15 + // } + // + // so we need to walk all the implicit generics and the trait bounds paths + // for more generics + + for (auto &implicit_generic : implicit_generics) + { + switch (implicit_generic->get_kind ()) + { + case GenericParam::Kind::Type: + { + TypeParam &p + = *static_cast (implicit_generic.get ()); + + process_type_param (p); + generic_params.push_back (std::move (implicit_generic)); + for (auto &synth : synthetic_params) + generic_params.push_back (std::move (synth)); + synthetic_params.clear (); + } + break; + + default: + generic_params.push_back (std::move (implicit_generic)); + break; + } + } + } + +private: + void process_type_param (TypeParam &p) + { + auto &bounds = p.get_type_param_bounds (); + std::vector bounds_to_remove; + for (size_t i = 0; i < bounds.size (); i++) + { + auto &tb = bounds[i]; + switch (tb->get_bound_type ()) + { + case TypeParamBound::TypeParamBoundType::TRAIT: + { + TraitBound &ttb = *static_cast (tb.get ()); + TypePath &path = ttb.get_type_path (); + bool deusgared = process_type_path (p, ttb, path); + if (deusgared) + bounds_to_remove.push_back (i); + } + + default: + break; + } + } + for (auto it = bounds_to_remove.rbegin (); it != bounds_to_remove.rend (); + ++it) + bounds.erase (bounds.begin () + *it); + } + + bool process_type_path (TypeParam &p, TraitBound &parent, TypePath &path) + { + bool desugared = false; + for (auto &segment : path.get_segments ()) + { + switch (segment->get_type ()) + { + case TypePathSegment::SegmentType::GENERIC: + { + TypePathSegmentGeneric &seg + = *static_cast (segment.get ()); + desugared |= process_generic_segment (p, parent, path, seg); + } + + default: + break; + } + } + return desugared; + } + + bool process_generic_segment (TypeParam &p, TraitBound &parent, + TypePath &path, TypePathSegmentGeneric &seg) + { + // we need to look for any impl types as default arguments in any generics + // and remove this index from the generic arguments by using a where + // constraint instead + + std::vector> new_clauses; + GenericArgs &generic_args = seg.get_generic_args (); + std::vector> + bindings_desugared; + std::vector &bindings + = generic_args.get_binding_args (); + + for (auto &generic : bindings) + { + auto &t = generic.get_type (); + auto translated = DesugarApitType::Desugar (t); + auto tt = translated.first; + + auto &implicit_generics = translated.second; + if (implicit_generics.empty ()) + continue; + + if (tt != &t) + { + bindings_desugared.push_back (generic); + generic.get_type_ptr () = std::unique_ptr (tt); + } + + for (auto &implicit_generic : implicit_generics) + { + switch (implicit_generic->get_kind ()) + { + case GenericParam::Kind::Type: + { + TypeParam &tp + = *static_cast (implicit_generic.get ()); + + std::vector> + type_param_bounds; + for (auto &b : tp.get_type_param_bounds ()) + type_param_bounds.push_back (std::move (b)); + tp.get_type_param_bounds ().clear (); + + // add synthetic parameter for this + synthetic_params.push_back (std::move (implicit_generic)); + + auto bound_type_path + = get_type_for_identifier (tp.get_type_representation ()); + + auto clause = new TypeBoundWhereClauseItem ( + {}, std::move (bound_type_path), + std::move (type_param_bounds), tp.get_locus ()); + std::unique_ptr clause_item + = std::unique_ptr (clause); + new_clauses.push_back (std::move (clause_item)); + } + break; + + default: + synthetic_params.push_back (std::move (implicit_generic)); + break; + } + } + } + + std::vector> type_param_bounds; + auto bound = std::unique_ptr (new TraitBound (parent)); + type_param_bounds.push_back (std::move (bound)); + auto parent_type_path + = get_type_for_identifier (p.get_type_representation ()); + auto clause + = new TypeBoundWhereClauseItem ({}, std::move (parent_type_path), + std::move (type_param_bounds), + parent.get_locus ()); + std::unique_ptr clause_item + = std::unique_ptr (clause); + where_clause.get_items ().push_back (std::move (clause_item)); + + for (auto &where_item : new_clauses) + where_clause.get_items ().push_back (std::move (where_item)); + + return !bindings_desugared.empty (); + } + + static std::unique_ptr get_type_for_identifier (const Identifier &ident) + { + auto simple_seg + = SimplePathSegment (ident.as_string (), ident.get_locus ()); + std::vector simple_segs = {simple_seg}; + auto simple_path = SimplePath (simple_segs, false, ident.get_locus ()); + std::vector> segments; + segments.push_back (std::unique_ptr (new TypePathSegment ( + PathIdentSegment (ident.as_string (), ident.get_locus ()), false, + ident.get_locus ()))); + auto type_path = new TypePath (std::move (segments), ident.get_locus ()); + return std::unique_ptr (type_path); + } + +private: + WhereClause &where_clause; + std::vector> &generic_params; + + // mutates + std::vector> synthetic_params; +}; + +// --------- + +DesugarApit::DesugarApit () {} + +void +DesugarApit::go (AST::Crate &crate) +{ + DefaultASTVisitor::visit (crate); +} + +void +DesugarApit::visit (AST::Function &function) +{ + if (!function.has_function_params ()) + return; + + auto &fn_params = function.get_function_params (); + for (auto ¶m : fn_params) + { + if (param->is_variadic () || param->is_self ()) + continue; + + auto *p = param.get (); + auto &fp = *static_cast (p); + auto &type = fp.get_type (); + + auto translated = DesugarApitType::Desugar (type); + auto tt = translated.first; + + auto &implicit_generics = translated.second; + if (implicit_generics.empty ()) + continue; + + if (fp.get_type_ptr ().get () != tt) + { + fp.get_type_ptr () = std::unique_ptr (tt); + } + + ApitBoundProcessor processor (function.get_where_clause (), + function.get_generic_params ()); + processor.go (implicit_generics); + } +} + +} // namespace AST +} // namespace Rust diff --git a/gcc/rust/ast/rust-macro.cc b/gcc/rust/ast/rust-desugar-apit.h similarity index 66% rename from gcc/rust/ast/rust-macro.cc rename to gcc/rust/ast/rust-desugar-apit.h index 270343872933..07c25e2405cf 100644 --- a/gcc/rust/ast/rust-macro.cc +++ b/gcc/rust/ast/rust-desugar-apit.h @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2025 Free Software Foundation, Inc. +// Copyright (C) 2025 Free Software Foundation, Inc. // This file is part of GCC. @@ -16,10 +16,27 @@ // along with GCC; see the file COPYING3. If not see // . -#include "rust-macro.h" +#ifndef RUST_DESUGAR_APIT_H +#define RUST_DESUGAR_APIT_H + +#include "rust-ast-visitor.h" namespace Rust { namespace AST { +class DesugarApit : public DefaultASTVisitor +{ + using DefaultASTVisitor::visit; + +public: + DesugarApit (); + void go (AST::Crate &); + +private: + void visit (AST::Function &) override; +}; + } // namespace AST } // namespace Rust + +#endif // ! RUST_DESUGAR_APIT_H diff --git a/gcc/rust/ast/rust-expr.h b/gcc/rust/ast/rust-expr.h index fdb6360eb3b4..8d650b2ded1f 100644 --- a/gcc/rust/ast/rust-expr.h +++ b/gcc/rust/ast/rust-expr.h @@ -1,6 +1,7 @@ #ifndef RUST_AST_EXPR_H #define RUST_AST_EXPR_H +#include "optional.h" #include "rust-ast.h" #include "rust-common.h" #include "rust-path.h" @@ -395,6 +396,8 @@ class BorrowExpr : public OperatorExpr return *main_or_left_expr; } + bool has_borrow_expr () const { return main_or_left_expr != nullptr; } + bool get_is_mut () const { return mutability == Mutability::Mut; } Mutability get_mutability () const { return mutability; } @@ -1160,11 +1163,11 @@ class ArrayElems // Value array elements class ArrayElemsValues : public ArrayElems { - std::vector > values; + std::vector> values; location_t locus; public: - ArrayElemsValues (std::vector > elems, location_t locus) + ArrayElemsValues (std::vector> elems, location_t locus) : ArrayElems (), values (std::move (elems)), locus (locus) {} @@ -1192,14 +1195,16 @@ class ArrayElemsValues : public ArrayElems std::string as_string () const override; + location_t get_locus () const { return locus; } + void accept_vis (ASTVisitor &vis) override; // TODO: this mutable getter seems really dodgy. Think up better way. - const std::vector > &get_values () const + const std::vector> &get_values () const { return values; } - std::vector > &get_values () { return values; } + std::vector> &get_values () { return values; } size_t get_num_values () const { return values.size (); } @@ -1214,6 +1219,8 @@ class ArrayElemsValues : public ArrayElems class ArrayElemsCopied : public ArrayElems { std::unique_ptr elem_to_copy; + + // TODO: This should be replaced by a ConstExpr std::unique_ptr num_copies; location_t locus; @@ -1246,6 +1253,8 @@ class ArrayElemsCopied : public ArrayElems std::string as_string () const override; + location_t get_locus () const { return locus; } + void accept_vis (ASTVisitor &vis) override; // TODO: is this better? Or is a "vis_block" better? @@ -1472,7 +1481,7 @@ class TupleExpr : public ExprWithoutBlock { std::vector outer_attrs; std::vector inner_attrs; - std::vector > tuple_elems; + std::vector> tuple_elems; location_t locus; // TODO: find another way to store this to save memory? @@ -1492,7 +1501,7 @@ class TupleExpr : public ExprWithoutBlock outer_attrs = std::move (new_attrs); } - TupleExpr (std::vector > tuple_elements, + TupleExpr (std::vector> tuple_elements, std::vector inner_attribs, std::vector outer_attribs, location_t locus) : outer_attrs (std::move (outer_attribs)), @@ -1543,14 +1552,11 @@ class TupleExpr : public ExprWithoutBlock bool is_marked_for_strip () const override { return marked_for_strip; } // TODO: this mutable getter seems really dodgy. Think up better way. - const std::vector > &get_tuple_elems () const - { - return tuple_elems; - } - std::vector > &get_tuple_elems () + const std::vector> &get_tuple_elems () const { return tuple_elems; } + std::vector> &get_tuple_elems () { return tuple_elems; } bool is_unit () const { return tuple_elems.size () == 0; } @@ -1775,6 +1781,8 @@ struct StructBase std::string as_string () const; + location_t get_locus () const { return locus; } + // TODO: is this better? Or is a "vis_block" better? Expr &get_base_struct () { @@ -1972,7 +1980,7 @@ class StructExprFieldIndexValue : public StructExprFieldWithVal class StructExprStructFields : public StructExprStruct { // std::vector fields; - std::vector > fields; + std::vector> fields; // bool has_struct_base; StructBase struct_base; @@ -1985,8 +1993,8 @@ class StructExprStructFields : public StructExprStruct // Constructor for StructExprStructFields when no struct base is used StructExprStructFields ( PathInExpression struct_path, - std::vector > expr_fields, - location_t locus, StructBase base_struct = StructBase::error (), + std::vector> expr_fields, location_t locus, + StructBase base_struct = StructBase::error (), std::vector inner_attribs = std::vector (), std::vector outer_attribs = std::vector ()) : StructExprStruct (std::move (struct_path), std::move (inner_attribs), @@ -2023,11 +2031,11 @@ class StructExprStructFields : public StructExprStruct void accept_vis (ASTVisitor &vis) override; // TODO: this mutable getter seems really dodgy. Think up better way. - std::vector > &get_fields () + std::vector> &get_fields () { return fields; } - const std::vector > &get_fields () const + const std::vector> &get_fields () const { return fields; } @@ -2084,7 +2092,7 @@ class CallExpr : public ExprWithoutBlock { std::vector outer_attrs; std::unique_ptr function; - std::vector > params; + std::vector> params; location_t locus; public: @@ -2093,7 +2101,7 @@ class CallExpr : public ExprWithoutBlock std::string as_string () const override; CallExpr (std::unique_ptr function_expr, - std::vector > function_params, + std::vector> function_params, std::vector outer_attribs, location_t locus) : outer_attrs (std::move (outer_attribs)), function (std::move (function_expr)), @@ -2150,11 +2158,11 @@ class CallExpr : public ExprWithoutBlock bool is_marked_for_strip () const override { return function == nullptr; } // TODO: this mutable getter seems really dodgy. Think up better way. - const std::vector > &get_params () const + const std::vector> &get_params () const { return params; } - std::vector > &get_params () { return params; } + std::vector> &get_params () { return params; } // TODO: is this better? Or is a "vis_block" better? Expr &get_function_expr () @@ -2190,7 +2198,7 @@ class MethodCallExpr : public ExprWithoutBlock std::vector outer_attrs; std::unique_ptr receiver; PathExprSegment method_name; - std::vector > params; + std::vector> params; location_t locus; public: @@ -2198,7 +2206,7 @@ class MethodCallExpr : public ExprWithoutBlock MethodCallExpr (std::unique_ptr call_receiver, PathExprSegment method_path, - std::vector > method_params, + std::vector> method_params, std::vector outer_attribs, location_t locus) : outer_attrs (std::move (outer_attribs)), receiver (std::move (call_receiver)), @@ -2254,11 +2262,11 @@ class MethodCallExpr : public ExprWithoutBlock bool is_marked_for_strip () const override { return receiver == nullptr; } // TODO: this mutable getter seems really dodgy. Think up better way. - const std::vector > &get_params () const + const std::vector> &get_params () const { return params; } - std::vector > &get_params () { return params; } + std::vector> &get_params () { return params; } // TODO: is this better? Or is a "vis_block" better? Expr &get_receiver_expr () @@ -2504,6 +2512,8 @@ class ClosureExpr : public ExprWithoutBlock bool get_has_move () const { return has_move; } Expr::Kind get_expr_kind () const override { return Expr::Kind::Closure; } + + virtual Expr &get_definition_expr () = 0; }; // Represents a non-type-specified closure expression AST node @@ -2563,7 +2573,7 @@ class ClosureExprInner : public ClosureExpr return closure_inner == nullptr; } - Expr &get_definition_expr () + Expr &get_definition_expr () override { rust_assert (closure_inner != nullptr); return *closure_inner; @@ -2583,7 +2593,7 @@ class BlockExpr : public ExprWithBlock { std::vector outer_attrs; std::vector inner_attrs; - std::vector > statements; + std::vector> statements; std::unique_ptr expr; tl::optional label; location_t start_locus; @@ -2599,7 +2609,7 @@ class BlockExpr : public ExprWithBlock // Returns whether the block contains a final expression. bool has_tail_expr () const { return expr != nullptr; } - BlockExpr (std::vector > block_statements, + BlockExpr (std::vector> block_statements, std::unique_ptr block_expr, std::vector inner_attribs, std::vector outer_attribs, @@ -2678,11 +2688,11 @@ class BlockExpr : public ExprWithBlock const std::vector &get_inner_attrs () const { return inner_attrs; } std::vector &get_inner_attrs () { return inner_attrs; } - const std::vector > &get_statements () const + const std::vector> &get_statements () const { return statements; } - std::vector > &get_statements () { return statements; } + std::vector> &get_statements () { return statements; } // TODO: is this better? Or is a "vis_block" better? Expr &get_tail_expr () @@ -2744,6 +2754,151 @@ class BlockExpr : public ExprWithBlock } }; +class AnonConst : public ExprWithBlock +{ +public: + enum class Kind + { + Explicit, + DeferredInference, + }; + + AnonConst (std::unique_ptr &&expr, location_t locus = UNKNOWN_LOCATION) + : ExprWithBlock (), locus (locus), kind (Kind::Explicit), + expr (std::move (expr)) + { + rust_assert (this->expr.value ()); + } + + AnonConst (location_t locus = UNKNOWN_LOCATION) + : ExprWithBlock (), locus (locus), kind (Kind::DeferredInference), + expr (tl::nullopt) + {} + + AnonConst (const AnonConst &other) + { + node_id = other.node_id; + locus = other.locus; + kind = other.kind; + + if (other.expr) + expr = other.expr.value ()->clone_expr (); + } + + AnonConst operator= (const AnonConst &other) + { + node_id = other.node_id; + locus = other.locus; + kind = other.kind; + + if (other.expr) + expr = other.expr.value ()->clone_expr (); + + return *this; + } + + std::string as_string () const override; + + Expr::Kind get_expr_kind () const override { return Expr::Kind::ConstExpr; } + + location_t get_locus () const override { return locus; } + + Expr &get_inner_expr () + { + rust_assert (expr.has_value ()); + return *expr.value (); + } + + NodeId get_node_id () const override { return node_id; } + + /* FIXME: AnonConst are always "internal" and should not have outer attributes + * - is that true? Or should we instead call + * expr->get_outer_attrs()/expr->set_outer_attrs() */ + + std::vector &get_outer_attrs () override + { + static auto attrs = std::vector (); + return attrs; + } + + void set_outer_attrs (std::vector) override {} + + /* FIXME: Likewise for mark_for_strip() ? */ + void mark_for_strip () override {} + bool is_marked_for_strip () const override { return false; } + + void accept_vis (ASTVisitor &vis) override; + + bool is_deferred () const { return kind == Kind::DeferredInference; } + +private: + location_t locus; + Kind kind; + tl::optional> expr; + + AnonConst *clone_expr_with_block_impl () const override + { + return new AnonConst (*this); + } +}; + +class ConstBlock : public ExprWithBlock +{ +public: + ConstBlock (AnonConst &&expr, location_t locus = UNKNOWN_LOCATION, + std::vector &&outer_attrs = {}) + : ExprWithBlock (), expr (std::move (expr)), + outer_attrs (std::move (outer_attrs)), locus (locus) + {} + + ConstBlock (const ConstBlock &other) + : ExprWithBlock (other), expr (other.expr), outer_attrs (other.outer_attrs), + locus (other.locus) + {} + + ConstBlock operator= (const ConstBlock &other) + { + expr = other.expr; + node_id = other.node_id; + outer_attrs = other.outer_attrs; + locus = other.locus; + + return *this; + } + + std::string as_string () const override; + + Expr::Kind get_expr_kind () const override { return Expr::Kind::ConstBlock; } + + AnonConst &get_const_expr () { return expr; } + + void accept_vis (ASTVisitor &vis) override; + + std::vector &get_outer_attrs () override { return outer_attrs; } + + void set_outer_attrs (std::vector new_attrs) override + { + outer_attrs = std::move (new_attrs); + } + + location_t get_locus () const override { return locus; } + + bool is_marked_for_strip () const override { return marked_for_strip; } + void mark_for_strip () override { marked_for_strip = true; } + +private: + AnonConst expr; + + std::vector outer_attrs; + location_t locus; + bool marked_for_strip = false; + + ConstBlock *clone_expr_with_block_impl () const override + { + return new ConstBlock (*this); + } +}; + // Represents a type-specified closure expression AST node class ClosureExprInnerTyped : public ClosureExpr { @@ -2812,7 +2967,7 @@ class ClosureExprInnerTyped : public ClosureExpr bool is_marked_for_strip () const override { return expr == nullptr; } // TODO: is this better? Or is a "vis_block" better? - BlockExpr &get_definition_block () + BlockExpr &get_definition_expr () override { rust_assert (expr != nullptr); return *expr; @@ -3572,6 +3727,82 @@ class ReturnExpr : public ExprWithoutBlock } }; +// Try expression AST node representation +class TryExpr : public ExprWithBlock +{ + std::vector outer_attrs; + std::unique_ptr block_expr; + location_t locus; + + // TODO: find another way to store this to save memory? + bool marked_for_strip = false; + +public: + std::string as_string () const override; + + // Constructor for ReturnExpr. + TryExpr (std::unique_ptr block_expr, + std::vector outer_attribs, location_t locus) + : outer_attrs (std::move (outer_attribs)), + block_expr (std::move (block_expr)), locus (locus) + { + rust_assert (this->block_expr); + } + + // Copy constructor with clone + TryExpr (TryExpr const &other) + : ExprWithBlock (other), outer_attrs (other.outer_attrs), + block_expr (other.block_expr->clone_block_expr ()), locus (other.locus), + marked_for_strip (other.marked_for_strip) + {} + + // Overloaded assignment operator to clone return_expr pointer + TryExpr &operator= (TryExpr const &other) + { + ExprWithBlock::operator= (other); + locus = other.locus; + marked_for_strip = other.marked_for_strip; + outer_attrs = other.outer_attrs; + + block_expr = other.block_expr->clone_block_expr (); + + return *this; + } + + // move constructors + TryExpr (TryExpr &&other) = default; + TryExpr &operator= (TryExpr &&other) = default; + + location_t get_locus () const override final { return locus; } + + void accept_vis (ASTVisitor &vis) override; + + // Can't think of any invalid invariants, so store boolean. + void mark_for_strip () override { marked_for_strip = true; } + bool is_marked_for_strip () const override { return marked_for_strip; } + + // TODO: is this better? Or is a "vis_block" better? + BlockExpr &get_block_expr () { return *block_expr; } + + const std::vector &get_outer_attrs () const { return outer_attrs; } + std::vector &get_outer_attrs () override { return outer_attrs; } + + void set_outer_attrs (std::vector new_attrs) override + { + outer_attrs = std::move (new_attrs); + } + + Expr::Kind get_expr_kind () const override { return Expr::Kind::Return; } + +protected: + /* Use covariance to implement clone function as returning this object rather + * than base */ + TryExpr *clone_expr_with_block_impl () const override + { + return new TryExpr (*this); + } +}; + // Forward decl - defined in rust-macro.h class MacroInvocation; @@ -3847,14 +4078,14 @@ class WhileLoopExpr : public BaseLoopExpr class WhileLetLoopExpr : public BaseLoopExpr { // MatchArmPatterns patterns; - std::vector > match_arm_patterns; // inlined + std::vector> match_arm_patterns; // inlined std::unique_ptr scrutinee; public: std::string as_string () const override; // Constructor with a loop label - WhileLetLoopExpr (std::vector > match_arm_patterns, + WhileLetLoopExpr (std::vector> match_arm_patterns, std::unique_ptr scrutinee, std::unique_ptr loop_block, location_t locus, tl::optional loop_label = tl::nullopt, @@ -3908,11 +4139,11 @@ class WhileLetLoopExpr : public BaseLoopExpr } // TODO: this mutable getter seems really dodgy. Think up better way. - const std::vector > &get_patterns () const + const std::vector> &get_patterns () const { return match_arm_patterns; } - std::vector > &get_patterns () + std::vector> &get_patterns () { return match_arm_patterns; } @@ -4195,7 +4426,7 @@ class IfExprConseqElse : public IfExpr class IfLetExpr : public ExprWithBlock { std::vector outer_attrs; - std::vector > match_arm_patterns; // inlined + std::vector> match_arm_patterns; // inlined std::unique_ptr value; std::unique_ptr if_block; location_t locus; @@ -4203,7 +4434,7 @@ class IfLetExpr : public ExprWithBlock public: std::string as_string () const override; - IfLetExpr (std::vector > match_arm_patterns, + IfLetExpr (std::vector> match_arm_patterns, std::unique_ptr value, std::unique_ptr if_block, std::vector outer_attrs, location_t locus) : outer_attrs (std::move (outer_attrs)), @@ -4297,11 +4528,11 @@ class IfLetExpr : public ExprWithBlock } // TODO: this mutable getter seems really dodgy. Think up better way. - const std::vector > &get_patterns () const + const std::vector> &get_patterns () const { return match_arm_patterns; } - std::vector > &get_patterns () + std::vector> &get_patterns () { return match_arm_patterns; } @@ -4341,11 +4572,11 @@ class IfLetExprConseqElse : public IfLetExpr public: std::string as_string () const override; - IfLetExprConseqElse ( - std::vector > match_arm_patterns, - std::unique_ptr value, std::unique_ptr if_block, - std::unique_ptr else_block, - std::vector outer_attrs, location_t locus) + IfLetExprConseqElse (std::vector> match_arm_patterns, + std::unique_ptr value, + std::unique_ptr if_block, + std::unique_ptr else_block, + std::vector outer_attrs, location_t locus) : IfLetExpr (std::move (match_arm_patterns), std::move (value), std::move (if_block), std::move (outer_attrs), locus), else_block (std::move (else_block)) @@ -4398,7 +4629,7 @@ struct MatchArm private: std::vector outer_attrs; // MatchArmPatterns patterns; - std::vector > match_arm_patterns; // inlined + std::vector> match_arm_patterns; // inlined // bool has_match_arm_guard; // inlined from MatchArmGuard @@ -4411,7 +4642,7 @@ struct MatchArm bool has_match_arm_guard () const { return guard_expr != nullptr; } // Constructor for match arm with a guard expression - MatchArm (std::vector > match_arm_patterns, + MatchArm (std::vector> match_arm_patterns, location_t locus, std::unique_ptr guard_expr = nullptr, std::vector outer_attrs = std::vector ()) : outer_attrs (std::move (outer_attrs)), @@ -4463,7 +4694,7 @@ struct MatchArm static MatchArm create_error () { location_t locus = UNDEF_LOCATION; - return MatchArm (std::vector > (), locus); + return MatchArm (std::vector> (), locus); } std::string as_string () const; @@ -4485,11 +4716,11 @@ struct MatchArm const std::vector &get_outer_attrs () const { return outer_attrs; } std::vector &get_outer_attrs () { return outer_attrs; } - const std::vector > &get_patterns () const + const std::vector> &get_patterns () const { return match_arm_patterns; } - std::vector > &get_patterns () + std::vector> &get_patterns () { return match_arm_patterns; } @@ -4836,29 +5067,6 @@ enum class InlineAsmOption MAY_UNWIND = 1 << 8, }; -struct AnonConst -{ - NodeId id; - std::unique_ptr expr; - AnonConst (NodeId id, std::unique_ptr expr) - : id (id), expr (std::move (expr)) - { - rust_assert (this->expr != nullptr); - } - AnonConst (const AnonConst &other) - { - id = other.id; - expr = other.expr->clone_expr (); - } - - AnonConst operator= (const AnonConst &other) - { - id = other.id; - expr = other.expr->clone_expr (); - return *this; - } -}; - struct InlineAsmRegOrRegClass { enum Type @@ -5288,6 +5496,20 @@ struct TupleTemplateStr // Inline Assembly Node class InlineAsm : public ExprWithoutBlock { +public: + enum class Option + { + PURE = 1 << 0, + NOMEM = 1 << 1, + READONLY = 1 << 2, + PRESERVES_FLAGS = 1 << 3, + NORETURN = 1 << 4, + NOSTACK = 1 << 5, + ATT_SYNTAX = 1 << 6, + RAW = 1 << 7, + MAY_UNWIND = 1 << 8, + }; + private: location_t locus; // TODO: Not sure how outer_attrs plays with InlineAsm, I put it here in order @@ -5311,7 +5533,7 @@ class InlineAsm : public ExprWithoutBlock std::map named_args; std::set reg_args; std::vector clobber_abi; - std::set options; + std::set options; std::vector line_spans; @@ -5342,7 +5564,7 @@ class InlineAsm : public ExprWithoutBlock std::vector get_clobber_abi () { return clobber_abi; } - std::set get_options () { return options; } + std::set get_options () { return options; } InlineAsm *clone_expr_without_block_impl () const override { @@ -5350,6 +5572,33 @@ class InlineAsm : public ExprWithoutBlock } Expr::Kind get_expr_kind () const override { return Expr::Kind::InlineAsm; } + + static std::string option_to_string (Option option) + { + switch (option) + { + case Option::PURE: + return "pure"; + case Option::NOMEM: + return "nomem"; + case Option::READONLY: + return "readonly"; + case Option::PRESERVES_FLAGS: + return "preserves_flags"; + case Option::NORETURN: + return "noreturn"; + case Option::NOSTACK: + return "nostack"; + case Option::ATT_SYNTAX: + return "att_syntax"; + case Option::RAW: + return "raw"; + case Option::MAY_UNWIND: + return "may_unwind"; + default: + rust_unreachable (); + } + } }; class LlvmInlineAsm : public ExprWithoutBlock diff --git a/gcc/rust/ast/rust-fmt.h b/gcc/rust/ast/rust-fmt.h index a54faec6381a..3722db291ab8 100644 --- a/gcc/rust/ast/rust-fmt.h +++ b/gcc/rust/ast/rust-fmt.h @@ -266,11 +266,10 @@ enum ParseMode extern "C" { -FormatArgsHandle -collect_pieces (const char *input, bool append_newline, ParseMode parse_mode); +FormatArgsHandle collect_pieces (const char *input, bool append_newline, + ParseMode parse_mode); -FormatArgsHandle -clone_pieces (const FormatArgsHandle &); +FormatArgsHandle clone_pieces (const FormatArgsHandle &); void destroy_pieces (FormatArgsHandle); diff --git a/gcc/rust/ast/rust-item.h b/gcc/rust/ast/rust-item.h index 062f85d22127..d11eed7687b5 100644 --- a/gcc/rust/ast/rust-item.h +++ b/gcc/rust/ast/rust-item.h @@ -51,21 +51,12 @@ class TypePath; // A type generic parameter (as opposed to a lifetime generic parameter) class TypeParam : public GenericParam { - // bool has_outer_attribute; - // std::unique_ptr outer_attr; AST::AttrVec outer_attrs; - Identifier type_representation; - - // bool has_type_param_bounds; - // TypeParamBounds type_param_bounds; - std::vector> - type_param_bounds; // inlined form - - // bool has_type; + std::vector> type_param_bounds; std::unique_ptr type; - location_t locus; + bool was_impl_trait; public: Identifier get_type_representation () const { return type_representation; } @@ -85,18 +76,19 @@ class TypeParam : public GenericParam std::vector> type_param_bounds = std::vector> (), std::unique_ptr type = nullptr, - AST::AttrVec outer_attrs = {}) + AST::AttrVec outer_attrs = {}, bool was_impl_trait = false) : GenericParam (Analysis::Mappings::get ().get_next_node_id ()), outer_attrs (std::move (outer_attrs)), type_representation (std::move (type_representation)), type_param_bounds (std::move (type_param_bounds)), - type (std::move (type)), locus (locus) + type (std::move (type)), locus (locus), was_impl_trait (was_impl_trait) {} // Copy constructor uses clone TypeParam (TypeParam const &other) : GenericParam (other.node_id), outer_attrs (other.outer_attrs), - type_representation (other.type_representation), locus (other.locus) + type_representation (other.type_representation), locus (other.locus), + was_impl_trait (other.was_impl_trait) { // guard to prevent null pointer dereference if (other.type != nullptr) @@ -114,6 +106,7 @@ class TypeParam : public GenericParam outer_attrs = other.outer_attrs; locus = other.locus; node_id = other.node_id; + was_impl_trait = other.was_impl_trait; // guard to prevent null pointer dereference if (other.type != nullptr) @@ -153,17 +146,19 @@ class TypeParam : public GenericParam return type; } - // TODO: mutable getter seems kinda dodgy std::vector> &get_type_param_bounds () { return type_param_bounds; } + const std::vector> & get_type_param_bounds () const { return type_param_bounds; } + bool from_impl_trait () const { return was_impl_trait; } + protected: // Clone function implementation as virtual method TypeParam *clone_generic_param_impl () const override @@ -2455,7 +2450,7 @@ class ConstantItem : public VisItem, public AssociatedItem // either has an identifier or "_" - maybe handle in identifier? // bool identifier_is_underscore; // if no identifier declared, identifier will be "_" - std::string identifier; + Identifier identifier; std::unique_ptr type; std::unique_ptr const_expr; @@ -2465,7 +2460,7 @@ class ConstantItem : public VisItem, public AssociatedItem public: std::string as_string () const override; - ConstantItem (std::string ident, Visibility vis, std::unique_ptr type, + ConstantItem (Identifier ident, Visibility vis, std::unique_ptr type, std::unique_ptr const_expr, std::vector outer_attrs, location_t locus) : VisItem (std::move (vis), std::move (outer_attrs)), @@ -2473,7 +2468,7 @@ class ConstantItem : public VisItem, public AssociatedItem const_expr (std::move (const_expr)), locus (locus) {} - ConstantItem (std::string ident, Visibility vis, std::unique_ptr type, + ConstantItem (Identifier ident, Visibility vis, std::unique_ptr type, std::vector outer_attrs, location_t locus) : VisItem (std::move (vis), std::move (outer_attrs)), identifier (std::move (ident)), type (std::move (type)), @@ -2516,7 +2511,7 @@ class ConstantItem : public VisItem, public AssociatedItem /* Returns whether constant item is an "unnamed" (wildcard underscore used * as identifier) constant. */ - bool is_unnamed () const { return identifier == "_"; } + bool is_unnamed () const { return identifier.as_string () == "_"; } location_t get_locus () const override final { return locus; } @@ -2561,7 +2556,7 @@ class ConstantItem : public VisItem, public AssociatedItem return type; } - std::string get_identifier () const { return identifier; } + const Identifier &get_identifier () const { return identifier; } Item::Kind get_item_kind () const override { diff --git a/gcc/rust/ast/rust-macro.h b/gcc/rust/ast/rust-macro.h index fc01e571b916..d32acf30669b 100644 --- a/gcc/rust/ast/rust-macro.h +++ b/gcc/rust/ast/rust-macro.h @@ -27,6 +27,11 @@ #include "rust-macro-builtins.h" namespace Rust { + +// forward declarations for AttributeParser +class MacroInvocLexer; +template class Parser; + namespace AST { class MacroFragSpec @@ -756,22 +761,16 @@ class MacroInvocation : public TypeNoBounds, std::vector> pending_eager_invocs; protected: - /* Use covariance to implement clone function as returning this object rather - * than base */ MacroInvocation *clone_pattern_impl () const final override { return clone_macro_invocation_impl (); } - /* Use covariance to implement clone function as returning this object rather - * than base */ MacroInvocation *clone_expr_without_block_impl () const final override { return clone_macro_invocation_impl (); } - /* Use covariance to implement clone function as returning this object rather - * than base */ MacroInvocation *clone_type_no_bounds_impl () const final override { return clone_macro_invocation_impl (); @@ -788,6 +787,20 @@ class MacroInvocation : public TypeNoBounds, return new MacroInvocation (*this); } + std::unique_ptr reconstruct_macro_invocation () const + { + return nullptr; + // return reconstruct (this, + // &MacroInvocation::reconstruct_macro_invocation_impl); + } + + MacroInvocation *reconstruct_impl () const override + { + return new MacroInvocation (kind, builtin_kind, invoc_data, outer_attrs, + locus, is_semi_coloned, + reconstruct_vec (pending_eager_invocs)); + } + void add_semicolon () override { is_semi_coloned = true; } Pattern::Kind get_pattern_kind () override @@ -1108,16 +1121,14 @@ struct AttributeParser { private: // TODO: might as well rewrite to use lexer tokens - std::vector> token_stream; - int stream_pos; + std::unique_ptr lexer; + std::unique_ptr> parser; public: AttributeParser (std::vector> token_stream, - int stream_start_pos = 0) - : token_stream (std::move (token_stream)), stream_pos (stream_start_pos) - {} + int stream_start_pos = 0); - ~AttributeParser () = default; + ~AttributeParser (); std::vector> parse_meta_item_seq (); @@ -1138,12 +1149,9 @@ struct AttributeParser std::unique_ptr parse_path_meta_item (); // TODO: should this be const? - std::unique_ptr &peek_token (int i = 0) - { - return token_stream[stream_pos + i]; - } + const_TokenPtr peek_token (int i = 0); - void skip_token (int i = 0) { stream_pos += 1 + i; } + void skip_token (int i = 0); }; } // namespace AST } // namespace Rust diff --git a/gcc/rust/ast/rust-path.cc b/gcc/rust/ast/rust-path.cc index 8e43ddf648a9..793423aa6ee8 100644 --- a/gcc/rust/ast/rust-path.cc +++ b/gcc/rust/ast/rust-path.cc @@ -266,6 +266,27 @@ TypePath::as_simple_path () const locus); } +std::string +TypePath::make_debug_string () const +{ + rust_assert (!segments.empty ()); + + std::string output; + + for (const auto &segment : segments) + { + if (segment != nullptr && !segment->is_lang_item () + && !segment->is_error ()) + { + if (!output.empty () || has_opening_scope_resolution_op ()) + output.append ("::"); + output.append (segment->get_ident_segment ().as_string ()); + } + } + + return output; +} + // hopefully definition here will prevent circular dependency issue TraitBound * TypePath::to_trait_bound (bool in_parens) const diff --git a/gcc/rust/ast/rust-path.h b/gcc/rust/ast/rust-path.h index a4ba93b718e7..a1b19d559c33 100644 --- a/gcc/rust/ast/rust-path.h +++ b/gcc/rust/ast/rust-path.h @@ -391,6 +391,13 @@ class ConstGenericParam : public GenericParam return default_value.value (); } + tl::optional &get_default_value () { return default_value; } + + const tl::optional &get_default_value () const + { + return default_value; + } + std::string as_string () const override; void accept_vis (ASTVisitor &vis) override; @@ -779,6 +786,11 @@ class TypePathSegment { return new TypePathSegment (*this); } + virtual TypePathSegment *reconstruct_impl () const + { + return new TypePathSegment (lang_item, ident_segment, + has_separating_scope_resolution, locus); + } public: virtual ~TypePathSegment () {} @@ -790,6 +802,11 @@ class TypePathSegment { return std::unique_ptr (clone_type_path_segment_impl ()); } + // Unique pointer custom reconstruct function + std::unique_ptr reconstruct () const + { + return reconstruct_base (this); + } TypePathSegment (PathIdentSegment ident_segment, bool has_separating_scope_resolution, location_t locus) @@ -814,6 +831,15 @@ class TypePathSegment node_id (Analysis::Mappings::get ().get_next_node_id ()) {} + // General constructor + TypePathSegment (tl::optional lang_item, + tl::optional ident_segment, + bool has_separating_scope_resolution, location_t locus) + : lang_item (lang_item), ident_segment (ident_segment), locus (locus), + has_separating_scope_resolution (has_separating_scope_resolution), + node_id (Analysis::Mappings::get ().get_next_node_id ()) + {} + TypePathSegment (TypePathSegment const &other) : lang_item (other.lang_item), ident_segment (other.ident_segment), locus (other.locus), @@ -968,11 +994,7 @@ class TypePathSegmentGeneric : public TypePathSegment void accept_vis (ASTVisitor &vis) override; // TODO: is this better? Or is a "vis_pattern" better? - GenericArgs &get_generic_args () - { - rust_assert (has_generic_args ()); - return generic_args; - } + GenericArgs &get_generic_args () { return generic_args; } // Use covariance to override base class method TypePathSegmentGeneric *clone_type_path_segment_impl () const override @@ -1149,6 +1171,11 @@ class TypePath : public TypeNoBounds { return new TypePath (*this); } + TypePath *reconstruct_impl () const override + { + return new TypePath (reconstruct_vec (segments), locus, + has_opening_scope_resolution); + } public: /* Returns whether the TypePath has an opening scope resolution operator @@ -1215,6 +1242,8 @@ class TypePath : public TypeNoBounds std::string as_string () const override; + std::string make_debug_string () const; + /* Converts TypePath to SimplePath if possible (i.e. no generic or function * arguments). Otherwise returns an empty SimplePath. */ SimplePath as_simple_path () const; @@ -1438,6 +1467,12 @@ class QualifiedPathInType : public TypeNoBounds { return new QualifiedPathInType (*this); } + QualifiedPathInType *reconstruct_impl () const override + { + return new QualifiedPathInType (path_type, + associated_segment->reconstruct (), + reconstruct_vec (segments), locus); + } public: QualifiedPathInType ( diff --git a/gcc/rust/ast/rust-pattern.cc b/gcc/rust/ast/rust-pattern.cc index fc7b6107be0e..62bf6f2c5e89 100644 --- a/gcc/rust/ast/rust-pattern.cc +++ b/gcc/rust/ast/rust-pattern.cc @@ -65,8 +65,8 @@ IdentifierPattern::as_string () const str += variable_ident.as_string (); - if (has_pattern_to_bind ()) - str += " @ " + to_bind->as_string (); + if (has_subpattern ()) + str += " @ " + subpattern->as_string (); return str; } diff --git a/gcc/rust/ast/rust-pattern.h b/gcc/rust/ast/rust-pattern.h index 69dbd98a1d32..57c065ff6955 100644 --- a/gcc/rust/ast/rust-pattern.h +++ b/gcc/rust/ast/rust-pattern.h @@ -74,7 +74,7 @@ class IdentifierPattern : public Pattern bool is_mut; // bool has_pattern; - std::unique_ptr to_bind; + std::unique_ptr subpattern; location_t locus; NodeId node_id; @@ -82,22 +82,22 @@ class IdentifierPattern : public Pattern std::string as_string () const override; // Returns whether the IdentifierPattern has a pattern to bind. - bool has_pattern_to_bind () const { return to_bind != nullptr; } + bool has_subpattern () const { return subpattern != nullptr; } // Constructor IdentifierPattern (Identifier ident, location_t locus, bool is_ref = false, bool is_mut = false, - std::unique_ptr to_bind = nullptr) + std::unique_ptr subpattern = nullptr) : Pattern (), variable_ident (std::move (ident)), is_ref (is_ref), - is_mut (is_mut), to_bind (std::move (to_bind)), locus (locus), + is_mut (is_mut), subpattern (std::move (subpattern)), locus (locus), node_id (Analysis::Mappings::get ().get_next_node_id ()) {} IdentifierPattern (NodeId node_id, Identifier ident, location_t locus, bool is_ref = false, bool is_mut = false, - std::unique_ptr to_bind = nullptr) + std::unique_ptr subpattern = nullptr) : Pattern (), variable_ident (std::move (ident)), is_ref (is_ref), - is_mut (is_mut), to_bind (std::move (to_bind)), locus (locus), + is_mut (is_mut), subpattern (std::move (subpattern)), locus (locus), node_id (node_id) {} @@ -107,8 +107,8 @@ class IdentifierPattern : public Pattern is_mut (other.is_mut), locus (other.locus), node_id (other.node_id) { // fix to get prevent null pointer dereference - if (other.to_bind != nullptr) - to_bind = other.to_bind->clone_pattern (); + if (other.subpattern != nullptr) + subpattern = other.subpattern->clone_pattern (); } // Overload assignment operator to use clone @@ -121,10 +121,10 @@ class IdentifierPattern : public Pattern node_id = other.node_id; // fix to prevent null pointer dereference - if (other.to_bind != nullptr) - to_bind = other.to_bind->clone_pattern (); + if (other.subpattern != nullptr) + subpattern = other.subpattern->clone_pattern (); else - to_bind = nullptr; + subpattern = nullptr; return *this; } @@ -137,11 +137,10 @@ class IdentifierPattern : public Pattern void accept_vis (ASTVisitor &vis) override; - // TODO: is this better? Or is a "vis_pattern" better? - Pattern &get_pattern_to_bind () + Pattern &get_subpattern () { - rust_assert (has_pattern_to_bind ()); - return *to_bind; + rust_assert (has_subpattern ()); + return *subpattern; } Identifier get_ident () const { return variable_ident; } @@ -375,8 +374,7 @@ enum class RangeKind EXCLUDED, }; -RangeKind -tokenid_to_rangekind (TokenId id); +RangeKind tokenid_to_rangekind (TokenId id); // AST node for matching within a certain range (range pattern) class RangePattern : public Pattern { @@ -950,7 +948,7 @@ class StructPattern : public Pattern * is empty). */ bool has_struct_pattern_elems () const { return !elems.is_empty (); } - location_t get_locus () const override { return path.get_locus (); } + location_t get_locus () const override { return locus; } void accept_vis (ASTVisitor &vis) override; diff --git a/gcc/rust/ast/rust-type.h b/gcc/rust/ast/rust-type.h index 1bb521d85850..2a3496b11c62 100644 --- a/gcc/rust/ast/rust-type.h +++ b/gcc/rust/ast/rust-type.h @@ -19,7 +19,9 @@ #ifndef RUST_AST_TYPE_H #define RUST_AST_TYPE_H +#include "optional.h" #include "rust-ast.h" +#include "rust-expr.h" #include "rust-path.h" namespace Rust { @@ -73,6 +75,13 @@ class TraitBound : public TypeParamBound type_path (std::move (type_path)), locus (locus) {} + TraitBound (TraitBound const &other) + : TypeParamBound (other.get_node_id ()), in_parens (other.in_parens), + opening_question_mark (other.opening_question_mark), + for_lifetimes (other.for_lifetimes), type_path (other.type_path), + locus (other.locus) + {} + std::string as_string () const override; location_t get_locus () const override final { return locus; } @@ -99,6 +108,11 @@ class TraitBound : public TypeParamBound return new TraitBound (node_id, type_path, locus, in_parens, opening_question_mark, for_lifetimes); } + TraitBound *reconstruct_impl () const override + { + return new TraitBound (type_path, locus, in_parens, opening_question_mark, + for_lifetimes); + } }; // definition moved to rust-ast.h @@ -120,6 +134,10 @@ class ImplTraitType : public Type { return new ImplTraitType (*this); } + ImplTraitType *reconstruct_impl () const override + { + return new ImplTraitType (reconstruct_vec (type_param_bounds), locus); + } public: ImplTraitType ( @@ -129,7 +147,8 @@ class ImplTraitType : public Type {} // copy constructor with vector clone - ImplTraitType (ImplTraitType const &other) : locus (other.locus) + ImplTraitType (ImplTraitType const &other) + : Type (other.node_id), locus (other.locus) { type_param_bounds.reserve (other.type_param_bounds.size ()); for (const auto &e : other.type_param_bounds) @@ -184,6 +203,11 @@ class TraitObjectType : public Type { return new TraitObjectType (*this); } + TraitObjectType *reconstruct_impl () const override + { + return new TraitObjectType (reconstruct_vec (type_param_bounds), locus, + has_dyn); + } public: TraitObjectType ( @@ -195,7 +219,7 @@ class TraitObjectType : public Type // copy constructor with vector clone TraitObjectType (TraitObjectType const &other) - : has_dyn (other.has_dyn), locus (other.locus) + : Type (other.node_id), has_dyn (other.has_dyn), locus (other.locus) { type_param_bounds.reserve (other.type_param_bounds.size ()); for (const auto &e : other.type_param_bounds) @@ -251,6 +275,10 @@ class ParenthesisedType : public TypeNoBounds { return new ParenthesisedType (*this); } + ParenthesisedType *reconstruct_impl () const override + { + return new ParenthesisedType (type_in_parens->reconstruct (), locus); + } public: // Constructor uses Type pointer for polymorphism @@ -305,33 +333,35 @@ class ParenthesisedType : public TypeNoBounds // Impl trait with a single bound? Poor reference material here. class ImplTraitTypeOneBound : public TypeNoBounds { - TraitBound trait_bound; + std::unique_ptr trait_bound; location_t locus; -protected: - /* Use covariance to implement clone function as returning this object rather - * than base */ - ImplTraitTypeOneBound *clone_type_no_bounds_impl () const override - { - return new ImplTraitTypeOneBound (*this); - } - public: - ImplTraitTypeOneBound (TraitBound trait_bound, location_t locus) + ImplTraitTypeOneBound (std::unique_ptr trait_bound, + location_t locus) : trait_bound (std::move (trait_bound)), locus (locus) {} + ImplTraitTypeOneBound (ImplTraitTypeOneBound const &other) + : trait_bound (other.trait_bound->clone_type_param_bound ()), + locus (other.locus) + {} + std::string as_string () const override; location_t get_locus () const override final { return locus; } void accept_vis (ASTVisitor &vis) override; - // TODO: would a "vis_type" be better? - TraitBound &get_trait_bound () + std::unique_ptr &get_trait_bound () { return trait_bound; } + + TypeNoBounds *clone_type_no_bounds_impl () const override { - // TODO: check to ensure invariants are met? - return trait_bound; + return new ImplTraitTypeOneBound (*this); + } + TypeNoBounds *reconstruct_impl () const override + { + return new ImplTraitTypeOneBound (trait_bound->reconstruct (), locus); } }; @@ -350,6 +380,10 @@ class TraitObjectTypeOneBound : public TypeNoBounds { return new TraitObjectTypeOneBound (*this); } + TraitObjectTypeOneBound *reconstruct_impl () const override + { + return new TraitObjectTypeOneBound (trait_bound, locus, has_dyn); + } public: TraitObjectTypeOneBound (TraitBound trait_bound, location_t locus, @@ -443,6 +477,10 @@ class TupleType : public TypeNoBounds { return new TupleType (*this); } + TupleType *reconstruct_impl () const override + { + return new TupleType (reconstruct_vec (elems), locus); + } }; /* A type with no values, representing the result of computations that never @@ -459,6 +497,10 @@ class NeverType : public TypeNoBounds { return new NeverType (*this); } + NeverType *reconstruct_impl () const override + { + return new NeverType (locus); + } public: NeverType (location_t locus) : locus (locus) {} @@ -529,6 +571,9 @@ class RawPointerType : public TypeNoBounds return *type; } + // Getter for direct access to the type unique_ptr + std::unique_ptr &get_type_ptr () { return type; } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -536,6 +581,10 @@ class RawPointerType : public TypeNoBounds { return new RawPointerType (*this); } + RawPointerType *reconstruct_impl () const override + { + return new RawPointerType (pointer_type, type->reconstruct (), locus); + } }; // A type pointing to memory owned by another value @@ -604,6 +653,9 @@ class ReferenceType : public TypeNoBounds TypeNoBounds &get_base_type () { return *type; } + // Getter for direct access to the type unique_ptr + std::unique_ptr &get_type_ptr () { return type; } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -611,33 +663,42 @@ class ReferenceType : public TypeNoBounds { return new ReferenceType (*this); } + ReferenceType *reconstruct_impl () const override + { + return new ReferenceType (has_mut, type->reconstruct (), locus, + // TODO: Improve this - it's ugly! + has_lifetime () ? tl::make_optional ( + lifetime->get_lifetime_type (), + lifetime->get_lifetime_name (), + lifetime->get_locus ()) + : tl::nullopt); + } }; // A fixed-size sequence of elements of a specified type class ArrayType : public TypeNoBounds { std::unique_ptr elem_type; - std::unique_ptr size; + AnonConst size; location_t locus; public: // Constructor requires pointers for polymorphism - ArrayType (std::unique_ptr type, std::unique_ptr array_size, - location_t locus) + ArrayType (std::unique_ptr type, AnonConst array_size, location_t locus) : elem_type (std::move (type)), size (std::move (array_size)), locus (locus) {} // Copy constructor requires deep copies of both unique pointers ArrayType (ArrayType const &other) - : elem_type (other.elem_type->clone_type ()), - size (other.size->clone_expr ()), locus (other.locus) + : elem_type (other.elem_type->clone_type ()), size (other.size), + locus (other.locus) {} // Overload assignment operator to deep copy pointers ArrayType &operator= (ArrayType const &other) { elem_type = other.elem_type->clone_type (); - size = other.size->clone_expr (); + size = other.size; locus = other.locus; return *this; } @@ -660,12 +721,15 @@ class ArrayType : public TypeNoBounds } // TODO: would a "vis_expr" be better? - Expr &get_size_expr () + AnonConst &get_size_expr () { - rust_assert (size != nullptr); - return *size; + // rust_assert (size != nullptr); + + return size; } + std::unique_ptr &get_element_type () { return elem_type; } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -673,6 +737,12 @@ class ArrayType : public TypeNoBounds { return new ArrayType (*this); } + ArrayType *reconstruct_impl () const override + { + return new ArrayType (elem_type->reconstruct (), + size /* FIXME: This should be `reconstruct_expr()` */, + locus); + } }; /* A dynamically-sized type representing a "view" into a sequence of elements of @@ -719,13 +789,20 @@ class SliceType : public TypeNoBounds return *elem_type; } + // Getter for direct access to the elem_type unique_ptr + std::unique_ptr &get_elem_type_ptr () { return elem_type; } + protected: - /* Use covariance to implement clone function as returning this object rather - * than base */ + /* Use covariance to implement clone function as returning this object + * rather than base */ SliceType *clone_type_no_bounds_impl () const override { return new SliceType (*this); } + SliceType *reconstruct_impl () const override + { + return new SliceType (elem_type->reconstruct (), locus); + } }; /* Type used in generic arguments to explicitly request type inference (wildcard @@ -736,13 +813,21 @@ class InferredType : public TypeNoBounds // e.g. Vec<_> = whatever protected: - /* Use covariance to implement clone function as returning this object rather - * than base */ + /* Use covariance to implement clone function as returning this object + * rather than base */ InferredType *clone_type_no_bounds_impl () const override { + // This goes through the copy constructor return new InferredType (*this); } + InferredType *reconstruct_impl () const override + { + // This goes through the base constructor which calls the base + // TypeNoBounds constructor, which allocates a new NodeId + return new InferredType (locus); + } + public: InferredType (location_t locus) : locus (locus) {} @@ -961,9 +1046,17 @@ class BareFunctionType : public TypeNoBounds FunctionQualifiers &get_function_qualifiers () { return function_qualifiers; } + BareFunctionType *reconstruct_impl () const override + { + return new BareFunctionType ( + for_lifetimes, function_qualifiers, params, + /* FIXME: Should params be reconstruct() as well? */ + _is_variadic, variadic_attrs, return_type->reconstruct (), locus); + } + protected: - /* Use covariance to implement clone function as returning this object rather - * than base */ + /* Use covariance to implement clone function as returning this object + * rather than base */ BareFunctionType *clone_type_no_bounds_impl () const override { return new BareFunctionType (*this); @@ -980,13 +1073,13 @@ class MacroInvocation; * function item type? * closure expression types? * primitive types (bool, int, float, char, str (the slice)) - * Although supposedly TypePaths are used to reference these types (including - * primitives) */ + * Although supposedly TypePaths are used to reference these types + * (including primitives) */ /* FIXME: Incomplete spec references: - * anonymous type parameters, aka "impl Trait in argument position" - impl then - * trait bounds abstract return types, aka "impl Trait in return position" - - * impl then trait bounds */ + * anonymous type parameters, aka "impl Trait in argument position" - impl + * then trait bounds abstract return types, aka "impl Trait in return + * position" - impl then trait bounds */ } // namespace AST } // namespace Rust diff --git a/gcc/rust/backend/rust-compile-base.cc b/gcc/rust/backend/rust-compile-base.cc index 12b956168bd3..8994520f16d5 100644 --- a/gcc/rust/backend/rust-compile-base.cc +++ b/gcc/rust/backend/rust-compile-base.cc @@ -575,6 +575,25 @@ HIRCompileBase::compile_constant_expr ( expr_locus); } +tree +HIRCompileBase::query_compile_const_expr (Context *ctx, TyTy::BaseType *expr_ty, + HIR::Expr &const_value_expr) +{ + HIRCompileBase c (ctx); + + ctx->push_const_context (); + + HirId expr_id = const_value_expr.get_mappings ().get_hirid (); + location_t locus = const_value_expr.get_locus (); + tree capacity_expr = HIRCompileBase::compile_constant_expr ( + ctx, expr_id, expr_ty, expr_ty, Resolver::CanonicalPath::create_empty (), + const_value_expr, locus, locus); + + ctx->pop_const_context (); + + return fold_expr (capacity_expr); +} + tree HIRCompileBase::indirect_expression (tree expr, location_t locus) { @@ -678,7 +697,8 @@ HIRCompileBase::compile_function ( = canonical_path.get () + fntype->subst_as_string (); // we don't mangle the main fn since we haven't implemented the main shim - bool is_main_fn = fn_name.compare ("main") == 0 && is_root_item; + bool is_main_fn = fn_name.compare ("main") == 0 && is_root_item + && canonical_path.size () <= 2; if (is_main_fn) { rust_assert (!main_identifier_node); @@ -687,14 +707,9 @@ HIRCompileBase::compile_function ( } std::string asm_name = fn_name; - auto &mappings = Analysis::Mappings::get (); - - if (flag_name_resolution_2_0) - ir_symbol_name = mappings.get_current_crate_name () + "::" + ir_symbol_name; - unsigned int flags = 0; tree fndecl = Backend::function (compiled_fn_type, ir_symbol_name, - "" /* asm_name */, flags, locus); + tl::nullopt /* asm_name */, flags, locus); setup_fndecl (fndecl, is_main_fn, fntype->has_substitutions_defined (), visibility, qualifiers, outer_attrs); @@ -812,11 +827,12 @@ HIRCompileBase::compile_constant_item ( // machineary that we already have. This means the best approach is to // make a _fake_ function with a block so it can hold onto temps then // use our constexpr code to fold it completely or error_mark_node - Backend::typed_identifier receiver; + Backend::typed_identifier receiver ("", NULL_TREE, UNKNOWN_LOCATION); tree compiled_fn_type = Backend::function_type ( receiver, {}, {Backend::typed_identifier ("_", const_type, locus)}, NULL, locus); - tree fndecl = Backend::function (compiled_fn_type, ident, "", 0, locus); + tree fndecl + = Backend::function (compiled_fn_type, ident, tl::nullopt, 0, locus); TREE_READONLY (fndecl) = 1; tree enclosing_scope = NULL_TREE; diff --git a/gcc/rust/backend/rust-compile-base.h b/gcc/rust/backend/rust-compile-base.h index 6814abcf9deb..e9b85968fac3 100644 --- a/gcc/rust/backend/rust-compile-base.h +++ b/gcc/rust/backend/rust-compile-base.h @@ -38,6 +38,9 @@ class HIRCompileBase const Resolver::CanonicalPath &canonical_path, HIR::Expr &const_value_expr, location_t locus, location_t expr_locus); + static tree query_compile_const_expr (Context *ctx, TyTy::BaseType *expr_ty, + HIR::Expr &const_value_expr); + protected: HIRCompileBase (Context *ctx) : ctx (ctx) {} diff --git a/gcc/rust/backend/rust-compile-block.cc b/gcc/rust/backend/rust-compile-block.cc index f844a27e9890..03c36d21709f 100644 --- a/gcc/rust/backend/rust-compile-block.cc +++ b/gcc/rust/backend/rust-compile-block.cc @@ -19,6 +19,7 @@ #include "rust-compile-block.h" #include "rust-compile-stmt.h" #include "rust-compile-expr.h" +#include "rust-hir-expr.h" namespace Rust { namespace Compile { diff --git a/gcc/rust/backend/rust-compile-block.h b/gcc/rust/backend/rust-compile-block.h index 3f38d087859f..90515f648831 100644 --- a/gcc/rust/backend/rust-compile-block.h +++ b/gcc/rust/backend/rust-compile-block.h @@ -83,6 +83,8 @@ class CompileConditionalBlocks : public HIRCompileBase, void visit (HIR::MethodCallExpr &) override {} void visit (HIR::FieldAccessExpr &) override {} void visit (HIR::BlockExpr &) override {} + void visit (HIR::AnonConst &) override {} + void visit (HIR::ConstBlock &) override {} void visit (HIR::ContinueExpr &) override {} void visit (HIR::BreakExpr &) override {} void visit (HIR::RangeFromToExpr &) override {} @@ -138,6 +140,12 @@ class CompileExprWithBlock : public HIRCompileBase, translated = CompileBlock::compile (expr, ctx, result); } + void visit (HIR::ConstBlock &expr) override + { + rust_unreachable (); + // translated = CompileExpr::compile (expr, ctx, result); + } + // Empty visit for unused Expression HIR nodes. void visit (HIR::PathInExpression &) override {} void visit (HIR::QualifiedPathInExpression &) override {} @@ -184,6 +192,7 @@ class CompileExprWithBlock : public HIRCompileBase, void visit (HIR::AsyncBlockExpr &) override {} void visit (HIR::InlineAsm &) override {} void visit (HIR::LlvmInlineAsm &) override {} + void visit (HIR::AnonConst &) override {} private: CompileExprWithBlock (Context *ctx, Bvariable *result) diff --git a/gcc/rust/backend/rust-compile-context.cc b/gcc/rust/backend/rust-compile-context.cc index 86f089440ac0..349d4927cb48 100644 --- a/gcc/rust/backend/rust-compile-context.cc +++ b/gcc/rust/backend/rust-compile-context.cc @@ -22,9 +22,18 @@ namespace Rust { namespace Compile { +Context * +Context::get () +{ + static Context *instance; + if (instance == nullptr) + instance = new Context (); + + return instance; +} + Context::Context () - : resolver (Resolver::Resolver::get ()), - tyctx (Resolver::TypeCheckContext::get ()), + : tyctx (Resolver::TypeCheckContext::get ()), mappings (Analysis::Mappings::get ()), mangler (Mangler ()) { setup_builtins (); @@ -70,7 +79,8 @@ Context::type_hasher (tree type) hstate.add_object (TYPE_HASH (TYPE_OFFSET_BASETYPE (type))); break; - case ARRAY_TYPE: { + case ARRAY_TYPE: + { if (TYPE_DOMAIN (type)) hstate.add_object (TYPE_HASH (TYPE_DOMAIN (type))); if (!AGGREGATE_TYPE_P (TREE_TYPE (type))) @@ -81,7 +91,8 @@ Context::type_hasher (tree type) } break; - case INTEGER_TYPE: { + case INTEGER_TYPE: + { tree t = TYPE_MAX_VALUE (type); if (!t) t = TYPE_MIN_VALUE (type); @@ -91,7 +102,8 @@ Context::type_hasher (tree type) } case REAL_TYPE: - case FIXED_POINT_TYPE: { + case FIXED_POINT_TYPE: + { unsigned prec = TYPE_PRECISION (type); hstate.add_object (prec); break; @@ -103,7 +115,8 @@ Context::type_hasher (tree type) case RECORD_TYPE: case UNION_TYPE: - case QUAL_UNION_TYPE: { + case QUAL_UNION_TYPE: + { for (tree t = TYPE_FIELDS (type); t; t = TREE_CHAIN (t)) { hashval_t name_hash = IDENTIFIER_HASH_VALUE (DECL_NAME (t)); @@ -118,7 +131,8 @@ Context::type_hasher (tree type) break; case REFERENCE_TYPE: - case POINTER_TYPE: { + case POINTER_TYPE: + { hashval_t type_hash = type_hasher (TREE_TYPE (type)); hstate.add_object (type_hash); } diff --git a/gcc/rust/backend/rust-compile-context.h b/gcc/rust/backend/rust-compile-context.h index ce81a1d0db2c..d4a642b653ca 100644 --- a/gcc/rust/backend/rust-compile-context.h +++ b/gcc/rust/backend/rust-compile-context.h @@ -49,7 +49,7 @@ struct CustomDeriveInfo class Context { public: - Context (); + static Context *get (); void setup_builtins (); @@ -90,7 +90,6 @@ class Context return type; } - Resolver::Resolver *get_resolver () { return resolver; } Resolver::TypeCheckContext *get_tyctx () { return tyctx; } Analysis::Mappings &get_mappings () { return mappings; } @@ -391,7 +390,8 @@ class Context } private: - Resolver::Resolver *resolver; + Context (); + Resolver::TypeCheckContext *tyctx; Analysis::Mappings &mappings; Mangler mangler; diff --git a/gcc/rust/backend/rust-compile-expr.cc b/gcc/rust/backend/rust-compile-expr.cc index dd3420f9f2fa..25da59d982d2 100644 --- a/gcc/rust/backend/rust-compile-expr.cc +++ b/gcc/rust/backend/rust-compile-expr.cc @@ -30,6 +30,7 @@ #include "realmpfr.h" #include "convert.h" #include "print-tree.h" +#include "rust-hir-expr.h" #include "rust-system.h" #include "rust-tyty.h" @@ -440,6 +441,18 @@ CompileExpr::visit (HIR::BlockExpr &expr) translated = Backend::var_expression (tmp, expr.get_locus ()); } +void +CompileExpr::visit (HIR::AnonConst &expr) +{ + expr.get_inner_expr ().accept_vis (*this); +} + +void +CompileExpr::visit (HIR::ConstBlock &expr) +{ + expr.get_const_expr ().accept_vis (*this); +} + void CompileExpr::visit (HIR::UnsafeBlockExpr &expr) { @@ -669,6 +682,15 @@ void CompileExpr::visit (HIR::LoopExpr &expr) { TyTy::BaseType *block_tyty = nullptr; + fncontext fnctx = ctx->peek_fn (); + if (ctx->const_context_p () && !DECL_DECLARED_CONSTEXPR_P (fnctx.fndecl)) + { + rich_location r (line_table, expr.get_locus ()); + rust_error_at (r, ErrorCode::E0658, + "% is not allowed in const context"); + return; + } + if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (), &block_tyty)) { @@ -676,7 +698,6 @@ CompileExpr::visit (HIR::LoopExpr &expr) return; } - fncontext fnctx = ctx->peek_fn (); tree enclosing_scope = ctx->peek_enclosing_scope (); tree block_type = TyTyResolveCompile::compile (ctx, block_tyty); @@ -701,7 +722,8 @@ CompileExpr::visit (HIR::LoopExpr &expr) loop_label.get_lifetime ().get_mappings ().get_hirid (), label); } - tree loop_begin_label = Backend::label (fnctx.fndecl, "", expr.get_locus ()); + tree loop_begin_label + = Backend::label (fnctx.fndecl, tl::nullopt, expr.get_locus ()); tree loop_begin_label_decl = Backend::label_definition_statement (loop_begin_label); ctx->add_statement (loop_begin_label_decl); @@ -743,7 +765,8 @@ CompileExpr::visit (HIR::WhileLoopExpr &expr) start_location, end_location); ctx->push_block (loop_block); - tree loop_begin_label = Backend::label (fnctx.fndecl, "", expr.get_locus ()); + tree loop_begin_label + = Backend::label (fnctx.fndecl, tl::nullopt, expr.get_locus ()); tree loop_begin_label_decl = Backend::label_definition_statement (loop_begin_label); ctx->add_statement (loop_begin_label_decl); @@ -787,25 +810,16 @@ CompileExpr::visit (HIR::BreakExpr &expr) if (expr.has_label ()) { - NodeId resolved_node_id = UNKNOWN_NODEID; - if (flag_name_resolution_2_0) - { - auto &nr_ctx - = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); + auto &nr_ctx + = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); - if (auto id - = nr_ctx.lookup (expr.get_label ().get_mappings ().get_nodeid ())) - resolved_node_id = *id; - } - else + NodeId resolved_node_id; + if (auto id + = nr_ctx.lookup (expr.get_label ().get_mappings ().get_nodeid ())) { - NodeId tmp = UNKNOWN_NODEID; - if (ctx->get_resolver ()->lookup_resolved_label ( - expr.get_label ().get_mappings ().get_nodeid (), &tmp)) - resolved_node_id = tmp; + resolved_node_id = *id; } - - if (resolved_node_id == UNKNOWN_NODEID) + else { rust_error_at ( expr.get_label ().get_locus (), @@ -849,26 +863,16 @@ CompileExpr::visit (HIR::ContinueExpr &expr) tree label = ctx->peek_loop_begin_label (); if (expr.has_label ()) { - NodeId resolved_node_id = UNKNOWN_NODEID; - if (flag_name_resolution_2_0) - { - auto &nr_ctx - = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); + auto &nr_ctx + = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); - if (auto id - = nr_ctx.lookup (expr.get_label ().get_mappings ().get_nodeid ())) - resolved_node_id = *id; - } - else + NodeId resolved_node_id; + if (auto id + = nr_ctx.lookup (expr.get_label ().get_mappings ().get_nodeid ())) { - NodeId tmp = UNKNOWN_NODEID; - - if (ctx->get_resolver ()->lookup_resolved_label ( - expr.get_label ().get_mappings ().get_nodeid (), &tmp)) - resolved_node_id = tmp; + resolved_node_id = *id; } - - if (resolved_node_id == UNKNOWN_NODEID) + else { rust_error_at ( expr.get_label ().get_locus (), @@ -1130,9 +1134,8 @@ CompileExpr::visit (HIR::MatchExpr &expr) // setup the end label so the cases can exit properly tree fndecl = fnctx.fndecl; location_t end_label_locus = expr.get_locus (); // FIXME - tree end_label - = Backend::label (fndecl, "" /* empty creates an artificial label */, - end_label_locus); + // tl::nullopt creates an artificial label + tree end_label = Backend::label (fndecl, tl::nullopt, end_label_locus); tree end_label_decl_statement = Backend::label_definition_statement (end_label); @@ -1325,6 +1328,28 @@ CompileExpr::visit (HIR::CallExpr &expr) }; auto fn_address = CompileExpr::Compile (expr.get_fnexpr (), ctx); + if (ctx->const_context_p ()) + { + if (!FUNCTION_POINTER_TYPE_P (TREE_TYPE (fn_address))) + { + rust_error_at (expr.get_locus (), + "calls in constants are limited to constant " + "functions, tuple structs and tuple variants"); + return; + } + + if (TREE_CODE (fn_address) == ADDR_EXPR) + { + tree fndecl = TREE_OPERAND (fn_address, 0); + if (!DECL_DECLARED_CONSTEXPR_P (fndecl)) + { + rust_error_at (expr.get_locus (), + "calls in constants are limited to constant " + "functions, tuple structs and tuple variants"); + return; + } + } + } // is this a closure call? bool possible_trait_call @@ -1883,7 +1908,8 @@ CompileExpr::visit (HIR::ArrayExpr &expr) HIR::ArrayElems &elements = expr.get_internal_elements (); switch (elements.get_array_expr_type ()) { - case HIR::ArrayElems::ArrayExprType::VALUES: { + case HIR::ArrayElems::ArrayExprType::VALUES: + { HIR::ArrayElemsValues &elems = static_cast (elements); translated @@ -2032,7 +2058,8 @@ HIRCompileBase::resolve_adjustements ( return error_mark_node; case Resolver::Adjustment::AdjustmentType::IMM_REF: - case Resolver::Adjustment::AdjustmentType::MUT_REF: { + case Resolver::Adjustment::AdjustmentType::MUT_REF: + { if (!RS_DST_FLAG (TREE_TYPE (e))) { e = address_expression (e, locus); @@ -2474,23 +2501,12 @@ CompileExpr::generate_closure_function (HIR::ClosureExpr &expr, if (is_block_expr) { auto body_mappings = function_body.get_mappings (); - if (flag_name_resolution_2_0) - { - auto &nr_ctx - = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); + auto &nr_ctx + = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); - auto candidate = nr_ctx.values.to_rib (body_mappings.get_nodeid ()); + auto candidate = nr_ctx.values.to_rib (body_mappings.get_nodeid ()); - rust_assert (candidate.has_value ()); - } - else - { - Resolver::Rib *rib = nullptr; - bool ok - = ctx->get_resolver ()->find_name_rib (body_mappings.get_nodeid (), - &rib); - rust_assert (ok); - } + rust_assert (candidate.has_value ()); } tree enclosing_scope = NULL_TREE; diff --git a/gcc/rust/backend/rust-compile-expr.h b/gcc/rust/backend/rust-compile-expr.h index 65ed4b39e2dd..bc347bf5066f 100644 --- a/gcc/rust/backend/rust-compile-expr.h +++ b/gcc/rust/backend/rust-compile-expr.h @@ -48,6 +48,8 @@ class CompileExpr : private HIRCompileBase, protected HIR::HIRExpressionVisitor void visit (HIR::IfExpr &expr) override; void visit (HIR::IfExprConseqElse &expr) override; void visit (HIR::BlockExpr &expr) override; + void visit (HIR::AnonConst &expr) override; + void visit (HIR::ConstBlock &expr) override; void visit (HIR::UnsafeBlockExpr &expr) override; void visit (HIR::StructExprStruct &struct_expr) override; void visit (HIR::StructExprStructFields &struct_expr) override; diff --git a/gcc/rust/backend/rust-compile-implitem.cc b/gcc/rust/backend/rust-compile-implitem.cc index 1230c85c57ca..63df2f57c16e 100644 --- a/gcc/rust/backend/rust-compile-implitem.cc +++ b/gcc/rust/backend/rust-compile-implitem.cc @@ -27,22 +27,11 @@ CompileTraitItem::visit (HIR::TraitItemConst &constant) rust_assert (concrete != nullptr); TyTy::BaseType *resolved_type = concrete; - tl::optional canonical_path; - if (flag_name_resolution_2_0) - { - auto &nr_ctx - = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); - - canonical_path = nr_ctx.values.to_canonical_path ( - constant.get_mappings ().get_nodeid ()); - } - else - { - canonical_path = ctx->get_mappings ().lookup_canonical_path ( - constant.get_mappings ().get_nodeid ()); - } + auto &nr_ctx + = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); - rust_assert (canonical_path); + Resolver::CanonicalPath canonical_path + = nr_ctx.to_canonical_path (constant.get_mappings ().get_nodeid ()); HIR::Expr &const_value_expr = constant.get_expr (); TyTy::BaseType *expr_type = nullptr; @@ -52,7 +41,7 @@ CompileTraitItem::visit (HIR::TraitItemConst &constant) tree const_expr = compile_constant_item (constant.get_mappings ().get_hirid (), expr_type, - resolved_type, *canonical_path, const_value_expr, + resolved_type, canonical_path, const_value_expr, constant.get_locus (), const_value_expr.get_locus ()); ctx->push_const (const_expr); @@ -96,22 +85,11 @@ CompileTraitItem::visit (HIR::TraitItemFunc &func) fntype->override_context (); } - tl::optional canonical_path; - if (flag_name_resolution_2_0) - { - auto &nr_ctx - = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); - - canonical_path - = nr_ctx.values.to_canonical_path (func.get_mappings ().get_nodeid ()); - } - else - { - canonical_path = ctx->get_mappings ().lookup_canonical_path ( - func.get_mappings ().get_nodeid ()); - } + auto &nr_ctx + = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); - rust_assert (canonical_path); + Resolver::CanonicalPath canonical_path + = nr_ctx.to_canonical_path (func.get_mappings ().get_nodeid ()); // FIXME: How do we get the proper visibility here? auto vis = HIR::Visibility (HIR::Visibility::VisType::PUBLIC); @@ -121,7 +99,7 @@ CompileTraitItem::visit (HIR::TraitItemFunc &func) function.get_self (), function.get_function_params (), function.get_qualifiers (), vis, func.get_outer_attrs (), func.get_locus (), - &func.get_block_expr (), *canonical_path, fntype); + &func.get_block_expr (), canonical_path, fntype); reference = address_expression (fndecl, ref_locus); } diff --git a/gcc/rust/backend/rust-compile-intrinsic.cc b/gcc/rust/backend/rust-compile-intrinsic.cc index 4888e23ed1ef..7627620c4713 100644 --- a/gcc/rust/backend/rust-compile-intrinsic.cc +++ b/gcc/rust/backend/rust-compile-intrinsic.cc @@ -32,8 +32,7 @@ // declaration taken from "stringpool.h" // the get_identifier macro causes compilation issues -extern tree -get_identifier (const char *); +extern tree get_identifier (const char *); namespace Rust { namespace Compile { @@ -70,28 +69,19 @@ check_for_basic_integer_type (const std::string &intrinsic_str, return is_basic_integer; } -static tree -offset_handler (Context *ctx, TyTy::FnType *fntype); -static tree -sizeof_handler (Context *ctx, TyTy::FnType *fntype); -static tree -transmute_handler (Context *ctx, TyTy::FnType *fntype); -static tree -rotate_handler (Context *ctx, TyTy::FnType *fntype, tree_code op); -static tree -wrapping_op_handler_inner (Context *ctx, TyTy::FnType *fntype, tree_code op); -static tree -op_with_overflow_inner (Context *ctx, TyTy::FnType *fntype, tree_code op); -static tree -uninit_handler (Context *ctx, TyTy::FnType *fntype); -static tree -move_val_init_handler (Context *ctx, TyTy::FnType *fntype); -static tree -assume_handler (Context *ctx, TyTy::FnType *fntype); -static tree -discriminant_value_handler (Context *ctx, TyTy::FnType *fntype); -static tree -variant_count_handler (Context *ctx, TyTy::FnType *fntype); +static tree offset_handler (Context *ctx, TyTy::FnType *fntype); +static tree sizeof_handler (Context *ctx, TyTy::FnType *fntype); +static tree transmute_handler (Context *ctx, TyTy::FnType *fntype); +static tree rotate_handler (Context *ctx, TyTy::FnType *fntype, tree_code op); +static tree wrapping_op_handler_inner (Context *ctx, TyTy::FnType *fntype, + tree_code op); +static tree op_with_overflow_inner (Context *ctx, TyTy::FnType *fntype, + tree_code op); +static tree uninit_handler (Context *ctx, TyTy::FnType *fntype); +static tree move_val_init_handler (Context *ctx, TyTy::FnType *fntype); +static tree assume_handler (Context *ctx, TyTy::FnType *fntype); +static tree discriminant_value_handler (Context *ctx, TyTy::FnType *fntype); +static tree variant_count_handler (Context *ctx, TyTy::FnType *fntype); enum class Prefetch { @@ -99,8 +89,8 @@ enum class Prefetch Write }; -static tree -prefetch_data_handler (Context *ctx, TyTy::FnType *fntype, Prefetch kind); +static tree prefetch_data_handler (Context *ctx, TyTy::FnType *fntype, + Prefetch kind); static inline tree rotate_left_handler (Context *ctx, TyTy::FnType *fntype) @@ -140,10 +130,10 @@ prefetch_write_data (Context *ctx, TyTy::FnType *fntype) return prefetch_data_handler (ctx, fntype, Prefetch::Write); } -static tree -atomic_store_handler_inner (Context *ctx, TyTy::FnType *fntype, int ordering); -static tree -atomic_load_handler_inner (Context *ctx, TyTy::FnType *fntype, int ordering); +static tree atomic_store_handler_inner (Context *ctx, TyTy::FnType *fntype, + int ordering); +static tree atomic_load_handler_inner (Context *ctx, TyTy::FnType *fntype, + int ordering); static inline std::function atomic_store_handler (int ordering) @@ -161,8 +151,8 @@ atomic_load_handler (int ordering) }; } -static inline tree -unchecked_op_inner (Context *ctx, TyTy::FnType *fntype, tree_code op); +static inline tree unchecked_op_inner (Context *ctx, TyTy::FnType *fntype, + tree_code op); const static std::function unchecked_op_handler (tree_code op) @@ -172,8 +162,8 @@ unchecked_op_handler (tree_code op) }; } -static inline tree -copy_handler_inner (Context *ctx, TyTy::FnType *fntype, bool overlaps); +static inline tree copy_handler_inner (Context *ctx, TyTy::FnType *fntype, + bool overlaps); const static std::function copy_handler (bool overlaps) @@ -183,8 +173,8 @@ copy_handler (bool overlaps) }; } -static inline tree -expect_handler_inner (Context *ctx, TyTy::FnType *fntype, bool likely); +static inline tree expect_handler_inner (Context *ctx, TyTy::FnType *fntype, + bool likely); const static std::function expect_handler (bool likely) @@ -194,8 +184,8 @@ expect_handler (bool likely) }; } -static tree -try_handler_inner (Context *ctx, TyTy::FnType *fntype, bool is_new_api); +static tree try_handler_inner (Context *ctx, TyTy::FnType *fntype, + bool is_new_api); const static std::function try_handler (bool is_new_api) diff --git a/gcc/rust/backend/rust-compile-item.cc b/gcc/rust/backend/rust-compile-item.cc index 96669903fd55..b72e70d113ec 100644 --- a/gcc/rust/backend/rust-compile-item.cc +++ b/gcc/rust/backend/rust-compile-item.cc @@ -50,33 +50,21 @@ CompileItem::visit (HIR::StaticItem &var) tree type = TyTyResolveCompile::compile (ctx, resolved_type); - tl::optional canonical_path; + auto &nr_ctx + = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); - if (flag_name_resolution_2_0) - { - auto &nr_ctx - = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); - - canonical_path - = nr_ctx.values.to_canonical_path (var.get_mappings ().get_nodeid ()); - } - else - { - canonical_path = ctx->get_mappings ().lookup_canonical_path ( - var.get_mappings ().get_nodeid ()); - } - - rust_assert (canonical_path.has_value ()); + Resolver::CanonicalPath canonical_path + = nr_ctx.to_canonical_path (var.get_mappings ().get_nodeid ()); ctx->push_const_context (); tree value = compile_constant_item (var.get_mappings ().get_hirid (), expr_type, - resolved_type, *canonical_path, const_value_expr, + resolved_type, canonical_path, const_value_expr, var.get_locus (), const_value_expr.get_locus ()); ctx->pop_const_context (); - std::string name = canonical_path->get (); - std::string asm_name = ctx->mangle_item (resolved_type, *canonical_path); + std::string name = canonical_path.get (); + std::string asm_name = ctx->mangle_item (resolved_type, canonical_path); bool is_external = false; bool is_hidden = false; @@ -115,24 +103,12 @@ CompileItem::visit (HIR::ConstantItem &constant) const_value_expr.get_mappings ().get_hirid (), &expr_type); rust_assert (ok); + auto &nr_ctx + = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); + // canonical path Resolver::CanonicalPath canonical_path - = Resolver::CanonicalPath::create_empty (); - - if (flag_name_resolution_2_0) - { - auto &nr_ctx - = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); - - canonical_path - = nr_ctx.values.to_canonical_path (mappings.get_nodeid ()).value (); - } - else - { - canonical_path = ctx->get_mappings () - .lookup_canonical_path (mappings.get_nodeid ()) - .value (); - } + = nr_ctx.to_canonical_path (mappings.get_nodeid ()); ctx->push_const_context (); tree const_expr @@ -210,26 +186,11 @@ CompileItem::visit (HIR::Function &function) } } - Resolver::CanonicalPath canonical_path - = Resolver::CanonicalPath::create_empty (); - - if (flag_name_resolution_2_0) - { - auto &nr_ctx - = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); - - auto path = nr_ctx.values.to_canonical_path ( - function.get_mappings ().get_nodeid ()); + auto &nr_ctx + = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); - canonical_path = path.value (); - } - else - { - auto path = ctx->get_mappings ().lookup_canonical_path ( - function.get_mappings ().get_nodeid ()); - - canonical_path = *path; - } + Resolver::CanonicalPath canonical_path + = nr_ctx.to_canonical_path (function.get_mappings ().get_nodeid ()); const std::string asm_name = ctx->mangle_item (fntype, canonical_path); @@ -300,5 +261,65 @@ CompileItem::visit (HIR::Module &module) CompileItem::compile (item.get (), ctx); } +void +CompileItem::visit (HIR::TupleStruct &tuple_struct_decl) +{ + TyTy::BaseType *lookup = nullptr; + if (!ctx->get_tyctx ()->lookup_type ( + tuple_struct_decl.get_mappings ().get_hirid (), &lookup)) + { + rust_error_at (tuple_struct_decl.get_locus (), "failed to resolve type"); + return; + } + + if (lookup->is_concrete ()) + TyTyResolveCompile::compile (ctx, lookup); +} + +void +CompileItem::visit (HIR::Enum &enum_decl) +{ + TyTy::BaseType *lookup = nullptr; + if (!ctx->get_tyctx ()->lookup_type (enum_decl.get_mappings ().get_hirid (), + &lookup)) + { + rust_error_at (enum_decl.get_locus (), "failed to resolve type"); + return; + } + + if (lookup->is_concrete ()) + TyTyResolveCompile::compile (ctx, lookup); +} + +void +CompileItem::visit (HIR::Union &union_decl) +{ + TyTy::BaseType *lookup = nullptr; + if (!ctx->get_tyctx ()->lookup_type (union_decl.get_mappings ().get_hirid (), + &lookup)) + { + rust_error_at (union_decl.get_locus (), "failed to resolve type"); + return; + } + + if (lookup->is_concrete ()) + TyTyResolveCompile::compile (ctx, lookup); +} + +void +CompileItem::visit (HIR::StructStruct &struct_decl) +{ + TyTy::BaseType *lookup = nullptr; + if (!ctx->get_tyctx ()->lookup_type (struct_decl.get_mappings ().get_hirid (), + &lookup)) + { + rust_error_at (struct_decl.get_locus (), "failed to resolve type"); + return; + } + + if (lookup->is_concrete ()) + TyTyResolveCompile::compile (ctx, lookup); +} + } // namespace Compile } // namespace Rust diff --git a/gcc/rust/backend/rust-compile-item.h b/gcc/rust/backend/rust-compile-item.h index d9d946d25140..56baaabce877 100644 --- a/gcc/rust/backend/rust-compile-item.h +++ b/gcc/rust/backend/rust-compile-item.h @@ -44,9 +44,12 @@ class CompileItem : private HIRCompileBase, protected HIR::HIRStmtVisitor void visit (HIR::ImplBlock &impl_block) override; void visit (HIR::ExternBlock &extern_block) override; void visit (HIR::Module &module) override; + void visit (HIR::TupleStruct &tuple_struct) override; + void visit (HIR::Enum &enum_decl) override; + void visit (HIR::Union &union_decl) override; + void visit (HIR::StructStruct &struct_decl) override; // Empty visit for unused Stmt HIR nodes. - void visit (HIR::TupleStruct &) override {} void visit (HIR::EnumItem &) override {} void visit (HIR::EnumItemTuple &) override {} void visit (HIR::EnumItemStruct &) override {} @@ -57,9 +60,6 @@ class CompileItem : private HIRCompileBase, protected HIR::HIRStmtVisitor void visit (HIR::ExternCrate &) override {} void visit (HIR::UseDeclaration &) override {} void visit (HIR::TypeAlias &) override {} - void visit (HIR::StructStruct &) override {} - void visit (HIR::Enum &) override {} - void visit (HIR::Union &) override {} void visit (HIR::Trait &) override {} void visit (HIR::EmptyStmt &) override {} void visit (HIR::LetStmt &) override {} diff --git a/gcc/rust/backend/rust-compile-pattern.cc b/gcc/rust/backend/rust-compile-pattern.cc index e83717b378bc..6d889baa1992 100644 --- a/gcc/rust/backend/rust-compile-pattern.cc +++ b/gcc/rust/backend/rust-compile-pattern.cc @@ -22,6 +22,11 @@ #include "rust-constexpr.h" #include "rust-compile-type.h" #include "print-tree.h" +#include "rust-diagnostics.h" +#include "rust-hir-pattern-abstract.h" +#include "rust-hir-pattern.h" +#include "rust-system.h" +#include "rust-tyty.h" namespace Rust { namespace Compile { @@ -107,7 +112,8 @@ compile_range_pattern_bound (HIR::RangePatternBound &bound, tree result = NULL_TREE; switch (bound.get_bound_type ()) { - case HIR::RangePatternBound::RangePatternBoundType::LITERAL: { + case HIR::RangePatternBound::RangePatternBoundType::LITERAL: + { auto &ref = static_cast (bound); HIR::LiteralExpr litexpr (mappings, ref.get_literal (), locus, @@ -117,7 +123,8 @@ compile_range_pattern_bound (HIR::RangePatternBound &bound, } break; - case HIR::RangePatternBound::RangePatternBoundType::PATH: { + case HIR::RangePatternBound::RangePatternBoundType::PATH: + { auto &ref = static_cast (bound); result = ResolvePathRef::Compile (ref.get_path (), ctx); @@ -127,7 +134,8 @@ compile_range_pattern_bound (HIR::RangePatternBound &bound, } break; - case HIR::RangePatternBound::RangePatternBoundType::QUALPATH: { + case HIR::RangePatternBound::RangePatternBoundType::QUALPATH: + { auto &ref = static_cast (bound); result = ResolvePathRef::Compile (ref.get_qualified_path (), ctx); @@ -204,6 +212,7 @@ CompilePatternCheckExpr::visit (HIR::StructPattern &pattern) rust_assert (adt->number_of_variants () > 0); TyTy::VariantDef *variant = nullptr; + tree variant_accesser_expr = nullptr; if (adt->is_enum ()) { // lookup the variant @@ -218,9 +227,7 @@ CompilePatternCheckExpr::visit (HIR::StructPattern &pattern) // find expected discriminant // // need to access qualifier the field, if we use QUAL_UNION_TYPE this - // // would be DECL_QUALIFIER i think. For now this will just access the - // // first record field and its respective qualifier because it will - // // always be set because this is all a big special union + // // would be DECL_QUALIFIER i think. HIR::Expr &discrim_expr = variant->get_discriminant (); tree discrim_expr_node = CompileExpr::Compile (discrim_expr, ctx); @@ -229,6 +236,14 @@ CompilePatternCheckExpr::visit (HIR::StructPattern &pattern) = Backend::struct_field_expression (match_scrutinee_expr, 0, pattern.get_path ().get_locus ()); + // access variant data + tree scrutinee_union_expr + = Backend::struct_field_expression (match_scrutinee_expr, 1, + pattern.get_path ().get_locus ()); + variant_accesser_expr + = Backend::struct_field_expression (scrutinee_union_expr, variant_index, + pattern.get_path ().get_locus ()); + check_expr = Backend::comparison_expression (ComparisonOperator::EQUAL, scrutinee_expr_qualifier_expr, @@ -240,6 +255,7 @@ CompilePatternCheckExpr::visit (HIR::StructPattern &pattern) else { variant = adt->get_variants ().at (0); + variant_accesser_expr = match_scrutinee_expr; check_expr = boolean_true_node; } @@ -248,13 +264,15 @@ CompilePatternCheckExpr::visit (HIR::StructPattern &pattern) { switch (field->get_item_type ()) { - case HIR::StructPatternField::ItemType::TUPLE_PAT: { + case HIR::StructPatternField::ItemType::TUPLE_PAT: + { // TODO rust_unreachable (); } break; - case HIR::StructPatternField::ItemType::IDENT_PAT: { + case HIR::StructPatternField::ItemType::IDENT_PAT: + { HIR::StructPatternFieldIdentPat &ident = static_cast (*field.get ()); @@ -263,11 +281,8 @@ CompilePatternCheckExpr::visit (HIR::StructPattern &pattern) nullptr, &offs); rust_assert (ok); - // we may be offsetting by + 1 here since the first field in the - // record is always the discriminator - offs += adt->is_enum (); tree field_expr - = Backend::struct_field_expression (match_scrutinee_expr, offs, + = Backend::struct_field_expression (variant_accesser_expr, offs, ident.get_locus ()); tree check_expr_sub @@ -279,7 +294,8 @@ CompilePatternCheckExpr::visit (HIR::StructPattern &pattern) } break; - case HIR::StructPatternField::ItemType::IDENT: { + case HIR::StructPatternField::ItemType::IDENT: + { // ident pattern always matches - do nothing } break; @@ -338,44 +354,70 @@ CompilePatternCheckExpr::visit (HIR::TupleStructPattern &pattern) HIR::TupleStructItems &items = pattern.get_items (); switch (items.get_item_type ()) { - case HIR::TupleStructItems::RANGED: { + case HIR::TupleStructItems::RANGED: + { // TODO rust_unreachable (); } break; - case HIR::TupleStructItems::MULTIPLE: { + case HIR::TupleStructItems::MULTIPLE: + { HIR::TupleStructItemsNoRange &items_no_range = static_cast (items); rust_assert (items_no_range.get_patterns ().size () == variant->num_fields ()); - size_t tuple_field_index = 0; - for (auto &pattern : items_no_range.get_patterns ()) + if (adt->is_enum ()) { - // find payload union field of scrutinee - tree payload_ref - = Backend::struct_field_expression (match_scrutinee_expr, 1, - pattern->get_locus ()); + size_t tuple_field_index = 0; + for (auto &pattern : items_no_range.get_patterns ()) + { + // find payload union field of scrutinee + tree payload_ref + = Backend::struct_field_expression (match_scrutinee_expr, 1, + pattern->get_locus ()); - tree variant_ref - = Backend::struct_field_expression (payload_ref, variant_index, - pattern->get_locus ()); + tree variant_ref + = Backend::struct_field_expression (payload_ref, + variant_index, + pattern->get_locus ()); - tree field_expr - = Backend::struct_field_expression (variant_ref, - tuple_field_index++, - pattern->get_locus ()); + tree field_expr + = Backend::struct_field_expression (variant_ref, + tuple_field_index++, + pattern->get_locus ()); - tree check_expr_sub - = CompilePatternCheckExpr::Compile (*pattern, field_expr, ctx); - check_expr = Backend::arithmetic_or_logical_expression ( - ArithmeticOrLogicalOperator::BITWISE_AND, check_expr, - check_expr_sub, pattern->get_locus ()); + tree check_expr_sub + = CompilePatternCheckExpr::Compile (*pattern, field_expr, + ctx); + check_expr = Backend::arithmetic_or_logical_expression ( + ArithmeticOrLogicalOperator::BITWISE_AND, check_expr, + check_expr_sub, pattern->get_locus ()); + } } + else + { + // For non-enum TupleStructPatterns + size_t tuple_field_index = 0; + for (auto &pattern : items_no_range.get_patterns ()) + { + tree field_expr + = Backend::struct_field_expression (match_scrutinee_expr, + tuple_field_index++, + pattern->get_locus ()); + + tree check_expr_sub + = CompilePatternCheckExpr::Compile (*pattern, field_expr, + ctx); + check_expr = Backend::arithmetic_or_logical_expression ( + ArithmeticOrLogicalOperator::BITWISE_AND, check_expr, + check_expr_sub, pattern->get_locus ()); + } + } + break; } - break; } } @@ -386,13 +428,57 @@ CompilePatternCheckExpr::visit (HIR::TuplePattern &pattern) switch (pattern.get_items ().get_item_type ()) { - case HIR::TuplePatternItems::RANGED: { - // TODO - gcc_unreachable (); + case HIR::TuplePatternItems::RANGED: + { + auto &items + = static_cast (pattern.get_items ()); + size_t tuple_field_index = 0; + + // lookup the type to find out number of fields + TyTy::BaseType *ty = nullptr; + bool ok = ctx->get_tyctx ()->lookup_type ( + pattern.get_mappings ().get_hirid (), &ty); + rust_assert (ok); + rust_assert (ty->get_kind () == TyTy::TypeKind::TUPLE); + + // compile check expr for lower patterns + for (auto &pat : items.get_lower_patterns ()) + { + tree field_expr + = Backend::struct_field_expression (match_scrutinee_expr, + tuple_field_index++, + pat->get_locus ()); + + tree check_expr_sub + = CompilePatternCheckExpr::Compile (*pat, field_expr, ctx); + check_expr = Backend::arithmetic_or_logical_expression ( + ArithmeticOrLogicalOperator::BITWISE_AND, check_expr, + check_expr_sub, pat->get_locus ()); + } + + // skip the fields that are not checked + tuple_field_index = static_cast (*ty).num_fields () + - items.get_upper_patterns ().size (); + + // compile check expr for upper patterns + for (auto &pat : items.get_upper_patterns ()) + { + tree field_expr + = Backend::struct_field_expression (match_scrutinee_expr, + tuple_field_index++, + pat->get_locus ()); + + tree check_expr_sub + = CompilePatternCheckExpr::Compile (*pat, field_expr, ctx); + check_expr = Backend::arithmetic_or_logical_expression ( + ArithmeticOrLogicalOperator::BITWISE_AND, check_expr, + check_expr_sub, pat->get_locus ()); + } } break; - case HIR::TuplePatternItems::MULTIPLE: { + case HIR::TuplePatternItems::MULTIPLE: + { auto &items = static_cast ( pattern.get_items ()); size_t tuple_field_index = 0; @@ -414,6 +500,67 @@ CompilePatternCheckExpr::visit (HIR::TuplePattern &pattern) } } +void +CompilePatternCheckExpr::visit (HIR::IdentifierPattern &pattern) +{ + if (pattern.has_subpattern ()) + { + check_expr = CompilePatternCheckExpr::Compile (pattern.get_subpattern (), + match_scrutinee_expr, ctx); + } + else + { + check_expr = boolean_true_node; + } +} + +void +CompilePatternCheckExpr::visit (HIR::SlicePattern &pattern) +{ + check_expr = boolean_true_node; + + // lookup the type + TyTy::BaseType *lookup = nullptr; + bool ok + = ctx->get_tyctx ()->lookup_type (pattern.get_mappings ().get_hirid (), + &lookup); + rust_assert (ok); + + // pattern must either be ArrayType or SliceType, should be already confirmed + // by type checking + rust_assert (lookup->get_kind () == TyTy::TypeKind::ARRAY + || lookup->get_kind () == TyTy::TypeKind::SLICE); + + size_t array_element_index = 0; + switch (lookup->get_kind ()) + { + case TyTy::TypeKind::ARRAY: + for (auto &pattern_member : pattern.get_items ()) + { + tree array_index_tree + = Backend::size_constant_expression (array_element_index++); + tree element_expr + = Backend::array_index_expression (match_scrutinee_expr, + array_index_tree, + pattern.get_locus ()); + tree check_expr_sub + = CompilePatternCheckExpr::Compile (*pattern_member, element_expr, + ctx); + check_expr = Backend::arithmetic_or_logical_expression ( + ArithmeticOrLogicalOperator::BITWISE_AND, check_expr, + check_expr_sub, pattern.get_locus ()); + } + break; + case TyTy::TypeKind::SLICE: + rust_sorry_at ( + pattern.get_locus (), + "SlicePattern matching against slices are not yet supported"); + break; + default: + rust_unreachable (); + } +} + // setup the bindings void @@ -449,13 +596,15 @@ CompilePatternBindings::visit (HIR::TupleStructPattern &pattern) HIR::TupleStructItems &items = pattern.get_items (); switch (items.get_item_type ()) { - case HIR::TupleStructItems::RANGED: { + case HIR::TupleStructItems::RANGED: + { // TODO rust_unreachable (); } break; - case HIR::TupleStructItems::MULTIPLE: { + case HIR::TupleStructItems::MULTIPLE: + { HIR::TupleStructItemsNoRange &items_no_range = static_cast (items); @@ -504,6 +653,71 @@ CompilePatternBindings::visit (HIR::TupleStructPattern &pattern) } } +tree +CompilePatternBindings::make_struct_access (TyTy::ADTType *adt, + TyTy::VariantDef *variant, + const Identifier &ident, + int variant_index) +{ + size_t offs = 0; + auto ok = variant->lookup_field (ident.as_string (), nullptr, &offs); + rust_assert (ok); + + if (adt->is_enum ()) + { + tree payload_accessor_union + = Backend::struct_field_expression (match_scrutinee_expr, 1, + ident.get_locus ()); + + tree variant_accessor + = Backend::struct_field_expression (payload_accessor_union, + variant_index, ident.get_locus ()); + + return Backend::struct_field_expression (variant_accessor, offs, + ident.get_locus ()); + } + else + { + tree variant_accessor = match_scrutinee_expr; + + return Backend::struct_field_expression (variant_accessor, offs, + ident.get_locus ()); + } +} + +void +CompilePatternBindings::handle_struct_pattern_ident ( + HIR::StructPatternField &pat, TyTy::ADTType *adt, TyTy::VariantDef *variant, + int variant_index) +{ + HIR::StructPatternFieldIdent &ident + = static_cast (pat); + + auto identifier = ident.get_identifier (); + tree binding = make_struct_access (adt, variant, identifier, variant_index); + + ctx->insert_pattern_binding (ident.get_mappings ().get_hirid (), binding); +} + +void +CompilePatternBindings::handle_struct_pattern_ident_pat ( + HIR::StructPatternField &pat, TyTy::ADTType *adt, TyTy::VariantDef *variant, + int variant_index) +{ + auto &pattern = static_cast (pat); + + tree binding = make_struct_access (adt, variant, pattern.get_identifier (), + variant_index); + CompilePatternBindings::Compile (pattern.get_pattern (), binding, ctx); +} + +void +CompilePatternBindings::handle_struct_pattern_tuple_pat ( + HIR::StructPatternField &pat) +{ + rust_unreachable (); +} + void CompilePatternBindings::visit (HIR::StructPattern &pattern) { @@ -539,54 +753,14 @@ CompilePatternBindings::visit (HIR::StructPattern &pattern) { switch (field->get_item_type ()) { - case HIR::StructPatternField::ItemType::TUPLE_PAT: { - // TODO - rust_unreachable (); - } + case HIR::StructPatternField::ItemType::TUPLE_PAT: + handle_struct_pattern_tuple_pat (*field); break; - - case HIR::StructPatternField::ItemType::IDENT_PAT: { - // TODO - rust_unreachable (); - } + case HIR::StructPatternField::ItemType::IDENT_PAT: + handle_struct_pattern_ident_pat (*field, adt, variant, variant_index); break; - - case HIR::StructPatternField::ItemType::IDENT: { - HIR::StructPatternFieldIdent &ident - = static_cast (*field.get ()); - - size_t offs = 0; - ok = variant->lookup_field (ident.get_identifier ().as_string (), - nullptr, &offs); - rust_assert (ok); - - tree binding = error_mark_node; - if (adt->is_enum ()) - { - tree payload_accessor_union - = Backend::struct_field_expression (match_scrutinee_expr, 1, - ident.get_locus ()); - - tree variant_accessor - = Backend::struct_field_expression (payload_accessor_union, - variant_index, - ident.get_locus ()); - - binding - = Backend::struct_field_expression (variant_accessor, offs, - ident.get_locus ()); - } - else - { - tree variant_accessor = match_scrutinee_expr; - binding - = Backend::struct_field_expression (variant_accessor, offs, - ident.get_locus ()); - } - - ctx->insert_pattern_binding (ident.get_mappings ().get_hirid (), - binding); - } + case HIR::StructPatternField::ItemType::IDENT: + handle_struct_pattern_ident (*field, adt, variant, variant_index); break; } } @@ -605,6 +779,12 @@ CompilePatternBindings::visit (HIR::ReferencePattern &pattern) void CompilePatternBindings::visit (HIR::IdentifierPattern &pattern) { + if (pattern.has_subpattern ()) + { + CompilePatternBindings::Compile (pattern.get_subpattern (), + match_scrutinee_expr, ctx); + } + if (!pattern.get_is_ref ()) { ctx->insert_pattern_binding (pattern.get_mappings ().get_hirid (), @@ -631,7 +811,8 @@ CompilePatternBindings::visit (HIR::TuplePattern &pattern) switch (pattern.get_items ().get_item_type ()) { - case HIR::TuplePatternItems::ItemType::RANGED: { + case HIR::TuplePatternItems::ItemType::RANGED: + { size_t tuple_idx = 0; auto &items = static_cast (pattern.get_items ()); @@ -674,7 +855,8 @@ CompilePatternBindings::visit (HIR::TuplePattern &pattern) return; } - case HIR::TuplePatternItems::ItemType::MULTIPLE: { + case HIR::TuplePatternItems::ItemType::MULTIPLE: + { size_t tuple_idx = 0; auto &items = static_cast ( pattern.get_items ()); @@ -695,12 +877,51 @@ CompilePatternBindings::visit (HIR::TuplePattern &pattern) return; } - default: { + default: + { rust_unreachable (); } } } +void +CompilePatternBindings::visit (HIR::SlicePattern &pattern) +{ + // lookup the type + TyTy::BaseType *lookup = nullptr; + bool ok + = ctx->get_tyctx ()->lookup_type (pattern.get_mappings ().get_hirid (), + &lookup); + rust_assert (ok); + + rust_assert (lookup->get_kind () == TyTy::TypeKind::ARRAY + || lookup->get_kind () == TyTy::TypeKind::SLICE); + + size_t array_element_index = 0; + switch (lookup->get_kind ()) + { + case TyTy::TypeKind::ARRAY: + for (auto &pattern_member : pattern.get_items ()) + { + tree array_index_tree + = Backend::size_constant_expression (array_element_index++); + tree element_expr + = Backend::array_index_expression (match_scrutinee_expr, + array_index_tree, + pattern.get_locus ()); + CompilePatternBindings::Compile (*pattern_member, element_expr, ctx); + } + break; + case TyTy::TypeKind::SLICE: + rust_sorry_at ( + pattern.get_locus (), + "SlicePattern matching against slices are not yet supported"); + break; + default: + rust_unreachable (); + } +} + // void @@ -755,7 +976,8 @@ CompilePatternLet::visit (HIR::TuplePattern &pattern) switch (pattern.get_items ().get_item_type ()) { - case HIR::TuplePatternItems::ItemType::RANGED: { + case HIR::TuplePatternItems::ItemType::RANGED: + { size_t tuple_idx = 0; auto &items = static_cast (pattern.get_items ()); @@ -799,7 +1021,8 @@ CompilePatternLet::visit (HIR::TuplePattern &pattern) return; } - case HIR::TuplePatternItems::ItemType::MULTIPLE: { + case HIR::TuplePatternItems::ItemType::MULTIPLE: + { size_t tuple_idx = 0; auto &items = static_cast ( pattern.get_items ()); @@ -821,7 +1044,8 @@ CompilePatternLet::visit (HIR::TuplePattern &pattern) return; } - default: { + default: + { rust_unreachable (); } } diff --git a/gcc/rust/backend/rust-compile-pattern.h b/gcc/rust/backend/rust-compile-pattern.h index c7a62fcbc532..233799e21da3 100644 --- a/gcc/rust/backend/rust-compile-pattern.h +++ b/gcc/rust/backend/rust-compile-pattern.h @@ -17,7 +17,9 @@ // . #include "rust-compile-base.h" +#include "rust-hir-pattern.h" #include "rust-hir-visitor.h" +#include "rust-tyty.h" namespace Rust { namespace Compile { @@ -43,12 +45,10 @@ class CompilePatternCheckExpr : public HIRCompileBase, void visit (HIR::StructPattern &) override; void visit (HIR::TupleStructPattern &) override; void visit (HIR::TuplePattern &) override; + void visit (HIR::IdentifierPattern &) override; + void visit (HIR::SlicePattern &) override; // Always succeeds - void visit (HIR::IdentifierPattern &) override - { - check_expr = boolean_true_node; - } void visit (HIR::WildcardPattern &) override { check_expr = boolean_true_node; @@ -56,7 +56,6 @@ class CompilePatternCheckExpr : public HIRCompileBase, // Empty visit for unused Pattern HIR nodes. void visit (HIR::QualifiedPathInExpression &) override {} - void visit (HIR::SlicePattern &) override {} CompilePatternCheckExpr (Context *ctx, tree match_scrutinee_expr) : HIRCompileBase (ctx), match_scrutinee_expr (match_scrutinee_expr), @@ -78,11 +77,25 @@ class CompilePatternBindings : public HIRCompileBase, pattern.accept_vis (compiler); } + tree make_struct_access (TyTy::ADTType *adt, TyTy::VariantDef *variant, + const Identifier &ident, int variant_index); + + void handle_struct_pattern_ident (HIR::StructPatternField &pat, + TyTy::ADTType *adt, + TyTy::VariantDef *variant, + int variant_index); + void handle_struct_pattern_ident_pat (HIR::StructPatternField &pat, + TyTy::ADTType *adt, + TyTy::VariantDef *variant, + int variant_index); + void handle_struct_pattern_tuple_pat (HIR::StructPatternField &pat); + void visit (HIR::StructPattern &pattern) override; void visit (HIR::TupleStructPattern &pattern) override; void visit (HIR::ReferencePattern &pattern) override; void visit (HIR::IdentifierPattern &) override; void visit (HIR::TuplePattern &pattern) override; + void visit (HIR::SlicePattern &) override; // Empty visit for unused Pattern HIR nodes. void visit (HIR::AltPattern &) override {} @@ -90,7 +103,6 @@ class CompilePatternBindings : public HIRCompileBase, void visit (HIR::PathInExpression &) override {} void visit (HIR::QualifiedPathInExpression &) override {} void visit (HIR::RangePattern &) override {} - void visit (HIR::SlicePattern &) override {} void visit (HIR::WildcardPattern &) override {} protected: diff --git a/gcc/rust/backend/rust-compile-resolve-path.cc b/gcc/rust/backend/rust-compile-resolve-path.cc index 81d2dbb033f1..be2af64fc38a 100644 --- a/gcc/rust/backend/rust-compile-resolve-path.cc +++ b/gcc/rust/backend/rust-compile-resolve-path.cc @@ -187,13 +187,18 @@ ResolvePathRef::resolve_with_node_id ( } // Handle unit struct + tree resolved_item = error_mark_node; if (lookup->get_kind () == TyTy::TypeKind::ADT) - return attempt_constructor_expression_lookup (lookup, ctx, mappings, - expr_locus); + resolved_item + = attempt_constructor_expression_lookup (lookup, ctx, mappings, + expr_locus); + + if (!error_operand_p (resolved_item)) + return resolved_item; // let the query system figure it out - tree resolved_item = query_compile (ref, lookup, final_segment, mappings, - expr_locus, is_qualified_path); + resolved_item = query_compile (ref, lookup, final_segment, mappings, + expr_locus, is_qualified_path); if (resolved_item != error_mark_node) { TREE_USED (resolved_item) = 1; @@ -209,36 +214,24 @@ ResolvePathRef::resolve (const HIR::PathIdentSegment &final_segment, { TyTy::BaseType *lookup = nullptr; bool ok = ctx->get_tyctx ()->lookup_type (mappings.get_hirid (), &lookup); - rust_assert (ok); + if (!ok) + return error_mark_node; // need to look up the reference for this identifier // this can fail because it might be a Constructor for something // in that case the caller should attempt ResolvePathType::Compile - NodeId ref_node_id = UNKNOWN_NODEID; - if (flag_name_resolution_2_0) - { - auto &nr_ctx - = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); - - auto resolved = nr_ctx.lookup (mappings.get_nodeid ()); + auto &nr_ctx + = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); - if (!resolved) - return attempt_constructor_expression_lookup (lookup, ctx, mappings, - expr_locus); + auto resolved = nr_ctx.lookup (mappings.get_nodeid ()); - ref_node_id = *resolved; - } - else - { - if (!ctx->get_resolver ()->lookup_resolved_name (mappings.get_nodeid (), - &ref_node_id)) - return attempt_constructor_expression_lookup (lookup, ctx, mappings, - expr_locus); - } + if (!resolved) + return attempt_constructor_expression_lookup (lookup, ctx, mappings, + expr_locus); return resolve_with_node_id (final_segment, mappings, expr_locus, - is_qualified_path, ref_node_id); + is_qualified_path, *resolved); } tree @@ -336,11 +329,18 @@ HIRCompileBase::query_compile (HirId ref, TyTy::BaseType *lookup, rust_assert (lookup->is ()); auto fn = lookup->as (); rust_assert (fn->get_num_type_params () > 0); - auto &self = fn->get_substs ().at (0); - auto receiver = self.get_param_ty (); + TyTy::SubstitutionParamMapping &self = fn->get_substs ().at (0); + TyTy::ParamType *receiver = self.get_param_ty (); + TyTy::BaseType *r = receiver; + if (!receiver->can_resolve ()) + { + bool ok + = ctx->get_tyctx ()->lookup_type (receiver->get_ref (), &r); + rust_assert (ok); + } + auto candidates - = Resolver::PathProbeImplTrait::Probe (receiver, final_segment, - trait_ref); + = Resolver::PathProbeImplTrait::Probe (r, final_segment, trait_ref); if (candidates.size () == 0) { // this means we are defaulting back to the trait_item if diff --git a/gcc/rust/backend/rust-compile-type.cc b/gcc/rust/backend/rust-compile-type.cc index 83e5756429f5..8f13bba534b6 100644 --- a/gcc/rust/backend/rust-compile-type.cc +++ b/gcc/rust/backend/rust-compile-type.cc @@ -17,11 +17,11 @@ // . #include "rust-compile-type.h" -#include "rust-compile-expr.h" #include "rust-constexpr.h" -#include "rust-gcc.h" +#include "rust-compile-base.h" #include "tree.h" +#include "fold-const.h" #include "stor-layout.h" namespace Rust { @@ -121,6 +121,13 @@ TyTyResolveCompile::visit (const TyTy::InferType &type) if (orig == lookup) { + TyTy::BaseType *def = nullptr; + if (type.default_type (&def)) + { + translated = TyTyResolveCompile::compile (ctx, def); + return; + } + translated = error_mark_node; return; } @@ -189,7 +196,7 @@ TyTyResolveCompile::visit (const TyTy::ClosureType &type) void TyTyResolveCompile::visit (const TyTy::FnType &type) { - Backend::typed_identifier receiver; + Backend::typed_identifier receiver ("", NULL_TREE, UNKNOWN_LOCATION); std::vector parameters; std::vector results; @@ -454,7 +461,7 @@ TyTyResolveCompile::visit (const TyTy::TupleType &type) } tree struct_type_record = Backend::struct_type (fields); - translated = Backend::named_type (type.as_string (), struct_type_record, + translated = Backend::named_type (type.get_name (), struct_type_record, type.get_ident ().locus); } @@ -463,26 +470,14 @@ TyTyResolveCompile::visit (const TyTy::ArrayType &type) { tree element_type = TyTyResolveCompile::compile (ctx, type.get_element_type ()); + tree folded_capacity_expr = type.get_capacity (); - ctx->push_const_context (); - - HIR::Expr &hir_capacity_expr = type.get_capacity_expr (); - TyTy::BaseType *capacity_expr_ty = nullptr; - bool ok = ctx->get_tyctx ()->lookup_type ( - hir_capacity_expr.get_mappings ().get_hirid (), &capacity_expr_ty); - rust_assert (ok); - tree capacity_expr = HIRCompileBase::compile_constant_expr ( - ctx, hir_capacity_expr.get_mappings ().get_hirid (), capacity_expr_ty, - capacity_expr_ty, Resolver::CanonicalPath::create_empty (), - hir_capacity_expr, type.get_locus (), hir_capacity_expr.get_locus ()); - - ctx->pop_const_context (); + // build_index_type takes the maximum index, which is one less than + // the length. + tree index_type_tree = build_index_type ( + fold_build2 (MINUS_EXPR, sizetype, folded_capacity_expr, size_one_node)); - tree folded_capacity_expr = fold_expr (capacity_expr); - - translated = Backend::array_type (element_type, folded_capacity_expr); - if (translated != error_mark_node) - translated = ctx->insert_compiled_type (translated); + translated = build_array_type (element_type, index_type_tree, false); } void @@ -755,7 +750,9 @@ TyTyResolveCompile::visit (const TyTy::DynamicObjectType &type) void TyTyResolveCompile::visit (const TyTy::OpaqueType &type) { - translated = error_mark_node; + rust_assert (type.can_resolve ()); + auto underlying = type.resolve (); + translated = TyTyResolveCompile::compile (ctx, underlying, trait_object_mode); } tree diff --git a/gcc/rust/backend/rust-compile-var-decl.h b/gcc/rust/backend/rust-compile-var-decl.h index 4c46a7b17d6d..5c6d1459c39b 100644 --- a/gcc/rust/backend/rust-compile-var-decl.h +++ b/gcc/rust/backend/rust-compile-var-decl.h @@ -70,7 +70,8 @@ class CompileVarDecl : public HIRCompileBase, public HIR::HIRPatternVisitor { switch (pattern.get_items ().get_item_type ()) { - case HIR::TuplePatternItems::ItemType::MULTIPLE: { + case HIR::TuplePatternItems::ItemType::MULTIPLE: + { rust_assert (TREE_CODE (translated_type) == RECORD_TYPE); auto &items = static_cast ( pattern.get_items ()); diff --git a/gcc/rust/backend/rust-constexpr.cc b/gcc/rust/backend/rust-constexpr.cc index dc2d6b1066be..d524d09f88ec 100644 --- a/gcc/rust/backend/rust-constexpr.cc +++ b/gcc/rust/backend/rust-constexpr.cc @@ -68,32 +68,24 @@ literal_type_p (tree t) return false; } -static bool -verify_constant (tree, bool, bool *, bool *); - -static HOST_WIDE_INT -find_array_ctor_elt (tree ary, tree dindex, bool insert = false); -static int -array_index_cmp (tree key, tree index); -static bool -potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, - tsubst_flags_t flags, tree *jump_target); -bool -potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, - tsubst_flags_t flags); -tree -unshare_constructor (tree t MEM_STAT_DECL); -void -maybe_save_constexpr_fundef (tree fun); - -static bool -returns (tree *jump_target); -static bool -breaks (tree *jump_target); -static bool -continues (tree *jump_target); -static bool -switches (tree *jump_target); +static bool verify_constant (tree, bool, bool *, bool *); + +static HOST_WIDE_INT find_array_ctor_elt (tree ary, tree dindex, + bool insert = false); +static int array_index_cmp (tree key, tree index); +static bool potential_constant_expression_1 (tree t, bool want_rval, + bool strict, bool now, + tsubst_flags_t flags, + tree *jump_target); +bool potential_constant_expression_1 (tree t, bool want_rval, bool strict, + bool now, tsubst_flags_t flags); +tree unshare_constructor (tree t MEM_STAT_DECL); +void maybe_save_constexpr_fundef (tree fun); + +static bool returns (tree *jump_target); +static bool breaks (tree *jump_target); +static bool continues (tree *jump_target); +static bool switches (tree *jump_target); struct constexpr_global_ctx { @@ -463,60 +455,52 @@ save_fundef_copy (tree fun, tree copy) *slot = copy; } -static tree -constant_value_1 (tree decl, bool strict_p, bool return_aggregate_cst_ok_p, - bool unshare_p); -tree -decl_constant_value (tree decl, bool unshare_p); +static tree constant_value_1 (tree decl, bool strict_p, + bool return_aggregate_cst_ok_p, bool unshare_p); +tree decl_constant_value (tree decl, bool unshare_p); -static void -non_const_var_error (location_t loc, tree r); +static void non_const_var_error (location_t loc, tree r); -static tree -eval_constant_expression (const constexpr_ctx *ctx, tree, bool, bool *, bool *, - tree * = NULL); +static tree eval_constant_expression (const constexpr_ctx *ctx, tree, bool, + bool *, bool *, tree * = NULL); -static tree -constexpr_fn_retval (const constexpr_ctx *ctx, tree r); +static tree constexpr_fn_retval (const constexpr_ctx *ctx, tree r); -static tree -eval_store_expression (const constexpr_ctx *ctx, tree r, bool, bool *, bool *); +static tree eval_store_expression (const constexpr_ctx *ctx, tree r, bool, + bool *, bool *); -static tree -eval_call_expression (const constexpr_ctx *ctx, tree r, bool, bool *, bool *); +static tree eval_call_expression (const constexpr_ctx *ctx, tree r, bool, + bool *, bool *); -static tree -eval_binary_expression (const constexpr_ctx *ctx, tree r, bool, bool *, bool *); +static tree eval_binary_expression (const constexpr_ctx *ctx, tree r, bool, + bool *, bool *); -static tree -get_function_named_in_call (tree t); +static tree get_function_named_in_call (tree t); -static tree -eval_statement_list (const constexpr_ctx *ctx, tree t, bool *non_constant_p, - bool *overflow_p, tree *jump_target); -static tree -extract_string_elt (tree string, unsigned chars_per_elt, unsigned index); +static tree eval_statement_list (const constexpr_ctx *ctx, tree t, + bool *non_constant_p, bool *overflow_p, + tree *jump_target); +static tree extract_string_elt (tree string, unsigned chars_per_elt, + unsigned index); -static tree -eval_conditional_expression (const constexpr_ctx *ctx, tree t, bool lval, - bool *non_constant_p, bool *overflow_p, - tree *jump_target); +static tree eval_conditional_expression (const constexpr_ctx *ctx, tree t, + bool lval, bool *non_constant_p, + bool *overflow_p, tree *jump_target); -static tree -eval_bit_field_ref (const constexpr_ctx *ctx, tree t, bool lval, - bool *non_constant_p, bool *overflow_p); +static tree eval_bit_field_ref (const constexpr_ctx *ctx, tree t, bool lval, + bool *non_constant_p, bool *overflow_p); -static tree -eval_loop_expr (const constexpr_ctx *ctx, tree t, bool *non_constant_p, - bool *overflow_p, tree *jump_target); +static tree eval_loop_expr (const constexpr_ctx *ctx, tree t, + bool *non_constant_p, bool *overflow_p, + tree *jump_target); -static tree -eval_switch_expr (const constexpr_ctx *ctx, tree t, bool *non_constant_p, - bool *overflow_p, tree *jump_target); +static tree eval_switch_expr (const constexpr_ctx *ctx, tree t, + bool *non_constant_p, bool *overflow_p, + tree *jump_target); -static tree -eval_unary_expression (const constexpr_ctx *ctx, tree t, bool /*lval*/, - bool *non_constant_p, bool *overflow_p); +static tree eval_unary_expression (const constexpr_ctx *ctx, tree t, + bool /*lval*/, bool *non_constant_p, + bool *overflow_p); /* Variables and functions to manage constexpr call expansion context. These do not need to be marked for PCH or GC. */ @@ -1235,7 +1219,8 @@ get_or_insert_ctor_field (tree ctor, tree index, int pos_hint = -1) /* We fell off the end of the CONSTRUCTOR, so insert a new entry at the end. */ - insert : { + insert: + { constructor_elt ce = {index, NULL_TREE}; vec_safe_insert (CONSTRUCTOR_ELTS (ctor), idx, ce); @@ -1568,10 +1553,9 @@ free_constructor (tree t) } } -static tree -eval_and_check_array_index (const constexpr_ctx *ctx, tree t, - bool allow_one_past, bool *non_constant_p, - bool *overflow_p); +static tree eval_and_check_array_index (const constexpr_ctx *ctx, tree t, + bool allow_one_past, + bool *non_constant_p, bool *overflow_p); // forked from gcc/cp/constexpr.cc cxx_eval_array_reference @@ -1901,6 +1885,9 @@ eval_constant_expression (const constexpr_ctx *ctx, tree t, bool lval, location_t loc = EXPR_LOCATION (t); + if (t == NULL_TREE) + return NULL_TREE; + if (CONSTANT_CLASS_P (t)) { if (TREE_OVERFLOW (t)) @@ -1936,8 +1923,9 @@ eval_constant_expression (const constexpr_ctx *ctx, tree t, bool lval, return eval_constant_expression (ctx, r, lval, non_constant_p, overflow_p); } - /* fall through */ - case CONST_DECL: { + /* fall through */ + case CONST_DECL: + { /* We used to not check lval for CONST_DECL, but darwin.cc uses CONST_DECL for aggregate constants. */ if (lval) @@ -2045,7 +2033,8 @@ eval_constant_expression (const constexpr_ctx *ctx, tree t, bool lval, overflow_p); break; - case TARGET_EXPR: { + case TARGET_EXPR: + { tree type = TREE_TYPE (t); if (!literal_type_p (type)) @@ -2129,7 +2118,8 @@ eval_constant_expression (const constexpr_ctx *ctx, tree t, bool lval, } break; - case DECL_EXPR: { + case DECL_EXPR: + { r = DECL_EXPR_DECL (t); if (AGGREGATE_TYPE_P (TREE_TYPE (r)) || VECTOR_TYPE_P (TREE_TYPE (r))) @@ -2201,7 +2191,8 @@ eval_constant_expression (const constexpr_ctx *ctx, tree t, bool lval, return eval_constant_expression (ctx, OBJ_TYPE_REF_EXPR (t), lval, non_constant_p, overflow_p); - case EXIT_EXPR: { + case EXIT_EXPR: + { tree cond = TREE_OPERAND (t, 0); cond = eval_constant_expression (ctx, cond, /*lval*/ false, non_constant_p, overflow_p); @@ -2243,7 +2234,8 @@ eval_constant_expression (const constexpr_ctx *ctx, tree t, bool lval, } break; - case ADDR_EXPR: { + case ADDR_EXPR: + { tree oldop = TREE_OPERAND (t, 0); tree op = eval_constant_expression (ctx, oldop, /*lval*/ true, non_constant_p, @@ -2261,7 +2253,8 @@ eval_constant_expression (const constexpr_ctx *ctx, tree t, bool lval, break; } - case COMPOUND_EXPR: { + case COMPOUND_EXPR: + { /* check_return_expr sometimes wraps a TARGET_EXPR in a COMPOUND_EXPR; don't get confused. Also handle EMPTY_CLASS_EXPR introduced by build_call_a. */ @@ -2401,7 +2394,8 @@ eval_constant_expression (const constexpr_ctx *ctx, tree t, bool lval, non_constant_p, overflow_p, jump_target); break; - case CLEANUP_POINT_EXPR: { + case CLEANUP_POINT_EXPR: + { auto_vec cleanups; vec *prev_cleanups = ctx->global->cleanups; ctx->global->cleanups = &cleanups; @@ -2441,7 +2435,8 @@ eval_constant_expression (const constexpr_ctx *ctx, tree t, bool lval, /* FALLTHROUGH. */ case NOP_EXPR: case CONVERT_EXPR: - case VIEW_CONVERT_EXPR: { + case VIEW_CONVERT_EXPR: + { tree oldop = TREE_OPERAND (t, 0); tree op = eval_constant_expression (ctx, oldop, lval, non_constant_p, @@ -2688,7 +2683,8 @@ eval_store_expression (const constexpr_ctx *ctx, tree t, bool lval, { case BIT_FIELD_REF: case COMPONENT_REF: - case ARRAY_REF: { + case ARRAY_REF: + { tree ob = TREE_OPERAND (probe, 0); tree elt = TREE_OPERAND (probe, 1); if (TREE_CODE (elt) == FIELD_DECL /*&& DECL_MUTABLE_P (elt)*/) @@ -3940,7 +3936,8 @@ constexpr_fn_retval (const constexpr_ctx *ctx, tree body) { switch (TREE_CODE (body)) { - case STATEMENT_LIST: { + case STATEMENT_LIST: + { tree expr = NULL_TREE; for (tree stmt : tsi_range (body)) { @@ -3958,13 +3955,15 @@ constexpr_fn_retval (const constexpr_ctx *ctx, tree body) return expr; } - case RETURN_EXPR: { + case RETURN_EXPR: + { bool non_constant_p = false; bool overflow_p = false; return eval_constant_expression (ctx, body, false, &non_constant_p, &overflow_p); } - case DECL_EXPR: { + case DECL_EXPR: + { tree decl = DECL_EXPR_DECL (body); if (TREE_CODE (decl) == USING_DECL /* Accept __func__, __FUNCTION__, and __PRETTY_FUNCTION__. */ @@ -3976,7 +3975,8 @@ constexpr_fn_retval (const constexpr_ctx *ctx, tree body) case CLEANUP_POINT_EXPR: return constexpr_fn_retval (ctx, TREE_OPERAND (body, 0)); - case BIND_EXPR: { + case BIND_EXPR: + { tree b = BIND_EXPR_BODY (body); return constexpr_fn_retval (ctx, b); } @@ -4136,7 +4136,8 @@ array_index_cmp (tree key, tree index) { case INTEGER_CST: return tree_int_cst_compare (key, index); - case RANGE_EXPR: { + case RANGE_EXPR: + { tree lo = TREE_OPERAND (index, 0); tree hi = TREE_OPERAND (index, 1); if (tree_int_cst_lt (key, lo)) @@ -5943,7 +5944,8 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, case BIT_FIELD_REF: return RECUR (TREE_OPERAND (t, 0), want_rval); - case INDIRECT_REF: { + case INDIRECT_REF: + { tree x = TREE_OPERAND (t, 0); STRIP_NOPS (x); return RECUR (x, rval); @@ -6214,7 +6216,8 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, case INIT_EXPR: return RECUR (TREE_OPERAND (t, 1), rval); - case CONSTRUCTOR: { + case CONSTRUCTOR: + { vec *v = CONSTRUCTOR_ELTS (t); constructor_elt *ce; for (i = 0; vec_safe_iterate (v, i, &ce); ++i) @@ -6223,7 +6226,8 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, return true; } - case TREE_LIST: { + case TREE_LIST: + { gcc_assert (TREE_PURPOSE (t) == NULL_TREE || DECL_P (TREE_PURPOSE (t))); if (!RECUR (TREE_VALUE (t), want_rval)) return false; @@ -6238,7 +6242,8 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, case ROUND_DIV_EXPR: case TRUNC_MOD_EXPR: case CEIL_MOD_EXPR: - case ROUND_MOD_EXPR: { + case ROUND_MOD_EXPR: + { tree denom = TREE_OPERAND (t, 1); if (!RECUR (denom, rval)) return false; @@ -6258,7 +6263,8 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, } } - case COMPOUND_EXPR: { + case COMPOUND_EXPR: + { /* check_return_expr sometimes wraps a TARGET_EXPR in a COMPOUND_EXPR; don't get confused. */ tree op0 = TREE_OPERAND (t, 0); @@ -6280,7 +6286,8 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, case TRUTH_OR_EXPR: case TRUTH_ORIF_EXPR: tmp = boolean_false_node; - truth : { + truth: + { tree op0 = TREE_OPERAND (t, 0); tree op1 = TREE_OPERAND (t, 1); if (!RECUR (op0, rval)) diff --git a/gcc/rust/backend/rust-constexpr.h b/gcc/rust/backend/rust-constexpr.h index 77a0797a019d..27f0a2e7fc5e 100644 --- a/gcc/rust/backend/rust-constexpr.h +++ b/gcc/rust/backend/rust-constexpr.h @@ -24,8 +24,7 @@ namespace Rust { namespace Compile { extern tree fold_expr (tree); -extern void -maybe_save_constexpr_fundef (tree fun); +extern void maybe_save_constexpr_fundef (tree fun); } // namespace Compile } // namespace Rust diff --git a/gcc/rust/backend/rust-mangle-v0.cc b/gcc/rust/backend/rust-mangle-v0.cc index d0df4aba27c3..f6b1a4cb54e6 100644 --- a/gcc/rust/backend/rust-mangle-v0.cc +++ b/gcc/rust/backend/rust-mangle-v0.cc @@ -62,9 +62,9 @@ struct V0Path } }; -static std::string -v0_path (Rust::Compile::Context *ctx, const TyTy::BaseType *ty, - const Resolver::CanonicalPath &path); +static std::string v0_path (Rust::Compile::Context *ctx, + const TyTy::BaseType *ty, + const Resolver::CanonicalPath &path); static std::string v0_tuple_prefix (const TyTy::BaseType *ty) @@ -148,7 +148,8 @@ v0_complex_type_prefix (Context *ctx, const TyTy::BaseType *ty) // TODO: generics switch (ty->get_kind ()) { - case TyTy::TypeKind::ADT: { + case TyTy::TypeKind::ADT: + { const TyTy::ADTType *adt = static_cast (ty); return v0_path (ctx, ty, adt->get_ident ().path); } @@ -387,7 +388,8 @@ v0_path (Rust::Compile::Context *ctx, const TyTy::BaseType *ty, { switch (impl_item->first->get_impl_item_type ()) { - case HIR::ImplItem::FUNCTION: { + case HIR::ImplItem::FUNCTION: + { HIR::Function *fn = static_cast (impl_item->first); v0path @@ -408,7 +410,8 @@ v0_path (Rust::Compile::Context *ctx, const TyTy::BaseType *ty, { switch (trait_item.value ()->get_item_kind ()) { - case HIR::TraitItem::FUNC: { + case HIR::TraitItem::FUNC: + { auto fn = static_cast (*trait_item); rust_unreachable (); v0path = v0_function_path (v0path, ctx, ty, @@ -428,7 +431,8 @@ v0_path (Rust::Compile::Context *ctx, const TyTy::BaseType *ty, else if (auto item = mappings.lookup_hir_item (hir_id)) switch (item.value ()->get_item_kind ()) { - case HIR::Item::ItemKind::Function: { + case HIR::Item::ItemKind::Function: + { HIR::Function *fn = static_cast (*item); v0path = v0_function_path (v0path, ctx, ty, fn->get_generic_params (), diff --git a/gcc/rust/backend/rust-mangle.h b/gcc/rust/backend/rust-mangle.h index 2a84b6b1deaa..418f2bdca881 100644 --- a/gcc/rust/backend/rust-mangle.h +++ b/gcc/rust/backend/rust-mangle.h @@ -49,13 +49,12 @@ class Mangler static enum MangleVersion version; }; -std::string -legacy_mangle_item (const TyTy::BaseType *ty, - const Resolver::CanonicalPath &path); +std::string legacy_mangle_item (const TyTy::BaseType *ty, + const Resolver::CanonicalPath &path); -std::string -v0_mangle_item (Rust::Compile::Context *ctx, const TyTy::BaseType *ty, - const Resolver::CanonicalPath &path); +std::string v0_mangle_item (Rust::Compile::Context *ctx, + const TyTy::BaseType *ty, + const Resolver::CanonicalPath &path); } // namespace Compile } // namespace Rust diff --git a/gcc/rust/backend/rust-tree.cc b/gcc/rust/backend/rust-tree.cc index 6cba04b3c277..a3d605cab4b8 100644 --- a/gcc/rust/backend/rust-tree.cc +++ b/gcc/rust/backend/rust-tree.cc @@ -268,7 +268,8 @@ convert_to_void (tree expr, impl_conv_void implicit) return expr; switch (TREE_CODE (expr)) { - case COND_EXPR: { + case COND_EXPR: + { /* The two parts of a cond expr might be separate lvalues. */ tree op1 = TREE_OPERAND (expr, 1); tree op2 = TREE_OPERAND (expr, 2); @@ -294,7 +295,8 @@ convert_to_void (tree expr, impl_conv_void implicit) break; } - case COMPOUND_EXPR: { + case COMPOUND_EXPR: + { /* The second part of a compound expr contains the value. */ tree op1 = TREE_OPERAND (expr, 1); tree new_op1; @@ -323,7 +325,8 @@ convert_to_void (tree expr, impl_conv_void implicit) maybe_warn_nodiscard (expr, implicit); break; - case INDIRECT_REF: { + case INDIRECT_REF: + { tree type = TREE_TYPE (expr); int is_reference = TYPE_REF_P (TREE_TYPE (TREE_OPERAND (expr, 0))); int is_volatile = TYPE_VOLATILE (type); @@ -518,7 +521,8 @@ convert_to_void (tree expr, impl_conv_void implicit) break; } - case VAR_DECL: { + case VAR_DECL: + { /* External variables might be incomplete. */ tree type = TREE_TYPE (expr); int is_complete = COMPLETE_TYPE_P (type); @@ -1485,7 +1489,8 @@ find_parameter_packs_r (tree *tp, int *walk_subtrees, void *data) parameter pack. ??? Should some of these be in cp_walk_subtrees? */ switch (TREE_CODE (t)) { - case DECL_EXPR: { + case DECL_EXPR: + { tree decl = DECL_EXPR_DECL (t); if (is_typedef_decl (decl)) /* Since we stop at typedefs above, we need to look through them at @@ -1506,7 +1511,8 @@ find_parameter_packs_r (tree *tp, int *walk_subtrees, void *data) *walk_subtrees = 0; return NULL_TREE; - case DECLTYPE_TYPE: { + case DECLTYPE_TYPE: + { /* When traversing a DECLTYPE_TYPE_EXPR, we need to set type_pack_expansion_p to false so that any placeholders within the expression don't get marked as parameter packs. */ @@ -1970,7 +1976,8 @@ rs_tree_equal (tree t1, tree t2) case SAVE_EXPR: return rs_tree_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0)); - case CALL_EXPR: { + case CALL_EXPR: + { if (KOENIG_LOOKUP_P (t1) != KOENIG_LOOKUP_P (t2)) return false; @@ -1996,7 +2003,8 @@ rs_tree_equal (tree t1, tree t2) return true; } - case TARGET_EXPR: { + case TARGET_EXPR: + { tree o1 = TREE_OPERAND (t1, 0); tree o2 = TREE_OPERAND (t2, 0); @@ -2067,7 +2075,8 @@ rs_tree_equal (tree t1, tree t2) case tcc_expression: case tcc_vl_exp: case tcc_reference: - case tcc_statement: { + case tcc_statement: + { int n = rs_tree_operand_length (t1); if (TREE_CODE_CLASS (code1) == tcc_vl_exp && n != TREE_OPERAND_LENGTH (t2)) @@ -2095,7 +2104,11 @@ rs_tree_equal (tree t1, tree t2) /* TRUE iff TYPE is publicly & uniquely derived from PARENT. */ -bool publicly_uniquely_derived_p (tree, tree) { return false; } +bool +publicly_uniquely_derived_p (tree, tree) +{ + return false; +} // forked from gcc/cp/typeck.cc comp_except_types @@ -3375,7 +3388,11 @@ release_tree_vector (vec *vec) /* As above, but also check value-dependence of the expression as a whole. */ -bool instantiation_dependent_expression_p (tree) { return false; } +bool +instantiation_dependent_expression_p (tree) +{ + return false; +} // forked from gcc/cp/cvt.cc cp_get_callee @@ -3425,7 +3442,11 @@ scalarish_type_p (const_tree t) constructors are deleted. This function implements the ABI notion of non-trivial copy, which has diverged from the one in the standard. */ -bool type_has_nontrivial_copy_init (const_tree) { return false; } +bool +type_has_nontrivial_copy_init (const_tree) +{ + return false; +} // forked from gcc/cp/tree.cc build_local_temp @@ -3448,7 +3469,11 @@ build_local_temp (tree type) /* Returns true iff DECL is a capture proxy for a normal capture (i.e. without explicit initializer). */ -bool is_normal_capture_proxy (tree) { return false; } +bool +is_normal_capture_proxy (tree) +{ + return false; +} // forked from gcc/cp/c-common.cc reject_gcc_builtin @@ -3522,7 +3547,8 @@ is_bitfield_expr_with_lowered_type (const_tree exp) case BIT_NOT_EXPR: return is_bitfield_expr_with_lowered_type (TREE_OPERAND (exp, 0)); - case COMPONENT_REF: { + case COMPONENT_REF: + { tree field; field = TREE_OPERAND (exp, 1); @@ -3907,7 +3933,8 @@ cxx_incomplete_type_diagnostic (location_t loc, const_tree value, break; case OFFSET_TYPE: - bad_member : { + bad_member: + { tree member = TREE_OPERAND (value, 1); if (is_overloaded_fn (member)) member = get_first_fn (member); @@ -3992,13 +4019,21 @@ decl_constant_var_p (tree decl) /* Returns true iff DECL is a variable or function declared with an auto type that has not yet been deduced to a real type. */ -bool undeduced_auto_decl (tree) { return false; } +bool +undeduced_auto_decl (tree) +{ + return false; +} // forked from gcc/cp/decl.cc require_deduced_type /* Complain if DECL has an undeduced return type. */ -bool require_deduced_type (tree, tsubst_flags_t) { return true; } +bool +require_deduced_type (tree, tsubst_flags_t) +{ + return true; +} /* Return the location of a tree passed to %+ formats. */ @@ -4288,10 +4323,9 @@ struct GTY ((for_user)) source_location_table_entry } // namespace Rust -extern void -gt_pch_nx (Rust::source_location_table_entry &); -extern void -gt_pch_nx (Rust::source_location_table_entry *, gt_pointer_operator, void *); +extern void gt_pch_nx (Rust::source_location_table_entry &); +extern void gt_pch_nx (Rust::source_location_table_entry *, gt_pointer_operator, + void *); namespace Rust { @@ -4419,7 +4453,8 @@ lvalue_kind (const_tree ref) case VIEW_CONVERT_EXPR: return lvalue_kind (TREE_OPERAND (ref, 0)); - case ARRAY_REF: { + case ARRAY_REF: + { tree op1 = TREE_OPERAND (ref, 0); if (TREE_CODE (TREE_TYPE (op1)) == ARRAY_TYPE) { @@ -4516,7 +4551,8 @@ lvalue_kind (const_tree ref) op2_lvalue_kind = lvalue_kind (TREE_OPERAND (ref, 1)); break; - case COND_EXPR: { + case COND_EXPR: + { tree op1 = TREE_OPERAND (ref, 1); if (!op1) op1 = TREE_OPERAND (ref, 0); diff --git a/gcc/rust/backend/rust-tree.h b/gcc/rust/backend/rust-tree.h index bb99684b2bf8..28d93565ac4b 100644 --- a/gcc/rust/backend/rust-tree.h +++ b/gcc/rust/backend/rust-tree.h @@ -1543,7 +1543,7 @@ extern GTY (()) tree cp_global_trees[CPTI_MAX]; #if defined ENABLE_TREE_CHECKING #define LANG_DECL_MIN_CHECK(NODE) \ - __extension__({ \ + __extension__ ({ \ struct lang_decl *lt = DECL_LANG_SPECIFIC (NODE); \ if (!LANG_DECL_HAS_MIN (NODE)) \ lang_check_failed (__FILE__, __LINE__, __FUNCTION__); \ @@ -1554,7 +1554,7 @@ extern GTY (()) tree cp_global_trees[CPTI_MAX]; template, not just on a FUNCTION_DECL. So when looking for things in lang_decl_fn, look down through a TEMPLATE_DECL into its result. */ #define LANG_DECL_FN_CHECK(NODE) \ - __extension__({ \ + __extension__ ({ \ struct lang_decl *lt = DECL_LANG_SPECIFIC (NODE); \ if (!DECL_DECLARES_FUNCTION_P (NODE) || lt->u.base.selector != lds_fn) \ lang_check_failed (__FILE__, __LINE__, __FUNCTION__); \ @@ -1562,7 +1562,7 @@ extern GTY (()) tree cp_global_trees[CPTI_MAX]; }) #define LANG_DECL_NS_CHECK(NODE) \ - __extension__({ \ + __extension__ ({ \ struct lang_decl *lt = DECL_LANG_SPECIFIC (NODE); \ if (TREE_CODE (NODE) != NAMESPACE_DECL || lt->u.base.selector != lds_ns) \ lang_check_failed (__FILE__, __LINE__, __FUNCTION__); \ @@ -1570,7 +1570,7 @@ extern GTY (()) tree cp_global_trees[CPTI_MAX]; }) #define LANG_DECL_PARM_CHECK(NODE) \ - __extension__({ \ + __extension__ ({ \ struct lang_decl *lt = DECL_LANG_SPECIFIC (NODE); \ if (TREE_CODE (NODE) != PARM_DECL || lt->u.base.selector != lds_parm) \ lang_check_failed (__FILE__, __LINE__, __FUNCTION__); \ @@ -1578,7 +1578,7 @@ extern GTY (()) tree cp_global_trees[CPTI_MAX]; }) #define LANG_DECL_DECOMP_CHECK(NODE) \ - __extension__({ \ + __extension__ ({ \ struct lang_decl *lt = DECL_LANG_SPECIFIC (NODE); \ if (!VAR_P (NODE) || lt->u.base.selector != lds_decomp) \ lang_check_failed (__FILE__, __LINE__, __FUNCTION__); \ @@ -2060,8 +2060,8 @@ struct GTY (()) rust_cxx_saved_binding // forked from gcc/cp/name-lookup.h resort_type_member_vec /* needed for GTY annotation */ -extern void -resort_type_member_vec (void *, void *, gt_pointer_operator, void *); +extern void resort_type_member_vec (void *, void *, gt_pointer_operator, + void *); // forked from gcc/cp/cp-tree.h saved_scope @@ -2895,8 +2895,7 @@ enum compare_bounds_t bounds_first }; -extern tree -convert_to_void (tree expr, impl_conv_void implicit); +extern tree convert_to_void (tree expr, impl_conv_void implicit); // The lvalue-to-rvalue conversion (7.1) is applied if and only if the // expression is a glvalue of volatile-qualified type and it is one of the @@ -2911,63 +2910,52 @@ convert_to_void (tree expr, impl_conv_void implicit); // operands are one of these expressions, or // * comma expression (8.19) where the right operand is one of these // expressions. -extern tree -mark_discarded_use (tree expr); +extern tree mark_discarded_use (tree expr); // Mark EXP as read, not just set, for set but not used -Wunused warning // purposes. -extern void -mark_exp_read (tree exp); +extern void mark_exp_read (tree exp); // We've seen an actual use of EXPR. Possibly replace an outer variable // reference inside with its constant value or a lambda capture. -extern tree -mark_use (tree expr, bool rvalue_p, bool read_p, location_t loc, - bool reject_builtin); +extern tree mark_use (tree expr, bool rvalue_p, bool read_p, location_t loc, + bool reject_builtin); // Called whenever the expression EXPR is used in an rvalue context. // When REJECT_BUILTIN is true the expression is checked to make sure // it doesn't make it possible to obtain the address of a GCC built-in // function with no library fallback (or any of its bits, such as in // a conversion to bool). -extern tree -mark_rvalue_use (tree, location_t = UNKNOWN_LOCATION, - bool reject_builtin = true); +extern tree mark_rvalue_use (tree, location_t = UNKNOWN_LOCATION, + bool reject_builtin = true); // Called whenever an expression is used in an lvalue context. -extern tree -mark_lvalue_use (tree expr); +extern tree mark_lvalue_use (tree expr); // As above, but don't consider this use a read. -extern tree -mark_lvalue_use_nonread (tree expr); +extern tree mark_lvalue_use_nonread (tree expr); // We are using a reference VAL for its value. Bash that reference all the way // down to its lowest form. -extern tree -convert_from_reference (tree val); +extern tree convert_from_reference (tree val); // Subroutine of convert_to_void. Warn if we're discarding something with // attribute [[nodiscard]]. -extern void -maybe_warn_nodiscard (tree expr, impl_conv_void implicit); +extern void maybe_warn_nodiscard (tree expr, impl_conv_void implicit); -extern location_t -expr_loc_or_loc (const_tree t, location_t or_loc); +extern location_t expr_loc_or_loc (const_tree t, location_t or_loc); -extern location_t -expr_loc_or_input_loc (const_tree t); +extern location_t expr_loc_or_input_loc (const_tree t); // FN is the callee of a CALL_EXPR or AGGR_INIT_EXPR; return the FUNCTION_DECL // if we can. -extern tree -get_fndecl_from_callee (tree fn); +extern tree get_fndecl_from_callee (tree fn); // FIXME some helpers from HIRCompileBase could probably be moved here over time // Return an expression for the address of BASE[INDEX], used in offset intrinsic -extern tree -pointer_offset_expression (tree base_tree, tree index_tree, location_t locus); +extern tree pointer_offset_expression (tree base_tree, tree index_tree, + location_t locus); /* A tree node, together with a location, so that we can track locations (and ranges) during parsing. @@ -2978,11 +2966,9 @@ pointer_offset_expression (tree base_tree, tree index_tree, location_t locus); extern location_t rs_expr_location (const_tree); -extern int -is_empty_class (tree type); +extern int is_empty_class (tree type); -extern bool -is_really_empty_class (tree, bool); +extern bool is_really_empty_class (tree, bool); extern bool builtin_valid_in_constant_expr_p (const_tree); @@ -2990,15 +2976,13 @@ extern bool maybe_constexpr_fn (tree); extern bool var_in_maybe_constexpr_fn (tree); -extern int -rs_type_quals (const_tree type); +extern int rs_type_quals (const_tree type); inline bool type_unknown_p (const_tree); extern bool decl_maybe_constant_var_p (tree); -extern void -init_modules (); +extern void init_modules (); extern bool var_in_constexpr_fn (tree); @@ -3006,11 +2990,9 @@ inline tree ovl_first (tree) ATTRIBUTE_PURE; inline bool type_unknown_p (const_tree); -extern tree -lookup_add (tree fns, tree lookup); +extern tree lookup_add (tree fns, tree lookup); -extern tree -ovl_make (tree fn, tree next = NULL_TREE); +extern tree ovl_make (tree fn, tree next = NULL_TREE); extern int is_overloaded_fn (tree) ATTRIBUTE_PURE; @@ -3024,19 +3006,15 @@ extern tree make_conv_op_name (tree); extern int type_memfn_quals (const_tree); -struct c_fileinfo * -get_fileinfo (const char *); +struct c_fileinfo *get_fileinfo (const char *); -extern tree -cxx_make_type (enum tree_code CXX_MEM_STAT_INFO); +extern tree cxx_make_type (enum tree_code CXX_MEM_STAT_INFO); -extern tree -build_cplus_array_type (tree, tree, int is_dep = -1); +extern tree build_cplus_array_type (tree, tree, int is_dep = -1); extern bool is_byte_access_type (tree); -extern bool -comptypes (tree, tree, int); +extern bool comptypes (tree, tree, int); extern tree canonical_eh_spec (tree); @@ -3046,8 +3024,7 @@ extern bool rs_tree_equal (tree, tree); extern bool compparms (const_tree, const_tree); -extern tree -rs_build_qualified_type_real (tree, int, tsubst_flags_t); +extern tree rs_build_qualified_type_real (tree, int, tsubst_flags_t); #define rs_build_qualified_type(TYPE, QUALS) \ rs_build_qualified_type_real ((TYPE), (QUALS), tf_warning_or_error) extern bool cv_qualified_p (const_tree); @@ -3056,21 +3033,18 @@ extern bool similar_type_p (tree, tree); extern bool rs_tree_equal (tree, tree); -extern bool -vector_targets_convertible_p (const_tree t1, const_tree t2); +extern bool vector_targets_convertible_p (const_tree t1, const_tree t2); extern bool same_type_ignoring_top_level_qualifiers_p (tree, tree); extern bool comp_ptr_ttypes_const (tree, tree, compare_bounds_t); -extern tree -get_class_binding_direct (tree, tree, bool want_type = false); +extern tree get_class_binding_direct (tree, tree, bool want_type = false); extern tree skip_artificial_parms_for (const_tree, tree); -extern void -lang_check_failed (const char *, int, - const char *) ATTRIBUTE_NORETURN ATTRIBUTE_COLD; +extern void lang_check_failed (const char *, int, + const char *) ATTRIBUTE_NORETURN ATTRIBUTE_COLD; extern tree default_init_uninitialized_part (tree); @@ -3088,8 +3062,7 @@ extern tree in_class_defaulted_default_constructor (tree); extern bool is_instantiation_of_constexpr (tree); -extern bool -check_for_uninitialized_const_var (tree, bool, tsubst_flags_t); +extern bool check_for_uninitialized_const_var (tree, bool, tsubst_flags_t); extern bool reduced_constant_expression_p (tree); @@ -3108,19 +3081,17 @@ extern tree is_bitfield_expr_with_lowered_type (const_tree); extern tree convert_bitfield_to_declared_type (tree); -extern tree -cp_fold_maybe_rvalue (tree, bool); +extern tree cp_fold_maybe_rvalue (tree, bool); extern tree maybe_undo_parenthesized_ref (tree); -extern tree -fold_offsetof (tree, tree = size_type_node, tree_code ctx = ERROR_MARK); +extern tree fold_offsetof (tree, tree = size_type_node, + tree_code ctx = ERROR_MARK); extern tree cp_truthvalue_conversion (tree, tsubst_flags_t); -extern tree -fold_non_dependent_expr (tree, tsubst_flags_t = tf_warning_or_error, - bool = false, tree = NULL_TREE); +extern tree fold_non_dependent_expr (tree, tsubst_flags_t = tf_warning_or_error, + bool = false, tree = NULL_TREE); extern int char_type_p (tree); @@ -3163,13 +3134,11 @@ extern tree build_new_constexpr_heap_type (tree, tree, tree); extern bool is_empty_field (tree); -extern bool -in_immediate_context (); +extern bool in_immediate_context (); extern tree cp_get_callee_fndecl_nofold (tree); -extern bool -cxx_mark_addressable (tree, bool = false); +extern bool cxx_mark_addressable (tree, bool = false); extern tree fold_builtin_source_location (location_t); @@ -3183,25 +3152,22 @@ extern bool glvalue_p (const_tree); extern cp_lvalue_kind lvalue_kind (const_tree); -extern tree -decl_constant_value (tree, bool); +extern tree decl_constant_value (tree, bool); extern tree lookup_enumerator (tree, tree); -extern int -is_class_type (tree, int); +extern int is_class_type (tree, int); extern tree braced_lists_to_strings (tree, tree); -extern tree -fold_builtin_is_pointer_inverconvertible_with_class (location_t, int, tree *); +extern tree fold_builtin_is_pointer_inverconvertible_with_class (location_t, + int, tree *); extern bool layout_compatible_type_p (tree, tree); extern tree finish_underlying_type (tree); -extern tree -c_common_type_for_mode (machine_mode, int); +extern tree c_common_type_for_mode (machine_mode, int); extern bool std_layout_type_p (const_tree); @@ -3213,25 +3179,21 @@ extern void note_failed_type_completion_for_satisfaction (tree); extern tree complete_type_or_maybe_complain (tree, tree, tsubst_flags_t); -extern bool -next_common_initial_seqence (tree &, tree &); +extern bool next_common_initial_seqence (tree &, tree &); extern bool null_member_pointer_value_p (tree); -extern tree -fold_builtin_is_corresponding_member (location_t, int, tree *); +extern tree fold_builtin_is_corresponding_member (location_t, int, tree *); extern tree cp_fold_rvalue (tree); -extern tree -maybe_constant_value (tree, tree = NULL_TREE, bool = false); +extern tree maybe_constant_value (tree, tree = NULL_TREE, bool = false); extern tree lvalue_type (tree); extern void lvalue_error (location_t, enum lvalue_use); -extern tree -cp_fold_maybe_rvalue (tree, bool); +extern tree cp_fold_maybe_rvalue (tree, bool); extern tree get_first_fn (tree) ATTRIBUTE_PURE; @@ -3253,13 +3215,12 @@ enum ce_exact }; -extern tree -rs_build_qualified_type_real (tree, int, tsubst_flags_t); +extern tree rs_build_qualified_type_real (tree, int, tsubst_flags_t); #define rs_build_qualified_type(TYPE, QUALS) \ rs_build_qualified_type_real ((TYPE), (QUALS), tf_warning_or_error) -extern tree -rs_walk_subtrees (tree *, int *, walk_tree_fn, void *, hash_set *); +extern tree rs_walk_subtrees (tree *, int *, walk_tree_fn, void *, + hash_set *); #define rs_walk_tree(tp, func, data, pset) \ walk_tree_1 (tp, func, data, pset, rs_walk_subtrees) #define rs_walk_tree_without_duplicates(tp, func, data) \ @@ -3351,11 +3312,9 @@ gnu_vector_type_p (const_tree type) return TREE_CODE (type) == VECTOR_TYPE && !TYPE_INDIVISIBLE_P (type); } -extern vec * -make_tree_vector (void); +extern vec *make_tree_vector (void); -extern void -release_tree_vector (vec *); +extern void release_tree_vector (vec *); /* Simplified unique_ptr clone to release a tree vec on exit. */ @@ -3373,7 +3332,7 @@ class releasing_vec releasing_vec &operator= (const releasing_vec &); vec_t &operator* () const { return *v; } - vec_t *operator-> () const { return v; } + vec_t *operator->() const { return v; } vec_t *get () const { return v; } operator vec_t * () const { return v; } vec_t **operator& () { return &v; } @@ -3442,8 +3401,7 @@ cxx_incomplete_type_error (const_tree value, const_tree type) cxx_incomplete_type_diagnostic (value, type, DK_ERROR); } -extern location_t -location_of (tree t); +extern location_t location_of (tree t); /* Helpers for IMPLICIT_RVALUE_P to look through automatic dereference. */ @@ -3465,23 +3423,18 @@ set_implicit_rvalue_p (tree ot) } namespace Compile { -extern tree -maybe_constant_init (tree, tree = NULL_TREE, bool = false); +extern tree maybe_constant_init (tree, tree = NULL_TREE, bool = false); -extern void -explain_invalid_constexpr_fn (tree fun); +extern void explain_invalid_constexpr_fn (tree fun); extern bool potential_constant_expression (tree); -extern bool -literal_type_p (tree t); +extern bool literal_type_p (tree t); -extern bool -maybe_constexpr_fn (tree t); +extern bool maybe_constexpr_fn (tree t); -extern tree -fold_non_dependent_init (tree, tsubst_flags_t = tf_warning_or_error, - bool = false, tree = NULL_TREE); +extern tree fold_non_dependent_init (tree, tsubst_flags_t = tf_warning_or_error, + bool = false, tree = NULL_TREE); } // namespace Compile } // namespace Rust diff --git a/gcc/rust/checks/errors/borrowck/polonius/rust-polonius.h b/gcc/rust/checks/errors/borrowck/polonius/rust-polonius.h index 0ce214218212..0434bcfed034 100644 --- a/gcc/rust/checks/errors/borrowck/polonius/rust-polonius.h +++ b/gcc/rust/checks/errors/borrowck/polonius/rust-polonius.h @@ -239,31 +239,25 @@ struct Facts * * Output is not yet implemented and is only dumped to stdout. */ -extern "C" FFI::Output -polonius_run (FFI::FactsView input, bool dump_enabled); +extern "C" FFI::Output polonius_run (FFI::FactsView input, bool dump_enabled); // Helper functions for FFIVector to be used on Rust side extern "C" { -FFI::FFIVector * -FFIVector__new (); +FFI::FFIVector *FFIVector__new (); -FFI::FFIVectorPair * -FFIVector__new_vec_pair (); +FFI::FFIVectorPair *FFIVector__new_vec_pair (); -FFI::FFIVectorTriple * -FFIVector__new_vec_triple (); +FFI::FFIVectorTriple *FFIVector__new_vec_triple (); -void -FFIVector__push (FFI::FFIVector *vector, size_t element); +void FFIVector__push (FFI::FFIVector *vector, size_t element); void FFIVector__push_vec_pair (FFI::FFIVectorPair *vector, FFI::Pair *> element); -void -FFIVector__push_vec_triple (FFI::FFIVectorTriple *vector, - FFI::Triple element); +void FFIVector__push_vec_triple (FFI::FFIVectorTriple *vector, + FFI::Triple element); } } // namespace Polonius diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.cc b/gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.cc index 6b8b2e97ba74..0799a4ea84c1 100644 --- a/gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.cc +++ b/gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.cc @@ -240,7 +240,8 @@ ExprStmtBuilder::visit (HIR::ArrayExpr &expr) auto &elems = expr.get_internal_elements (); switch (elems.get_array_expr_type ()) { - case HIR::ArrayElems::VALUES: { + case HIR::ArrayElems::VALUES: + { auto &elem_vals = (static_cast (elems)); auto init_values = visit_list (elem_vals.get_values ()); // collect locations @@ -254,7 +255,8 @@ ExprStmtBuilder::visit (HIR::ArrayExpr &expr) lookup_type (expr), expr.get_locus ()); break; } - case HIR::ArrayElems::COPIED: { + case HIR::ArrayElems::COPIED: + { auto &elem_copied = (static_cast (elems)); auto init = visit_expr (elem_copied.get_elem_to_copy ()); return_expr (new InitializerExpr ({init}), lookup_type (expr), @@ -414,6 +416,18 @@ ExprStmtBuilder::visit (HIR::BlockExpr &block) ctx.place_db.pop_scope (); } +void +ExprStmtBuilder::visit (HIR::AnonConst &block) +{ + rust_unreachable (); +} + +void +ExprStmtBuilder::visit (HIR::ConstBlock &block) +{ + rust_unreachable (); +} + void ExprStmtBuilder::visit (HIR::ContinueExpr &cont) { diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.h b/gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.h index 5cab3c495fd1..45d3d584825b 100644 --- a/gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.h +++ b/gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.h @@ -84,6 +84,8 @@ class ExprStmtBuilder final : public AbstractExprBuilder, void visit (HIR::MethodCallExpr &expr) override; void visit (HIR::FieldAccessExpr &expr) override; void visit (HIR::BlockExpr &block) override; + void visit (HIR::AnonConst &block) override; + void visit (HIR::ConstBlock &block) override; void visit (HIR::ContinueExpr &cont) override; void visit (HIR::BreakExpr &brk) override; void visit (HIR::RangeFromToExpr &range) override; diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-builder-internal.h b/gcc/rust/checks/errors/borrowck/rust-bir-builder-internal.h index 4df0e14c0ecd..e2cc2ddb0d87 100644 --- a/gcc/rust/checks/errors/borrowck/rust-bir-builder-internal.h +++ b/gcc/rust/checks/errors/borrowck/rust-bir-builder-internal.h @@ -27,6 +27,8 @@ #include "rust-name-resolver.h" #include "rust-bir.h" #include "rust-bir-free-region.h" +#include "rust-immutable-name-resolution-context.h" +#include "options.h" namespace Rust { @@ -402,19 +404,40 @@ class AbstractBuilder template NodeId resolve_label (T &expr) { NodeId resolved_label; - bool ok - = ctx.resolver.lookup_resolved_label (expr.get_mappings ().get_nodeid (), - &resolved_label); - rust_assert (ok); + if (flag_name_resolution_2_0) + { + auto &nr_ctx + = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); + auto res = nr_ctx.lookup (expr.get_mappings ().get_nodeid ()); + rust_assert (res.has_value ()); + resolved_label = res.value (); + } + else + { + bool ok = ctx.resolver.lookup_resolved_label ( + expr.get_mappings ().get_nodeid (), &resolved_label); + rust_assert (ok); + } return resolved_label; } template PlaceId resolve_variable (T &variable) { NodeId variable_id; - bool ok = ctx.resolver.lookup_resolved_name ( - variable.get_mappings ().get_nodeid (), &variable_id); - rust_assert (ok); + if (flag_name_resolution_2_0) + { + auto &nr_ctx + = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); + auto res = nr_ctx.lookup (variable.get_mappings ().get_nodeid ()); + rust_assert (res.has_value ()); + variable_id = res.value (); + } + else + { + bool ok = ctx.resolver.lookup_resolved_name ( + variable.get_mappings ().get_nodeid (), &variable_id); + rust_assert (ok); + } return ctx.place_db.lookup_variable (variable_id); } @@ -425,9 +448,20 @@ class AbstractBuilder // Unlike variables, // functions do not have to be declared in PlaceDB before use. NodeId variable_id; - bool ok = ctx.resolver.lookup_resolved_name ( - variable.get_mappings ().get_nodeid (), &variable_id); - rust_assert (ok); + if (flag_name_resolution_2_0) + { + auto &nr_ctx + = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); + auto res = nr_ctx.lookup (variable.get_mappings ().get_nodeid ()); + rust_assert (res.has_value ()); + variable_id = res.value (); + } + else + { + bool ok = ctx.resolver.lookup_resolved_name ( + variable.get_mappings ().get_nodeid (), &variable_id); + rust_assert (ok); + } if (ty->is ()) return ctx.place_db.get_constant (ty); else diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-builder-lazyboolexpr.h b/gcc/rust/checks/errors/borrowck/rust-bir-builder-lazyboolexpr.h index b7a1555b392b..a5ec56907438 100644 --- a/gcc/rust/checks/errors/borrowck/rust-bir-builder-lazyboolexpr.h +++ b/gcc/rust/checks/errors/borrowck/rust-bir-builder-lazyboolexpr.h @@ -169,6 +169,14 @@ class LazyBooleanExprBuilder : public AbstractExprBuilder { return_place (ExprStmtBuilder (ctx).build (expr), expr.get_locus ()); } + void visit (HIR::AnonConst &expr) override + { + return_place (ExprStmtBuilder (ctx).build (expr), expr.get_locus ()); + } + void visit (HIR::ConstBlock &expr) override + { + return_place (ExprStmtBuilder (ctx).build (expr), expr.get_locus ()); + } void visit (HIR::UnsafeBlockExpr &expr) override { return_place (ExprStmtBuilder (ctx).build (expr), expr.get_locus ()); diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-builder-pattern.cc b/gcc/rust/checks/errors/borrowck/rust-bir-builder-pattern.cc index ee37bb09bc43..2d655f910342 100644 --- a/gcc/rust/checks/errors/borrowck/rust-bir-builder-pattern.cc +++ b/gcc/rust/checks/errors/borrowck/rust-bir-builder-pattern.cc @@ -101,7 +101,8 @@ PatternBindingBuilder::visit (HIR::StructPattern &pattern) { switch (field->get_item_type ()) { - case HIR::StructPatternField::TUPLE_PAT: { + case HIR::StructPatternField::TUPLE_PAT: + { auto tuple = static_cast (field.get ()); @@ -123,7 +124,8 @@ PatternBindingBuilder::visit (HIR::StructPattern &pattern) tuple->get_tuple_pattern ().accept_vis (*this); break; } - case HIR::StructPatternField::IDENT_PAT: { + case HIR::StructPatternField::IDENT_PAT: + { auto ident_field = static_cast (field.get ()); TyTy::StructFieldType *field_ty = nullptr; @@ -139,7 +141,8 @@ PatternBindingBuilder::visit (HIR::StructPattern &pattern) ident_field->get_pattern ().accept_vis (*this); break; } - case HIR::StructPatternField::IDENT: { + case HIR::StructPatternField::IDENT: + { auto ident_field = static_cast (field.get ()); TyTy::StructFieldType *field_ty = nullptr; @@ -199,13 +202,15 @@ PatternBindingBuilder::visit (HIR::TuplePattern &pattern) size_t index = 0; switch (pattern.get_items ().get_item_type ()) { - case HIR::TuplePatternItems::MULTIPLE: { + case HIR::TuplePatternItems::MULTIPLE: + { auto &items = static_cast ( pattern.get_items ()); visit_tuple_fields (items.get_patterns (), saved, index); break; } - case HIR::TuplePatternItems::RANGED: { + case HIR::TuplePatternItems::RANGED: + { auto &items = static_cast (pattern.get_items ()); @@ -244,7 +249,8 @@ PatternBindingBuilder::visit (HIR::TupleStructPattern &pattern) size_t index = 0; switch (pattern.get_items ().get_item_type ()) { - case HIR::TupleStructItems::RANGED: { + case HIR::TupleStructItems::RANGED: + { auto &items = static_cast (pattern.get_items ()); @@ -261,7 +267,8 @@ PatternBindingBuilder::visit (HIR::TupleStructPattern &pattern) visit_tuple_fields (items.get_upper_patterns (), saved, index); break; } - case HIR::TupleStructItems::MULTIPLE: { + case HIR::TupleStructItems::MULTIPLE: + { auto &items = static_cast (pattern.get_items ()); visit_tuple_fields (items.get_patterns (), saved, index); diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-builder-struct.h b/gcc/rust/checks/errors/borrowck/rust-bir-builder-struct.h index 84311cc7a2a7..2e11f635110f 100644 --- a/gcc/rust/checks/errors/borrowck/rust-bir-builder-struct.h +++ b/gcc/rust/checks/errors/borrowck/rust-bir-builder-struct.h @@ -133,6 +133,8 @@ class StructBuilder : public AbstractBuilder, public HIR::HIRFullVisitor void visit (HIR::MethodCallExpr &expr) override { rust_unreachable (); } void visit (HIR::FieldAccessExpr &expr) override { rust_unreachable (); } void visit (HIR::BlockExpr &expr) override { rust_unreachable (); } + void visit (HIR::AnonConst &expr) override { rust_unreachable (); } + void visit (HIR::ConstBlock &expr) override { rust_unreachable (); } void visit (HIR::ClosureExpr &expr) override { rust_unreachable (); } void visit (HIR::ContinueExpr &expr) override { rust_unreachable (); } void visit (HIR::BreakExpr &expr) override { rust_unreachable (); } diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-dump.cc b/gcc/rust/checks/errors/borrowck/rust-bir-dump.cc index 3864b81a4d9e..9a7bb2054aeb 100644 --- a/gcc/rust/checks/errors/borrowck/rust-bir-dump.cc +++ b/gcc/rust/checks/errors/borrowck/rust-bir-dump.cc @@ -182,7 +182,8 @@ Dump::visit (const Statement &stmt) statement_place = stmt.get_place (); switch (stmt.get_kind ()) { - case Statement::Kind::ASSIGNMENT: { + case Statement::Kind::ASSIGNMENT: + { visit_place (stmt.get_place ()); stream << " = "; stmt.get_expr ().accept_vis (*this); diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-fact-collector.h b/gcc/rust/checks/errors/borrowck/rust-bir-fact-collector.h index 32a4cd7b76c8..e3a1247206d6 100644 --- a/gcc/rust/checks/errors/borrowck/rust-bir-fact-collector.h +++ b/gcc/rust/checks/errors/borrowck/rust-bir-fact-collector.h @@ -232,42 +232,50 @@ class FactCollector : public Visitor { switch (stmt.get_kind ()) { - case Statement::Kind::ASSIGNMENT: { + case Statement::Kind::ASSIGNMENT: + { // TODO: for unwind, must had hadning for non-panic-only assignements issue_write_deep (stmt.get_place ()); visit_assignment_expr (stmt.get_place (), stmt.get_expr ()); break; } - case Statement::Kind::SWITCH: { + case Statement::Kind::SWITCH: + { issue_read_move (stmt.get_place ()); issue_jumps (); } break; - case Statement::Kind::GOTO: { + case Statement::Kind::GOTO: + { issue_jumps (); } break; - case Statement::Kind::RETURN: { + case Statement::Kind::RETURN: + { issue_place_access (RETURN_VALUE_PLACE); issue_locals_dealloc (); break; } - case Statement::Kind::STORAGE_DEAD: { + case Statement::Kind::STORAGE_DEAD: + { facts.path_moved_at_base.emplace_back (stmt.get_place ().value, get_current_point_mid ()); facts.var_defined_at.emplace_back (stmt.get_place ().value, get_current_point_mid ()); break; } - case Statement::Kind::STORAGE_LIVE: { + case Statement::Kind::STORAGE_LIVE: + { issue_write_deep (stmt.get_place (), true); break; } - case Statement::Kind::USER_TYPE_ASCRIPTION: { + case Statement::Kind::USER_TYPE_ASCRIPTION: + { issue_user_type_constraints (stmt.get_place (), stmt.get_type ()); break; } - case Statement::Kind::FAKE_READ: { + case Statement::Kind::FAKE_READ: + { issue_place_access (stmt.get_place ()); break; } @@ -791,7 +799,8 @@ class FactCollector : public Visitor type->as ()->get_element_type (), region_start, regions); case TyTy::FNDEF: - case TyTy::TUPLE: { + case TyTy::TUPLE: + { for (auto &field : type->as ()->get_fields ()) sanitize_constraints (field.get_tyty (), region_start, regions); } diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-place.h b/gcc/rust/checks/errors/borrowck/rust-bir-place.h index dd9e672f4120..c4631c7b2f16 100644 --- a/gcc/rust/checks/errors/borrowck/rust-bir-place.h +++ b/gcc/rust/checks/errors/borrowck/rust-bir-place.h @@ -53,7 +53,7 @@ using Variance = TyTy::VarianceAnalysis::Variance; /** A unique identifier for a loan in the BIR. */ struct LoanId { - uint32_t value; + size_t value; // some overloads for comparision bool operator== (const LoanId &rhs) const { return value == rhs.value; } bool operator!= (const LoanId &rhs) const { return !(operator== (rhs)); } @@ -217,7 +217,7 @@ template class IndexVec const T &operator[] (I pid) const { return internal_vector[pid.value]; } void push_back (T &¶m) { internal_vector.push_back (std::move (param)); } - template void emplace_back (Args &&... args) + template void emplace_back (Args &&...args) { internal_vector.emplace_back (std::forward (args)...); } @@ -471,14 +471,16 @@ class PlaceDB case TyTy::FNDEF: case TyTy::NEVER: return true; - case TyTy::TUPLE: { + case TyTy::TUPLE: + { auto &fields = ty->as ()->get_fields (); return std::all_of (fields.begin (), fields.end (), [] (const TyTy::TyVar &field) { return is_type_copy (field.get_tyty ()); }); } - case TyTy::ARRAY: { + case TyTy::ARRAY: + { return is_type_copy (ty->as ()->get_element_type ()); } case TyTy::INFER: diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-visitor.h b/gcc/rust/checks/errors/borrowck/rust-bir-visitor.h index 5dac89e51170..d405569b566d 100644 --- a/gcc/rust/checks/errors/borrowck/rust-bir-visitor.h +++ b/gcc/rust/checks/errors/borrowck/rust-bir-visitor.h @@ -51,7 +51,7 @@ template class VisitableImpl : public BASE { public: template - explicit VisitableImpl (Args &&... args) : BASE (std::forward (args)...) + explicit VisitableImpl (Args &&...args) : BASE (std::forward (args)...) {} void accept_vis (Visitor &visitor) override diff --git a/gcc/rust/checks/errors/borrowck/rust-function-collector.h b/gcc/rust/checks/errors/borrowck/rust-function-collector.h index 7cf095240072..860915e09202 100644 --- a/gcc/rust/checks/errors/borrowck/rust-function-collector.h +++ b/gcc/rust/checks/errors/borrowck/rust-function-collector.h @@ -104,6 +104,8 @@ class FunctionCollector : public HIR::HIRFullVisitor void visit (HIR::MethodCallExpr &expr) override {} void visit (HIR::FieldAccessExpr &expr) override {} void visit (HIR::BlockExpr &expr) override {} + void visit (HIR::AnonConst &expr) override {} + void visit (HIR::ConstBlock &expr) override {} void visit (HIR::ContinueExpr &expr) override {} void visit (HIR::BreakExpr &expr) override {} void visit (HIR::RangeFromToExpr &expr) override {} diff --git a/gcc/rust/checks/errors/privacy/rust-privacy-check.cc b/gcc/rust/checks/errors/privacy/rust-privacy-check.cc index 3d25459d9cfd..5291276a7a37 100644 --- a/gcc/rust/checks/errors/privacy/rust-privacy-check.cc +++ b/gcc/rust/checks/errors/privacy/rust-privacy-check.cc @@ -25,8 +25,7 @@ #include "rust-pub-restricted-visitor.h" #include "rust-privacy-reporter.h" -extern bool -saw_errors (void); +extern bool saw_errors (void); namespace Rust { namespace Privacy { diff --git a/gcc/rust/checks/errors/privacy/rust-privacy-ctx.h b/gcc/rust/checks/errors/privacy/rust-privacy-ctx.h index a506613f64e8..9699ac4f98c7 100644 --- a/gcc/rust/checks/errors/privacy/rust-privacy-ctx.h +++ b/gcc/rust/checks/errors/privacy/rust-privacy-ctx.h @@ -71,8 +71,7 @@ class PrivacyContext #if CHECKING_P namespace selftest { -void -rust_privacy_ctx_test (void); +void rust_privacy_ctx_test (void); } #endif // !CHECKING_P diff --git a/gcc/rust/checks/errors/privacy/rust-privacy-reporter.cc b/gcc/rust/checks/errors/privacy/rust-privacy-reporter.cc index 2a1005343a15..e8a679214d48 100644 --- a/gcc/rust/checks/errors/privacy/rust-privacy-reporter.cc +++ b/gcc/rust/checks/errors/privacy/rust-privacy-reporter.cc @@ -157,7 +157,8 @@ PrivacyReporter::check_for_privacy_violation (const NodeId &use_id, { case ModuleVisibility::Public: break; - case ModuleVisibility::Restricted: { + case ModuleVisibility::Restricted: + { // If we are in the crate, everything is restricted correctly, but we // can't get a module for it if (!current_module.has_value ()) @@ -215,12 +216,14 @@ PrivacyReporter::check_base_type_privacy (Analysis::NodeMapping &node_mappings, case TyTy::USIZE: case TyTy::ISIZE: case TyTy::ADT: - case TyTy::STR: { + case TyTy::STR: + { auto ref_id = ty->get_ref (); if (auto lookup_id = mappings.lookup_hir_to_node (ref_id)) return check_for_privacy_violation (*lookup_id, locus); - rust_unreachable (); } + break; + case TyTy::REF: return recursive_check ( static_cast (ty)->get_base ()); @@ -243,7 +246,8 @@ PrivacyReporter::check_base_type_privacy (Analysis::NodeMapping &node_mappings, static_cast (ty)->get_fields ()) recursive_check (param.get_tyty ()); return; - case TyTy::PLACEHOLDER: { + case TyTy::PLACEHOLDER: + { const auto p = static_cast (ty); if (!p->can_resolve ()) return; @@ -413,7 +417,8 @@ PrivacyReporter::visit (HIR::ArrayExpr &expr) HIR::ArrayElems &elements = expr.get_internal_elements (); switch (elements.get_array_expr_type ()) { - case HIR::ArrayElems::ArrayExprType::VALUES: { + case HIR::ArrayElems::ArrayExprType::VALUES: + { auto &elems = static_cast (elements); for (auto &value : elems.get_values ()) value->accept_vis (*this); @@ -517,6 +522,18 @@ PrivacyReporter::visit (HIR::BlockExpr &expr) expr.get_final_expr ().accept_vis (*this); } +void +PrivacyReporter::visit (HIR::AnonConst &expr) +{ + expr.get_inner_expr ().accept_vis (*this); +} + +void +PrivacyReporter::visit (HIR::ConstBlock &expr) +{ + expr.get_const_expr ().accept_vis (*this); +} + void PrivacyReporter::visit (HIR::ContinueExpr &) {} diff --git a/gcc/rust/checks/errors/privacy/rust-privacy-reporter.h b/gcc/rust/checks/errors/privacy/rust-privacy-reporter.h index 7df2cf488b65..07eebf65df02 100644 --- a/gcc/rust/checks/errors/privacy/rust-privacy-reporter.h +++ b/gcc/rust/checks/errors/privacy/rust-privacy-reporter.h @@ -106,6 +106,8 @@ types virtual void visit (HIR::MethodCallExpr &expr); virtual void visit (HIR::FieldAccessExpr &expr); virtual void visit (HIR::BlockExpr &expr); + virtual void visit (HIR::AnonConst &expr); + virtual void visit (HIR::ConstBlock &expr); virtual void visit (HIR::ContinueExpr &expr); virtual void visit (HIR::BreakExpr &expr); virtual void visit (HIR::RangeFromToExpr &expr); diff --git a/gcc/rust/checks/errors/privacy/rust-reachability.cc b/gcc/rust/checks/errors/privacy/rust-reachability.cc index 1e57674b4024..223c77b5f71f 100644 --- a/gcc/rust/checks/errors/privacy/rust-reachability.cc +++ b/gcc/rust/checks/errors/privacy/rust-reachability.cc @@ -158,7 +158,8 @@ ReachabilityVisitor::visit (HIR::Enum &enum_item) switch (variant->get_enum_item_kind ()) { - case HIR::EnumItem::Tuple: { + case HIR::EnumItem::Tuple: + { // Should we update the fields only if they are public? Similarly to // what we do in the ReachabilityVisitor for HIR::TupleStruct? auto tuple_variant @@ -167,7 +168,8 @@ ReachabilityVisitor::visit (HIR::Enum &enum_item) ctx.update_reachability (field.get_mappings (), variant_reach); break; } - case HIR::EnumItem::Struct: { + case HIR::EnumItem::Struct: + { // Should we update the fields only if they are public? Similarly to // what we do in the ReachabilityVisitor for HIR::StructStruct? auto struct_variant diff --git a/gcc/rust/checks/errors/privacy/rust-visibility-resolver.cc b/gcc/rust/checks/errors/privacy/rust-visibility-resolver.cc index f0da74560768..c59763d73782 100644 --- a/gcc/rust/checks/errors/privacy/rust-visibility-resolver.cc +++ b/gcc/rust/checks/errors/privacy/rust-visibility-resolver.cc @@ -127,7 +127,8 @@ VisibilityResolver::resolve_visibility (const HIR::Visibility &visibility, case HIR::Visibility::PUBLIC: to_resolve = ModuleVisibility::create_public (); return true; - case HIR::Visibility::RESTRICTED: { + case HIR::Visibility::RESTRICTED: + { // FIXME: We also need to handle 2015 vs 2018 edition conflicts auto id = UNKNOWN_DEFID; auto result = resolve_module_path (visibility.get_path (), id); diff --git a/gcc/rust/checks/errors/rust-const-checker.cc b/gcc/rust/checks/errors/rust-const-checker.cc index 3716ea53174f..5cbab3d554ca 100644 --- a/gcc/rust/checks/errors/rust-const-checker.cc +++ b/gcc/rust/checks/errors/rust-const-checker.cc @@ -416,6 +416,26 @@ ConstChecker::visit (BlockExpr &expr) expr.get_final_expr ().accept_vis (*this); } +void +ConstChecker::visit (AnonConst &expr) +{ + const_context.enter (expr.get_mappings ().get_hirid ()); + + expr.get_inner_expr ().accept_vis (*this); + + const_context.exit (); +} + +void +ConstChecker::visit (ConstBlock &expr) +{ + const_context.enter (expr.get_mappings ().get_hirid ()); + + expr.get_const_expr ().accept_vis (*this); + + const_context.exit (); +} + void ConstChecker::visit (ContinueExpr &) {} diff --git a/gcc/rust/checks/errors/rust-const-checker.h b/gcc/rust/checks/errors/rust-const-checker.h index b954330df4ca..22398747e585 100644 --- a/gcc/rust/checks/errors/rust-const-checker.h +++ b/gcc/rust/checks/errors/rust-const-checker.h @@ -113,6 +113,8 @@ class ConstChecker : public HIRFullVisitor virtual void visit (FieldAccessExpr &expr) override; virtual void visit (ClosureExpr &expr) override; virtual void visit (BlockExpr &expr) override; + virtual void visit (AnonConst &expr) override; + virtual void visit (ConstBlock &expr) override; virtual void visit (ContinueExpr &expr) override; virtual void visit (BreakExpr &expr) override; virtual void visit (RangeFromToExpr &expr) override; diff --git a/gcc/rust/checks/errors/rust-hir-pattern-analysis.cc b/gcc/rust/checks/errors/rust-hir-pattern-analysis.cc index 648bc07762db..ec22a0ee92eb 100644 --- a/gcc/rust/checks/errors/rust-hir-pattern-analysis.cc +++ b/gcc/rust/checks/errors/rust-hir-pattern-analysis.cc @@ -294,6 +294,18 @@ PatternChecker::visit (BlockExpr &expr) expr.get_final_expr ().accept_vis (*this); } +void +PatternChecker::visit (AnonConst &expr) +{ + expr.get_inner_expr ().accept_vis (*this); +} + +void +PatternChecker::visit (ConstBlock &expr) +{ + expr.get_const_expr ().accept_vis (*this); +} + void PatternChecker::visit (ContinueExpr &) {} @@ -728,23 +740,27 @@ Constructor::is_covered_by (const Constructor &o) const switch (kind) { - case ConstructorKind::VARIANT: { + case ConstructorKind::VARIANT: + { rust_assert (kind == ConstructorKind::VARIANT); return variant_idx == o.variant_idx; } break; - case ConstructorKind::INT_RANGE: { + case ConstructorKind::INT_RANGE: + { rust_assert (kind == ConstructorKind::INT_RANGE); return int_range.lo >= o.int_range.lo && int_range.hi <= o.int_range.hi; } break; - case ConstructorKind::WILDCARD: { + case ConstructorKind::WILDCARD: + { // TODO: wildcard is covered by a variant of enum with a single // variant return false; } break; - case ConstructorKind::STRUCT: { + case ConstructorKind::STRUCT: + { // Struct pattern is always covered by a other struct constructor. return true; } @@ -900,19 +916,22 @@ PlaceInfo::specialize (const Constructor &c) const switch (c.get_kind ()) { case Constructor::ConstructorKind::WILDCARD: - case Constructor::ConstructorKind::INT_RANGE: { + case Constructor::ConstructorKind::INT_RANGE: + { return {}; } break; case Constructor::ConstructorKind::STRUCT: - case Constructor::ConstructorKind::VARIANT: { + case Constructor::ConstructorKind::VARIANT: + { rust_assert (ty->get_kind () == TyTy::TypeKind::ADT); TyTy::ADTType *adt = static_cast (ty); switch (adt->get_adt_kind ()) { case TyTy::ADTType::ADTKind::ENUM: case TyTy::ADTType::ADTKind::STRUCT_STRUCT: - case TyTy::ADTType::ADTKind::TUPLE_STRUCT: { + case TyTy::ADTType::ADTKind::TUPLE_STRUCT: + { TyTy::VariantDef *variant = adt->get_variants ().at (c.get_variant_index ()); if (variant->get_variant_type () @@ -926,14 +945,16 @@ PlaceInfo::specialize (const Constructor &c) const return new_place_infos; } break; - case TyTy::ADTType::ADTKind::UNION: { + case TyTy::ADTType::ADTKind::UNION: + { // TODO: support unions rust_unreachable (); } } } break; - default: { + default: + { rust_unreachable (); } break; @@ -991,7 +1012,8 @@ WitnessPat::to_string () const { switch (ctor.get_kind ()) { - case Constructor::ConstructorKind::STRUCT: { + case Constructor::ConstructorKind::STRUCT: + { TyTy::ADTType *adt = static_cast (ty); TyTy::VariantDef *variant = adt->get_variants ().at (ctor.get_variant_index ()); @@ -1016,7 +1038,8 @@ WitnessPat::to_string () const return buf; } break; - case Constructor::ConstructorKind::VARIANT: { + case Constructor::ConstructorKind::VARIANT: + { std::string buf; TyTy::ADTType *adt = static_cast (ty); buf += adt->get_identifier (); @@ -1026,11 +1049,13 @@ WitnessPat::to_string () const switch (variant->get_variant_type ()) { - case TyTy::VariantDef::VariantType::NUM: { + case TyTy::VariantDef::VariantType::NUM: + { return buf; } break; - case TyTy::VariantDef::VariantType::TUPLE: { + case TyTy::VariantDef::VariantType::TUPLE: + { buf += "("; for (size_t i = 0; i < fields.size (); i++) { @@ -1042,7 +1067,8 @@ WitnessPat::to_string () const return buf; } break; - case TyTy::VariantDef::VariantType::STRUCT: { + case TyTy::VariantDef::VariantType::STRUCT: + { buf += " {"; if (!fields.empty ()) buf += " "; @@ -1061,7 +1087,8 @@ WitnessPat::to_string () const buf += "}"; } break; - default: { + default: + { rust_unreachable (); } break; @@ -1069,21 +1096,25 @@ WitnessPat::to_string () const return buf; } break; - case Constructor::ConstructorKind::INT_RANGE: { + case Constructor::ConstructorKind::INT_RANGE: + { // TODO: implement rust_unreachable (); } break; - case Constructor::ConstructorKind::WILDCARD: { + case Constructor::ConstructorKind::WILDCARD: + { return "_"; } break; - case Constructor::ConstructorKind::REFERENCE: { + case Constructor::ConstructorKind::REFERENCE: + { // TODO: implement rust_unreachable (); } break; - default: { + default: + { rust_unreachable (); } break; @@ -1100,12 +1131,14 @@ WitnessMatrix::apply_constructor (const Constructor &ctor, // TODO: only support struct and variant ctor for now. switch (ctor.get_kind ()) { - case Constructor::ConstructorKind::WILDCARD: { + case Constructor::ConstructorKind::WILDCARD: + { arity = 0; } break; case Constructor::ConstructorKind::STRUCT: - case Constructor::ConstructorKind::VARIANT: { + case Constructor::ConstructorKind::VARIANT: + { if (ty->get_kind () == TyTy::TypeKind::ADT) { TyTy::ADTType *adt = static_cast (ty); @@ -1118,7 +1151,8 @@ WitnessMatrix::apply_constructor (const Constructor &ctor, } } break; - default: { + default: + { rust_unreachable (); } } @@ -1160,9 +1194,9 @@ WitnessMatrix::extend (const WitnessMatrix &other) } // forward declarations -static DeconstructedPat -lower_pattern (Resolver::TypeCheckContext *ctx, HIR::Pattern &pattern, - TyTy::BaseType *scrutinee_ty); +static DeconstructedPat lower_pattern (Resolver::TypeCheckContext *ctx, + HIR::Pattern &pattern, + TyTy::BaseType *scrutinee_ty); static DeconstructedPat lower_tuple_pattern (Resolver::TypeCheckContext *ctx, @@ -1175,7 +1209,8 @@ lower_tuple_pattern (Resolver::TypeCheckContext *ctx, std::vector fields; switch (elems.get_item_type ()) { - case HIR::TupleStructItems::ItemType::MULTIPLE: { + case HIR::TupleStructItems::ItemType::MULTIPLE: + { HIR::TupleStructItemsNoRange &multiple = static_cast (elems); @@ -1191,12 +1226,14 @@ lower_tuple_pattern (Resolver::TypeCheckContext *ctx, return DeconstructedPat (ctor, arity, fields, pattern.get_locus ()); } break; - case HIR::TupleStructItems::ItemType::RANGED: { + case HIR::TupleStructItems::ItemType::RANGED: + { // TODO: ranged tuple struct items rust_unreachable (); } break; - default: { + default: + { rust_unreachable (); } } @@ -1227,7 +1264,8 @@ lower_struct_pattern (Resolver::TypeCheckContext *ctx, { switch (elem->get_item_type ()) { - case HIR::StructPatternField::ItemType::IDENT: { + case HIR::StructPatternField::ItemType::IDENT: + { HIR::StructPatternFieldIdent *ident = static_cast (elem.get ()); int field_idx @@ -1236,7 +1274,8 @@ lower_struct_pattern (Resolver::TypeCheckContext *ctx, = DeconstructedPat::make_wildcard (pattern.get_locus ()); } break; - case HIR::StructPatternField::ItemType::IDENT_PAT: { + case HIR::StructPatternField::ItemType::IDENT_PAT: + { HIR::StructPatternFieldIdentPat *ident_pat = static_cast (elem.get ()); int field_idx @@ -1246,12 +1285,14 @@ lower_struct_pattern (Resolver::TypeCheckContext *ctx, variant->get_fields ().at (field_idx)->get_field_type ()); } break; - case HIR::StructPatternField::ItemType::TUPLE_PAT: { + case HIR::StructPatternField::ItemType::TUPLE_PAT: + { // TODO: tuple: pat rust_unreachable (); } break; - default: { + default: + { rust_unreachable (); } } @@ -1268,11 +1309,13 @@ lower_pattern (Resolver::TypeCheckContext *ctx, HIR::Pattern &pattern, switch (pat_type) { case HIR::Pattern::PatternType::WILDCARD: - case HIR::Pattern::PatternType::IDENTIFIER: { + case HIR::Pattern::PatternType::IDENTIFIER: + { return DeconstructedPat::make_wildcard (pattern.get_locus ()); } break; - case HIR::Pattern::PatternType::PATH: { + case HIR::Pattern::PatternType::PATH: + { // TODO: support constants, associated constants, enum variants and // structs // https://doc.rust-lang.org/reference/patterns.html#path-patterns @@ -1280,13 +1323,15 @@ lower_pattern (Resolver::TypeCheckContext *ctx, HIR::Pattern &pattern, return DeconstructedPat::make_wildcard (pattern.get_locus ()); } break; - case HIR::Pattern::PatternType::REFERENCE: { + case HIR::Pattern::PatternType::REFERENCE: + { // TODO: unimplemented. Treat this pattern as wildcard for now. return DeconstructedPat::make_wildcard (pattern.get_locus ()); } break; case HIR::Pattern::PatternType::STRUCT: - case HIR::Pattern::PatternType::TUPLE_STRUCT: { + case HIR::Pattern::PatternType::TUPLE_STRUCT: + { HirId path_id = UNKNOWN_HIRID; if (pat_type == HIR::Pattern::PatternType::STRUCT) { @@ -1343,37 +1388,44 @@ lower_pattern (Resolver::TypeCheckContext *ctx, HIR::Pattern &pattern, } } break; - case HIR::Pattern::PatternType::TUPLE: { + case HIR::Pattern::PatternType::TUPLE: + { // TODO: unimplemented. Treat this pattern as wildcard for now. return DeconstructedPat::make_wildcard (pattern.get_locus ()); } break; - case HIR::Pattern::PatternType::SLICE: { + case HIR::Pattern::PatternType::SLICE: + { // TODO: unimplemented. Treat this pattern as wildcard for now. return DeconstructedPat::make_wildcard (pattern.get_locus ()); } break; - case HIR::Pattern::PatternType::ALT: { + case HIR::Pattern::PatternType::ALT: + { // TODO: unimplemented. Treat this pattern as wildcard for now. return DeconstructedPat::make_wildcard (pattern.get_locus ()); } break; - case HIR::Pattern::PatternType::LITERAL: { + case HIR::Pattern::PatternType::LITERAL: + { // TODO: unimplemented. Treat this pattern as wildcard for now. return DeconstructedPat::make_wildcard (pattern.get_locus ()); } break; - case HIR::Pattern::PatternType::RANGE: { + case HIR::Pattern::PatternType::RANGE: + { // TODO: unimplemented. Treat this pattern as wildcard for now. return DeconstructedPat::make_wildcard (pattern.get_locus ()); } break; - case HIR::Pattern::PatternType::GROUPED: { + case HIR::Pattern::PatternType::GROUPED: + { // TODO: unimplemented. Treat this pattern as wildcard for now. return DeconstructedPat::make_wildcard (pattern.get_locus ()); } break; - default: { + default: + { rust_unreachable (); } } diff --git a/gcc/rust/checks/errors/rust-hir-pattern-analysis.h b/gcc/rust/checks/errors/rust-hir-pattern-analysis.h index 6d60ceda5384..5766180ec799 100644 --- a/gcc/rust/checks/errors/rust-hir-pattern-analysis.h +++ b/gcc/rust/checks/errors/rust-hir-pattern-analysis.h @@ -33,9 +33,9 @@ namespace Analysis { using namespace HIR; -void -check_match_usefulness (Resolver::TypeCheckContext *ctx, - TyTy::BaseType *scrutinee_ty, HIR::MatchExpr &expr); +void check_match_usefulness (Resolver::TypeCheckContext *ctx, + TyTy::BaseType *scrutinee_ty, + HIR::MatchExpr &expr); class PatternChecker : public HIR::HIRFullVisitor { @@ -86,6 +86,8 @@ class PatternChecker : public HIR::HIRFullVisitor virtual void visit (MethodCallExpr &expr) override; virtual void visit (FieldAccessExpr &expr) override; virtual void visit (BlockExpr &expr) override; + virtual void visit (AnonConst &expr) override; + virtual void visit (ConstBlock &expr) override; virtual void visit (ClosureExpr &expr) override; virtual void visit (ContinueExpr &expr) override; virtual void visit (BreakExpr &expr) override; diff --git a/gcc/rust/checks/errors/rust-unsafe-checker.cc b/gcc/rust/checks/errors/rust-unsafe-checker.cc index 46eef115877e..d90088faf74e 100644 --- a/gcc/rust/checks/errors/rust-unsafe-checker.cc +++ b/gcc/rust/checks/errors/rust-unsafe-checker.cc @@ -539,6 +539,18 @@ UnsafeChecker::visit (BlockExpr &expr) expr.get_final_expr ().accept_vis (*this); } +void +UnsafeChecker::visit (AnonConst &expr) +{ + expr.get_inner_expr ().accept_vis (*this); +} + +void +UnsafeChecker::visit (ConstBlock &expr) +{ + expr.get_const_expr ().accept_vis (*this); +} + void UnsafeChecker::visit (ContinueExpr &) {} diff --git a/gcc/rust/checks/errors/rust-unsafe-checker.h b/gcc/rust/checks/errors/rust-unsafe-checker.h index 9a8fb7cdb0a7..8a9830f7cd6e 100644 --- a/gcc/rust/checks/errors/rust-unsafe-checker.h +++ b/gcc/rust/checks/errors/rust-unsafe-checker.h @@ -95,6 +95,8 @@ class UnsafeChecker : public HIRFullVisitor virtual void visit (FieldAccessExpr &expr) override; virtual void visit (ClosureExpr &expr) override; virtual void visit (BlockExpr &expr) override; + virtual void visit (AnonConst &expr) override; + virtual void visit (ConstBlock &expr) override; virtual void visit (ContinueExpr &expr) override; virtual void visit (BreakExpr &expr) override; virtual void visit (RangeFromToExpr &expr) override; diff --git a/gcc/rust/expand/rust-cfg-strip.cc b/gcc/rust/expand/rust-cfg-strip.cc index a8c3ca5bfc98..ac795f7259d7 100644 --- a/gcc/rust/expand/rust-cfg-strip.cc +++ b/gcc/rust/expand/rust-cfg-strip.cc @@ -289,7 +289,8 @@ CfgStrip::maybe_strip_generic_args (AST::GenericArgs &args) { switch (arg.get_kind ()) { - case AST::GenericArg::Kind::Type: { + case AST::GenericArg::Kind::Type: + { auto &type = arg.get_type (); type.accept_vis (*this); @@ -298,7 +299,8 @@ CfgStrip::maybe_strip_generic_args (AST::GenericArgs &args) "cannot strip type in this position"); break; } - case AST::GenericArg::Kind::Const: { + case AST::GenericArg::Kind::Const: + { auto &expr = arg.get_expression (); expr.accept_vis (*this); @@ -1190,7 +1192,7 @@ CfgStrip::visit (AST::ClosureExprInnerTyped &expr) rust_error_at (type.get_locus (), "cannot strip type in this position"); // can't strip expression itself, but can strip sub-expressions - auto &definition_block = expr.get_definition_block (); + auto &definition_block = expr.get_definition_expr (); definition_block.accept_vis (*this); if (definition_block.is_marked_for_strip ()) rust_error_at (definition_block.get_locus (), @@ -1763,16 +1765,17 @@ CfgStrip::visit (AST::Module &module) return; } - // A loaded module might have inner attributes - if (module.get_kind () == AST::Module::ModuleKind::LOADED) + if (module.get_kind () == AST::Module::UNLOADED) { - // strip test based on inner attrs - expand_cfg_attrs (module.get_inner_attrs ()); - if (fails_cfg_with_expand (module.get_inner_attrs ())) - { - module.mark_for_strip (); - return; - } + module.load_items (); + } + + // strip test based on inner attrs + expand_cfg_attrs (module.get_inner_attrs ()); + if (fails_cfg_with_expand (module.get_inner_attrs ())) + { + module.mark_for_strip (); + return; } // strip items if required @@ -2260,12 +2263,12 @@ void CfgStrip::visit (AST::IdentifierPattern &pattern) { // can only strip sub-patterns of the inner pattern to bind - if (!pattern.has_pattern_to_bind ()) + if (!pattern.has_subpattern ()) return; AST::DefaultASTVisitor::visit (pattern); - auto &sub_pattern = pattern.get_pattern_to_bind (); + auto &sub_pattern = pattern.get_subpattern (); if (sub_pattern.is_marked_for_strip ()) rust_error_at (sub_pattern.get_locus (), "cannot strip pattern in this position"); diff --git a/gcc/rust/expand/rust-derive-clone.h b/gcc/rust/expand/rust-derive-clone.h index 61224ba527b6..a3320c77f306 100644 --- a/gcc/rust/expand/rust-derive-clone.h +++ b/gcc/rust/expand/rust-derive-clone.h @@ -29,7 +29,7 @@ class DeriveClone : DeriveVisitor public: DeriveClone (location_t loc); - std::unique_ptr go (Item &item); + std::unique_ptr go (Item &item); private: std::unique_ptr expanded; @@ -80,10 +80,10 @@ class DeriveClone : DeriveVisitor MatchCase clone_enum_struct (PathInExpression variant_path, const EnumItemStruct &variant); - virtual void visit_struct (StructStruct &item); - virtual void visit_tuple (TupleStruct &item); - virtual void visit_enum (Enum &item); - virtual void visit_union (Union &item); + virtual void visit_struct (StructStruct &item) override; + virtual void visit_tuple (TupleStruct &item) override; + virtual void visit_enum (Enum &item) override; + virtual void visit_union (Union &item) override; }; } // namespace AST diff --git a/gcc/rust/expand/rust-derive-cmp-common.cc b/gcc/rust/expand/rust-derive-cmp-common.cc new file mode 100644 index 000000000000..22ca16f17729 --- /dev/null +++ b/gcc/rust/expand/rust-derive-cmp-common.cc @@ -0,0 +1,191 @@ +// Copyright (C) 2025 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 +// . + +#include "rust-derive-cmp-common.h" +#include "rust-ast-builder.h" +#include "rust-item.h" + +namespace Rust { +namespace AST { + +SelfOther +SelfOther::index (Builder builder, int idx) +{ + return SelfOther{ + builder.tuple_idx ("self", idx), + builder.tuple_idx ("other", idx), + }; +} + +std::vector +SelfOther::indexes (Builder builder, const std::vector &fields) +{ + std::vector vec; + + for (size_t i = 0; i < fields.size (); i++) + vec.emplace_back (SelfOther::index (builder, i)); + + return vec; +} + +SelfOther +SelfOther::field (Builder builder, const std::string &field_name) +{ + return SelfOther{ + builder.field_access (builder.identifier ("self"), field_name), + builder.field_access (builder.identifier ("other"), field_name), + }; +} + +std::vector +SelfOther::fields (Builder builder, const std::vector &fields) +{ + std::vector vec; + + for (const auto &field : fields) + vec.emplace_back ( + SelfOther::field (builder, field.get_field_name ().as_string ())); + + return vec; +} + +MatchCase +EnumMatchBuilder::tuple (EnumItem &variant_raw) +{ + auto &variant = static_cast (variant_raw); + + auto self_patterns = std::vector> (); + auto other_patterns = std::vector> (); + + auto self_other_exprs = std::vector (); + + for (size_t i = 0; i < variant.get_tuple_fields ().size (); i++) + { + // The patterns we're creating for each field are `self_` and + // `other_` where `i` is the index of the field. It doesn't actually + // matter what we use, as long as it's ordered, unique, and that we can + // reuse it in the match case's return expression to check that they are + // equal. + + auto self_pattern_str = "__self_" + std::to_string (i); + auto other_pattern_str = "__other_" + std::to_string (i); + + self_patterns.emplace_back ( + builder.identifier_pattern (self_pattern_str)); + other_patterns.emplace_back ( + builder.identifier_pattern (other_pattern_str)); + + self_other_exprs.emplace_back (SelfOther{ + builder.identifier (self_pattern_str), + builder.identifier (other_pattern_str), + }); + } + + // TODO: Replace with `reconstruct()` instead of building these twice + auto self_variant_path = builder.variant_path (enum_path, variant_path); + auto other_variant_path = builder.variant_path (enum_path, variant_path); + + auto self_pattern_items = std::unique_ptr ( + new TupleStructItemsNoRange (std::move (self_patterns))); + auto other_pattern_items = std::unique_ptr ( + new TupleStructItemsNoRange (std::move (other_patterns))); + + auto self_pattern = std::unique_ptr ( + new ReferencePattern (std::unique_ptr (new TupleStructPattern ( + self_variant_path, std::move (self_pattern_items))), + false, false, builder.loc)); + auto other_pattern = std::unique_ptr (new ReferencePattern ( + std::unique_ptr (new TupleStructPattern ( + other_variant_path, std::move (other_pattern_items))), + false, false, builder.loc)); + + auto tuple_items = std::make_unique ( + vec (std::move (self_pattern), std::move (other_pattern))); + + auto pattern + = std::make_unique (std::move (tuple_items), builder.loc); + + auto expr = fn (std::move (self_other_exprs)); + + return builder.match_case (std::move (pattern), std::move (expr)); +} + +MatchCase +EnumMatchBuilder::strukt (EnumItem &variant_raw) +{ + auto &variant = static_cast (variant_raw); + + auto self_fields = std::vector> (); + auto other_fields = std::vector> (); + + auto self_other_exprs = std::vector (); + + for (auto &field : variant.get_struct_fields ()) + { + // The patterns we're creating for each field are `self_` and + // `other_` where `field` is the name of the field. It doesn't + // actually matter what we use, as long as it's ordered, unique, and that + // we can reuse it in the match case's return expression to check that + // they are equal. + + auto field_name = field.get_field_name ().as_string (); + + auto self_pattern_str = "__self_" + field_name; + auto other_pattern_str = "__other_" + field_name; + + self_fields.emplace_back (builder.struct_pattern_ident_pattern ( + field_name, builder.identifier_pattern (self_pattern_str))); + other_fields.emplace_back (builder.struct_pattern_ident_pattern ( + field_name, builder.identifier_pattern (other_pattern_str))); + + self_other_exprs.emplace_back (SelfOther{ + builder.identifier (self_pattern_str), + builder.identifier (other_pattern_str), + }); + } + + // TODO: Replace with `reconstruct()` instead of building these twice + auto self_variant_path = builder.variant_path (enum_path, variant_path); + auto other_variant_path = builder.variant_path (enum_path, variant_path); + + auto self_elts = StructPatternElements (std::move (self_fields)); + auto other_elts = StructPatternElements (std::move (other_fields)); + + auto self_pattern = std::unique_ptr (new ReferencePattern ( + std::unique_ptr (new StructPattern (self_variant_path, builder.loc, + std::move (self_elts))), + false, false, builder.loc)); + auto other_pattern = std::unique_ptr ( + new ReferencePattern (std::unique_ptr ( + new StructPattern (other_variant_path, builder.loc, + std::move (other_elts))), + false, false, builder.loc)); + + auto tuple_items = std::make_unique ( + vec (std::move (self_pattern), std::move (other_pattern))); + + auto pattern + = std::make_unique (std::move (tuple_items), builder.loc); + + auto expr = fn (std::move (self_other_exprs)); + + return builder.match_case (std::move (pattern), std::move (expr)); +} + +} // namespace AST +} // namespace Rust diff --git a/gcc/rust/expand/rust-derive-cmp-common.h b/gcc/rust/expand/rust-derive-cmp-common.h new file mode 100644 index 000000000000..4efbed82aaa0 --- /dev/null +++ b/gcc/rust/expand/rust-derive-cmp-common.h @@ -0,0 +1,99 @@ +// Copyright (C) 2025 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 +// . + +#ifndef RUST_DERIVE_CMP_COMMON_H +#define RUST_DERIVE_CMP_COMMON_H + +#include "rust-ast.h" +#include "rust-ast-builder.h" +#include "rust-item.h" +#include "rust-path.h" + +namespace Rust { +namespace AST { + +/** + * A pair of two expressions from each instance being compared. E.g. this + * could be `self.0` and `other.0`, or `self.field` and `other.field` + */ +struct SelfOther +{ + std::unique_ptr self_expr; + std::unique_ptr other_expr; + + /* Create a and an expression */ + static SelfOther index (Builder builder, int idx); + static std::vector indexes (Builder builder, + const std::vector &fields); + + /* Create a and an expression */ + static SelfOther field (Builder builder, const std::string &field_name); + static std::vector fields (Builder builder, + const std::vector &fields); +}; + +/** + * Builder for common match cases used when comparing two enum instances. This + * builder takes care of creating the unique patterns for the `self` instance + * and `other` instance, as well as the entire `MatchCase` required for building + * a proper comparision expression for an implementation of a comparision trait + * for an enum type. The functions take a lambda to use when creating the + * expression of the generated `MatchCase`. + */ +class EnumMatchBuilder +{ +public: + /** + * The type of functions to call when creating the resulting expression in the + * generated `MatchCase` + */ + using ExprFn + = std::function (std::vector &&)>; + + EnumMatchBuilder (const std::string &enum_path, + const std::string &variant_path, ExprFn fn, + Builder &builder) + : enum_path (enum_path), variant_path (variant_path), fn (fn), + builder (builder) + {} + + /** + * Generate a `MatchCase` for an enum tuple variant + * + * (&Enum::Tuple(self0, self1), &Enum::Tuple(other0, other1)) => + */ + MatchCase tuple (EnumItem &variant); + + /** + * Generate a `MatchCase` for an enum struct variant + * + * (&Enum::Struct { a: self_a }, &Enum::Struct { a: other_a }) => + */ + MatchCase strukt (EnumItem &variant); + +private: + const std::string &enum_path; + const std::string &variant_path; + ExprFn fn; + Builder &builder; +}; + +} // namespace AST +} // namespace Rust + +#endif // ! RUST_DERIVE_CMP_COMMON_H diff --git a/gcc/rust/expand/rust-derive-copy.h b/gcc/rust/expand/rust-derive-copy.h index 71972ebf6f72..664a8e0e290b 100644 --- a/gcc/rust/expand/rust-derive-copy.h +++ b/gcc/rust/expand/rust-derive-copy.h @@ -44,10 +44,10 @@ class DeriveCopy : DeriveVisitor copy_impl (std::string name, const std::vector> &type_generics); - virtual void visit_struct (StructStruct &item); - virtual void visit_tuple (TupleStruct &item); - virtual void visit_enum (Enum &item); - virtual void visit_union (Union &item); + virtual void visit_struct (StructStruct &item) override; + virtual void visit_tuple (TupleStruct &item) override; + virtual void visit_enum (Enum &item) override; + virtual void visit_union (Union &item) override; }; } // namespace AST diff --git a/gcc/rust/expand/rust-derive-default.cc b/gcc/rust/expand/rust-derive-default.cc index 2e8b45681994..26ee5461095a 100644 --- a/gcc/rust/expand/rust-derive-default.cc +++ b/gcc/rust/expand/rust-derive-default.cc @@ -98,7 +98,8 @@ DeriveDefault::visit_struct (StructStruct &item) for (auto &field : item.get_fields ()) { auto name = field.get_field_name ().as_string (); - auto expr = default_call (field.get_field_type ().clone_type ()); + auto type = field.get_field_type ().reconstruct (); + auto expr = default_call (std::move (type)); cloned_fields.emplace_back ( builder.struct_expr_field (std::move (name), std::move (expr))); @@ -119,7 +120,7 @@ DeriveDefault::visit_tuple (TupleStruct &tuple_item) for (auto &field : tuple_item.get_fields ()) { - auto type = field.get_field_type ().clone_type (); + auto type = field.get_field_type ().reconstruct (); defaulted_fields.emplace_back (default_call (std::move (type))); } diff --git a/gcc/rust/expand/rust-derive-eq.cc b/gcc/rust/expand/rust-derive-eq.cc index 5e7a8946dfdb..7da137fb5c27 100644 --- a/gcc/rust/expand/rust-derive-eq.cc +++ b/gcc/rust/expand/rust-derive-eq.cc @@ -142,7 +142,7 @@ DeriveEq::visit_tuple (TupleStruct &item) auto types = std::vector> (); for (auto &field : item.get_fields ()) - types.emplace_back (field.get_field_type ().clone_type ()); + types.emplace_back (field.get_field_type ().reconstruct ()); expanded = eq_impls (assert_receiver_is_total_eq_fn (std::move (types)), item.get_identifier ().as_string (), @@ -155,7 +155,7 @@ DeriveEq::visit_struct (StructStruct &item) auto types = std::vector> (); for (auto &field : item.get_fields ()) - types.emplace_back (field.get_field_type ().clone_type ()); + types.emplace_back (field.get_field_type ().reconstruct ()); expanded = eq_impls (assert_receiver_is_total_eq_fn (std::move (types)), item.get_identifier ().as_string (), @@ -175,19 +175,20 @@ DeriveEq::visit_enum (Enum &item) case EnumItem::Kind::Discriminant: // nothing to do as they contain no inner types continue; - case EnumItem::Kind::Tuple: { + case EnumItem::Kind::Tuple: + { auto &tuple = static_cast (*variant); for (auto &field : tuple.get_tuple_fields ()) - types.emplace_back (field.get_field_type ().clone_type ()); - + types.emplace_back (field.get_field_type ().reconstruct ()); break; } - case EnumItem::Kind::Struct: { + case EnumItem::Kind::Struct: + { auto &tuple = static_cast (*variant); for (auto &field : tuple.get_struct_fields ()) - types.emplace_back (field.get_field_type ().clone_type ()); + types.emplace_back (field.get_field_type ().reconstruct ()); break; } @@ -205,7 +206,7 @@ DeriveEq::visit_union (Union &item) auto types = std::vector> (); for (auto &field : item.get_variants ()) - types.emplace_back (field.get_field_type ().clone_type ()); + types.emplace_back (field.get_field_type ().reconstruct ()); expanded = eq_impls (assert_receiver_is_total_eq_fn (std::move (types)), item.get_identifier ().as_string (), diff --git a/gcc/rust/expand/rust-derive-eq.h b/gcc/rust/expand/rust-derive-eq.h index 17af52653dea..fb187ccb02cb 100644 --- a/gcc/rust/expand/rust-derive-eq.h +++ b/gcc/rust/expand/rust-derive-eq.h @@ -31,7 +31,7 @@ class DeriveEq : DeriveVisitor public: DeriveEq (location_t loc); - std::vector> go (Item &item); + std::vector> go (Item &item); private: std::vector> expanded; @@ -70,10 +70,10 @@ class DeriveEq : DeriveVisitor */ std::unique_ptr assert_type_is_eq (std::unique_ptr &&type); - virtual void visit_struct (StructStruct &item); - virtual void visit_tuple (TupleStruct &item); - virtual void visit_enum (Enum &item); - virtual void visit_union (Union &item); + virtual void visit_struct (StructStruct &item) override; + virtual void visit_tuple (TupleStruct &item) override; + virtual void visit_enum (Enum &item) override; + virtual void visit_union (Union &item) override; }; } // namespace AST diff --git a/gcc/rust/expand/rust-derive-hash.cc b/gcc/rust/expand/rust-derive-hash.cc index 0c9b0f7b1057..94aede2fe030 100644 --- a/gcc/rust/expand/rust-derive-hash.cc +++ b/gcc/rust/expand/rust-derive-hash.cc @@ -231,14 +231,7 @@ DeriveHash::visit_enum (Enum &item) auto cases = std::vector (); auto type_name = item.get_identifier ().as_string (); - auto intrinsic = ptrify ( - builder.path_in_expression ({"core", "intrinsics", "discriminant_value"}, - true)); - - auto let_discr - = builder.let (builder.identifier_pattern (DeriveHash::discr), nullptr, - builder.call (std::move (intrinsic), - builder.identifier ("self"))); + auto let_discr = builder.discriminant_value (DeriveHash::discr); auto discr_hash = builder.statementify ( hash_call (builder.ref (builder.identifier (DeriveHash::discr)))); diff --git a/gcc/rust/expand/rust-derive-hash.h b/gcc/rust/expand/rust-derive-hash.h index 02b0bee10a5d..67170d0c8a01 100644 --- a/gcc/rust/expand/rust-derive-hash.h +++ b/gcc/rust/expand/rust-derive-hash.h @@ -29,7 +29,7 @@ class DeriveHash : DeriveVisitor public: DeriveHash (location_t loc); - std::unique_ptr go (Item &item); + std::unique_ptr go (Item &item); private: std::unique_ptr expanded; @@ -49,10 +49,10 @@ class DeriveHash : DeriveVisitor MatchCase match_enum_struct (PathInExpression variant_path, const EnumItemStruct &variant); - virtual void visit_struct (StructStruct &item); - virtual void visit_tuple (TupleStruct &item); - virtual void visit_enum (Enum &item); - virtual void visit_union (Union &item); + virtual void visit_struct (StructStruct &item) override; + virtual void visit_tuple (TupleStruct &item) override; + virtual void visit_enum (Enum &item) override; + virtual void visit_union (Union &item) override; }; } // namespace AST diff --git a/gcc/rust/expand/rust-derive-ord.cc b/gcc/rust/expand/rust-derive-ord.cc new file mode 100644 index 000000000000..afc4b71676a1 --- /dev/null +++ b/gcc/rust/expand/rust-derive-ord.cc @@ -0,0 +1,323 @@ +// Copyright (C) 2025 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 +// . + +#include "rust-derive-ord.h" +#include "rust-ast.h" +#include "rust-derive-cmp-common.h" +#include "rust-derive.h" +#include "rust-item.h" +#include "rust-system.h" + +namespace Rust { +namespace AST { + +DeriveOrd::DeriveOrd (Ordering ordering, location_t loc) + : DeriveVisitor (loc), ordering (ordering) +{} + +std::unique_ptr +DeriveOrd::go (Item &item) +{ + item.accept_vis (*this); + + return std::move (expanded); +} + +std::unique_ptr +DeriveOrd::cmp_call (std::unique_ptr &&self_expr, + std::unique_ptr &&other_expr) +{ + auto cmp_fn_path = builder.path_in_expression ( + {"core", "cmp", trait (ordering), fn (ordering)}, true); + + return builder.call (ptrify (cmp_fn_path), + vec (builder.ref (std::move (self_expr)), + builder.ref (std::move (other_expr)))); +} + +std::unique_ptr +DeriveOrd::cmp_impl ( + std::unique_ptr &&fn_block, Identifier type_name, + const std::vector> &type_generics) +{ + auto fn = cmp_fn (std::move (fn_block), type_name); + + auto trait = ordering == Ordering::Partial ? "PartialOrd" : "Ord"; + auto trait_path = builder.type_path ({"core", "cmp", trait}, true); + + auto trait_bound + = builder.trait_bound (builder.type_path ({"core", "cmp", trait}, true)); + + auto trait_items = vec (std::move (fn)); + + auto cmp_generics + = setup_impl_generics (type_name.as_string (), type_generics, + std::move (trait_bound)); + + return builder.trait_impl (trait_path, std::move (cmp_generics.self_type), + std::move (trait_items), + std::move (cmp_generics.impl)); +} + +std::unique_ptr +DeriveOrd::cmp_fn (std::unique_ptr &&block, Identifier type_name) +{ + // Ordering + auto return_type = builder.type_path ({"core", "cmp", "Ordering"}, true); + + // In the case of PartialOrd, we return an Option + if (ordering == Ordering::Partial) + { + auto generic = GenericArg::create_type (ptrify (return_type)); + + auto generic_seg = builder.type_path_segment_generic ( + "Option", GenericArgs ({}, {generic}, {}, loc)); + auto core = builder.type_path_segment ("core"); + auto option = builder.type_path_segment ("option"); + + return_type + = builder.type_path (vec (std::move (core), std::move (option), + std::move (generic_seg)), + true); + } + + // &self, other: &Self + auto params = vec ( + builder.self_ref_param (), + builder.function_param (builder.identifier_pattern ("other"), + builder.reference_type (ptrify ( + builder.type_path (type_name.as_string ()))))); + + auto function_name = fn (ordering); + + return builder.function (function_name, std::move (params), + ptrify (return_type), std::move (block)); +} + +std::unique_ptr +DeriveOrd::make_equal () +{ + std::unique_ptr equal = ptrify ( + builder.path_in_expression ({"core", "cmp", "Ordering", "Equal"}, true)); + + // We need to wrap the pattern in Option::Some if we are doing partial + // ordering + if (ordering == Ordering::Partial) + { + auto pattern_items = std::unique_ptr ( + new TupleStructItemsNoRange (vec (std::move (equal)))); + + equal + = std::make_unique (builder.path_in_expression ( + LangItem::Kind::OPTION_SOME), + std::move (pattern_items)); + } + + return equal; +} + +std::pair +DeriveOrd::make_cmp_arms () +{ + // All comparison results other than Ordering::Equal + auto non_equal = builder.identifier_pattern (DeriveOrd::not_equal); + auto equal = make_equal (); + + return {builder.match_arm (std::move (equal)), + builder.match_arm (std::move (non_equal))}; +} + +std::unique_ptr +DeriveOrd::recursive_match (std::vector &&members) +{ + if (members.empty ()) + { + std::unique_ptr value = ptrify ( + builder.path_in_expression ({"core", "cmp", "Ordering", "Equal"}, + true)); + + if (ordering == Ordering::Partial) + value = builder.call (ptrify (builder.path_in_expression ( + LangItem::Kind::OPTION_SOME)), + std::move (value)); + + return value; + } + + std::unique_ptr final_expr = nullptr; + + for (auto it = members.rbegin (); it != members.rend (); it++) + { + auto &member = *it; + + auto call = cmp_call (std::move (member.self_expr), + std::move (member.other_expr)); + + // For the last member (so the first iterator), we just create a call + // expression + if (it == members.rbegin ()) + { + final_expr = std::move (call); + continue; + } + + // If we aren't dealing with the last member, then we need to wrap all of + // that in a big match expression and keep going + auto match_arms = make_cmp_arms (); + + auto match_cases + = {builder.match_case (std::move (match_arms.first), + std::move (final_expr)), + builder.match_case (std::move (match_arms.second), + builder.identifier (DeriveOrd::not_equal))}; + + final_expr = builder.match (std::move (call), std::move (match_cases)); + } + + return final_expr; +} + +// we need to do a recursive match expression for all of the fields used in a +// struct so for something like struct Foo { a: i32, b: i32, c: i32 } we must +// first compare each `a` field, then `b`, then `c`, like this: +// +// match cmp_fn(self., other.) { +// Ordering::Equal => , +// cmp => cmp, +// } +// +// and the recurse will be the exact same expression, on the next field. so that +// our result looks like this: +// +// match cmp_fn(self.a, other.a) { +// Ordering::Equal => match cmp_fn(self.b, other.b) { +// Ordering::Equal =>cmp_fn(self.c, other.c), +// cmp => cmp, +// } +// cmp => cmp, +// } +// +// the last field comparison needs not to be a match but just the function call. +// this is going to be annoying lol +void +DeriveOrd::visit_struct (StructStruct &item) +{ + auto fields = SelfOther::fields (builder, item.get_fields ()); + + auto match_expr = recursive_match (std::move (fields)); + + expanded = cmp_impl (builder.block (std::move (match_expr)), + item.get_identifier (), item.get_generic_params ()); +} + +// same as structs, but for each field index instead of each field name - +// straightforward once we have `visit_struct` working +void +DeriveOrd::visit_tuple (TupleStruct &item) +{ + auto fields = SelfOther::indexes (builder, item.get_fields ()); + + auto match_expr = recursive_match (std::move (fields)); + + expanded = cmp_impl (builder.block (std::move (match_expr)), + item.get_identifier (), item.get_generic_params ()); +} + +// for enums, we need to generate a match for each of the enum's variant that +// contains data and then do the same thing as visit_struct or visit_enum. if +// the two aren't the same variant, then compare the two discriminant values for +// all the dataless enum variants and in the general case. +// +// so for enum Foo { A(i32, i32), B, C } we need to do the following +// +// match (self, other) { +// (A(self_0, self_1), A(other_0, other_1)) => { +// match cmp_fn(self_0, other_0) { +// Ordering::Equal => cmp_fn(self_1, other_1), +// cmp => cmp, +// }, +// _ => cmp_fn(discr_value(self), discr_value(other)) +// } +void +DeriveOrd::visit_enum (Enum &item) +{ + // NOTE: We can factor this even further with DerivePartialEq, but this is + // getting out of scope for this PR surely + + auto cases = std::vector (); + auto type_name = item.get_identifier ().as_string (); + + auto let_sd = builder.discriminant_value (DeriveOrd::self_discr, "self"); + auto let_od = builder.discriminant_value (DeriveOrd::other_discr, "other"); + + auto discr_cmp = cmp_call (builder.identifier (DeriveOrd::self_discr), + builder.identifier (DeriveOrd::other_discr)); + + auto recursive_match_fn = [this] (std::vector &&fields) { + return recursive_match (std::move (fields)); + }; + + for (auto &variant : item.get_variants ()) + { + auto enum_builder + = EnumMatchBuilder (type_name, variant->get_identifier ().as_string (), + recursive_match_fn, builder); + + switch (variant->get_enum_item_kind ()) + { + case EnumItem::Kind::Struct: + cases.emplace_back (enum_builder.strukt (*variant)); + break; + case EnumItem::Kind::Tuple: + cases.emplace_back (enum_builder.tuple (*variant)); + break; + case EnumItem::Kind::Identifier: + case EnumItem::Kind::Discriminant: + // We don't need to do anything for these, as they are handled by the + // discriminant value comparison + break; + } + } + + // Add the last case which compares the discriminant values in case `self` and + // `other` are actually different variants of the enum + cases.emplace_back ( + builder.match_case (builder.wildcard (), std::move (discr_cmp))); + + auto match + = builder.match (builder.tuple (vec (builder.identifier ("self"), + builder.identifier ("other"))), + std::move (cases)); + + expanded + = cmp_impl (builder.block (vec (std::move (let_sd), std::move (let_od)), + std::move (match)), + type_name, item.get_generic_params ()); +} + +void +DeriveOrd::visit_union (Union &item) +{ + auto trait_name = trait (ordering); + + rust_error_at (item.get_locus (), "derive(%s) cannot be used on unions", + trait_name.c_str ()); +} + +} // namespace AST +} // namespace Rust diff --git a/gcc/rust/expand/rust-derive-ord.h b/gcc/rust/expand/rust-derive-ord.h new file mode 100644 index 000000000000..90ce9c8ca6f1 --- /dev/null +++ b/gcc/rust/expand/rust-derive-ord.h @@ -0,0 +1,122 @@ +// Copyright (C) 2025 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 +// . + +#ifndef RUST_DERIVE_ORD_H +#define RUST_DERIVE_ORD_H + +#include "rust-ast.h" +#include "rust-derive-cmp-common.h" +#include "rust-derive.h" + +namespace Rust { +namespace AST { + +/** + * DeriveOrd is a bit special as the expansion of both `PartialOrd` and `Ord` + * is extremely similar. The only difference is that `PartialOrd` concerns + * partial-ordering, and thus its main method returns an `Option`, + * while `Ord` concerns total-ordering, and its main method returns an + * `Ordering`. Otherwise, the expansion logic is the same, so we factor both + * derives into one. + */ +class DeriveOrd : public DeriveVisitor +{ +public: + enum class Ordering + { + Total, + Partial + }; + + std::string fn (Ordering ordering) + { + if (ordering == Ordering::Total) + return "cmp"; + else + return "partial_cmp"; + } + + std::string trait (Ordering ordering) + { + if (ordering == Ordering::Total) + return "Ord"; + else + return "PartialOrd"; + } + + DeriveOrd (Ordering ordering, location_t loc); + + std::unique_ptr go (Item &item); + +private: + std::unique_ptr expanded; + + Ordering ordering; + + /* Identifier patterns for the non-equal match arms */ + constexpr static const char *not_equal = "#non_eq"; + constexpr static const char *self_discr = "#self_discr"; + constexpr static const char *other_discr = "#other_discr"; + + /** + * Create the recursive matching structure used when implementing the + * comparison function on multiple sub items (fields, tuple indexes...) + */ + std::unique_ptr recursive_match (std::vector &&members); + + /** + * Create a pattern for the `Ordering::Equal` case. In the case of partial + * ordering, `Option::Some(Ordering::Equal)`. + */ + std::unique_ptr make_equal (); + + /** + * Make the match arms for one inner match in a comparison function block. + * This returns the "equal" match arm and the "rest" match arm, so something + * like `Ordering::Equal` and `non_eq` in the following match expression: + * + * match cmp(...) { + * Ordering::Equal => match cmp(...) { ... } + * non_eq => non_eq, + * } + */ + std::pair make_cmp_arms (); + + /** + * Generate a call to the proper trait function, based on the ordering, in + * order to compare two given expressions + */ + std::unique_ptr cmp_call (std::unique_ptr &&self_expr, + std::unique_ptr &&other_expr); + + std::unique_ptr + cmp_impl (std::unique_ptr &&fn_block, Identifier type_name, + const std::vector> &type_generics); + std::unique_ptr cmp_fn (std::unique_ptr &&block, + Identifier type_name); + + virtual void visit_struct (StructStruct &item) override; + virtual void visit_tuple (TupleStruct &item) override; + virtual void visit_enum (Enum &item) override; + virtual void visit_union (Union &item) override; +}; + +} // namespace AST +} // namespace Rust + +#endif // ! RUST_DERIVE_ORD_H diff --git a/gcc/rust/expand/rust-derive-partial-eq.cc b/gcc/rust/expand/rust-derive-partial-eq.cc index ff66faabc781..a0bf87a32ddb 100644 --- a/gcc/rust/expand/rust-derive-partial-eq.cc +++ b/gcc/rust/expand/rust-derive-partial-eq.cc @@ -64,11 +64,9 @@ DerivePartialEq::partialeq_impls ( } std::unique_ptr -DerivePartialEq::eq_fn (std::unique_ptr &&cmp_expression, +DerivePartialEq::eq_fn (std::unique_ptr &&block, std::string type_name) { - auto block = builder.block (tl::nullopt, std::move (cmp_expression)); - auto self_type = std::unique_ptr (new TypePath (builder.type_path ("Self"))); @@ -83,24 +81,6 @@ DerivePartialEq::eq_fn (std::unique_ptr &&cmp_expression, std::move (block)); } -DerivePartialEq::SelfOther -DerivePartialEq::tuple_indexes (int idx) -{ - return SelfOther{ - builder.tuple_idx ("self", idx), - builder.tuple_idx ("other", idx), - }; -} - -DerivePartialEq::SelfOther -DerivePartialEq::field_acccesses (const std::string &field_name) -{ - return SelfOther{ - builder.field_access (builder.identifier ("self"), field_name), - builder.field_access (builder.identifier ("other"), field_name), - }; -} - std::unique_ptr DerivePartialEq::build_eq_expression ( std::vector &&field_expressions) @@ -134,12 +114,10 @@ void DerivePartialEq::visit_tuple (TupleStruct &item) { auto type_name = item.get_struct_name ().as_string (); - auto fields = std::vector (); - - for (size_t idx = 0; idx < item.get_fields ().size (); idx++) - fields.emplace_back (tuple_indexes (idx)); + auto fields = SelfOther::indexes (builder, item.get_fields ()); - auto fn = eq_fn (build_eq_expression (std::move (fields)), type_name); + auto fn = eq_fn (builder.block (build_eq_expression (std::move (fields))), + type_name); expanded = partialeq_impls (std::move (fn), type_name, item.get_generic_params ()); @@ -149,13 +127,10 @@ void DerivePartialEq::visit_struct (StructStruct &item) { auto type_name = item.get_struct_name ().as_string (); - auto fields = std::vector (); + auto fields = SelfOther::fields (builder, item.get_fields ()); - for (auto &field : item.get_fields ()) - fields.emplace_back ( - field_acccesses (field.get_field_name ().as_string ())); - - auto fn = eq_fn (build_eq_expression (std::move (fields)), type_name); + auto fn = eq_fn (builder.block (build_eq_expression (std::move (fields))), + type_name); expanded = partialeq_impls (std::move (fn), type_name, item.get_generic_params ()); @@ -199,8 +174,6 @@ DerivePartialEq::match_enum_tuple (PathInExpression variant_path, auto self_pattern_str = "__self_" + std::to_string (i); auto other_pattern_str = "__other_" + std::to_string (i); - rust_debug ("]ARTHUR[ %s", self_pattern_str.c_str ()); - self_patterns.emplace_back ( builder.identifier_pattern (self_pattern_str)); other_patterns.emplace_back ( @@ -240,15 +213,55 @@ MatchCase DerivePartialEq::match_enum_struct (PathInExpression variant_path, const EnumItemStruct &variant) { - // NOTE: We currently do not support compiling struct patterns where an - // identifier is assigned a new pattern, e.g. Bloop { f0: x } - // This is what we should be using to compile PartialEq for enum struct - // variants, as we need to be comparing the field of each instance meaning we - // need to give two different names to two different instances of the same - // field. We cannot just use the field's name like we do when deriving - // `Clone`. - - rust_unreachable (); + auto self_fields = std::vector> (); + auto other_fields = std::vector> (); + + auto self_other_exprs = std::vector (); + + for (auto &field : variant.get_struct_fields ()) + { + // The patterns we're creating for each field are `self_` and + // `other_` where `field` is the name of the field. It doesn't + // actually matter what we use, as long as it's ordered, unique, and that + // we can reuse it in the match case's return expression to check that + // they are equal. + + auto field_name = field.get_field_name ().as_string (); + + auto self_pattern_str = "__self_" + field_name; + auto other_pattern_str = "__other_" + field_name; + + self_fields.emplace_back (builder.struct_pattern_ident_pattern ( + field_name, builder.identifier_pattern (self_pattern_str))); + other_fields.emplace_back (builder.struct_pattern_ident_pattern ( + field_name, builder.identifier_pattern (other_pattern_str))); + + self_other_exprs.emplace_back (SelfOther{ + builder.identifier (self_pattern_str), + builder.identifier (other_pattern_str), + }); + } + + auto self_elts = StructPatternElements (std::move (self_fields)); + auto other_elts = StructPatternElements (std::move (other_fields)); + + auto self_pattern = std::unique_ptr ( + new ReferencePattern (std::unique_ptr (new StructPattern ( + variant_path, loc, std::move (self_elts))), + false, false, loc)); + auto other_pattern = std::unique_ptr ( + new ReferencePattern (std::unique_ptr (new StructPattern ( + variant_path, loc, std::move (other_elts))), + false, false, loc)); + + auto tuple_items = std::make_unique ( + vec (std::move (self_pattern), std::move (other_pattern))); + + auto pattern = std::make_unique (std::move (tuple_items), loc); + + auto expr = build_eq_expression (std::move (self_other_exprs)); + + return builder.match_case (std::move (pattern), std::move (expr)); } void @@ -257,46 +270,56 @@ DerivePartialEq::visit_enum (Enum &item) auto cases = std::vector (); auto type_name = item.get_identifier ().as_string (); + auto eq_expr_fn = [this] (std::vector &&fields) { + return build_eq_expression (std::move (fields)); + }; + + auto let_sd + = builder.discriminant_value (DerivePartialEq::self_discr, "self"); + auto let_od + = builder.discriminant_value (DerivePartialEq::other_discr, "other"); + + auto discr_cmp + = builder.comparison_expr (builder.identifier (DerivePartialEq::self_discr), + builder.identifier ( + DerivePartialEq::other_discr), + ComparisonOperator::EQUAL); + for (auto &variant : item.get_variants ()) { - auto variant_path - = builder.variant_path (type_name, - variant->get_identifier ().as_string ()); + auto enum_builder + = EnumMatchBuilder (type_name, variant->get_identifier ().as_string (), + eq_expr_fn, builder); switch (variant->get_enum_item_kind ()) { - case EnumItem::Kind::Identifier: - case EnumItem::Kind::Discriminant: - cases.emplace_back (match_enum_identifier (variant_path, variant)); - break; case EnumItem::Kind::Tuple: - cases.emplace_back ( - match_enum_tuple (variant_path, - static_cast (*variant))); + cases.emplace_back (enum_builder.tuple (*variant)); break; case EnumItem::Kind::Struct: - rust_sorry_at ( - item.get_locus (), - "cannot derive(PartialEq) for enum struct variants yet"); + cases.emplace_back (enum_builder.strukt (*variant)); + break; + case EnumItem::Kind::Identifier: + case EnumItem::Kind::Discriminant: + // We don't need to do anything for these, as they are handled by the + // discriminant value comparison break; } } - // NOTE: Mention using discriminant_value and skipping that last case, and - // instead skipping all identifiers/discriminant enum items and returning - // `true` in the wildcard case - // In case the two instances of `Self` don't have the same discriminant, // automatically return false. cases.emplace_back ( - builder.match_case (builder.wildcard (), builder.literal_bool (false))); + builder.match_case (builder.wildcard (), std::move (discr_cmp))); auto match = builder.match (builder.tuple (vec (builder.identifier ("self"), builder.identifier ("other"))), std::move (cases)); - auto fn = eq_fn (std::move (match), type_name); + auto fn = eq_fn (builder.block (vec (std::move (let_sd), std::move (let_od)), + std::move (match)), + type_name); expanded = partialeq_impls (std::move (fn), type_name, item.get_generic_params ()); diff --git a/gcc/rust/expand/rust-derive-partial-eq.h b/gcc/rust/expand/rust-derive-partial-eq.h index ac963a63c8aa..7985414c2528 100644 --- a/gcc/rust/expand/rust-derive-partial-eq.h +++ b/gcc/rust/expand/rust-derive-partial-eq.h @@ -21,6 +21,7 @@ #include "rust-derive.h" #include "rust-path.h" +#include "rust-derive-cmp-common.h" namespace Rust { namespace AST { @@ -30,7 +31,7 @@ class DerivePartialEq : DeriveVisitor public: DerivePartialEq (location_t loc); - std::vector> go (Item &item); + std::vector> go (Item &item); private: std::vector> expanded; @@ -43,22 +44,9 @@ class DerivePartialEq : DeriveVisitor std::unique_ptr &&eq_fn, std::string name, const std::vector> &type_generics); - std::unique_ptr eq_fn (std::unique_ptr &&cmp_expression, + std::unique_ptr eq_fn (std::unique_ptr &&block, std::string type_name); - /** - * A pair of two expressions from each instance being compared. E.g. this - * could be `self.0` and `other.0`, or `self.field` and `other.field` - */ - struct SelfOther - { - std::unique_ptr self_expr; - std::unique_ptr other_expr; - }; - - SelfOther tuple_indexes (int idx); - SelfOther field_acccesses (const std::string &field_name); - /** * Build a suite of equality arithmetic expressions chained together by a * boolean AND operator @@ -73,10 +61,13 @@ class DerivePartialEq : DeriveVisitor MatchCase match_enum_struct (PathInExpression variant_path, const EnumItemStruct &variant); - virtual void visit_struct (StructStruct &item); - virtual void visit_tuple (TupleStruct &item); - virtual void visit_enum (Enum &item); - virtual void visit_union (Union &item); + constexpr static const char *self_discr = "#self_discr"; + constexpr static const char *other_discr = "#other_discr"; + + virtual void visit_struct (StructStruct &item) override; + virtual void visit_tuple (TupleStruct &item) override; + virtual void visit_enum (Enum &item) override; + virtual void visit_union (Union &item) override; }; } // namespace AST diff --git a/gcc/rust/expand/rust-derive.cc b/gcc/rust/expand/rust-derive.cc index 015b81e90df2..55147df26f24 100644 --- a/gcc/rust/expand/rust-derive.cc +++ b/gcc/rust/expand/rust-derive.cc @@ -22,6 +22,7 @@ #include "rust-derive-debug.h" #include "rust-derive-default.h" #include "rust-derive-eq.h" +#include "rust-derive-ord.h" #include "rust-derive-partial-eq.h" #include "rust-derive-hash.h" @@ -59,10 +60,11 @@ DeriveVisitor::derive (Item &item, const Attribute &attr, case BuiltinMacro::Hash: return vec (DeriveHash (loc).go (item)); case BuiltinMacro::Ord: + return vec (DeriveOrd (DeriveOrd::Ordering::Total, loc).go (item)); case BuiltinMacro::PartialOrd: + return vec (DeriveOrd (DeriveOrd::Ordering::Partial, loc).go (item)); default: - rust_sorry_at (loc, "unimplemented builtin derive macro"); - return {}; + rust_unreachable (); }; } @@ -79,7 +81,8 @@ DeriveVisitor::setup_impl_generics ( { switch (generic->get_kind ()) { - case GenericParam::Kind::Lifetime: { + case GenericParam::Kind::Lifetime: + { LifetimeParam &lifetime_param = (LifetimeParam &) *generic.get (); Lifetime l = builder.new_lifetime (lifetime_param.get_lifetime ()); @@ -91,7 +94,8 @@ DeriveVisitor::setup_impl_generics ( } break; - case GenericParam::Kind::Type: { + case GenericParam::Kind::Type: + { TypeParam &type_param = (TypeParam &) *generic.get (); std::unique_ptr associated_type = builder.single_type_path ( @@ -104,7 +108,8 @@ DeriveVisitor::setup_impl_generics ( std::vector> extra_bounds; if (extra_bound) - extra_bounds.emplace_back (std::move (*extra_bound)); + extra_bounds.emplace_back ( + extra_bound.value ()->clone_type_param_bound ()); auto impl_type_param = builder.new_type_param (type_param, std::move (extra_bounds)); @@ -113,17 +118,20 @@ DeriveVisitor::setup_impl_generics ( } break; - case GenericParam::Kind::Const: { - rust_unreachable (); + case GenericParam::Kind::Const: + { + ConstGenericParam &const_param + = (ConstGenericParam &) *generic.get (); - // TODO - // const ConstGenericParam *const_param - // = (const ConstGenericParam *) generic.get (); - // std::unique_ptr const_expr = nullptr; + std::unique_ptr associated_type + = builder.single_type_path (const_param.get_name ().as_string ()); - // GenericArg type_arg - // = GenericArg::create_const (std::move (const_expr)); - // generic_args.push_back (std::move (type_arg)); + GenericArg type_arg + = GenericArg::create_type (std::move (associated_type)); + generic_args.push_back (std::move (type_arg)); + + auto impl_const_param = builder.new_const_param (const_param); + impl_generics.push_back (std::move (impl_const_param)); } break; } diff --git a/gcc/rust/expand/rust-derive.h b/gcc/rust/expand/rust-derive.h index 5fca49ca1f32..61c7355e7ab2 100644 --- a/gcc/rust/expand/rust-derive.h +++ b/gcc/rust/expand/rust-derive.h @@ -147,6 +147,8 @@ class DeriveVisitor : public AST::ASTVisitor virtual void visit (FieldAccessExpr &expr) override final{}; virtual void visit (ClosureExprInner &expr) override final{}; virtual void visit (BlockExpr &expr) override final{}; + virtual void visit (AnonConst &expr) override final{}; + virtual void visit (ConstBlock &expr) override final{}; virtual void visit (ClosureExprInnerTyped &expr) override final{}; virtual void visit (ContinueExpr &expr) override final{}; virtual void visit (BreakExpr &expr) override final{}; @@ -157,6 +159,7 @@ class DeriveVisitor : public AST::ASTVisitor virtual void visit (RangeFromToInclExpr &expr) override final{}; virtual void visit (RangeToInclExpr &expr) override final{}; virtual void visit (ReturnExpr &expr) override final{}; + virtual void visit (TryExpr &expr) override final{}; virtual void visit (BoxExpr &expr) override final{}; virtual void visit (UnsafeBlockExpr &expr) override final{}; virtual void visit (LoopExpr &expr) override final{}; diff --git a/gcc/rust/expand/rust-expand-format-args.cc b/gcc/rust/expand/rust-expand-format-args.cc index af6182f627f8..bda28dd61ce8 100644 --- a/gcc/rust/expand/rust-expand-format-args.cc +++ b/gcc/rust/expand/rust-expand-format-args.cc @@ -85,11 +85,13 @@ expand_format_args (AST::FormatArgs &fmt, static_pieces.emplace_back ( builder.literal_string (node.string._0.to_string ())); break; - case ffi::Piece::Tag::NextArgument: { + case ffi::Piece::Tag::NextArgument: + { auto next_argument = node.next_argument._0; switch (node.next_argument._0.position.tag) { - case ffi::Position::Tag::ArgumentImplicitlyIs: { + case ffi::Position::Tag::ArgumentImplicitlyIs: + { auto idx = next_argument.position.argument_implicitly_is._0; auto trait = next_argument.format; auto arg = arguments.at (idx); diff --git a/gcc/rust/expand/rust-expand-visitor.cc b/gcc/rust/expand/rust-expand-visitor.cc index 42df5e1ee118..69959b541c7f 100644 --- a/gcc/rust/expand/rust-expand-visitor.cc +++ b/gcc/rust/expand/rust-expand-visitor.cc @@ -233,10 +233,7 @@ ExpandVisitor::expand_inner_items ( } } - std::function (AST::SingleASTNode)> extractor - = [] (AST::SingleASTNode node) { return node.take_item (); }; - - expand_macro_children (items, extractor); + expand_macro_children (items, &AST::SingleASTNode::take_item); expander.pop_context (); } @@ -324,10 +321,7 @@ ExpandVisitor::expand_inner_stmts (AST::BlockExpr &expr) if (!expr.has_tail_expr ()) expr.normalize_tail_expr (); - std::function (AST::SingleASTNode)> extractor - = [] (AST::SingleASTNode node) { return node.take_stmt (); }; - - expand_macro_children (stmts, extractor); + expand_macro_children (stmts, &AST::SingleASTNode::take_stmt); expander.pop_context (); } @@ -641,7 +635,7 @@ ExpandVisitor::visit (AST::ClosureExprInnerTyped &expr) maybe_expand_type (expr.get_return_type_ptr ()); - visit (expr.get_definition_block ()); + visit (expr.get_definition_expr ()); } void @@ -866,12 +860,9 @@ ExpandVisitor::visit (AST::Trait &trait) expander.push_context (MacroExpander::ContextType::TRAIT); - std::function (AST::SingleASTNode)> - extractor - = [] (AST::SingleASTNode node) { return node.take_assoc_item (); }; - expand_macro_children (MacroExpander::ContextType::TRAIT, - trait.get_trait_items (), extractor); + trait.get_trait_items (), + &AST::SingleASTNode::take_assoc_item); expander.pop_context (); } @@ -894,12 +885,9 @@ ExpandVisitor::visit (AST::InherentImpl &impl) if (impl.has_where_clause ()) expand_where_clause (impl.get_where_clause ()); - std::function (AST::SingleASTNode)> - extractor - = [] (AST::SingleASTNode node) { return node.take_assoc_item (); }; - expand_macro_children (MacroExpander::ContextType::IMPL, - impl.get_impl_items (), extractor); + impl.get_impl_items (), + &AST::SingleASTNode::take_assoc_item); } void @@ -922,12 +910,9 @@ ExpandVisitor::visit (AST::TraitImpl &impl) if (impl.has_where_clause ()) expand_where_clause (impl.get_where_clause ()); - std::function (AST::SingleASTNode)> - extractor - = [] (AST::SingleASTNode node) { return node.take_assoc_item (); }; - expand_macro_children (MacroExpander::ContextType::TRAIT_IMPL, - impl.get_impl_items (), extractor); + impl.get_impl_items (), + &AST::SingleASTNode::take_assoc_item); } void @@ -944,12 +929,10 @@ void ExpandVisitor::visit (AST::ExternBlock &block) { visit_inner_attrs (block); - std::function (AST::SingleASTNode)> - extractor - = [] (AST::SingleASTNode node) { return node.take_external_item (); }; expand_macro_children (MacroExpander::ContextType::EXTERN, - block.get_extern_items (), extractor); + block.get_extern_items (), + &AST::SingleASTNode::take_external_item); } void diff --git a/gcc/rust/expand/rust-expand-visitor.h b/gcc/rust/expand/rust-expand-visitor.h index ad237c07c2f4..ef78404ae6bc 100644 --- a/gcc/rust/expand/rust-expand-visitor.h +++ b/gcc/rust/expand/rust-expand-visitor.h @@ -28,14 +28,12 @@ namespace Rust { /** * Whether or not an attribute is a derive attribute */ -bool -is_derive (AST::Attribute &attr); +bool is_derive (AST::Attribute &attr); /** * Whether or not an attribute is builtin */ -bool -is_builtin (AST::Attribute &attr); +bool is_builtin (AST::Attribute &attr); class ExpandVisitor : public AST::DefaultASTVisitor { @@ -107,7 +105,7 @@ class ExpandVisitor : public AST::DefaultASTVisitor */ template void expand_macro_children (MacroExpander::ContextType ctx, T &values, - std::function extractor) + U (AST::SingleASTNode::*extractor) (void)) { expander.push_context (ctx); @@ -123,7 +121,7 @@ class ExpandVisitor : public AST::DefaultASTVisitor */ template void expand_macro_children (T &values, - std::function extractor) + U (AST::SingleASTNode::*extractor) (void)) { for (auto it = values.begin (); it != values.end ();) { @@ -140,7 +138,7 @@ class ExpandVisitor : public AST::DefaultASTVisitor it = values.erase (it); for (auto &node : final_fragment.get_nodes ()) { - U new_node = extractor (node); + U new_node = (node.*extractor) (); if (new_node != nullptr) { it = values.insert (it, std::move (new_node)); diff --git a/gcc/rust/expand/rust-macro-builtins-asm.cc b/gcc/rust/expand/rust-macro-builtins-asm.cc index e255729885b8..850c8ddb753b 100644 --- a/gcc/rust/expand/rust-macro-builtins-asm.cc +++ b/gcc/rust/expand/rust-macro-builtins-asm.cc @@ -25,18 +25,6 @@ #include "rust-parse.h" namespace Rust { -std::map InlineAsmOptionMap{ - {AST::InlineAsmOption::PURE, "pure"}, - {AST::InlineAsmOption::NOMEM, "nomem"}, - {AST::InlineAsmOption::READONLY, "readonly"}, - {AST::InlineAsmOption::PRESERVES_FLAGS, "preserves_flags"}, - {AST::InlineAsmOption::NORETURN, "noreturn"}, - {AST::InlineAsmOption::NOSTACK, "nostack"}, - {AST::InlineAsmOption::MAY_UNWIND, "may_unwind"}, - {AST::InlineAsmOption::ATT_SYNTAX, "att_syntax"}, - {AST::InlineAsmOption::RAW, "raw"}, -}; - std::set potentially_nonpromoted_keywords = {"in", "out", "lateout", "inout", "inlateout", "const", "sym", "label"}; @@ -500,7 +488,7 @@ parse_reg_operand_unexpected (InlineAsmContext inline_asm_ctx) } void -check_and_set (InlineAsmContext &inline_asm_ctx, AST::InlineAsmOption option) +check_and_set (InlineAsmContext &inline_asm_ctx, AST::InlineAsm::Option option) { auto &parser = inline_asm_ctx.parser; auto &inline_asm = inline_asm_ctx.inline_asm; @@ -509,7 +497,7 @@ check_and_set (InlineAsmContext &inline_asm_ctx, AST::InlineAsmOption option) // TODO: report an error of duplication rust_error_at (parser.peek_current_token ()->get_locus (), "the %qs option was already provided", - InlineAsmOptionMap[option].c_str ()); + AST::InlineAsm::option_to_string (option).c_str ()); return; } else @@ -536,39 +524,40 @@ parse_options (InlineAsmContext &inline_asm_ctx) { if (!is_global_asm && check_identifier (parser, "pure")) { - check_and_set (inline_asm_ctx, AST::InlineAsmOption::PURE); + check_and_set (inline_asm_ctx, AST::InlineAsm::Option::PURE); } else if (!is_global_asm && check_identifier (parser, "nomem")) { - check_and_set (inline_asm_ctx, AST::InlineAsmOption::NOMEM); + check_and_set (inline_asm_ctx, AST::InlineAsm::Option::NOMEM); } else if (!is_global_asm && check_identifier (parser, "readonly")) { - check_and_set (inline_asm_ctx, AST::InlineAsmOption::READONLY); + check_and_set (inline_asm_ctx, AST::InlineAsm::Option::READONLY); } else if (!is_global_asm && check_identifier (parser, "preserves_flags")) { - check_and_set (inline_asm_ctx, AST::InlineAsmOption::PRESERVES_FLAGS); + check_and_set (inline_asm_ctx, + AST::InlineAsm::Option::PRESERVES_FLAGS); } else if (!is_global_asm && check_identifier (parser, "noreturn")) { - check_and_set (inline_asm_ctx, AST::InlineAsmOption::NORETURN); + check_and_set (inline_asm_ctx, AST::InlineAsm::Option::NORETURN); } else if (!is_global_asm && check_identifier (parser, "nostack")) { - check_and_set (inline_asm_ctx, AST::InlineAsmOption::NOSTACK); + check_and_set (inline_asm_ctx, AST::InlineAsm::Option::NOSTACK); } else if (!is_global_asm && check_identifier (parser, "may_unwind")) { - check_and_set (inline_asm_ctx, AST::InlineAsmOption::MAY_UNWIND); + check_and_set (inline_asm_ctx, AST::InlineAsm::Option::MAY_UNWIND); } else if (check_identifier (parser, "att_syntax")) { - check_and_set (inline_asm_ctx, AST::InlineAsmOption::ATT_SYNTAX); + check_and_set (inline_asm_ctx, AST::InlineAsm::Option::ATT_SYNTAX); } else if (check_identifier (parser, "raw")) { - check_and_set (inline_asm_ctx, AST::InlineAsmOption::RAW); + check_and_set (inline_asm_ctx, AST::InlineAsm::Option::RAW); } else { @@ -807,7 +796,8 @@ expand_inline_asm_strings (InlineAsmContext inline_asm_ctx) auto next_argument = piece.next_argument._0; switch (piece.next_argument._0.position.tag) { - case Fmt::ffi::Position::Tag::ArgumentImplicitlyIs: { + case Fmt::ffi::Position::Tag::ArgumentImplicitlyIs: + { auto idx = next_argument.position.argument_implicitly_is._0; /*auto trait = next_argument.format;*/ /*auto arg = arguments.at (idx);*/ diff --git a/gcc/rust/expand/rust-macro-builtins-asm.h b/gcc/rust/expand/rust-macro-builtins-asm.h index bd64a7f4dd62..3196a5ae184c 100644 --- a/gcc/rust/expand/rust-macro-builtins-asm.h +++ b/gcc/rust/expand/rust-macro-builtins-asm.h @@ -142,16 +142,16 @@ tl::expected parse_reg_operand_unexpected (InlineAsmContext inline_asm_ctx); WARN_UNUSED_RESULT -tl::optional -parse_asm (location_t invoc_locus, AST::MacroInvocData &invoc, - AST::InvocKind semicolon, AST::AsmKind is_global_asm); +tl::optional parse_asm (location_t invoc_locus, + AST::MacroInvocData &invoc, + AST::InvocKind semicolon, + AST::AsmKind is_global_asm); WARN_UNUSED_RESULT -bool -check_identifier (Parser &parser, std::string ident); +bool check_identifier (Parser &parser, std::string ident); -void -check_and_set (InlineAsmContext &inline_asm_ctx, AST::InlineAsmOption option); +void check_and_set (InlineAsmContext &inline_asm_ctx, + AST::InlineAsm::Option option); // From rustc WARN_UNUSED_RESULT @@ -168,9 +168,9 @@ tl::optional parse_format_string (InlineAsmContext &inline_asm_ctx); WARN_UNUSED_RESULT -tl::optional -parse_label (Parser &parser, TokenId last_token_id, - InlineAsmContext &inline_asm_ctx); +tl::optional parse_label (Parser &parser, + TokenId last_token_id, + InlineAsmContext &inline_asm_ctx); // LLVM ASM bits @@ -188,17 +188,13 @@ class LlvmAsmContext {} }; -void -parse_llvm_outputs (LlvmAsmContext &ctx); +void parse_llvm_outputs (LlvmAsmContext &ctx); -void -parse_llvm_inputs (LlvmAsmContext &ctx); +void parse_llvm_inputs (LlvmAsmContext &ctx); -void -parse_llvm_clobbers (LlvmAsmContext &ctx); +void parse_llvm_clobbers (LlvmAsmContext &ctx); -void -parse_llvm_options (LlvmAsmContext &ctx); +void parse_llvm_options (LlvmAsmContext &ctx); WARN_UNUSED_RESULT tl::optional parse_llvm_asm (location_t invoc_locus, AST::MacroInvocData &invoc, diff --git a/gcc/rust/expand/rust-macro-builtins-format-args.cc b/gcc/rust/expand/rust-macro-builtins-format-args.cc index 3e1249d3d36f..b20c84953206 100644 --- a/gcc/rust/expand/rust-macro-builtins-format-args.cc +++ b/gcc/rust/expand/rust-macro-builtins-format-args.cc @@ -52,8 +52,15 @@ format_args_parse_arguments (AST::MacroInvocData &invoc) // TODO: Handle the case where we're not parsing a string literal (macro // invocation for e.g.) - if (parser.peek_current_token ()->get_id () == STRING_LITERAL) - format_expr = parser.parse_literal_expr (); + switch (parser.peek_current_token ()->get_id ()) + { + case STRING_LITERAL: + case RAW_STRING_LITERAL: + format_expr = parser.parse_literal_expr (); + default: + // do nothing + ; + } rust_assert (format_expr); diff --git a/gcc/rust/expand/rust-macro-builtins-helpers.h b/gcc/rust/expand/rust-macro-builtins-helpers.h index 429537e210a8..32cf58fd1bed 100644 --- a/gcc/rust/expand/rust-macro-builtins-helpers.h +++ b/gcc/rust/expand/rust-macro-builtins-helpers.h @@ -33,29 +33,23 @@ #include "rust-token.h" namespace Rust { -std::string -make_macro_path_str (BuiltinMacro kind); +std::string make_macro_path_str (BuiltinMacro kind); -std::vector> -check_for_eager_invocations ( +std::vector> check_for_eager_invocations ( std::vector> &expressions); // Shorthand function for creating unique_ptr tokens -std::unique_ptr -make_token (const TokenPtr tok); +std::unique_ptr make_token (const TokenPtr tok); -std::unique_ptr -make_string (location_t locus, std::string value); +std::unique_ptr make_string (location_t locus, std::string value); // TODO: Is this correct? -AST::Fragment -make_eager_builtin_invocation ( +AST::Fragment make_eager_builtin_invocation ( BuiltinMacro kind, location_t locus, AST::DelimTokenTree arguments, std::vector> &&pending_invocations); // Match the end token of a macro given the start delimiter of the macro -TokenId -macro_end_token (AST::DelimTokenTree &invoc_token_tree, - Parser &parser); +TokenId macro_end_token (AST::DelimTokenTree &invoc_token_tree, + Parser &parser); // Expand and then extract a string literal from the macro std::unique_ptr try_extract_string_literal_from_fragment (const location_t &parent_locus, @@ -70,21 +64,18 @@ try_expand_many_expr (Parser &parser, // and return the LiteralExpr for it. Allow for an optional trailing comma, // but otherwise enforce that these are the only tokens. -std::unique_ptr -parse_single_string_literal (BuiltinMacro kind, - AST::DelimTokenTree &invoc_token_tree, - location_t invoc_locus, MacroExpander *expander, - bool is_semicoloned = false); +std::unique_ptr parse_single_string_literal ( + BuiltinMacro kind, AST::DelimTokenTree &invoc_token_tree, + location_t invoc_locus, MacroExpander *expander, bool is_semicoloned = false); // Treat PATH as a path relative to the source file currently being // compiled, and return the absolute path for it. -std::string -source_relative_path (std::string path, location_t locus); +std::string source_relative_path (std::string path, location_t locus); // Read the full contents of the file FILENAME and return them in a vector. // FIXME: platform specific. -tl::optional> -load_file_bytes (location_t invoc_locus, const char *filename); +tl::optional> load_file_bytes (location_t invoc_locus, + const char *filename); } // namespace Rust #endif // GCCRS_RUST_MACRO_BUILTINS_HELPERS_H diff --git a/gcc/rust/expand/rust-macro-expand.cc b/gcc/rust/expand/rust-macro-expand.cc index 673b8fb20fa3..475ad56a3640 100644 --- a/gcc/rust/expand/rust-macro-expand.cc +++ b/gcc/rust/expand/rust-macro-expand.cc @@ -430,7 +430,8 @@ MacroExpander::match_fragment (Parser &parser, parser.parse_visibility (); break; - case AST::MacroFragSpec::STMT: { + case AST::MacroFragSpec::STMT: + { auto restrictions = ParseRestrictions (); restrictions.consume_semi = false; parser.parse_stmt (restrictions); @@ -480,19 +481,22 @@ MacroExpander::match_matcher (Parser &parser, // this is used so we can check that we delimit the stream correctly. switch (delimiter->get_id ()) { - case LEFT_PAREN: { + case LEFT_PAREN: + { if (!check_delim (AST::DelimType::PARENS)) return false; } break; - case LEFT_SQUARE: { + case LEFT_SQUARE: + { if (!check_delim (AST::DelimType::SQUARE)) return false; } break; - case LEFT_CURLY: { + case LEFT_CURLY: + { if (!check_delim (AST::DelimType::CURLY)) return false; } @@ -510,7 +514,8 @@ MacroExpander::match_matcher (Parser &parser, switch (match->get_macro_match_type ()) { - case AST::MacroMatch::MacroMatchType::Fragment: { + case AST::MacroMatch::MacroMatchType::Fragment: + { AST::MacroMatchFragment *fragment = static_cast (match.get ()); if (!match_fragment (parser, *fragment)) @@ -524,14 +529,16 @@ MacroExpander::match_matcher (Parser &parser, } break; - case AST::MacroMatch::MacroMatchType::Tok: { + case AST::MacroMatch::MacroMatchType::Tok: + { AST::Token *tok = static_cast (match.get ()); if (!match_token (parser, *tok)) return false; } break; - case AST::MacroMatch::MacroMatchType::Repetition: { + case AST::MacroMatch::MacroMatchType::Repetition: + { AST::MacroMatchRepetition *rep = static_cast (match.get ()); if (!match_repetition (parser, *rep)) @@ -539,7 +546,8 @@ MacroExpander::match_matcher (Parser &parser, } break; - case AST::MacroMatch::MacroMatchType::Matcher: { + case AST::MacroMatch::MacroMatchType::Matcher: + { AST::MacroMatcher *m = static_cast (match.get ()); expansion_depth++; @@ -556,19 +564,22 @@ MacroExpander::match_matcher (Parser &parser, switch (delimiter->get_id ()) { - case LEFT_PAREN: { + case LEFT_PAREN: + { if (!parser.skip_token (RIGHT_PAREN)) return false; } break; - case LEFT_SQUARE: { + case LEFT_SQUARE: + { if (!parser.skip_token (RIGHT_SQUARE)) return false; } break; - case LEFT_CURLY: { + case LEFT_CURLY: + { if (!parser.skip_token (RIGHT_CURLY)) return false; } @@ -617,7 +628,8 @@ MacroExpander::match_n_matches (Parser &parser, size_t offs_begin = source.get_offs (); switch (match->get_macro_match_type ()) { - case AST::MacroMatch::MacroMatchType::Fragment: { + case AST::MacroMatch::MacroMatchType::Fragment: + { AST::MacroMatchFragment *fragment = static_cast (match.get ()); valid_current_match = match_fragment (parser, *fragment); @@ -632,20 +644,23 @@ MacroExpander::match_n_matches (Parser &parser, } break; - case AST::MacroMatch::MacroMatchType::Tok: { + case AST::MacroMatch::MacroMatchType::Tok: + { AST::Token *tok = static_cast (match.get ()); valid_current_match = match_token (parser, *tok); } break; - case AST::MacroMatch::MacroMatchType::Repetition: { + case AST::MacroMatch::MacroMatchType::Repetition: + { AST::MacroMatchRepetition *rep = static_cast (match.get ()); valid_current_match = match_repetition (parser, *rep); } break; - case AST::MacroMatch::MacroMatchType::Matcher: { + case AST::MacroMatch::MacroMatchType::Matcher: + { AST::MacroMatcher *m = static_cast (match.get ()); valid_current_match = match_matcher (parser, *m, true); diff --git a/gcc/rust/expand/rust-macro-substitute-ctx.cc b/gcc/rust/expand/rust-macro-substitute-ctx.cc index 02e4e3b1c5ae..ac36ed8b0451 100644 --- a/gcc/rust/expand/rust-macro-substitute-ctx.cc +++ b/gcc/rust/expand/rust-macro-substitute-ctx.cc @@ -273,7 +273,8 @@ SubstituteCtx::substitute_token (size_t token_idx) // don't substitute, dollar sign is alone/metavar is unknown return {std::vector> (), 0}; - case LEFT_PAREN: { + case LEFT_PAREN: + { // We need to parse up until the closing delimiter and expand this // fragment->n times. rust_debug ("expanding repetition"); diff --git a/gcc/rust/expand/rust-proc-macro.h b/gcc/rust/expand/rust-proc-macro.h index 6ffaaf6c099f..058c93aa434b 100644 --- a/gcc/rust/expand/rust-proc-macro.h +++ b/gcc/rust/expand/rust-proc-macro.h @@ -82,11 +82,9 @@ class CustomDeriveProcMacro * * @param The path to the shared object file to load. */ -const std::vector -load_macros (std::string path); +const std::vector load_macros (std::string path); -std::string -generate_proc_macro_decls_symbol (std::uint32_t stable_crate_id); +std::string generate_proc_macro_decls_symbol (std::uint32_t stable_crate_id); } // namespace Rust diff --git a/gcc/rust/hir/rust-ast-lower-base.cc b/gcc/rust/hir/rust-ast-lower-base.cc index 2d9a4450c901..b07ac0c07500 100644 --- a/gcc/rust/hir/rust-ast-lower-base.cc +++ b/gcc/rust/hir/rust-ast-lower-base.cc @@ -201,6 +201,12 @@ void ASTLoweringBase::visit (AST::BlockExpr &) {} void +ASTLoweringBase::visit (AST::AnonConst &) +{} +void +ASTLoweringBase::visit (AST::ConstBlock &) +{} +void ASTLoweringBase::visit (AST::ClosureExprInnerTyped &) {} void @@ -236,6 +242,9 @@ void ASTLoweringBase::visit (AST::ReturnExpr &) {} void +ASTLoweringBase::visit (AST::TryExpr &) +{} +void ASTLoweringBase::visit (AST::UnsafeBlockExpr &) {} void @@ -648,12 +657,14 @@ ASTLoweringBase::lower_generic_args (AST::GenericArgs &args) { switch (arg.get_kind ()) { - case AST::GenericArg::Kind::Type: { + case AST::GenericArg::Kind::Type: + { auto type = ASTLoweringType::translate (arg.get_type ()); type_args.emplace_back (std::unique_ptr (type)); break; } - case AST::GenericArg::Kind::Const: { + case AST::GenericArg::Kind::Const: + { auto expr = ASTLoweringExpr::translate (arg.get_expression ()); const_args.emplace_back ( HIR::ConstGenericArg (std::unique_ptr (expr), @@ -887,7 +898,8 @@ ASTLoweringBase::lower_range_pattern_bound (AST::RangePatternBound &bound) std::unique_ptr hir_bound = nullptr; switch (bound.get_bound_type ()) { - case AST::RangePatternBound::RangePatternBoundType::LITERAL: { + case AST::RangePatternBound::RangePatternBoundType::LITERAL: + { AST::RangePatternBoundLiteral &ref = static_cast (bound); @@ -898,7 +910,8 @@ ASTLoweringBase::lower_range_pattern_bound (AST::RangePatternBound &bound) ref.get_has_minus ())); } break; - case AST::RangePatternBound::RangePatternBoundType::PATH: { + case AST::RangePatternBound::RangePatternBoundType::PATH: + { auto &ref = static_cast (bound); HIR::PathInExpression *path @@ -908,7 +921,8 @@ ASTLoweringBase::lower_range_pattern_bound (AST::RangePatternBound &bound) new HIR::RangePatternBoundPath (*path)); } break; - case AST::RangePatternBound::RangePatternBoundType::QUALPATH: { + case AST::RangePatternBound::RangePatternBoundType::QUALPATH: + { auto &ref = static_cast (bound); HIR::QualifiedPathInExpression *qualpath diff --git a/gcc/rust/hir/rust-ast-lower-base.h b/gcc/rust/hir/rust-ast-lower-base.h index 31161810c6fd..0284ff0c82bb 100644 --- a/gcc/rust/hir/rust-ast-lower-base.h +++ b/gcc/rust/hir/rust-ast-lower-base.h @@ -131,6 +131,8 @@ class ASTLoweringBase : public AST::ASTVisitor virtual void visit (AST::FieldAccessExpr &expr) override; virtual void visit (AST::ClosureExprInner &expr) override; virtual void visit (AST::BlockExpr &expr) override; + virtual void visit (AST::AnonConst &expr) override; + virtual void visit (AST::ConstBlock &expr) override; virtual void visit (AST::ClosureExprInnerTyped &expr) override; virtual void visit (AST::ContinueExpr &expr) override; virtual void visit (AST::BreakExpr &expr) override; @@ -142,6 +144,7 @@ class ASTLoweringBase : public AST::ASTVisitor virtual void visit (AST::RangeToInclExpr &expr) override; virtual void visit (AST::BoxExpr &expr) override; virtual void visit (AST::ReturnExpr &expr) override; + virtual void visit (AST::TryExpr &expr) override; virtual void visit (AST::UnsafeBlockExpr &expr) override; virtual void visit (AST::LoopExpr &expr) override; virtual void visit (AST::WhileLoopExpr &expr) override; diff --git a/gcc/rust/hir/rust-ast-lower-expr.cc b/gcc/rust/hir/rust-ast-lower-expr.cc index 07d0c835e567..96820fd8c18d 100644 --- a/gcc/rust/hir/rust-ast-lower-expr.cc +++ b/gcc/rust/hir/rust-ast-lower-expr.cc @@ -25,6 +25,7 @@ #include "rust-ast-lower-type.h" #include "rust-ast.h" #include "rust-diagnostics.h" +#include "rust-hir-map.h" #include "rust-system.h" #include "tree/rust-hir-expr.h" @@ -126,6 +127,50 @@ ASTLoweringExpr::visit (AST::BlockExpr &expr) translated = ASTLoweringBlock::translate (expr, &terminated); } +void +ASTLoweringExpr::visit (AST::AnonConst &expr) +{ + auto &mappings = Analysis::Mappings::get (); + auto crate_num = mappings.get_current_crate (); + auto mapping = Analysis::NodeMapping (crate_num, expr.get_node_id (), + mappings.get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + + if (expr.is_deferred ()) + { + translated = new HIR::AnonConst (std::move (mapping), expr.get_locus ()); + } + else + { + auto inner_expr = ASTLoweringExpr::translate (expr.get_inner_expr ()); + + translated = new HIR::AnonConst (std::move (mapping), + std::unique_ptr (inner_expr), + expr.get_locus ()); + } +} + +void +ASTLoweringExpr::visit (AST::ConstBlock &expr) +{ + auto inner_expr = ASTLoweringExpr::translate (expr.get_const_expr ()); + + // we know this will always be an `AnonConst`, or we have an issue. Let's + // assert just to be sure. + rust_assert (inner_expr->get_expression_type () == Expr::ExprType::AnonConst); + auto anon_const = static_cast (inner_expr); + + auto &mappings = Analysis::Mappings::get (); + auto crate_num = mappings.get_current_crate (); + auto mapping = Analysis::NodeMapping (crate_num, expr.get_node_id (), + mappings.get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + + translated + = new HIR::ConstBlock (std::move (mapping), std::move (*anon_const), + expr.get_locus (), expr.get_outer_attrs ()); +} + void ASTLoweringExpr::visit (AST::UnsafeBlockExpr &expr) { @@ -798,7 +843,7 @@ ASTLoweringExpr::visit (AST::ClosureExprInnerTyped &expr) { HIR::Type *closure_return_type = nullptr; HIR::Expr *closure_expr - = ASTLoweringExpr::translate (expr.get_definition_block ()); + = ASTLoweringExpr::translate (expr.get_definition_expr ()); std::vector closure_params; for (auto ¶m : expr.get_params ()) @@ -841,6 +886,7 @@ translate_operand_out (const AST::InlineAsmOperand &operand) *out_value.expr.get ()))); return out; } + HIR::InlineAsmOperand translate_operand_inout (const AST::InlineAsmOperand &operand) { @@ -851,6 +897,7 @@ translate_operand_inout (const AST::InlineAsmOperand &operand) *inout_value.expr.get ()))); return inout; } + HIR::InlineAsmOperand translate_operand_split_in_out (const AST::InlineAsmOperand &operand) { @@ -863,19 +910,21 @@ translate_operand_split_in_out (const AST::InlineAsmOperand &operand) ASTLoweringExpr::translate (*split_in_out_value.out_expr.get ()))); return split_in_out; } + HIR::InlineAsmOperand translate_operand_const (const AST::InlineAsmOperand &operand) { auto const_value = operand.get_const (); - struct HIR::AnonConst anon_const (const_value.anon_const.id, - std::unique_ptr ( - ASTLoweringExpr::translate ( - *const_value.anon_const.expr.get ()))); - struct HIR::InlineAsmOperand::Const cnst - { - anon_const - }; - return cnst; + + auto inner_expr = ASTLoweringExpr::translate (const_value.anon_const); + + // Like `ConstBlock`, we know this should only be an `AnonConst` - let's + // assert to make sure and static cast + rust_assert (inner_expr->get_expression_type () == Expr::ExprType::AnonConst); + + auto anon_const = static_cast (inner_expr); + + return HIR::InlineAsmOperand::Const{*anon_const}; } HIR::InlineAsmOperand diff --git a/gcc/rust/hir/rust-ast-lower-expr.h b/gcc/rust/hir/rust-ast-lower-expr.h index adedeb3cfcba..9d1bf68e8762 100644 --- a/gcc/rust/hir/rust-ast-lower-expr.h +++ b/gcc/rust/hir/rust-ast-lower-expr.h @@ -82,6 +82,8 @@ class ASTLoweringExpr : public ASTLoweringBase void visit (AST::IfLetExpr &expr) override; void visit (AST::IfLetExprConseqElse &expr) override; void visit (AST::BlockExpr &expr) override; + void visit (AST::AnonConst &expr) override; + void visit (AST::ConstBlock &expr) override; void visit (AST::UnsafeBlockExpr &expr) override; void visit (AST::PathInExpression &expr) override; void visit (AST::QualifiedPathInExpression &expr) override; diff --git a/gcc/rust/hir/rust-ast-lower-extern.h b/gcc/rust/hir/rust-ast-lower-extern.h index 0105e3840284..3dca1b62666f 100644 --- a/gcc/rust/hir/rust-ast-lower-extern.h +++ b/gcc/rust/hir/rust-ast-lower-extern.h @@ -99,7 +99,7 @@ class ASTLoweringExternItem : public ASTLoweringBase = static_cast (param.get_pattern ()); Identifier param_name = param_kind == AST::Pattern::Kind::Identifier ? param_ident.get_ident () - : std::string ("_"); + : Identifier ("_", param.get_locus ()); HIR::Type *param_type = ASTLoweringType::translate (param.get_type ()); diff --git a/gcc/rust/hir/rust-ast-lower-implitem.cc b/gcc/rust/hir/rust-ast-lower-implitem.cc index d815a71564ec..fc9fe1ace4a9 100644 --- a/gcc/rust/hir/rust-ast-lower-implitem.cc +++ b/gcc/rust/hir/rust-ast-lower-implitem.cc @@ -138,7 +138,8 @@ ASTLowerImplItem::visit (AST::Function &function) std::unique_ptr return_type = function.has_return_type () ? std::unique_ptr ( - ASTLoweringType::translate (function.get_return_type ())) + ASTLoweringType::translate (function.get_return_type (), false, + true /* impl trait is allowed here*/)) : nullptr; Defaultness defaultness diff --git a/gcc/rust/hir/rust-ast-lower-item.cc b/gcc/rust/hir/rust-ast-lower-item.cc index f4396b58e595..4e5a747b2a98 100644 --- a/gcc/rust/hir/rust-ast-lower-item.cc +++ b/gcc/rust/hir/rust-ast-lower-item.cc @@ -217,7 +217,7 @@ ASTLoweringItem::visit (AST::StructStruct &struct_decl) field.get_outer_attrs ()); if (struct_field_name_exists (fields, translated_field)) - break; + continue; fields.push_back (std::move (translated_field)); } @@ -367,7 +367,9 @@ ASTLoweringItem::visit (AST::ConstantItem &constant) HIR::Visibility vis = translate_visibility (constant.get_visibility ()); HIR::Type *type = ASTLoweringType::translate (constant.get_type (), true); - HIR::Expr *expr = ASTLoweringExpr::translate (constant.get_expr ()); + HIR::Expr *expr = nullptr; + if (constant.has_expr ()) + expr = ASTLoweringExpr::translate (constant.get_expr ()); auto crate_num = mappings.get_current_crate (); Analysis::NodeMapping mapping (crate_num, constant.get_node_id (), @@ -411,7 +413,8 @@ ASTLoweringItem::visit (AST::Function &function) std::unique_ptr return_type = function.has_return_type () ? std::unique_ptr ( - ASTLoweringType::translate (function.get_return_type ())) + ASTLoweringType::translate (function.get_return_type (), false, + true /* impl trait is allowed here*/)) : nullptr; std::vector function_params; @@ -494,7 +497,8 @@ ASTLoweringItem::visit (AST::InherentImpl &impl_block) { switch (generic_param->get_kind ()) { - case HIR::GenericParam::GenericKind::TYPE: { + case HIR::GenericParam::GenericKind::TYPE: + { const HIR::TypeParam &t = static_cast (*generic_param); @@ -651,7 +655,8 @@ ASTLoweringItem::visit (AST::TraitImpl &impl_block) { switch (generic_param->get_kind ()) { - case HIR::GenericParam::GenericKind::TYPE: { + case HIR::GenericParam::GenericKind::TYPE: + { const HIR::TypeParam &t = static_cast (*generic_param); @@ -729,6 +734,25 @@ ASTLoweringItem::visit (AST::MacroRulesDefinition &def) lower_macro_definition (def); } +void +ASTLoweringItem::visit (AST::ExternCrate &extern_crate) +{ + if (extern_crate.references_self ()) + return; + + auto &mappings = Analysis::Mappings::get (); + CrateNum num + = mappings.lookup_crate_name (extern_crate.get_referenced_crate ()) + .value (); + AST::Crate &crate = mappings.get_ast_crate (num); + + auto saved_crate_num = mappings.get_current_crate (); + mappings.set_current_crate (num); + auto lowered = ASTLowering::Resolve (crate); + mappings.insert_hir_crate (std::move (lowered)); + mappings.set_current_crate (saved_crate_num); +} + HIR::SimplePath ASTLoweringSimplePath::translate (const AST::SimplePath &path) { diff --git a/gcc/rust/hir/rust-ast-lower-item.h b/gcc/rust/hir/rust-ast-lower-item.h index 4e142ed5e7c4..dc750571d138 100644 --- a/gcc/rust/hir/rust-ast-lower-item.h +++ b/gcc/rust/hir/rust-ast-lower-item.h @@ -45,6 +45,7 @@ class ASTLoweringItem : public ASTLoweringBase void visit (AST::TraitImpl &impl_block) override; void visit (AST::ExternBlock &extern_block) override; void visit (AST::MacroRulesDefinition &rules_def) override; + void visit (AST::ExternCrate &extern_crate) override; private: ASTLoweringItem () : translated (nullptr) {} diff --git a/gcc/rust/hir/rust-ast-lower-pattern.cc b/gcc/rust/hir/rust-ast-lower-pattern.cc index b7a4c564782b..bb5b93b2c49b 100644 --- a/gcc/rust/hir/rust-ast-lower-pattern.cc +++ b/gcc/rust/hir/rust-ast-lower-pattern.cc @@ -49,13 +49,18 @@ ASTLoweringPattern::visit (AST::IdentifierPattern &pattern) mappings.get_next_hir_id (crate_num), UNKNOWN_LOCAL_DEFID); - std::unique_ptr to_bind; + std::unique_ptr subpattern; + if (pattern.has_subpattern ()) + { + subpattern = std::unique_ptr ( + ASTLoweringPattern::translate (pattern.get_subpattern ())); + } translated = new HIR::IdentifierPattern (mapping, pattern.get_ident (), pattern.get_locus (), pattern.get_is_ref (), pattern.get_is_mut () ? Mutability::Mut : Mutability::Imm, - std::move (to_bind)); + std::move (subpattern)); } void @@ -74,13 +79,15 @@ ASTLoweringPattern::visit (AST::TupleStructPattern &pattern) auto &items = pattern.get_items (); switch (items.get_item_type ()) { - case AST::TupleStructItems::RANGE: { + case AST::TupleStructItems::RANGE: + { // TODO rust_unreachable (); } break; - case AST::TupleStructItems::NO_RANGE: { + case AST::TupleStructItems::NO_RANGE: + { AST::TupleStructItemsNoRange &items_no_range = static_cast (items); @@ -120,7 +127,8 @@ ASTLoweringPattern::visit (AST::StructPattern &pattern) HIR::StructPatternField *f = nullptr; switch (field->get_item_type ()) { - case AST::StructPatternField::ItemType::TUPLE_PAT: { + case AST::StructPatternField::ItemType::TUPLE_PAT: + { auto &tuple = static_cast (*field); @@ -140,7 +148,8 @@ ASTLoweringPattern::visit (AST::StructPattern &pattern) } break; - case AST::StructPatternField::ItemType::IDENT_PAT: { + case AST::StructPatternField::ItemType::IDENT_PAT: + { AST::StructPatternFieldIdentPat &ident = static_cast (*field); @@ -160,7 +169,8 @@ ASTLoweringPattern::visit (AST::StructPattern &pattern) } break; - case AST::StructPatternField::ItemType::IDENT: { + case AST::StructPatternField::ItemType::IDENT: + { AST::StructPatternFieldIdent &ident = static_cast (*field.get ()); @@ -213,7 +223,8 @@ ASTLoweringPattern::visit (AST::TuplePattern &pattern) std::unique_ptr items; switch (pattern.get_items ().get_pattern_type ()) { - case AST::TuplePatternItems::TuplePatternItemType::MULTIPLE: { + case AST::TuplePatternItems::TuplePatternItemType::MULTIPLE: + { AST::TuplePatternItemsMultiple &ref = static_cast ( pattern.get_items ()); @@ -221,7 +232,8 @@ ASTLoweringPattern::visit (AST::TuplePattern &pattern) } break; - case AST::TuplePatternItems::TuplePatternItemType::RANGED: { + case AST::TuplePatternItems::TuplePatternItemType::RANGED: + { AST::TuplePatternItemsRanged &ref = static_cast (pattern.get_items ()); items = lower_tuple_pattern_ranged (ref); diff --git a/gcc/rust/hir/rust-ast-lower-type.cc b/gcc/rust/hir/rust-ast-lower-type.cc index a678f189ac28..1841576b29f4 100644 --- a/gcc/rust/hir/rust-ast-lower-type.cc +++ b/gcc/rust/hir/rust-ast-lower-type.cc @@ -209,10 +209,17 @@ ASTLowerQualifiedPathInType::visit (AST::QualifiedPathInType &path) path.get_locus ()); } +ASTLoweringType::ASTLoweringType (bool default_to_static_lifetime, + bool impl_trait_allowed) + : ASTLoweringBase (), default_to_static_lifetime (default_to_static_lifetime), + impl_trait_allowed (impl_trait_allowed), translated (nullptr) +{} + HIR::Type * -ASTLoweringType::translate (AST::Type &type, bool default_to_static_lifetime) +ASTLoweringType::translate (AST::Type &type, bool default_to_static_lifetime, + bool impl_trait_allowed) { - ASTLoweringType resolver (default_to_static_lifetime); + ASTLoweringType resolver (default_to_static_lifetime, impl_trait_allowed); type.accept_vis (resolver); rust_assert (resolver.translated != nullptr); @@ -260,7 +267,8 @@ ASTLoweringType::visit (AST::BareFunctionType &fntype) HIR::Type *param_type = ASTLoweringType::translate (param.get_type (), - default_to_static_lifetime); + default_to_static_lifetime, + impl_trait_allowed); HIR::MaybeNamedParam p (param.get_name (), kind, std::unique_ptr (param_type), @@ -272,7 +280,8 @@ ASTLoweringType::visit (AST::BareFunctionType &fntype) if (fntype.has_return_type ()) { return_type = ASTLoweringType::translate (fntype.get_return_type (), - default_to_static_lifetime); + default_to_static_lifetime, + impl_trait_allowed); } auto crate_num = mappings.get_current_crate (); @@ -292,8 +301,8 @@ ASTLoweringType::visit (AST::TupleType &tuple) std::vector> elems; for (auto &e : tuple.get_elems ()) { - HIR::Type *t - = ASTLoweringType::translate (*e, default_to_static_lifetime); + HIR::Type *t = ASTLoweringType::translate (*e, default_to_static_lifetime, + impl_trait_allowed); elems.push_back (std::unique_ptr (t)); } @@ -323,7 +332,8 @@ ASTLoweringType::visit (AST::ArrayType &type) { HIR::Type *translated_type = ASTLoweringType::translate (type.get_elem_type (), - default_to_static_lifetime); + default_to_static_lifetime, + impl_trait_allowed); HIR::Expr *array_size = ASTLoweringExpr::translate (type.get_size_expr ()); auto crate_num = mappings.get_current_crate (); @@ -343,9 +353,9 @@ ASTLoweringType::visit (AST::ReferenceType &type) HIR::Lifetime lifetime = lower_lifetime (type.get_lifetime (), default_to_static_lifetime); - HIR::Type *base_type - = ASTLoweringType::translate (type.get_base_type (), - default_to_static_lifetime); + HIR::Type *base_type = ASTLoweringType::translate (type.get_base_type (), + default_to_static_lifetime, + impl_trait_allowed); auto crate_num = mappings.get_current_crate (); Analysis::NodeMapping mapping (crate_num, type.get_node_id (), @@ -364,7 +374,8 @@ ASTLoweringType::visit (AST::RawPointerType &type) { HIR::Type *base_type = ASTLoweringType::translate (type.get_type_pointed_to (), - default_to_static_lifetime); + default_to_static_lifetime, + impl_trait_allowed); auto crate_num = mappings.get_current_crate (); Analysis::NodeMapping mapping (crate_num, type.get_node_id (), @@ -384,9 +395,9 @@ ASTLoweringType::visit (AST::RawPointerType &type) void ASTLoweringType::visit (AST::SliceType &type) { - HIR::Type *base_type - = ASTLoweringType::translate (type.get_elem_type (), - default_to_static_lifetime); + HIR::Type *base_type = ASTLoweringType::translate (type.get_elem_type (), + default_to_static_lifetime, + impl_trait_allowed); auto crate_num = mappings.get_current_crate (); Analysis::NodeMapping mapping (crate_num, type.get_node_id (), @@ -463,7 +474,8 @@ void ASTLoweringType::visit (AST::ParenthesisedType &type) { auto *inner = ASTLoweringType::translate (*type.get_type_in_parens (), - default_to_static_lifetime); + default_to_static_lifetime, + impl_trait_allowed); auto crate_num = mappings.get_current_crate (); Analysis::NodeMapping mapping (crate_num, type.get_node_id (), @@ -480,6 +492,9 @@ ASTLoweringType::visit (AST::ParenthesisedType &type) void ASTLoweringType::visit (AST::ImplTraitType &type) { + if (!impl_trait_allowed) + emit_impl_trait_error (type.get_locus ()); + std::vector> bounds; for (auto &bound : type.get_type_param_bounds ()) { @@ -499,9 +514,12 @@ ASTLoweringType::visit (AST::ImplTraitType &type) void ASTLoweringType::visit (AST::ImplTraitTypeOneBound &type) { + if (!impl_trait_allowed) + emit_impl_trait_error (type.get_locus ()); + std::vector> bounds; - auto b = ASTLoweringTypeBounds::translate (type.get_trait_bound ()); + auto b = ASTLoweringTypeBounds::translate (*type.get_trait_bound ().get ()); bounds.push_back (std::unique_ptr (b)); auto crate_num = mappings.get_current_crate (); @@ -513,6 +531,15 @@ ASTLoweringType::visit (AST::ImplTraitTypeOneBound &type) = new HIR::ImplTraitType (mapping, std::move (bounds), type.get_locus ()); } +void +ASTLoweringType::emit_impl_trait_error (location_t locus) +{ + rich_location r (line_table, locus); + rust_error_at (r, ErrorCode::E0562, + "% not allowed outside of function and inherent " + "method return types"); +} + HIR::GenericParam * ASTLowerGenericParam::translate (AST::GenericParam ¶m) { @@ -593,7 +620,8 @@ ASTLowerGenericParam::visit (AST::TypeParam ¶m) translated = new HIR::TypeParam (mapping, param.get_type_representation (), param.get_locus (), std::move (type_param_bounds), - std::move (type), param.get_outer_attrs ()); + std::move (type), param.get_outer_attrs (), + param.from_impl_trait ()); } HIR::TypeParamBound * diff --git a/gcc/rust/hir/rust-ast-lower-type.h b/gcc/rust/hir/rust-ast-lower-type.h index 4efaeee13149..50f543a357cf 100644 --- a/gcc/rust/hir/rust-ast-lower-type.h +++ b/gcc/rust/hir/rust-ast-lower-type.h @@ -66,7 +66,8 @@ class ASTLoweringType : public ASTLoweringBase public: static HIR::Type *translate (AST::Type &type, - bool default_to_static_lifetime = false); + bool default_to_static_lifetime = false, + bool impl_trait_allowed = false); void visit (AST::BareFunctionType &fntype) override; void visit (AST::TupleType &tuple) override; @@ -81,19 +82,17 @@ class ASTLoweringType : public ASTLoweringBase void visit (AST::TraitObjectTypeOneBound &type) override; void visit (AST::TraitObjectType &type) override; void visit (AST::ParenthesisedType &type) override; - void visit (AST::ImplTraitType &type) override; void visit (AST::ImplTraitTypeOneBound &type) override; + void emit_impl_trait_error (location_t locus); + private: - ASTLoweringType (bool default_to_static_lifetime) - : ASTLoweringBase (), - default_to_static_lifetime (default_to_static_lifetime), - translated (nullptr) - {} + ASTLoweringType (bool default_to_static_lifetime, bool impl_trait_allowed); /** Used when compiling const and static items. */ bool default_to_static_lifetime; + bool impl_trait_allowed; HIR::Type *translated; }; diff --git a/gcc/rust/hir/rust-ast-lower.h b/gcc/rust/hir/rust-ast-lower.h index cc7408277a31..0787ddfd0a32 100644 --- a/gcc/rust/hir/rust-ast-lower.h +++ b/gcc/rust/hir/rust-ast-lower.h @@ -28,16 +28,14 @@ namespace HIR { /* Checks whether the name of a field already exists. Returns true and produces an error if so. */ -bool -struct_field_name_exists (std::vector &fields, - HIR::StructField &new_field); +bool struct_field_name_exists (std::vector &fields, + HIR::StructField &new_field); /** * Lowers a Visibility from the AST into an HIR Visibility, desugaring it in * the process */ -Visibility -translate_visibility (const AST::Visibility &vis); +Visibility translate_visibility (const AST::Visibility &vis); /** * Main base class used for lowering AST to HIR. diff --git a/gcc/rust/hir/rust-hir-dump.cc b/gcc/rust/hir/rust-hir-dump.cc index cb32f68ab965..18589316e9f7 100644 --- a/gcc/rust/hir/rust-hir-dump.cc +++ b/gcc/rust/hir/rust-hir-dump.cc @@ -1296,6 +1296,28 @@ Dump::visit (BlockExpr &e) end ("BlockExpr"); } +void +Dump::visit (AnonConst &e) +{ + begin ("AnonConst"); + do_expr (e); + + visit_field ("inner", e.get_inner_expr ()); + + end ("AnonConst"); +} + +void +Dump::visit (ConstBlock &e) +{ + begin ("ConstBlock"); + do_expr (e); + + visit_field ("inner", e.get_const_expr ()); + + end ("ConstBlock"); +} + void Dump::visit (ContinueExpr &e) { @@ -1602,7 +1624,8 @@ Dump::visit (UseTreeGlob &e) case UseTreeGlob::PathType::GLOBAL: glob = "::*"; break; - case UseTreeGlob::PathType::PATH_PREFIXED: { + case UseTreeGlob::PathType::PATH_PREFIXED: + { path = e.get_path ().as_string (); glob = "::*"; break; @@ -1630,7 +1653,8 @@ Dump::visit (UseTreeList &e) case UseTreeList::PathType::GLOBAL: path_type = "::*"; break; - case UseTreeList::PathType::PATH_PREFIXED: { + case UseTreeList::PathType::PATH_PREFIXED: + { path = e.get_path ().as_string (); path_type = "::*"; break; @@ -1902,7 +1926,8 @@ Dump::visit (ConstantItem &e) do_vis_item (e); put_field ("identifier", e.get_identifier ().as_string ()); visit_field ("type", e.get_type ()); - visit_field ("const_expr", e.get_expr ()); + if (e.has_expr ()) + visit_field ("const_expr", e.get_expr ()); end ("ConstantItem"); } @@ -2091,10 +2116,10 @@ Dump::visit (IdentifierPattern &e) put_field ("is_ref", std::to_string (e.get_is_ref ())); put_field ("mut", std::to_string (e.is_mut ())); - if (e.has_pattern_to_bind ()) - put_field ("to_bind", e.get_to_bind ().as_string ()); + if (e.has_subpattern ()) + visit_field ("subpattern", e.get_subpattern ()); else - put_field ("to_bind", "none"); + put_field ("subpattern", "none"); end ("IdentifierPattern"); } @@ -2172,7 +2197,7 @@ Dump::visit (StructPatternFieldIdentPat &e) auto oa = e.get_outer_attrs (); do_outer_attrs (oa); put_field ("ident", e.get_identifier ().as_string ()); - put_field ("ident_pattern", e.get_pattern ().as_string ()); + visit_field ("ident_pattern", e.get_pattern ()); end ("StructPatternFieldIdentPat"); } @@ -2290,7 +2315,7 @@ Dump::visit (LetStmt &e) auto oa = e.get_outer_attrs (); do_outer_attrs (oa); - put_field ("variable_pattern", e.get_pattern ().as_string ()); + visit_field ("variable_pattern", e.get_pattern ()); if (e.has_type ()) visit_field ("type", e.get_type ()); diff --git a/gcc/rust/hir/rust-hir-dump.h b/gcc/rust/hir/rust-hir-dump.h index 45b17080e696..8c39f489baff 100644 --- a/gcc/rust/hir/rust-hir-dump.h +++ b/gcc/rust/hir/rust-hir-dump.h @@ -146,6 +146,8 @@ class Dump : public HIRFullVisitor virtual void visit (FieldAccessExpr &) override; virtual void visit (ClosureExpr &) override; virtual void visit (BlockExpr &) override; + virtual void visit (AnonConst &) override; + virtual void visit (ConstBlock &) override; virtual void visit (ContinueExpr &) override; virtual void visit (BreakExpr &) override; virtual void visit (RangeFromToExpr &) override; @@ -252,7 +254,6 @@ class Dump : public HIRFullVisitor } // namespace Rust // In the global namespace to make it easier to call from debugger -void -debug (Rust::HIR::FullVisitable &v); +void debug (Rust::HIR::FullVisitable &v); #endif // !RUST_HIR_DUMP_H diff --git a/gcc/rust/hir/tree/rust-hir-expr-abstract.h b/gcc/rust/hir/tree/rust-hir-expr-abstract.h index 5bc5d8903099..8272a82808c9 100644 --- a/gcc/rust/hir/tree/rust-hir-expr-abstract.h +++ b/gcc/rust/hir/tree/rust-hir-expr-abstract.h @@ -43,7 +43,7 @@ class Expr : public Node, virtual public FullVisitable WITHOUT_BLOCK, }; - enum ExprType + enum class ExprType { Lit, Operator, @@ -58,6 +58,8 @@ class Expr : public Node, virtual public FullVisitable FieldAccess, Closure, Block, + AnonConst, + ConstBlock, Continue, Break, Range, diff --git a/gcc/rust/hir/tree/rust-hir-expr.cc b/gcc/rust/hir/tree/rust-hir-expr.cc index 266c79c2fe89..8544ed6708b7 100644 --- a/gcc/rust/hir/tree/rust-hir-expr.cc +++ b/gcc/rust/hir/tree/rust-hir-expr.cc @@ -17,6 +17,8 @@ // . #include "rust-hir-expr.h" +#include "rust-hir-map.h" +#include "optional.h" #include "rust-operators.h" #include "rust-hir-stmt.h" @@ -790,6 +792,61 @@ BlockExpr::operator= (BlockExpr const &other) return *this; } +AnonConst::AnonConst (Analysis::NodeMapping mappings, + std::unique_ptr &&expr, location_t locus) + : ExprWithBlock (std::move (mappings), {}), locus (locus), + kind (Kind::Explicit), expr (std::move (expr)) +{ + rust_assert (this->expr.value ()); +} + +AnonConst::AnonConst (Analysis::NodeMapping mappings, location_t locus) + : ExprWithBlock (std::move (mappings), {}), locus (locus), + kind (Kind::DeferredInference), expr (tl::nullopt) +{} + +AnonConst::AnonConst (const AnonConst &other) + : ExprWithBlock (other), locus (other.locus), kind (other.kind) +{ + if (other.expr) + expr = other.expr.value ()->clone_expr (); +} + +AnonConst +AnonConst::operator= (const AnonConst &other) +{ + ExprWithBlock::operator= (other); + + locus = other.locus; + kind = other.kind; + + if (other.expr) + expr = other.expr.value ()->clone_expr (); + + return *this; +} + +ConstBlock::ConstBlock (Analysis::NodeMapping mappings, AnonConst &&expr, + location_t locus, AST::AttrVec outer_attrs) + : ExprWithBlock (std::move (mappings), std::move (outer_attrs)), + expr (std::move (expr)), locus (locus) +{} + +ConstBlock::ConstBlock (const ConstBlock &other) + : ExprWithBlock (other), expr (other.expr), locus (other.locus) +{} + +ConstBlock +ConstBlock::operator= (const ConstBlock &other) +{ + ExprWithBlock::operator= (other); + + expr = other.expr; + locus = other.locus; + + return *this; +} + ContinueExpr::ContinueExpr (Analysis::NodeMapping mappings, location_t locus, tl::optional label, AST::AttrVec outer_attribs) @@ -1277,59 +1334,42 @@ AsyncBlockExpr::operator= (AsyncBlockExpr const &other) OperatorExprMeta::OperatorExprMeta (HIR::CompoundAssignmentExpr &expr) : node_mappings (expr.get_mappings ()), lvalue_mappings (expr.get_expr ().get_mappings ()), - locus (expr.get_locus ()) + rvalue_mappings (expr.get_rhs ().get_mappings ()), locus (expr.get_locus ()) {} OperatorExprMeta::OperatorExprMeta (HIR::ArithmeticOrLogicalExpr &expr) : node_mappings (expr.get_mappings ()), lvalue_mappings (expr.get_expr ().get_mappings ()), - locus (expr.get_locus ()) + rvalue_mappings (expr.get_rhs ().get_mappings ()), locus (expr.get_locus ()) {} OperatorExprMeta::OperatorExprMeta (HIR::NegationExpr &expr) : node_mappings (expr.get_mappings ()), lvalue_mappings (expr.get_expr ().get_mappings ()), + rvalue_mappings (Analysis::NodeMapping::get_error ()), locus (expr.get_locus ()) {} OperatorExprMeta::OperatorExprMeta (HIR::DereferenceExpr &expr) : node_mappings (expr.get_mappings ()), lvalue_mappings (expr.get_expr ().get_mappings ()), + rvalue_mappings (Analysis::NodeMapping::get_error ()), locus (expr.get_locus ()) {} OperatorExprMeta::OperatorExprMeta (HIR::ArrayIndexExpr &expr) : node_mappings (expr.get_mappings ()), lvalue_mappings (expr.get_array_expr ().get_mappings ()), + rvalue_mappings (expr.get_index_expr ().get_mappings ()), locus (expr.get_locus ()) {} OperatorExprMeta::OperatorExprMeta (HIR::ComparisonExpr &expr) : node_mappings (expr.get_mappings ()), lvalue_mappings (expr.get_expr ().get_mappings ()), - locus (expr.get_locus ()) + rvalue_mappings (expr.get_rhs ().get_mappings ()), locus (expr.get_locus ()) {} -AnonConst::AnonConst (NodeId id, std::unique_ptr expr) - : id (id), expr (std::move (expr)) -{ - rust_assert (this->expr != nullptr); -} - -AnonConst::AnonConst (const AnonConst &other) -{ - id = other.id; - expr = other.expr->clone_expr (); -} - -AnonConst -AnonConst::operator= (const AnonConst &other) -{ - id = other.id; - expr = other.expr->clone_expr (); - return *this; -} - InlineAsmOperand::In::In ( const tl::optional ®, std::unique_ptr expr) @@ -1476,7 +1516,7 @@ InlineAsm::InlineAsm (location_t locus, bool is_global_asm, std::vector template_strs, std::vector operands, std::vector clobber_abi, - std::set options, + std::set options, Analysis::NodeMapping mappings, AST::AttrVec outer_attribs) : ExprWithoutBlock (std::move (mappings), std::move (outer_attribs)), diff --git a/gcc/rust/hir/tree/rust-hir-expr.h b/gcc/rust/hir/tree/rust-hir-expr.h index 375f47402f01..8e14a7b29125 100644 --- a/gcc/rust/hir/tree/rust-hir-expr.h +++ b/gcc/rust/hir/tree/rust-hir-expr.h @@ -19,12 +19,15 @@ #ifndef RUST_HIR_EXPR_H #define RUST_HIR_EXPR_H +#include "rust-ast.h" #include "rust-hir-expr-abstract.h" #include "rust-hir-literal.h" #include "rust-common.h" #include "rust-hir-bound.h" #include "rust-hir-attrs.h" #include "rust-expr.h" +#include "rust-hir-map.h" +#include "rust-mapping-common.h" namespace Rust { namespace HIR { @@ -1800,6 +1803,92 @@ class BlockExpr : public ExprWithBlock, public WithInnerAttrs } }; +class AnonConst : public ExprWithBlock +{ +public: + enum class Kind + { + Explicit, + DeferredInference + }; + + AnonConst (Analysis::NodeMapping mappings, std::unique_ptr &&expr, + location_t locus = UNKNOWN_LOCATION); + AnonConst (Analysis::NodeMapping mappings, + location_t locus = UNKNOWN_LOCATION); + AnonConst (const AnonConst &other); + AnonConst operator= (const AnonConst &other); + + std::string as_string () const override; + + void accept_vis (HIRFullVisitor &vis) override; + void accept_vis (HIRExpressionVisitor &vis) override; + + ExprType get_expression_type () const final override + { + return ExprType::AnonConst; + } + + location_t get_locus () const override { return locus; } + + Expr &get_inner_expr () + { + rust_assert (kind == Kind::Explicit); + return *expr.value (); + } + + const Expr &get_inner_expr () const + { + rust_assert (kind == Kind::Explicit); + return *expr.value (); + } + + bool is_deferred () const { return kind == Kind::DeferredInference; } + +private: + location_t locus; + Kind kind; + tl::optional> expr; + + AnonConst *clone_expr_with_block_impl () const override + { + return new AnonConst (*this); + } +}; + +class ConstBlock : public ExprWithBlock +{ +public: + ConstBlock (Analysis::NodeMapping mappings, AnonConst &&expr, + location_t locus = UNKNOWN_LOCATION, + AST::AttrVec outer_attrs = {}); + ConstBlock (const ConstBlock &other); + ConstBlock operator= (const ConstBlock &other); + + void accept_vis (HIRFullVisitor &vis) override; + void accept_vis (HIRExpressionVisitor &vis) override; + + std::string as_string () const override; + + ExprType get_expression_type () const final override + { + return ExprType::ConstBlock; + } + + location_t get_locus () const override { return locus; } + AnonConst &get_const_expr () { return expr; } + const AnonConst &get_const_expr () const { return expr; } + +private: + AnonConst expr; + location_t locus; + + ConstBlock *clone_expr_with_block_impl () const override + { + return new ConstBlock (*this); + } +}; + // HIR node representing continue expression within loops class ContinueExpr : public ExprWithoutBlock { @@ -2631,6 +2720,8 @@ struct MatchArm Expr &get_guard_expr () { return *guard_expr; } location_t get_locus () const { return locus; } + + AST::AttrVec &get_outer_attrs () { return outer_attrs; } }; /* A "match case" - a correlated match arm and resulting expression. Not @@ -2823,6 +2914,22 @@ class OperatorExprMeta OperatorExprMeta (HIR::ComparisonExpr &expr); + OperatorExprMeta (const OperatorExprMeta &other) + : node_mappings (other.node_mappings), + lvalue_mappings (other.lvalue_mappings), + rvalue_mappings (other.rvalue_mappings), locus (other.locus) + {} + + OperatorExprMeta &operator= (const OperatorExprMeta &other) + { + node_mappings = other.node_mappings; + lvalue_mappings = other.lvalue_mappings; + rvalue_mappings = other.rvalue_mappings; + locus = other.locus; + + return *this; + } + const Analysis::NodeMapping &get_mappings () const { return node_mappings; } const Analysis::NodeMapping &get_lvalue_mappings () const @@ -2830,11 +2937,22 @@ class OperatorExprMeta return lvalue_mappings; } + const Analysis::NodeMapping &get_rvalue_mappings () const + { + return rvalue_mappings; + } + + bool has_rvalue_mappings () const + { + return rvalue_mappings.get_hirid () != UNKNOWN_HIRID; + } + location_t get_locus () const { return locus; } private: - const Analysis::NodeMapping node_mappings; - const Analysis::NodeMapping lvalue_mappings; + Analysis::NodeMapping node_mappings; + Analysis::NodeMapping lvalue_mappings; + Analysis::NodeMapping rvalue_mappings; location_t locus; }; @@ -2892,18 +3010,6 @@ class InlineAsmRegClass std::string placeholder; }; -struct AnonConst -{ - NodeId id; - std::unique_ptr expr; - - AnonConst (NodeId id, std::unique_ptr expr); - - AnonConst (const AnonConst &other); - - AnonConst operator= (const AnonConst &other); -}; - class InlineAsmOperand { public: @@ -3059,7 +3165,7 @@ class InlineAsm : public ExprWithoutBlock std::vector template_strs; std::vector operands; std::vector clobber_abi; - std::set options; + std::set options; std::vector line_spans; @@ -3094,7 +3200,7 @@ class InlineAsm : public ExprWithoutBlock std::vector get_clobber_abi () { return clobber_abi; } - std::set get_options () { return options; } + std::set get_options () { return options; } bool is_simple_asm () { @@ -3113,7 +3219,7 @@ class InlineAsm : public ExprWithoutBlock std::vector template_strs, std::vector operands, std::vector clobber_abi, - std::set options, + std::set options, Analysis::NodeMapping mappings, AST::AttrVec outer_attribs = AST::AttrVec ()); }; diff --git a/gcc/rust/hir/tree/rust-hir-full-decls.h b/gcc/rust/hir/tree/rust-hir-full-decls.h index 1e313ec1c7b7..2905117dcb7c 100644 --- a/gcc/rust/hir/tree/rust-hir-full-decls.h +++ b/gcc/rust/hir/tree/rust-hir-full-decls.h @@ -95,6 +95,8 @@ class FieldAccessExpr; struct ClosureParam; class ClosureExpr; class BlockExpr; +class AnonConst; +class ConstBlock; class ContinueExpr; class BreakExpr; class RangeExpr; @@ -123,7 +125,6 @@ class AwaitExpr; class AsyncBlockExpr; class InlineAsmReg; class InlineAsmRegClass; -struct AnonConst; class InlineAsmOperand; class InlineAsm; class LlvmInlineAsm; diff --git a/gcc/rust/hir/tree/rust-hir-item.cc b/gcc/rust/hir/tree/rust-hir-item.cc index 160f710408af..1406e7aeb515 100644 --- a/gcc/rust/hir/tree/rust-hir-item.cc +++ b/gcc/rust/hir/tree/rust-hir-item.cc @@ -26,16 +26,18 @@ TypeParam::TypeParam ( Analysis::NodeMapping mappings, Identifier type_representation, location_t locus, std::vector> type_param_bounds, - tl::optional> type, AST::AttrVec outer_attrs) + tl::optional> type, AST::AttrVec outer_attrs, + bool was_impl_trait) : GenericParam (mappings), outer_attrs (std::move (outer_attrs)), type_representation (std::move (type_representation)), type_param_bounds (std::move (type_param_bounds)), type (std::move (type)), - locus (locus) + locus (locus), was_impl_trait (was_impl_trait) {} TypeParam::TypeParam (TypeParam const &other) : GenericParam (other.mappings), outer_attrs (other.outer_attrs), - type_representation (other.type_representation), locus (other.locus) + type_representation (other.type_representation), locus (other.locus), + was_impl_trait (other.was_impl_trait) { // guard to prevent null pointer dereference if (other.has_type ()) @@ -55,6 +57,7 @@ TypeParam::operator= (TypeParam const &other) outer_attrs = other.outer_attrs; locus = other.locus; mappings = other.mappings; + was_impl_trait = other.was_impl_trait; // guard to prevent null pointer dereference if (other.has_type ()) diff --git a/gcc/rust/hir/tree/rust-hir-item.h b/gcc/rust/hir/tree/rust-hir-item.h index 37f599cdee4a..d9df6029c5ac 100644 --- a/gcc/rust/hir/tree/rust-hir-item.h +++ b/gcc/rust/hir/tree/rust-hir-item.h @@ -95,17 +95,11 @@ class Item : public Stmt, public WithOuterAttrs class TypeParam : public GenericParam { AST::AttrVec outer_attrs; - Identifier type_representation; - - // bool has_type_param_bounds; - // TypeParamBounds type_param_bounds; - std::vector> - type_param_bounds; // inlined form - + std::vector> type_param_bounds; tl::optional> type; - location_t locus; + bool was_impl_trait; public: // Returns whether the type of the type param has been specified. @@ -121,9 +115,9 @@ class TypeParam : public GenericParam TypeParam (Analysis::NodeMapping mappings, Identifier type_representation, location_t locus = UNDEF_LOCATION, std::vector> type_param_bounds - = std::vector> (), + = {}, tl::optional> type = tl::nullopt, - AST::AttrVec outer_attrs = std::vector ()); + AST::AttrVec outer_attrs = {}, bool was_impl_trait = false); // Copy constructor uses clone TypeParam (TypeParam const &other); @@ -154,6 +148,8 @@ class TypeParam : public GenericParam std::vector> &get_type_param_bounds (); + bool from_impl_trait () const { return was_impl_trait; } + protected: // Clone function implementation as (not pure) virtual method TypeParam *clone_generic_param_impl () const override @@ -213,6 +209,8 @@ class LifetimeWhereClauseItem : public WhereClauseItem std::string as_string () const override; + location_t get_locus () const { return locus; } + void accept_vis (HIRFullVisitor &vis) override; Lifetime &get_lifetime () { return lifetime; } @@ -406,6 +404,8 @@ struct SelfParam const Lifetime &get_lifetime () const { return lifetime.value (); } + Lifetime &get_lifetime () { return lifetime.value (); } + std::string as_string () const; location_t get_locus () const { return locus; } @@ -1801,6 +1801,8 @@ class ConstantItem : public VisItem, public ImplItem return *type; } + bool has_expr () const { return const_expr != nullptr; } + Expr &get_expr () { return *const_expr; } Identifier get_identifier () const { return identifier; } diff --git a/gcc/rust/hir/tree/rust-hir-path.h b/gcc/rust/hir/tree/rust-hir-path.h index 3ce2662c8024..5f88c6827bb1 100644 --- a/gcc/rust/hir/tree/rust-hir-path.h +++ b/gcc/rust/hir/tree/rust-hir-path.h @@ -41,11 +41,15 @@ class PathIdentSegment : segment_name (std::move (segment_name)) {} - /* TODO: insert check in constructor for this? Or is this a semantic error - * best handled then? */ + PathIdentSegment (const PathIdentSegment &other) + : segment_name (other.segment_name) + {} - /* TODO: does this require visitor? pretty sure this isn't polymorphic, but - * not entirely sure */ + PathIdentSegment &operator= (PathIdentSegment const &other) + { + segment_name = other.segment_name; + return *this; + } // Creates an error PathIdentSegment. static PathIdentSegment create_error () { return PathIdentSegment (""); } diff --git a/gcc/rust/hir/tree/rust-hir-pattern.h b/gcc/rust/hir/tree/rust-hir-pattern.h index 5cc5c9512ecc..9c636caeb25a 100644 --- a/gcc/rust/hir/tree/rust-hir-pattern.h +++ b/gcc/rust/hir/tree/rust-hir-pattern.h @@ -80,7 +80,7 @@ class IdentifierPattern : public Pattern Identifier variable_ident; bool is_ref; Mutability mut; - std::unique_ptr to_bind; + std::unique_ptr subpattern; location_t locus; Analysis::NodeMapping mappings; @@ -88,15 +88,15 @@ class IdentifierPattern : public Pattern std::string as_string () const override; // Returns whether the IdentifierPattern has a pattern to bind. - bool has_pattern_to_bind () const { return to_bind != nullptr; } + bool has_subpattern () const { return subpattern != nullptr; } // Constructor IdentifierPattern (Analysis::NodeMapping mappings, Identifier ident, location_t locus, bool is_ref = false, Mutability mut = Mutability::Imm, - std::unique_ptr to_bind = nullptr) + std::unique_ptr subpattern = nullptr) : variable_ident (std::move (ident)), is_ref (is_ref), mut (mut), - to_bind (std::move (to_bind)), locus (locus), mappings (mappings) + subpattern (std::move (subpattern)), locus (locus), mappings (mappings) {} // Copy constructor with clone @@ -105,8 +105,8 @@ class IdentifierPattern : public Pattern mut (other.mut), locus (other.locus), mappings (other.mappings) { // fix to get prevent null pointer dereference - if (other.to_bind != nullptr) - to_bind = other.to_bind->clone_pattern (); + if (other.subpattern != nullptr) + subpattern = other.subpattern->clone_pattern (); } // Overload assignment operator to use clone @@ -119,8 +119,8 @@ class IdentifierPattern : public Pattern mappings = other.mappings; // fix to get prevent null pointer dereference - if (other.to_bind != nullptr) - to_bind = other.to_bind->clone_pattern (); + if (other.subpattern != nullptr) + subpattern = other.subpattern->clone_pattern (); return *this; } @@ -133,7 +133,7 @@ class IdentifierPattern : public Pattern bool is_mut () const { return mut == Mutability::Mut; } bool get_is_ref () const { return is_ref; } - Pattern &get_to_bind () { return *to_bind; } + Pattern &get_subpattern () { return *subpattern; } void accept_vis (HIRFullVisitor &vis) override; void accept_vis (HIRPatternVisitor &vis) override; diff --git a/gcc/rust/hir/tree/rust-hir-visibility.h b/gcc/rust/hir/tree/rust-hir-visibility.h index a750d88f284d..9dd6ff292674 100644 --- a/gcc/rust/hir/tree/rust-hir-visibility.h +++ b/gcc/rust/hir/tree/rust-hir-visibility.h @@ -73,6 +73,8 @@ struct Visibility } std::string as_string () const; + + location_t get_locus () const { return locus; } }; } // namespace HIR } // namespace Rust diff --git a/gcc/rust/hir/tree/rust-hir-visitor.cc b/gcc/rust/hir/tree/rust-hir-visitor.cc new file mode 100644 index 000000000000..ece47eba8519 --- /dev/null +++ b/gcc/rust/hir/tree/rust-hir-visitor.cc @@ -0,0 +1,1180 @@ +// Copyright (C) 2021-2025 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 +// . + +#include "rust-expr.h" +#include "rust-hir-full-decls.h" +#include "rust-hir-visitor.h" +#include "rust-hir-full.h" +#include "rust-system.h" + +namespace Rust { +namespace HIR { + +void +DefaultHIRVisitor::walk (Lifetime &) +{} + +void +DefaultHIRVisitor::walk (LifetimeParam &lifetime_param) +{ + visit_outer_attrs (lifetime_param); + lifetime_param.get_lifetime ().accept_vis (*this); + for (Lifetime &lifetime_bound : lifetime_param.get_lifetime_bounds ()) + lifetime_bound.accept_vis (*this); +} + +void +DefaultHIRVisitor::visit_generic_args (GenericArgs &generic_args) +{ + for (auto &lifetime : generic_args.get_lifetime_args ()) + lifetime.accept_vis (*this); + for (auto &type : generic_args.get_type_args ()) + type->accept_vis (*this); + for (auto &binding : generic_args.get_binding_args ()) + binding.get_type ().accept_vis (*this); + for (auto &const_arg : generic_args.get_const_args ()) + const_arg.get_expression ()->accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (PathInExpression &path_in_expr) +{ + visit_outer_attrs (path_in_expr); + if (!path_in_expr.is_lang_item ()) + for (auto &segment : path_in_expr.get_segments ()) + visit_path_expr_segment (segment); +} + +void +DefaultHIRVisitor::walk (TypePathSegment &) +{} + +void +DefaultHIRVisitor::walk (TypePathSegmentFunction &segment_function) +{ + TypePathFunction &function_path = segment_function.get_function_path (); + if (function_path.has_inputs ()) + for (auto ¶m : function_path.get_params ()) + param->accept_vis (*this); + if (function_path.has_return_type ()) + function_path.get_return_type ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (TypePathSegmentGeneric &segment_generic) +{ + if (segment_generic.has_generic_args ()) + visit_generic_args (segment_generic.get_generic_args ()); +} + +void +DefaultHIRVisitor::walk (TypePath &type_path) +{ + for (auto &segment : type_path.get_segments ()) + segment->accept_vis (*this); +} + +void +DefaultHIRVisitor::visit_qualified_path_type (QualifiedPathType &path) +{ + path.get_type ().accept_vis (*this); + if (path.has_as_clause ()) + path.get_trait ().accept_vis (*this); +} + +// TODO: Implement visit_path_expr_segment +void +DefaultHIRVisitor::visit_path_expr_segment (PathExprSegment &segment) +{ + if (segment.has_generic_args ()) + visit_generic_args (segment.get_generic_args ()); +} + +void +DefaultHIRVisitor::walk (QualifiedPathInExpression &path_in_expr) +{ + visit_outer_attrs (path_in_expr); + visit_qualified_path_type (path_in_expr.get_path_type ()); + for (auto &segment : path_in_expr.get_segments ()) + visit_path_expr_segment (segment); +} + +void +DefaultHIRVisitor::walk (QualifiedPathInType &path_in_type) +{ + visit_qualified_path_type (path_in_type.get_path_type ()); + path_in_type.get_associated_segment ().accept_vis (*this); + for (auto &segment : path_in_type.get_segments ()) + segment->accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (LiteralExpr &expr) +{ + visit_outer_attrs (expr); +} + +void +DefaultHIRVisitor::walk (BorrowExpr &expr) +{ + visit_outer_attrs (expr); + expr.get_expr ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (DereferenceExpr &expr) +{ + visit_outer_attrs (expr); + expr.get_expr ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (ErrorPropagationExpr &expr) +{ + visit_outer_attrs (expr); + expr.get_expr ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (NegationExpr &expr) +{ + visit_outer_attrs (expr); + expr.get_expr ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (ArithmeticOrLogicalExpr &expr) +{ + visit_outer_attrs (expr); + expr.get_lhs ().accept_vis (*this); + expr.get_rhs ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (ComparisonExpr &expr) +{ + visit_outer_attrs (expr); + expr.get_lhs ().accept_vis (*this); + expr.get_rhs ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (LazyBooleanExpr &expr) +{ + visit_outer_attrs (expr); + expr.get_lhs ().accept_vis (*this); + expr.get_rhs ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (TypeCastExpr &expr) +{ + visit_outer_attrs (expr); + expr.get_expr ().accept_vis (*this); + expr.get_type_to_convert_to ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (AssignmentExpr &expr) +{ + visit_outer_attrs (expr); + expr.get_lhs ().accept_vis (*this); + expr.get_rhs ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (CompoundAssignmentExpr &expr) +{ + visit_outer_attrs (expr); + expr.get_lhs ().accept_vis (*this); + expr.get_rhs ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (GroupedExpr &expr) +{ + visit_outer_attrs (expr); + visit_inner_attrs (expr); + expr.get_expr_in_parens ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (ArrayElemsValues &elems) +{ + for (auto &elem : elems.get_values ()) + elem->accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (ArrayElemsCopied &elems) +{ + elems.get_elem_to_copy ().accept_vis (*this); + elems.get_num_copies_expr ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (ArrayExpr &expr) +{ + visit_outer_attrs (expr); + visit_inner_attrs (expr); + expr.get_internal_elements ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (ArrayIndexExpr &expr) +{ + visit_outer_attrs (expr); + expr.get_array_expr ().accept_vis (*this); + expr.get_index_expr ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (TupleExpr &expr) +{ + visit_outer_attrs (expr); + visit_inner_attrs (expr); + for (auto &elem : expr.get_tuple_elems ()) + elem->accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (TupleIndexExpr &expr) +{ + visit_outer_attrs (expr); + expr.get_tuple_expr ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (StructExprStruct &expr) +{ + visit_outer_attrs (expr); + visit_inner_attrs (expr); + expr.get_struct_name ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (StructExprFieldIdentifier &) +{} + +void +DefaultHIRVisitor::walk (StructExprFieldIdentifierValue &field) +{ + field.get_value ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (StructExprFieldIndexValue &field) +{ + field.get_value ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (StructExprStructFields &expr) +{ + visit_outer_attrs (expr); + visit_inner_attrs (expr); + expr.get_struct_name ().accept_vis (*this); + if (expr.has_struct_base ()) + { + StructBase &base = expr.get_struct_base (); + base.get_base ().accept_vis (*this); + } + for (auto &field : expr.get_fields ()) + field->accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (StructExprStructBase &expr) +{ + visit_outer_attrs (expr); + visit_inner_attrs (expr); + expr.get_struct_name ().accept_vis (*this); + StructBase &base = expr.get_struct_base (); + base.get_base ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (CallExpr &expr) +{ + visit_outer_attrs (expr); + expr.get_fnexpr ().accept_vis (*this); + for (auto &arg : expr.get_arguments ()) + arg->accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (MethodCallExpr &expr) +{ + visit_outer_attrs (expr); + expr.get_receiver ().accept_vis (*this); + visit_path_expr_segment (expr.get_method_name ()); + for (auto &arg : expr.get_arguments ()) + arg->accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (FieldAccessExpr &expr) +{ + visit_outer_attrs (expr); + expr.get_receiver_expr ().accept_vis (*this); +} + +void +DefaultHIRVisitor::visit_closure_param (ClosureParam ¶m) +{ + visit_outer_attrs (param); + param.get_pattern ().accept_vis (*this); + if (param.has_type_given ()) + { + param.get_type ().accept_vis (*this); + } +} + +void +DefaultHIRVisitor::walk (ClosureExpr &expr) +{ + visit_outer_attrs (expr); + for (auto ¶m : expr.get_params ()) + visit_closure_param (param); + if (expr.has_return_type ()) + expr.get_return_type ().accept_vis (*this); + expr.get_expr ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (BlockExpr &expr) +{ + visit_outer_attrs (expr); + visit_inner_attrs (expr); + for (auto &stmt : expr.get_statements ()) + stmt->accept_vis (*this); + if (expr.has_expr ()) + expr.get_final_expr ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (AnonConst &expr) +{ + if (!expr.is_deferred ()) + expr.get_inner_expr ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (ConstBlock &expr) +{ + expr.get_const_expr ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (ContinueExpr &expr) +{ + visit_outer_attrs (expr); + if (expr.has_label ()) + expr.get_label ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (BreakExpr &expr) +{ + visit_outer_attrs (expr); + if (expr.has_label ()) + expr.get_label ().accept_vis (*this); + + if (expr.has_break_expr ()) + expr.get_expr ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (RangeFromToExpr &expr) +{ + expr.get_from_expr ().accept_vis (*this); + expr.get_to_expr ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (RangeFromExpr &expr) +{ + expr.get_from_expr ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (RangeToExpr &expr) +{ + expr.get_to_expr ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (RangeFullExpr &) +{} + +void +DefaultHIRVisitor::walk (RangeFromToInclExpr &expr) +{ + expr.get_from_expr ().accept_vis (*this); + expr.get_to_expr ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (RangeToInclExpr &expr) +{ + expr.get_to_expr ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (ReturnExpr &expr) +{ + visit_outer_attrs (expr); + if (expr.has_return_expr ()) + expr.get_expr ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (UnsafeBlockExpr &expr) +{ + visit_outer_attrs (expr); + expr.get_block_expr ().accept_vis (*this); +} + +void +DefaultHIRVisitor::visit_loop_label (LoopLabel &label) +{ + label.get_lifetime ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (LoopExpr &expr) +{ + visit_outer_attrs (expr); + if (expr.has_loop_label ()) + visit_loop_label (expr.get_loop_label ()); + expr.get_loop_block ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (WhileLoopExpr &expr) +{ + visit_outer_attrs (expr); + if (expr.has_loop_label ()) + visit_loop_label (expr.get_loop_label ()); + expr.get_predicate_expr ().accept_vis (*this); + expr.get_loop_block ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (WhileLetLoopExpr &expr) +{ + visit_outer_attrs (expr); + for (auto &pattern : expr.get_patterns ()) + pattern->accept_vis (*this); + if (expr.has_loop_label ()) + visit_loop_label (expr.get_loop_label ()); + expr.get_cond ().accept_vis (*this); + expr.get_loop_block ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (IfExpr &expr) +{ + visit_outer_attrs (expr); + expr.get_if_condition ().accept_vis (*this); + expr.get_if_block ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (IfExprConseqElse &expr) +{ + reinterpret_cast (expr).accept_vis (*this); + expr.get_else_block ().accept_vis (*this); +} + +void +DefaultHIRVisitor::visit_match_arm (MatchArm &arm) +{ + // visit_outer_attrs (arm); + for (auto &pattern : arm.get_patterns ()) + pattern->accept_vis (*this); + if (arm.has_match_arm_guard ()) + arm.get_guard_expr ().accept_vis (*this); +} + +void +DefaultHIRVisitor::visit_match_case (MatchCase &arm) +{ + visit_match_arm (arm.get_arm ()); + arm.get_expr ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (MatchExpr &expr) +{ + visit_outer_attrs (expr); + visit_inner_attrs (expr); + expr.get_scrutinee_expr ().accept_vis (*this); + for (auto &arm : expr.get_match_cases ()) + visit_match_case (arm); +} + +void +DefaultHIRVisitor::walk (AwaitExpr &expr) +{ + visit_outer_attrs (expr); + expr.get_awaited_expr ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (AsyncBlockExpr &expr) +{ + visit_outer_attrs (expr); + expr.get_block_expr ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (InlineAsm &expr) +{ + visit_outer_attrs (expr); + const auto &operands = expr.get_operands (); + using RegisterType = AST::InlineAsmOperand::RegisterType; + for (auto &operand : operands) + { + switch (operand.get_register_type ()) + { + case RegisterType::In: + { + operand.get_in ().expr->accept_vis (*this); + break; + } + case RegisterType::Out: + { + operand.get_out ().expr->accept_vis (*this); + break; + } + case RegisterType::InOut: + { + operand.get_in_out ().expr->accept_vis (*this); + break; + } + case RegisterType::SplitInOut: + { + operand.get_split_in_out ().in_expr->accept_vis (*this); + operand.get_split_in_out ().out_expr->accept_vis (*this); + break; + } + case RegisterType::Const: + { + operand.get_const ().anon_const.get_inner_expr ().accept_vis ( + *this); + break; + } + case RegisterType::Sym: + { + operand.get_sym ().expr->accept_vis (*this); + break; + } + case RegisterType::Label: + { + operand.get_label ().expr->accept_vis (*this); + break; + } + } + } +} + +void +DefaultHIRVisitor::walk (LlvmInlineAsm &expr) +{ + for (auto &output : expr.outputs) + output.expr->accept_vis (*this); + for (auto &input : expr.inputs) + input.expr->accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (TypeParam ¶m) +{ + visit_outer_attrs (param); + for (auto &bounds : param.get_type_param_bounds ()) + bounds->accept_vis (*this); + if (param.has_type ()) + param.get_type ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (ConstGenericParam &const_param) +{ + visit_outer_attrs (const_param); + const_param.get_type ().accept_vis (*this); + if (const_param.has_default_expression ()) + const_param.get_default_expression ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (LifetimeWhereClauseItem &item) +{ + item.get_lifetime ().accept_vis (*this); + for (auto &bound : item.get_lifetime_bounds ()) + bound.accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (TypeBoundWhereClauseItem &item) +{ + for (auto &lifetime : item.get_for_lifetimes ()) + lifetime.accept_vis (*this); + item.get_bound_type ().accept_vis (*this); + for (auto ¶m : item.get_type_param_bounds ()) + param->accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (Module &module) +{ + visit_outer_attrs (module); + visit_inner_attrs (module); + for (auto &item : module.get_items ()) + item->accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (ExternCrate &crate) +{ + visit_outer_attrs (crate); +} + +void +DefaultHIRVisitor::walk (UseTreeGlob &) +{} + +void +DefaultHIRVisitor::walk (UseTreeList &) +{} + +void +DefaultHIRVisitor::walk (UseTreeRebind &) +{} + +void +DefaultHIRVisitor::walk (UseDeclaration &) +{} + +void +DefaultHIRVisitor::visit_function_param (FunctionParam ¶m) +{ + param.get_param_name ().accept_vis (*this); + param.get_type ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (Function &function) +{ + visit_outer_attrs (function); + for (auto &generic : function.get_generic_params ()) + generic->accept_vis (*this); + for (auto ¶m : function.get_function_params ()) + visit_function_param (param); + if (function.has_return_type ()) + function.get_return_type ().accept_vis (*this); + if (function.has_where_clause ()) + visit_where_clause (function.get_where_clause ()); + function.get_definition ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (TypeAlias &type_alias) +{ + visit_outer_attrs (type_alias); + for (auto &generic : type_alias.get_generic_params ()) + generic->accept_vis (*this); + if (type_alias.has_where_clause ()) + visit_where_clause (type_alias.get_where_clause ()); + type_alias.get_type_aliased ().accept_vis (*this); +} + +void +DefaultHIRVisitor::visit_struct_field (StructField &field) +{ + field.get_field_type ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (StructStruct &struct_item) +{ + visit_outer_attrs (struct_item); + for (auto &generic : struct_item.get_generic_params ()) + generic->accept_vis (*this); + if (struct_item.has_where_clause ()) + visit_where_clause (struct_item.get_where_clause ()); + for (auto &field : struct_item.get_fields ()) + visit_struct_field (field); +} + +void +DefaultHIRVisitor::walk (TupleStruct &tuple_struct) +{ + visit_outer_attrs (tuple_struct); + for (auto &generic : tuple_struct.get_generic_params ()) + generic->accept_vis (*this); + if (tuple_struct.has_where_clause ()) + visit_where_clause (tuple_struct.get_where_clause ()); + for (auto &field : tuple_struct.get_fields ()) + field.get_field_type ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (EnumItem &item) +{ + visit_outer_attrs (item); +} + +void +DefaultHIRVisitor::walk (EnumItemTuple &item_tuple) +{ + reinterpret_cast (item_tuple).accept_vis (*this); + for (auto &field : item_tuple.get_tuple_fields ()) + field.get_field_type ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (EnumItemStruct &item_struct) +{ + reinterpret_cast (item_struct).accept_vis (*this); + for (auto &field : item_struct.get_struct_fields ()) + field.get_field_type ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (EnumItemDiscriminant &item) +{ + reinterpret_cast (item).accept_vis (*this); + item.get_discriminant_expression ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (Enum &enum_item) +{ + visit_outer_attrs (enum_item); + for (auto &generic : enum_item.get_generic_params ()) + generic->accept_vis (*this); + if (enum_item.has_where_clause ()) + visit_where_clause (enum_item.get_where_clause ()); + for (auto &item : enum_item.get_variants ()) + item->accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (Union &union_item) +{ + visit_outer_attrs (union_item); + for (auto &generic : union_item.get_generic_params ()) + generic->accept_vis (*this); + if (union_item.has_where_clause ()) + visit_where_clause (union_item.get_where_clause ()); + for (auto &variant : union_item.get_variants ()) + visit_struct_field (variant); +} + +void +DefaultHIRVisitor::walk (ConstantItem &const_item) +{ + visit_outer_attrs (const_item); + const_item.get_type ().accept_vis (*this); + const_item.get_expr ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (StaticItem &static_item) +{ + visit_outer_attrs (static_item); + static_item.get_type ().accept_vis (*this); + static_item.get_expr ().accept_vis (*this); +} + +void +DefaultHIRVisitor::visit_self_param (SelfParam &self_param) +{ + if (self_param.has_lifetime ()) + { + Lifetime lifetime = self_param.get_lifetime (); + lifetime.accept_vis (*this); + } + if (self_param.has_type ()) + self_param.get_type ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (TraitItemFunc &item) +{ + visit_outer_attrs (item); + TraitFunctionDecl &decl = item.get_decl (); + for (auto &generic : decl.get_generic_params ()) + generic->accept_vis (*this); + if (decl.get_self ().has_value ()) + visit_self_param (decl.get_self ().value ()); + for (auto ¶m : decl.get_function_params ()) + visit_function_param (param); + if (decl.has_return_type ()) + decl.get_return_type ().accept_vis (*this); + if (decl.has_where_clause ()) + visit_where_clause (decl.get_where_clause ()); + if (item.has_definition ()) + item.get_block_expr ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (TraitItemConst &item) +{ + visit_outer_attrs (item); + item.get_type ().accept_vis (*this); + if (item.has_expr ()) + item.get_expr ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (TraitItemType &item) +{ + visit_outer_attrs (item); + for (auto &bound : item.get_type_param_bounds ()) + bound->accept_vis (*this); +} + +void +DefaultHIRVisitor::visit_where_clause (const WhereClause &where_clause) +{ + for (auto &item : where_clause.get_items ()) + item->accept_vis (*this); +} + +void +DefaultHIRVisitor::visit_where_clause (WhereClause &where_clause) +{ + for (auto &item : where_clause.get_items ()) + { + item->accept_vis (*this); + } +} + +void +DefaultHIRVisitor::walk (WhereClauseItem &node) +{} + +void +DefaultHIRVisitor::walk (Trait &trait) +{ + visit_outer_attrs (trait); + for (auto &generic : trait.get_generic_params ()) + generic->accept_vis (*this); + if (trait.has_where_clause ()) + visit_where_clause (trait.get_where_clause ()); + for (auto &bound : trait.get_type_param_bounds ()) + bound->accept_vis (*this); + for (auto &item : trait.get_trait_items ()) + item->accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (ImplBlock &impl) +{ + visit_outer_attrs (impl); + for (auto &generic : impl.get_generic_params ()) + generic->accept_vis (*this); + impl.get_trait_ref ().accept_vis (*this); + impl.get_type ().accept_vis (*this); + if (impl.has_where_clause ()) + visit_where_clause (impl.get_where_clause ()); + visit_inner_attrs (impl); + for (auto &item : impl.get_impl_items ()) + item->accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (ExternalStaticItem &item) +{ + visit_outer_attrs (item); + item.get_item_type ().accept_vis (*this); +} + +void +DefaultHIRVisitor::visit_named_function_param (NamedFunctionParam ¶m) +{ + param.get_type ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (ExternalFunctionItem &item) +{ + visit_outer_attrs (item); + for (auto &generic : item.get_generic_params ()) + generic->accept_vis (*this); + for (auto ¶m : item.get_function_params ()) + visit_named_function_param (param); + if (item.has_return_type ()) + item.get_return_type ().accept_vis (*this); + if (item.has_where_clause ()) + visit_where_clause (item.get_where_clause ()); +} + +void +DefaultHIRVisitor::walk (ExternalTypeItem &item) +{ + visit_outer_attrs (item); +} + +void +DefaultHIRVisitor::walk (ExternBlock &block) +{ + visit_outer_attrs (block); + visit_inner_attrs (block); + for (auto &item : block.get_extern_items ()) + item->accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (LiteralPattern &) +{} + +void +DefaultHIRVisitor::walk (IdentifierPattern &pattern) +{ + if (pattern.has_subpattern ()) + pattern.get_subpattern ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (WildcardPattern &) +{} + +void +DefaultHIRVisitor::walk (RangePatternBoundLiteral &) +{} + +void +DefaultHIRVisitor::walk (RangePatternBoundPath &bound) +{ + bound.get_path ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (RangePatternBoundQualPath &bound) +{ + bound.get_qualified_path ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (RangePattern &pattern) +{ + pattern.get_lower_bound ().accept_vis (*this); + pattern.get_upper_bound ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (ReferencePattern &pattern) +{ + pattern.get_referenced_pattern ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (StructPatternFieldTuplePat &field) +{ + visit_outer_attrs (field); + field.get_tuple_pattern ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (StructPatternFieldIdentPat &field) +{ + visit_outer_attrs (field); + field.get_pattern ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (StructPatternFieldIdent &field) +{ + visit_outer_attrs (field); +} + +void +DefaultHIRVisitor::walk (StructPattern &pattern) +{ + pattern.get_path ().accept_vis (*this); + StructPatternElements &elements = pattern.get_struct_pattern_elems (); + for (auto &field : elements.get_struct_pattern_fields ()) + field->accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (TupleStructItemsNoRange &tuple_items) +{ + for (auto &item : tuple_items.get_patterns ()) + item->accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (TupleStructItemsRange &tuple_items) +{ + for (auto &lower : tuple_items.get_lower_patterns ()) + lower->accept_vis (*this); + for (auto &upper : tuple_items.get_upper_patterns ()) + upper->accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (TupleStructPattern &pattern) +{ + pattern.get_path ().accept_vis (*this); + pattern.get_items ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (TuplePatternItemsMultiple &tuple_items) +{ + for (auto &pattern : tuple_items.get_patterns ()) + pattern->accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (TuplePatternItemsRanged &tuple_items) +{ + for (auto &lower : tuple_items.get_lower_patterns ()) + lower->accept_vis (*this); + for (auto &upper : tuple_items.get_upper_patterns ()) + upper->accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (TuplePattern &pattern) +{ + pattern.get_items ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (SlicePattern &pattern) +{ + for (auto &item : pattern.get_items ()) + item->accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (AltPattern &pattern) +{ + for (auto &item : pattern.get_alts ()) + item->accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (EmptyStmt &stmt) +{} + +void +DefaultHIRVisitor::walk (LetStmt &stmt) +{ + visit_outer_attrs (stmt); + stmt.get_pattern ().accept_vis (*this); + if (stmt.has_type ()) + stmt.get_type ().accept_vis (*this); + if (stmt.has_init_expr ()) + stmt.get_init_expr ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (ExprStmt &stmt) +{ + stmt.get_expr ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (TraitBound &bound) +{ + for (auto &lifetime : bound.get_for_lifetimes ()) + lifetime.accept_vis (*this); + bound.get_path ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (ImplTraitType &type) +{ + for (auto &bound : type.get_type_param_bounds ()) + bound->accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (TraitObjectType &type) +{ + for (auto &bound : type.get_type_param_bounds ()) + bound->accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (ParenthesisedType &type) +{ + type.get_type_in_parens ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (TupleType &type) +{ + for (auto &elem : type.get_elems ()) + elem->accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (NeverType &type) +{} + +void +DefaultHIRVisitor::walk (RawPointerType &type) +{ + type.get_type ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (ReferenceType &type) +{ + if (type.has_lifetime ()) + type.get_lifetime ().accept_vis (*this); + type.get_base_type ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (ArrayType &type) +{ + type.get_element_type ().accept_vis (*this); + type.get_size_expr ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (SliceType &type) +{ + type.get_element_type ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (InferredType &type) +{} + +void +DefaultHIRVisitor::walk (BareFunctionType &type) +{ + for (auto &lifetime : type.get_for_lifetimes ()) + lifetime.accept_vis (*this); + for (auto ¶m : type.get_function_params ()) + param.get_type ().accept_vis (*this); + if (type.has_return_type ()) + type.get_return_type ().accept_vis (*this); +} + +} // namespace HIR +} // namespace Rust diff --git a/gcc/rust/hir/tree/rust-hir-visitor.h b/gcc/rust/hir/tree/rust-hir-visitor.h index 283cc346e1e3..544cf5128a5e 100644 --- a/gcc/rust/hir/tree/rust-hir-visitor.h +++ b/gcc/rust/hir/tree/rust-hir-visitor.h @@ -20,6 +20,7 @@ #define RUST_HIR_VISITOR_H #include "rust-hir-full-decls.h" +#include "rust-ast.h" namespace Rust { namespace HIR { @@ -64,6 +65,8 @@ class HIRFullVisitor virtual void visit (MethodCallExpr &expr) = 0; virtual void visit (FieldAccessExpr &expr) = 0; virtual void visit (BlockExpr &expr) = 0; + virtual void visit (AnonConst &expr) = 0; + virtual void visit (ConstBlock &expr) = 0; virtual void visit (ClosureExpr &expr) = 0; virtual void visit (ContinueExpr &expr) = 0; virtual void visit (BreakExpr &expr) = 0; @@ -153,6 +156,310 @@ class HIRFullVisitor virtual void visit (BareFunctionType &type) = 0; }; +class DefaultHIRVisitor : public HIRFullVisitor +{ +public: + virtual void visit_where_clause (WhereClause &); + virtual void visit_where_clause (const WhereClause &); + virtual void visit_named_function_param (NamedFunctionParam ¶m); + virtual void visit_function_param (FunctionParam ¶m); + virtual void visit_self_param (SelfParam ¶m); + virtual void visit_match_arm (MatchArm &arm); + virtual void visit_match_case (MatchCase &); + virtual void visit_struct_field (StructField &field); + virtual void visit_generic_args (GenericArgs &args); + virtual void visit_qualified_path_type (QualifiedPathType &); + virtual void visit_path_expr_segment (PathExprSegment &segment); + virtual void visit_closure_param (ClosureParam ¶m); + virtual void visit_loop_label (LoopLabel &); + + virtual void visit_attribute (AST::Attribute &attr) + { + visit_attribute (static_cast (attr)); + } + virtual void visit_attribute (const AST::Attribute &attr) {} + template void visit_outer_attrs (T &node) + { + for (auto &attr : node.get_outer_attrs ()) + visit_attribute (attr); + } + template void visit_inner_attrs (T &node) + { + for (auto &attr : node.get_inner_attrs ()) + visit_attribute (attr); + } + + virtual void visit (WhereClauseItem &node) { walk (node); } + + virtual void visit (Lifetime &node) override { walk (node); } + virtual void visit (LifetimeParam &node) override { walk (node); } + virtual void visit (PathInExpression &node) override { walk (node); } + virtual void visit (TypePathSegment &node) override { walk (node); } + virtual void visit (TypePathSegmentGeneric &node) override { walk (node); } + virtual void visit (TypePathSegmentFunction &node) override { walk (node); } + virtual void visit (TypePath &node) override { walk (node); } + virtual void visit (QualifiedPathInExpression &node) override { walk (node); } + virtual void visit (QualifiedPathInType &node) override { walk (node); } + virtual void visit (LiteralExpr &node) override { walk (node); } + virtual void visit (BorrowExpr &node) override { walk (node); } + virtual void visit (DereferenceExpr &node) override { walk (node); } + virtual void visit (ErrorPropagationExpr &node) override { walk (node); } + virtual void visit (NegationExpr &node) override { walk (node); } + virtual void visit (ArithmeticOrLogicalExpr &node) override { walk (node); } + virtual void visit (ComparisonExpr &node) override { walk (node); } + virtual void visit (LazyBooleanExpr &node) override { walk (node); } + virtual void visit (TypeCastExpr &node) override { walk (node); } + virtual void visit (AssignmentExpr &node) override { walk (node); } + virtual void visit (CompoundAssignmentExpr &node) override { walk (node); } + virtual void visit (GroupedExpr &node) override { walk (node); } + virtual void visit (ArrayElemsValues &node) override { walk (node); } + virtual void visit (ArrayElemsCopied &node) override { walk (node); } + virtual void visit (ArrayExpr &node) override { walk (node); } + virtual void visit (ArrayIndexExpr &node) override { walk (node); } + virtual void visit (TupleExpr &node) override { walk (node); } + virtual void visit (TupleIndexExpr &node) override { walk (node); } + virtual void visit (StructExprStruct &node) override { walk (node); } + virtual void visit (StructExprFieldIdentifier &node) override { walk (node); } + virtual void visit (StructExprFieldIdentifierValue &node) override + { + walk (node); + } + virtual void visit (StructExprFieldIndexValue &node) override { walk (node); } + virtual void visit (StructExprStructFields &node) override { walk (node); } + virtual void visit (StructExprStructBase &node) override { walk (node); } + virtual void visit (CallExpr &node) override { walk (node); } + virtual void visit (MethodCallExpr &node) override { walk (node); } + virtual void visit (FieldAccessExpr &node) override { walk (node); } + virtual void visit (ClosureExpr &node) override { walk (node); } + virtual void visit (BlockExpr &node) override { walk (node); } + virtual void visit (AnonConst &node) override { walk (node); } + virtual void visit (ConstBlock &node) override { walk (node); } + virtual void visit (ContinueExpr &node) override { walk (node); } + virtual void visit (BreakExpr &node) override { walk (node); } + virtual void visit (RangeFromToExpr &node) override { walk (node); } + virtual void visit (RangeFromExpr &node) override { walk (node); } + virtual void visit (RangeToExpr &node) override { walk (node); } + virtual void visit (RangeFullExpr &node) override { walk (node); } + virtual void visit (RangeFromToInclExpr &node) override { walk (node); } + virtual void visit (RangeToInclExpr &node) override { walk (node); } + virtual void visit (ReturnExpr &node) override { walk (node); } + virtual void visit (UnsafeBlockExpr &node) override { walk (node); } + virtual void visit (LoopExpr &node) override { walk (node); } + virtual void visit (WhileLoopExpr &node) override { walk (node); } + virtual void visit (WhileLetLoopExpr &node) override { walk (node); } + virtual void visit (IfExpr &node) override { walk (node); } + virtual void visit (IfExprConseqElse &node) override { walk (node); } + virtual void visit (MatchExpr &node) override { walk (node); } + virtual void visit (AwaitExpr &node) override { walk (node); } + virtual void visit (AsyncBlockExpr &node) override { walk (node); } + virtual void visit (InlineAsm &node) override { walk (node); } + virtual void visit (LlvmInlineAsm &node) override { walk (node); } + virtual void visit (TypeParam &node) override { walk (node); } + virtual void visit (ConstGenericParam &node) override { walk (node); } + virtual void visit (LifetimeWhereClauseItem &node) override { walk (node); } + virtual void visit (TypeBoundWhereClauseItem &node) override { walk (node); } + virtual void visit (Module &node) override { walk (node); } + virtual void visit (ExternCrate &node) override { walk (node); } + virtual void visit (UseTreeGlob &node) override { walk (node); } + virtual void visit (UseTreeList &node) override { walk (node); } + virtual void visit (UseTreeRebind &node) override { walk (node); } + virtual void visit (UseDeclaration &node) override { walk (node); } + virtual void visit (Function &node) override { walk (node); } + virtual void visit (TypeAlias &node) override { walk (node); } + virtual void visit (StructStruct &node) override { walk (node); } + virtual void visit (TupleStruct &node) override { walk (node); } + virtual void visit (EnumItem &node) override { walk (node); } + virtual void visit (EnumItemTuple &node) override { walk (node); } + virtual void visit (EnumItemStruct &node) override { walk (node); } + virtual void visit (EnumItemDiscriminant &node) override { walk (node); } + virtual void visit (Enum &node) override { walk (node); } + virtual void visit (Union &node) override { walk (node); } + virtual void visit (ConstantItem &node) override { walk (node); } + virtual void visit (StaticItem &node) override { walk (node); } + virtual void visit (TraitItemFunc &node) override { walk (node); } + virtual void visit (TraitItemConst &node) override { walk (node); } + virtual void visit (TraitItemType &node) override { walk (node); } + virtual void visit (Trait &node) override { walk (node); } + virtual void visit (ImplBlock &node) override { walk (node); } + virtual void visit (ExternalStaticItem &node) override { walk (node); } + virtual void visit (ExternalFunctionItem &node) override { walk (node); } + virtual void visit (ExternalTypeItem &node) override { walk (node); } + virtual void visit (ExternBlock &node) override { walk (node); } + virtual void visit (LiteralPattern &node) override { walk (node); } + virtual void visit (IdentifierPattern &node) override { walk (node); } + virtual void visit (WildcardPattern &node) override { walk (node); } + virtual void visit (RangePatternBoundLiteral &node) override { walk (node); } + virtual void visit (RangePatternBoundPath &node) override { walk (node); } + virtual void visit (RangePatternBoundQualPath &node) override { walk (node); } + virtual void visit (RangePattern &node) override { walk (node); } + virtual void visit (ReferencePattern &node) override { walk (node); } + virtual void visit (StructPatternFieldTuplePat &node) override + { + walk (node); + } + virtual void visit (StructPatternFieldIdentPat &node) override + { + walk (node); + } + virtual void visit (StructPatternFieldIdent &node) override { walk (node); } + virtual void visit (StructPattern &node) override { walk (node); } + virtual void visit (TupleStructItemsNoRange &node) override { walk (node); } + virtual void visit (TupleStructItemsRange &node) override { walk (node); } + virtual void visit (TupleStructPattern &node) override { walk (node); } + virtual void visit (TuplePatternItemsMultiple &node) override { walk (node); } + virtual void visit (TuplePatternItemsRanged &node) override { walk (node); } + virtual void visit (TuplePattern &node) override { walk (node); } + virtual void visit (SlicePattern &node) override { walk (node); } + virtual void visit (AltPattern &node) override { walk (node); } + virtual void visit (EmptyStmt &node) override { walk (node); } + virtual void visit (LetStmt &node) override { walk (node); } + virtual void visit (ExprStmt &node) override { walk (node); } + virtual void visit (TraitBound &node) override { walk (node); } + virtual void visit (ImplTraitType &node) override { walk (node); } + virtual void visit (TraitObjectType &node) override { walk (node); } + virtual void visit (ParenthesisedType &node) override { walk (node); } + virtual void visit (TupleType &node) override { walk (node); } + virtual void visit (NeverType &node) override { walk (node); } + virtual void visit (RawPointerType &node) override { walk (node); } + virtual void visit (ReferenceType &node) override { walk (node); } + virtual void visit (ArrayType &node) override { walk (node); } + virtual void visit (SliceType &node) override { walk (node); } + virtual void visit (InferredType &node) override { walk (node); } + virtual void visit (BareFunctionType &node) override { walk (node); } + +protected: + virtual void walk (WhereClauseItem &) final; + + virtual void walk (Lifetime &) final; + virtual void walk (LifetimeParam &) final; + virtual void walk (PathInExpression &) final; + virtual void walk (TypePathSegment &) final; + virtual void walk (TypePathSegmentGeneric &) final; + virtual void walk (TypePathSegmentFunction &) final; + virtual void walk (TypePath &) final; + virtual void walk (QualifiedPathInExpression &) final; + virtual void walk (QualifiedPathInType &) final; + + virtual void walk (LiteralExpr &) final; + virtual void walk (BorrowExpr &) final; + virtual void walk (DereferenceExpr &) final; + virtual void walk (ErrorPropagationExpr &) final; + virtual void walk (NegationExpr &) final; + virtual void walk (ArithmeticOrLogicalExpr &) final; + virtual void walk (ComparisonExpr &) final; + virtual void walk (LazyBooleanExpr &) final; + virtual void walk (TypeCastExpr &) final; + virtual void walk (AssignmentExpr &) final; + virtual void walk (CompoundAssignmentExpr &) final; + virtual void walk (GroupedExpr &) final; + + virtual void walk (ArrayElemsValues &) final; + virtual void walk (ArrayElemsCopied &) final; + virtual void walk (ArrayExpr &) final; + virtual void walk (ArrayIndexExpr &) final; + virtual void walk (TupleExpr &) final; + virtual void walk (TupleIndexExpr &) final; + virtual void walk (StructExprStruct &) final; + virtual void walk (StructExprFieldIdentifier &) final; + virtual void walk (StructExprFieldIdentifierValue &) final; + virtual void walk (StructExprFieldIndexValue &) final; + virtual void walk (StructExprStructFields &) final; + virtual void walk (StructExprStructBase &) final; + virtual void walk (CallExpr &) final; + virtual void walk (MethodCallExpr &) final; + virtual void walk (FieldAccessExpr &) final; + virtual void walk (ClosureExpr &) final; + virtual void walk (BlockExpr &) final; + virtual void walk (AnonConst &) final; + virtual void walk (ConstBlock &) final; + virtual void walk (ContinueExpr &) final; + virtual void walk (BreakExpr &) final; + virtual void walk (RangeFromToExpr &) final; + virtual void walk (RangeFromExpr &) final; + virtual void walk (RangeToExpr &) final; + virtual void walk (RangeFullExpr &) final; + virtual void walk (RangeFromToInclExpr &) final; + virtual void walk (RangeToInclExpr &) final; + virtual void walk (ReturnExpr &) final; + virtual void walk (UnsafeBlockExpr &) final; + virtual void walk (LoopExpr &) final; + virtual void walk (WhileLoopExpr &) final; + virtual void walk (WhileLetLoopExpr &) final; + virtual void walk (IfExpr &) final; + virtual void walk (IfExprConseqElse &) final; + virtual void walk (MatchExpr &) final; + virtual void walk (AwaitExpr &) final; + virtual void walk (AsyncBlockExpr &) final; + virtual void walk (InlineAsm &) final; + virtual void walk (LlvmInlineAsm &) final; + virtual void walk (TypeParam &) final; + virtual void walk (ConstGenericParam &) final; + virtual void walk (LifetimeWhereClauseItem &) final; + virtual void walk (TypeBoundWhereClauseItem &) final; + virtual void walk (Module &) final; + virtual void walk (ExternCrate &) final; + virtual void walk (UseTreeGlob &) final; + virtual void walk (UseTreeList &) final; + virtual void walk (UseTreeRebind &) final; + virtual void walk (UseDeclaration &) final; + virtual void walk (Function &) final; + virtual void walk (TypeAlias &) final; + virtual void walk (StructStruct &) final; + virtual void walk (TupleStruct &) final; + virtual void walk (EnumItem &) final; + virtual void walk (EnumItemTuple &) final; + virtual void walk (EnumItemStruct &) final; + virtual void walk (EnumItemDiscriminant &) final; + virtual void walk (Enum &) final; + virtual void walk (Union &) final; + virtual void walk (ConstantItem &) final; + virtual void walk (StaticItem &) final; + virtual void walk (TraitItemFunc &) final; + virtual void walk (TraitItemConst &) final; + virtual void walk (TraitItemType &) final; + virtual void walk (Trait &) final; + virtual void walk (ImplBlock &) final; + virtual void walk (ExternalStaticItem &) final; + virtual void walk (ExternalFunctionItem &) final; + virtual void walk (ExternalTypeItem &) final; + virtual void walk (ExternBlock &) final; + virtual void walk (LiteralPattern &) final; + virtual void walk (IdentifierPattern &) final; + virtual void walk (WildcardPattern &) final; + virtual void walk (RangePatternBoundLiteral &) final; + virtual void walk (RangePatternBoundPath &) final; + virtual void walk (RangePatternBoundQualPath &) final; + virtual void walk (RangePattern &) final; + virtual void walk (ReferencePattern &) final; + virtual void walk (StructPatternFieldTuplePat &) final; + virtual void walk (StructPatternFieldIdentPat &) final; + virtual void walk (StructPatternFieldIdent &) final; + virtual void walk (StructPattern &) final; + virtual void walk (TupleStructItemsNoRange &) final; + virtual void walk (TupleStructItemsRange &) final; + virtual void walk (TupleStructPattern &) final; + virtual void walk (TuplePatternItemsMultiple &) final; + virtual void walk (TuplePatternItemsRanged &) final; + virtual void walk (TuplePattern &) final; + virtual void walk (SlicePattern &) final; + virtual void walk (AltPattern &) final; + virtual void walk (EmptyStmt &) final; + virtual void walk (LetStmt &) final; + virtual void walk (ExprStmt &) final; + virtual void walk (TraitBound &) final; + virtual void walk (ImplTraitType &) final; + virtual void walk (TraitObjectType &) final; + virtual void walk (ParenthesisedType &) final; + virtual void walk (TupleType &) final; + virtual void walk (NeverType &) final; + virtual void walk (RawPointerType &) final; + virtual void walk (ReferenceType &) final; + virtual void walk (ArrayType &) final; + virtual void walk (SliceType &) final; + virtual void walk (InferredType &) final; + virtual void walk (BareFunctionType &) final; +}; + class HIRFullVisitorBase : public HIRFullVisitor { public: @@ -201,6 +508,8 @@ class HIRFullVisitorBase : public HIRFullVisitor virtual void visit (FieldAccessExpr &) override {} virtual void visit (ClosureExpr &) override {} virtual void visit (BlockExpr &) override {} + virtual void visit (AnonConst &) override {} + virtual void visit (ConstBlock &) override {} virtual void visit (ContinueExpr &) override {} virtual void visit (BreakExpr &) override {} virtual void visit (RangeFromToExpr &) override {} @@ -427,6 +736,8 @@ class HIRExpressionVisitor virtual void visit (MethodCallExpr &expr) = 0; virtual void visit (FieldAccessExpr &expr) = 0; virtual void visit (BlockExpr &expr) = 0; + virtual void visit (AnonConst &expr) = 0; + virtual void visit (ConstBlock &expr) = 0; virtual void visit (ContinueExpr &expr) = 0; virtual void visit (BreakExpr &expr) = 0; virtual void visit (RangeFromToExpr &expr) = 0; diff --git a/gcc/rust/hir/tree/rust-hir.cc b/gcc/rust/hir/tree/rust-hir.cc index 093d8d50146e..dc94fb5b1eb7 100644 --- a/gcc/rust/hir/tree/rust-hir.cc +++ b/gcc/rust/hir/tree/rust-hir.cc @@ -577,7 +577,8 @@ UseTreeGlob::as_string () const return "*"; case GLOBAL: return "::*"; - case PATH_PREFIXED: { + case PATH_PREFIXED: + { std::string path_str = path.as_string (); return path_str + "::*"; } @@ -600,7 +601,8 @@ UseTreeList::as_string () const case GLOBAL: path_str = "::{"; break; - case PATH_PREFIXED: { + case PATH_PREFIXED: + { path_str = path.as_string () + "::{"; break; } @@ -1047,6 +1049,33 @@ BlockExpr::as_string () const return str; } +std::string +AnonConst::as_string () const +{ + std::string istr = indent_spaces (enter); + std::string str = istr + "AnonConst:\n" + istr; + + str += get_inner_expr ().as_string (); + + str += "\n" + indent_spaces (out); + + return str; +} + +std::string +ConstBlock::as_string () const +{ + std::string istr = indent_spaces (enter); + + std::string str = istr + "ConstBlock:\n" + istr; + + str += get_const_expr ().as_string (); + + str += "\n" + indent_spaces (out); + + return str; +} + std::string TypeAlias::as_string () const { @@ -2579,9 +2608,9 @@ IdentifierPattern::as_string () const str += variable_ident.as_string (); - if (has_pattern_to_bind ()) + if (has_subpattern ()) { - str += " @ " + to_bind->as_string (); + str += " @ " + subpattern->as_string (); } return str; @@ -4054,6 +4083,18 @@ BlockExpr::accept_vis (HIRFullVisitor &vis) vis.visit (*this); } +void +AnonConst::accept_vis (HIRFullVisitor &vis) +{ + vis.visit (*this); +} + +void +ConstBlock::accept_vis (HIRFullVisitor &vis) +{ + vis.visit (*this); +} + void ContinueExpr::accept_vis (HIRFullVisitor &vis) { @@ -5026,6 +5067,18 @@ BlockExpr::accept_vis (HIRExpressionVisitor &vis) vis.visit (*this); } +void +AnonConst::accept_vis (HIRExpressionVisitor &vis) +{ + vis.visit (*this); +} + +void +ConstBlock::accept_vis (HIRExpressionVisitor &vis) +{ + vis.visit (*this); +} + void Function::accept_vis (HIRStmtVisitor &vis) { diff --git a/gcc/rust/lang.opt b/gcc/rust/lang.opt index 9cdbce2bc0af..4c48816affa5 100644 --- a/gcc/rust/lang.opt +++ b/gcc/rust/lang.opt @@ -205,7 +205,7 @@ EnumValue Enum(frust_compile_until) String(end) Value(13) frust-name-resolution-2.0 -Rust Var(flag_name_resolution_2_0) +Rust Var(flag_name_resolution_2_0) Init(1) Use the temporary and experimental name resolution pipeline instead of the stable one frust-borrowcheck diff --git a/gcc/rust/lex/rust-lex.cc b/gcc/rust/lex/rust-lex.cc index b143e70c9464..76ff15c21bc1 100644 --- a/gcc/rust/lex/rust-lex.cc +++ b/gcc/rust/lex/rust-lex.cc @@ -1317,7 +1317,8 @@ Lexer::parse_escape (char opening_char) switch (current_char.value) { - case 'x': { + case 'x': + { auto hex_escape_pair = parse_partial_hex_escape (); long hexLong = hex_escape_pair.first; additional_length_offset += hex_escape_pair.second; @@ -1400,7 +1401,8 @@ Lexer::parse_utf8_escape () switch (current_char.value) { - case 'x': { + case 'x': + { auto hex_escape_pair = parse_partial_hex_escape (); long hexLong = hex_escape_pair.first; additional_length_offset += hex_escape_pair.second; @@ -1438,7 +1440,8 @@ Lexer::parse_utf8_escape () case '"': output_char = '"'; break; - case 'u': { + case 'u': + { auto unicode_escape_pair = parse_partial_unicode_escape (); output_char = unicode_escape_pair.first; additional_length_offset += unicode_escape_pair.second; @@ -1894,6 +1897,11 @@ Lexer::parse_raw_byte_string (location_t loc) break; } } + else if (current_char.is_eof ()) + { + rust_error_at (string_begin_locus, "unended raw byte string literal"); + return Token::make (END_OF_FILE, get_current_location ()); + } else if (current_char.value > 127) { rust_error_at (get_current_location (), @@ -1901,11 +1909,6 @@ Lexer::parse_raw_byte_string (location_t loc) current_char.as_string ().c_str ()); current_char = 0; } - else if (current_char.is_eof ()) - { - rust_error_at (string_begin_locus, "unended raw byte string literal"); - return Token::make (END_OF_FILE, get_current_location ()); - } length++; current_column++; diff --git a/gcc/rust/lex/rust-lex.h b/gcc/rust/lex/rust-lex.h index 10293e0a8122..383ffac22558 100644 --- a/gcc/rust/lex/rust-lex.h +++ b/gcc/rust/lex/rust-lex.h @@ -263,8 +263,7 @@ class Lexer #if CHECKING_P namespace selftest { -void -rust_input_source_test (); +void rust_input_source_test (); } // namespace selftest diff --git a/gcc/rust/lex/rust-token.cc b/gcc/rust/lex/rust-token.cc index 8493889db9f1..c396e100dd8d 100644 --- a/gcc/rust/lex/rust-token.cc +++ b/gcc/rust/lex/rust-token.cc @@ -20,6 +20,7 @@ #include "rust-token.h" #include "rust-diagnostics.h" #include "rust-unicode.h" +#include "rust-ast.h" namespace Rust { // Hackily defined way to get token description for enum value using x-macros @@ -88,7 +89,8 @@ token_id_keyword_string (TokenId id) switch (id) { #define RS_TOKEN_KEYWORD_2015(id, str_ptr) \ - case id: { \ + case id: \ + { \ static const std::string str (str_ptr); \ return str; \ } \ @@ -234,6 +236,13 @@ escape_special_chars (const std::string &source, Context ctx) } // namespace +TokenPtr +Token::make_identifier (const Identifier &ident) +{ + std::string str = ident; + return make_identifier (ident.get_locus (), std::move (str)); +} + std::string Token::as_string () const { diff --git a/gcc/rust/lex/rust-token.h b/gcc/rust/lex/rust-token.h index c683ecd446ee..2021aec4e4ca 100644 --- a/gcc/rust/lex/rust-token.h +++ b/gcc/rust/lex/rust-token.h @@ -24,6 +24,10 @@ #include "rust-unicode.h" namespace Rust { + +// used by Rust::Token::make_identifier +class Identifier; + // "Primitive core types" in Rust - the different int and float types, as well // as some others enum PrimitiveCoreType @@ -221,25 +225,20 @@ typedef std::shared_ptr TokenPtr; typedef std::shared_ptr const_TokenPtr; // Hackily defined way to get token description for enum value using x-macros -const char * -get_token_description (TokenId id); +const char *get_token_description (TokenId id); /* Hackily defined way to get token description as a string for enum value using * x-macros */ -const char * -token_id_to_str (TokenId id); +const char *token_id_to_str (TokenId id); /* checks if a token is a keyword */ -bool -token_id_is_keyword (TokenId id); +bool token_id_is_keyword (TokenId id); /* gets the string associated with a keyword */ -const std::string & -token_id_keyword_string (TokenId id); +const std::string &token_id_keyword_string (TokenId id); // Get type hint description as a string. -const char * -get_type_hint_string (PrimitiveCoreType type); +const char *get_type_hint_string (PrimitiveCoreType type); /* Normalize string if a token is a identifier */ -std::string -nfc_normalize_token_string (location_t loc, TokenId id, const std::string &str); +std::string nfc_normalize_token_string (location_t loc, TokenId id, + const std::string &str); // Represents a single token. Create using factory static methods. class Token @@ -329,6 +328,8 @@ class Token return TokenPtr (new Token (IDENTIFIER, locus, std::move (str))); } + static TokenPtr make_identifier (const Identifier &ident); + // Makes and returns a new TokenPtr of type INT_LITERAL. static TokenPtr make_int (location_t locus, std::string &&str, PrimitiveCoreType type_hint = CORETYPE_UNKNOWN) diff --git a/gcc/rust/metadata/rust-export-metadata.cc b/gcc/rust/metadata/rust-export-metadata.cc index 771bec6e6378..1829a85d2e47 100644 --- a/gcc/rust/metadata/rust-export-metadata.cc +++ b/gcc/rust/metadata/rust-export-metadata.cc @@ -263,8 +263,7 @@ PublicInterface::write_to_path (const std::string &path) const FILE *nfd = fopen (path.c_str (), "wb"); if (nfd == NULL) { - rust_error_at (UNDEF_LOCATION, - "failed to open file %qs for writing: %s", + rust_error_at (UNDEF_LOCATION, "failed to open file %qs for writing: %s", path.c_str (), xstrerror (errno)); return; } diff --git a/gcc/rust/metadata/rust-import-archive.cc b/gcc/rust/metadata/rust-import-archive.cc index cf24607f099c..f64de4e061ce 100644 --- a/gcc/rust/metadata/rust-import-archive.cc +++ b/gcc/rust/metadata/rust-import-archive.cc @@ -683,7 +683,7 @@ class Archive_iterator const Header &operator* () const { return this->header_; } - const Header *operator-> () const { return &this->header_; } + const Header *operator->() const { return &this->header_; } Archive_iterator &operator++ () { diff --git a/gcc/rust/metadata/rust-imports.h b/gcc/rust/metadata/rust-imports.h index a497c6745174..65a2af11c0da 100644 --- a/gcc/rust/metadata/rust-imports.h +++ b/gcc/rust/metadata/rust-imports.h @@ -11,8 +11,7 @@ namespace Rust { -extern void -add_search_path (const std::string &path); +extern void add_search_path (const std::string &path); class Import { diff --git a/gcc/rust/parse/rust-cfg-parser.h b/gcc/rust/parse/rust-cfg-parser.h index 0d64016f86dc..61db240a3672 100644 --- a/gcc/rust/parse/rust-cfg-parser.h +++ b/gcc/rust/parse/rust-cfg-parser.h @@ -36,15 +36,14 @@ namespace Rust { * * @return false if the given input was invalid, true otherwise */ -bool -parse_cfg_option (std::string &input, std::string &key, std::string &value); +bool parse_cfg_option (std::string &input, std::string &key, + std::string &value); } // namespace Rust #if CHECKING_P namespace selftest { -extern void -rust_cfg_parser_test (void); +extern void rust_cfg_parser_test (void); } // namespace selftest #endif // CHECKING_P diff --git a/gcc/rust/parse/rust-parse-impl.h b/gcc/rust/parse/rust-parse-impl.h index 9dda231ba8fa..6d996ca60263 100644 --- a/gcc/rust/parse/rust-parse-impl.h +++ b/gcc/rust/parse/rust-parse-impl.h @@ -22,10 +22,13 @@ /* DO NOT INCLUDE ANYWHERE - this is automatically included with rust-parse.h * This is also the reason why there are no include guards. */ +#include "expected.h" +#include "rust-ast.h" #include "rust-common.h" #include "rust-expr.h" #include "rust-item.h" #include "rust-common.h" +#include "rust-parse.h" #include "rust-token.h" #define INCLUDE_ALGORITHM #include "rust-diagnostics.h" @@ -227,19 +230,22 @@ Parser::skip_generics_right_angle () // this is good - skip token lexer.skip_token (); return true; - case RIGHT_SHIFT: { + case RIGHT_SHIFT: + { // new implementation that should be better lexer.split_current_token (RIGHT_ANGLE, RIGHT_ANGLE); lexer.skip_token (); return true; } - case GREATER_OR_EQUAL: { + case GREATER_OR_EQUAL: + { // new implementation that should be better lexer.split_current_token (RIGHT_ANGLE, EQUAL); lexer.skip_token (); return true; } - case RIGHT_SHIFT_EQ: { + case RIGHT_SHIFT_EQ: + { // new implementation that should be better lexer.split_current_token (RIGHT_ANGLE, GREATER_OR_EQUAL); lexer.skip_token (); @@ -651,10 +657,7 @@ Parser::parse_simple_path () // Parse all other simple path segments while (lexer.peek_token ()->get_id () == SCOPE_RESOLUTION) { - // Skip scope resolution operator - lexer.skip_token (); - - AST::SimplePathSegment new_segment = parse_simple_path_segment (); + AST::SimplePathSegment new_segment = parse_simple_path_segment (1); // Return path as currently constructed if segment in error state. if (new_segment.is_error ()) @@ -682,35 +685,36 @@ Parser::parse_simple_path () } /* Parses a single SimplePathSegment (does not handle the scope resolution - * operators) */ + * operators) + * Starts parsing at an offset of base_peek */ template AST::SimplePathSegment -Parser::parse_simple_path_segment () +Parser::parse_simple_path_segment (int base_peek) { using namespace Values; - const_TokenPtr t = lexer.peek_token (); + const_TokenPtr t = lexer.peek_token (base_peek); switch (t->get_id ()) { case IDENTIFIER: - lexer.skip_token (); + lexer.skip_token (base_peek); return AST::SimplePathSegment (t->get_str (), t->get_locus ()); case SUPER: - lexer.skip_token (); + lexer.skip_token (base_peek); return AST::SimplePathSegment (Keywords::SUPER, t->get_locus ()); case SELF: - lexer.skip_token (); + lexer.skip_token (base_peek); return AST::SimplePathSegment (Keywords::SELF, t->get_locus ()); case CRATE: - lexer.skip_token (); + lexer.skip_token (base_peek); return AST::SimplePathSegment (Keywords::CRATE, t->get_locus ()); case DOLLAR_SIGN: - if (lexer.peek_token (1)->get_id () == CRATE) + if (lexer.peek_token (base_peek + 1)->get_id () == CRATE) { - lexer.skip_token (1); + lexer.skip_token (base_peek + 1); return AST::SimplePathSegment ("$crate", t->get_locus ()); } @@ -790,7 +794,8 @@ Parser::parse_attr_input () { case LEFT_PAREN: case LEFT_SQUARE: - case LEFT_CURLY: { + case LEFT_CURLY: + { // must be a delimited token tree, so parse that std::unique_ptr input_tree ( new AST::DelimTokenTree (parse_delim_token_tree ())); @@ -799,7 +804,8 @@ Parser::parse_attr_input () return input_tree; } - case EQUAL: { + case EQUAL: + { // = LiteralExpr lexer.skip_token (); @@ -877,7 +883,10 @@ Parser::parse_attr_input () return attr_input_lit; } break; + case RIGHT_PAREN: case RIGHT_SQUARE: + case RIGHT_CURLY: + case END_OF_FILE: // means AttrInput is missing, which is allowed return nullptr; default: @@ -2117,7 +2126,8 @@ Parser::parse_macro_match () { case LEFT_PAREN: case LEFT_SQUARE: - case LEFT_CURLY: { + case LEFT_CURLY: + { // must be macro matcher as delimited AST::MacroMatcher matcher = parse_macro_matcher (); if (matcher.is_error ()) @@ -2131,7 +2141,8 @@ Parser::parse_macro_match () return std::unique_ptr ( new AST::MacroMatcher (std::move (matcher))); } - case DOLLAR_SIGN: { + case DOLLAR_SIGN: + { // have to do more lookahead to determine if fragment or repetition const_TokenPtr t2 = lexer.peek_token (1); switch (t2->get_id ()) @@ -2402,7 +2413,8 @@ Parser::parse_visibility () skip_token (RIGHT_PAREN); return AST::Visibility::create_super (path_loc, vis_loc); - case IN: { + case IN: + { lexer.skip_token (); // parse the "in" path as well @@ -2466,7 +2478,8 @@ Parser::parse_module (AST::Visibility vis, new AST::Module (std::move (name), std::move (vis), std::move (outer_attrs), locus, safety, lexer.get_filename (), inline_module_stack)); - case LEFT_CURLY: { + case LEFT_CURLY: + { lexer.skip_token (); // parse inner attributes @@ -2730,7 +2743,8 @@ Parser::parse_use_tree () return std::unique_ptr ( new AST::UseTreeGlob (AST::UseTreeGlob::NO_PATH, AST::SimplePath::create_empty (), locus)); - case LEFT_CURLY: { + case LEFT_CURLY: + { // nested tree UseTree type lexer.skip_token (); @@ -2794,58 +2808,12 @@ Parser::parse_use_tree () } else { - /* Due to aforementioned implementation issues, the trailing :: token is - * consumed by the path, so it can not be used as a disambiguator. - * NOPE, not true anymore - TODO what are the consequences of this? */ - const_TokenPtr t = lexer.peek_token (); + switch (t->get_id ()) { - case ASTERISK: - // glob UseTree type - lexer.skip_token (); - - return std::unique_ptr ( - new AST::UseTreeGlob (AST::UseTreeGlob::PATH_PREFIXED, - std::move (path), locus)); - case LEFT_CURLY: { - // nested tree UseTree type - lexer.skip_token (); - - std::vector> use_trees; - - // TODO: think of better control structure - const_TokenPtr t = lexer.peek_token (); - while (t->get_id () != RIGHT_CURLY) - { - std::unique_ptr use_tree = parse_use_tree (); - if (use_tree == nullptr) - { - break; - } - - use_trees.push_back (std::move (use_tree)); - - if (lexer.peek_token ()->get_id () != COMMA) - break; - - lexer.skip_token (); - t = lexer.peek_token (); - } - - // skip end curly delimiter - if (!skip_token (RIGHT_CURLY)) - { - // skip after somewhere? - return nullptr; - } - - return std::unique_ptr ( - new AST::UseTreeList (AST::UseTreeList::PATH_PREFIXED, - std::move (path), std::move (use_trees), - locus)); - } - case AS: { + case AS: + { // rebind UseTree type lexer.skip_token (); @@ -2884,16 +2852,72 @@ Parser::parse_use_tree () // don't skip semicolon - handled in parse_use_tree // lexer.skip_token(); - - return std::unique_ptr ( - new AST::UseTreeRebind (AST::UseTreeRebind::NONE, std::move (path), - locus)); case COMMA: case RIGHT_CURLY: // this may occur in recursive calls - assume it is ok and ignore it return std::unique_ptr ( new AST::UseTreeRebind (AST::UseTreeRebind::NONE, std::move (path), locus)); + case SCOPE_RESOLUTION: + // keep going + break; + default: + add_error (Error (t->get_locus (), + "unexpected token %qs in use tree with valid path", + t->get_token_description ())); + return nullptr; + } + + skip_token (); + t = lexer.peek_token (); + + switch (t->get_id ()) + { + case ASTERISK: + // glob UseTree type + lexer.skip_token (); + + return std::unique_ptr ( + new AST::UseTreeGlob (AST::UseTreeGlob::PATH_PREFIXED, + std::move (path), locus)); + case LEFT_CURLY: + { + // nested tree UseTree type + lexer.skip_token (); + + std::vector> use_trees; + + // TODO: think of better control structure + const_TokenPtr t = lexer.peek_token (); + while (t->get_id () != RIGHT_CURLY) + { + std::unique_ptr use_tree = parse_use_tree (); + if (use_tree == nullptr) + { + break; + } + + use_trees.push_back (std::move (use_tree)); + + if (lexer.peek_token ()->get_id () != COMMA) + break; + + lexer.skip_token (); + t = lexer.peek_token (); + } + + // skip end curly delimiter + if (!skip_token (RIGHT_CURLY)) + { + // skip after somewhere? + return nullptr; + } + + return std::unique_ptr ( + new AST::UseTreeList (AST::UseTreeList::PATH_PREFIXED, + std::move (path), std::move (use_trees), + locus)); + } default: add_error (Error (t->get_locus (), "unexpected token %qs in use tree with valid path", @@ -3100,7 +3124,8 @@ Parser::parse_generic_param (EndTokenPred is_end_token) switch (token->get_id ()) { - case LIFETIME: { + case LIFETIME: + { auto lifetime = parse_lifetime (false); if (!lifetime) { @@ -3126,7 +3151,8 @@ Parser::parse_generic_param (EndTokenPred is_end_token) std::move (outer_attrs), token->get_locus ())); break; } - case IDENTIFIER: { + case IDENTIFIER: + { auto type_ident = token->get_str (); lexer.skip_token (); @@ -3161,7 +3187,8 @@ Parser::parse_generic_param (EndTokenPred is_end_token) std::move (outer_attrs))); break; } - case CONST: { + case CONST: + { lexer.skip_token (); auto name_token = expect_token (IDENTIFIER); @@ -4356,7 +4383,8 @@ Parser::parse_struct (AST::Visibility vis, const_TokenPtr t = lexer.peek_token (); switch (t->get_id ()) { - case LEFT_CURLY: { + case LEFT_CURLY: + { // struct with body // skip curly bracket @@ -4759,7 +4787,8 @@ Parser::parse_enum_item () const_TokenPtr t = lexer.peek_token (); switch (t->get_id ()) { - case LEFT_PAREN: { + case LEFT_PAREN: + { // tuple enum item lexer.skip_token (); @@ -4780,7 +4809,8 @@ Parser::parse_enum_item () std::move (item_name), std::move (vis), std::move (tuple_fields), std::move (outer_attrs), item_name_tok->get_locus ())); } - case LEFT_CURLY: { + case LEFT_CURLY: + { // struct enum item lexer.skip_token (); @@ -4797,7 +4827,8 @@ Parser::parse_enum_item () std::move (item_name), std::move (vis), std::move (struct_fields), std::move (outer_attrs), item_name_tok->get_locus ())); } - case EQUAL: { + case EQUAL: + { // discriminant enum item lexer.skip_token (); @@ -5450,7 +5481,8 @@ Parser::parse_inherent_impl_item () case SUPER: case SELF: case CRATE: - case PUB: { + case PUB: + { // visibility, so not a macro invocation semi - must be constant, // function, or method AST::Visibility vis = parse_visibility (); @@ -5581,7 +5613,8 @@ Parser::parse_inherent_impl_function_or_method ( // param auto initial_param = parse_self_param (); - if (!initial_param.has_value () && initial_param.error () != NOT_SELF) + if (!initial_param.has_value () + && initial_param.error () != ParseSelfError::NOT_SELF) return nullptr; /* FIXME: ensure that self param doesn't accidently consume tokens for a @@ -5780,7 +5813,8 @@ Parser::parse_trait_impl_function_or_method ( // param auto initial_param = parse_self_param (); - if (!initial_param.has_value () && initial_param.error () != NOT_SELF) + if (!initial_param.has_value () + && initial_param.error () != ParseSelfError::NOT_SELF) return nullptr; // FIXME: ensure that self param doesn't accidently consume tokens for a @@ -5964,7 +5998,8 @@ Parser::parse_external_item () { case IDENTIFIER: return parse_macro_invocation_semi (outer_attrs); - case STATIC_KW: { + case STATIC_KW: + { // parse extern static item lexer.skip_token (); @@ -6261,7 +6296,8 @@ Parser::parse_generic_arg () switch (tok->get_id ()) { - case IDENTIFIER: { + case IDENTIFIER: + { // This is a bit of a weird situation: With an identifier token, we // could either have a valid type or a macro (FIXME: anything else?). So // we need one bit of lookahead to differentiate if this is really @@ -6309,9 +6345,10 @@ Parser::parse_generic_arg () case FALSE_LITERAL: expr = parse_literal_expr (); break; - // FIXME: Because of this, error reporting is garbage for const generic - // parameter's default values - default: { + // FIXME: Because of this, error reporting is garbage for const generic + // parameter's default values + default: + { auto type = parse_type (); // FIXME: Find a better way to do this? if (type) @@ -6510,7 +6547,8 @@ Parser::parse_type_path_segment () switch (t->get_id ()) { case LEFT_SHIFT: - case LEFT_ANGLE: { + case LEFT_ANGLE: + { // parse generic args AST::GenericArgs generic_args = parse_path_generic_args (); @@ -6519,7 +6557,8 @@ Parser::parse_type_path_segment () has_separating_scope_resolution, std::move (generic_args), locus)); } - case LEFT_PAREN: { + case LEFT_PAREN: + { // parse type path function AST::TypePathFunction type_path_function = parse_type_path_function (locus); @@ -7068,16 +7107,14 @@ Parser::parse_expr_stmt (AST::AttrVec outer_attrs, case SELF: case SELF_ALIAS: case DOLLAR_SIGN: - case SCOPE_RESOLUTION: { + case SCOPE_RESOLUTION: + { AST::PathInExpression path = parse_path_in_expression (); std::unique_ptr null_denotation; if (lexer.peek_token ()->get_id () == EXCLAM) { - // Bind a reference to avoid -Wredundant-move on post-P1825R0 - // compilers. Change to non-reference type and remove the moves - // below once C++20 is required to build gcc. - std::unique_ptr &&invoc + std::unique_ptr invoc = parse_macro_invocation_partial (std::move (path), std::move (outer_attrs)); @@ -7085,7 +7122,7 @@ Parser::parse_expr_stmt (AST::AttrVec outer_attrs, { invoc->add_semicolon (); // Macro invocation with semicolon. - return std::move (invoc); + return invoc; } TokenId after_macro = lexer.peek_token ()->get_id (); @@ -7093,14 +7130,14 @@ Parser::parse_expr_stmt (AST::AttrVec outer_attrs, if (restrictions.allow_close_after_expr_stmt && (after_macro == RIGHT_PAREN || after_macro == RIGHT_CURLY || after_macro == RIGHT_SQUARE)) - return std::move (invoc); + return invoc; if (invoc->get_invoc_data ().get_delim_tok_tree ().get_delim_type () == AST::CURLY && after_macro != DOT && after_macro != QUESTION_MARK) { rust_debug ("braced macro statement"); - return std::move (invoc); + return invoc; } null_denotation = std::move (invoc); @@ -7238,6 +7275,51 @@ Parser::parse_block_expr ( std::move (label), locus, end_locus)); } +/* Parse an anonymous const expression. This can be a regular const expression + * or an underscore for deferred const inference */ +template +tl::expected +Parser::parse_anon_const () +{ + auto current = lexer.peek_token (); + auto locus = current->get_locus (); + + // Special case deferred inference constants + if (maybe_skip_token (UNDERSCORE)) + return AST::AnonConst (locus); + + auto expr = parse_expr (); + + if (!expr) + return tl::make_unexpected (AnonConstError::InvalidSizeExpr); + + return AST::AnonConst (std::move (expr), locus); +} + +/* Parse a "const block", a block preceded by the `const` keyword whose + * statements can be const evaluated and used in constant contexts */ +template +std::unique_ptr +Parser::parse_const_block_expr (AST::AttrVec outer_attrs, + location_t locus) +{ + auto block = parse_block_expr (); + + if (!block) + { + add_error (Error (locus, "failed to parse inner block in const block")); + skip_after_end_block (); + + return nullptr; + } + + auto block_locus = block->get_locus (); + + return std::make_unique (AST::AnonConst (std::move (block), + block_locus), + locus, std::move (outer_attrs)); +} + /* Parses a "grouped" expression (expression in parentheses), used to control * precedence. */ template @@ -7518,6 +7600,34 @@ Parser::parse_return_expr (AST::AttrVec outer_attrs, locus)); } +// Parses a try expression. +template +std::unique_ptr +Parser::parse_try_expr (AST::AttrVec outer_attrs, + location_t pratt_parsed_loc) +{ + location_t locus = pratt_parsed_loc; + if (locus == UNKNOWN_LOCATION) + { + locus = lexer.peek_token ()->get_locus (); + skip_token (TRY); + } + + std::unique_ptr block_expr = parse_block_expr (); + + if (!block_expr) + { + Error error (lexer.peek_token ()->get_locus (), + "failed to parse try block expression"); + add_error (std::move (error)); + + return nullptr; + } + + return std::unique_ptr ( + new AST::TryExpr (std::move (block_expr), std::move (outer_attrs), locus)); +} + /* Parses a break expression (including any label to break to AND any return * expression). */ template @@ -7675,7 +7785,8 @@ Parser::parse_if_expr (AST::AttrVec outer_attrs, const_TokenPtr t = lexer.peek_token (); switch (t->get_id ()) { - case LEFT_CURLY: { + case LEFT_CURLY: + { // double selection - else // parse else block expr (required) std::unique_ptr else_body = parse_block_expr (); @@ -7696,7 +7807,8 @@ Parser::parse_if_expr (AST::AttrVec outer_attrs, std::move (else_body), std::move (outer_attrs), locus)); } - case IF: { + case IF: + { // multiple selection - else if or else if let // branch on whether next token is 'let' or not if (lexer.peek_token (1)->get_id () == LET) @@ -7857,7 +7969,8 @@ Parser::parse_if_let_expr (AST::AttrVec outer_attrs, const_TokenPtr t = lexer.peek_token (); switch (t->get_id ()) { - case LEFT_CURLY: { + case LEFT_CURLY: + { // double selection - else // parse else block expr (required) std::unique_ptr else_body = parse_block_expr (); @@ -7879,7 +7992,8 @@ Parser::parse_if_let_expr (AST::AttrVec outer_attrs, std::move (else_body), std::move (outer_attrs), locus)); } - case IF: { + case IF: + { // multiple selection - else if or else if let // branch on whether next token is 'let' or not if (lexer.peek_token (1)->get_id () == LET) @@ -8931,7 +9045,8 @@ Parser::parse_type (bool save_errors) // slice type or array type - requires further disambiguation return parse_slice_or_array_type (); case LEFT_SHIFT: - case LEFT_ANGLE: { + case LEFT_ANGLE: + { // qualified path in type AST::QualifiedPathInType path = parse_qualified_path_in_type (); if (path.is_error ()) @@ -8960,7 +9075,8 @@ Parser::parse_type (bool save_errors) case LOGICAL_AND: // reference type return parse_reference_type (); - case LIFETIME: { + case LIFETIME: + { /* probably a lifetime bound, so probably type param bounds in * TraitObjectType */ std::vector> bounds @@ -8976,7 +9092,8 @@ Parser::parse_type (bool save_errors) case SELF_ALIAS: case CRATE: case DOLLAR_SIGN: - case SCOPE_RESOLUTION: { + case SCOPE_RESOLUTION: + { // macro invocation or type path - requires further disambiguation. /* for parsing path component of each rule, perhaps parse it as a * typepath and attempt conversion to simplepath if a trailing '!' is @@ -9006,7 +9123,8 @@ Parser::parse_type (bool save_errors) t = lexer.peek_token (); switch (t->get_id ()) { - case EXCLAM: { + case EXCLAM: + { // macro invocation // convert to simple path AST::SimplePath macro_path = path.as_simple_path (); @@ -9032,7 +9150,8 @@ Parser::parse_type (bool save_errors) std::move (tok_tree)), {}, locus); } - case PLUS: { + case PLUS: + { // type param bounds std::vector> bounds; @@ -9117,14 +9236,8 @@ Parser::parse_type (bool save_errors) t = lexer.peek_token (); if (t->get_id () != PLUS) { - // convert trait bound to value object - AST::TraitBound value_bound (*initial_bound); - - // DEBUG: removed as unique ptr, so should auto-delete - // delete initial_bound; - return std::unique_ptr ( - new AST::ImplTraitTypeOneBound (std::move (value_bound), + new AST::ImplTraitTypeOneBound (std::move (initial_bound), locus)); } @@ -9152,7 +9265,8 @@ Parser::parse_type (bool save_errors) new AST::ImplTraitType (std::move (bounds), locus)); } case DYN: - case QUESTION_MARK: { + case QUESTION_MARK: + { // either TraitObjectType or TraitObjectTypeOneBound bool has_dyn = false; if (t->get_id () == DYN) @@ -9405,7 +9519,8 @@ Parser::parse_for_prefixed_type () case SELF: case SELF_ALIAS: case CRATE: - case DOLLAR_SIGN: { + case DOLLAR_SIGN: + { // path, so trait type // parse type path to finish parsing trait bound @@ -9751,13 +9866,15 @@ Parser::parse_slice_or_array_type () return std::unique_ptr ( new AST::SliceType (std::move (inner_type), locus)); - case SEMICOLON: { + case SEMICOLON: + { // array type lexer.skip_token (); // parse required array size expression - std::unique_ptr size = parse_expr (); - if (size == nullptr) + auto size = parse_anon_const (); + + if (!size) { Error error (lexer.peek_token ()->get_locus (), "failed to parse size expression in array type"); @@ -9772,7 +9889,8 @@ Parser::parse_slice_or_array_type () } return std::unique_ptr ( - new AST::ArrayType (std::move (inner_type), std::move (size), locus)); + new AST::ArrayType (std::move (inner_type), std::move (*size), + locus)); } default: // error @@ -9802,7 +9920,8 @@ Parser::parse_type_no_bounds () // slice type or array type - requires further disambiguation return parse_slice_or_array_type (); case LEFT_SHIFT: - case LEFT_ANGLE: { + case LEFT_ANGLE: + { // qualified path in type AST::QualifiedPathInType path = parse_qualified_path_in_type (); if (path.is_error ()) @@ -9843,7 +9962,8 @@ Parser::parse_type_no_bounds () case SELF_ALIAS: case CRATE: case DOLLAR_SIGN: - case SCOPE_RESOLUTION: { + case SCOPE_RESOLUTION: + { // macro invocation or type path - requires further disambiguation. /* for parsing path component of each rule, perhaps parse it as a * typepath and attempt conversion to simplepath if a trailing '!' is @@ -9871,7 +9991,8 @@ Parser::parse_type_no_bounds () t = lexer.peek_token (); switch (t->get_id ()) { - case EXCLAM: { + case EXCLAM: + { // macro invocation // convert to simple path AST::SimplePath macro_path = path.as_simple_path (); @@ -9955,14 +10076,12 @@ Parser::parse_type_no_bounds () return nullptr; } - // convert trait bound to value object - AST::TraitBound value_bound (*initial_bound); - return std::unique_ptr ( - new AST::ImplTraitTypeOneBound (std::move (value_bound), locus)); + new AST::ImplTraitTypeOneBound (std::move (initial_bound), locus)); } case DYN: - case QUESTION_MARK: { + case QUESTION_MARK: + { // either TraitObjectTypeOneBound bool has_dyn = false; if (t->get_id () == DYN) @@ -10303,7 +10422,8 @@ Parser::parse_range_pattern_bound () case SELF_ALIAS: case CRATE: case SCOPE_RESOLUTION: - case DOLLAR_SIGN: { + case DOLLAR_SIGN: + { // path in expression AST::PathInExpression path = parse_path_in_expression (); if (path.is_error ()) @@ -10319,7 +10439,8 @@ Parser::parse_range_pattern_bound () new AST::RangePatternBoundPath (std::move (path))); } case LEFT_SHIFT: - case LEFT_ANGLE: { + case LEFT_ANGLE: + { // qualified path in expression AST::QualifiedPathInExpression path = parse_qualified_path_in_expression (); @@ -10464,7 +10585,8 @@ Parser::parse_pattern_no_alt () // slice pattern return parse_slice_pattern (); case LEFT_SHIFT: - case LEFT_ANGLE: { + case LEFT_ANGLE: + { // qualified path in expression or qualified range pattern bound AST::QualifiedPathInExpression path = parse_qualified_path_in_expression (); @@ -10500,7 +10622,8 @@ Parser::parse_pattern_no_alt () case SELF_ALIAS: case CRATE: case SCOPE_RESOLUTION: - case DOLLAR_SIGN: { + case DOLLAR_SIGN: + { // path in expression or range pattern bound AST::PathInExpression path = parse_path_in_expression (); @@ -10509,7 +10632,8 @@ Parser::parse_pattern_no_alt () { case DOT_DOT_EQ: case DOT_DOT: - case ELLIPSIS: { + case ELLIPSIS: + { // qualified range pattern bound, so parse rest of range pattern AST::RangeKind kind = AST::tokenid_to_rangekind (next->get_id ()); lexer.skip_token (); @@ -10527,7 +10651,8 @@ Parser::parse_pattern_no_alt () case EXCLAM: return parse_macro_invocation_partial (std::move (path), AST::AttrVec ()); - case LEFT_PAREN: { + case LEFT_PAREN: + { // tuple struct lexer.skip_token (); @@ -10552,7 +10677,8 @@ Parser::parse_pattern_no_alt () new AST::TupleStructPattern (std::move (path), std::move (items))); } - case LEFT_CURLY: { + case LEFT_CURLY: + { // struct lexer.skip_token (); @@ -10722,7 +10848,8 @@ Parser::parse_grouped_or_tuple_pattern () return std::unique_ptr ( new AST::GroupedPattern (std::move (initial_pattern), paren_locus)); - case COMMA: { + case COMMA: + { // tuple pattern lexer.skip_token (); @@ -10979,7 +11106,8 @@ Parser::parse_ident_leading_pattern () { case EXCLAM: return parse_macro_invocation_partial (std::move (path), AST::AttrVec ()); - case LEFT_PAREN: { + case LEFT_PAREN: + { // tuple struct lexer.skip_token (); @@ -11012,7 +11140,8 @@ Parser::parse_ident_leading_pattern () return std::unique_ptr ( new AST::TupleStructPattern (std::move (path), std::move (items))); } - case LEFT_CURLY: { + case LEFT_CURLY: + { // struct lexer.skip_token (); @@ -11033,7 +11162,8 @@ Parser::parse_ident_leading_pattern () } case DOT_DOT_EQ: case DOT_DOT: - case ELLIPSIS: { + case ELLIPSIS: + { // range AST::RangeKind kind = AST::tokenid_to_rangekind (lexer.peek_token ()->get_id ()); @@ -11050,7 +11180,8 @@ Parser::parse_ident_leading_pattern () std::move (upper_bound), kind, t->get_locus ())); } - case PATTERN_BIND: { + case PATTERN_BIND: + { // only allow on single-segment paths if (path.is_single_segment ()) { @@ -11188,7 +11319,8 @@ Parser::parse_tuple_struct_items () case RIGHT_PAREN: return std::unique_ptr ( new AST::TupleStructItemsNoRange (std::move (lower_patterns))); - case DOT_DOT: { + case DOT_DOT: + { // has an upper range that must be parsed separately lexer.skip_token (); @@ -11308,7 +11440,8 @@ Parser::parse_struct_pattern_field_partial ( const_TokenPtr t = lexer.peek_token (); switch (t->get_id ()) { - case INT_LITERAL: { + case INT_LITERAL: + { // tuple index std::string index_str = t->get_str (); int index = atoi (index_str.c_str ()); @@ -11342,7 +11475,8 @@ Parser::parse_struct_pattern_field_partial ( // branch on next token switch (lexer.peek_token (1)->get_id ()) { - case COLON: { + case COLON: + { // identifier-pattern Identifier ident{t}; lexer.skip_token (); @@ -11367,7 +11501,8 @@ Parser::parse_struct_pattern_field_partial ( t->get_locus ())); } case COMMA: - case RIGHT_CURLY: { + case RIGHT_CURLY: + { // identifier only Identifier ident = {t}; lexer.skip_token (); @@ -11386,7 +11521,8 @@ Parser::parse_struct_pattern_field_partial ( return nullptr; } case REF: - case MUT: { + case MUT: + { // only identifier bool has_ref = false; if (t->get_id () == REF) @@ -11458,7 +11594,8 @@ Parser::parse_stmt_or_expr () t = lexer.peek_token (); switch (t->get_id ()) { - case LET: { + case LET: + { // let statement std::unique_ptr stmt ( parse_let_stmt (std::move (outer_attrs))); @@ -11476,42 +11613,48 @@ Parser::parse_stmt_or_expr () case STATIC_KW: case AUTO: case TRAIT: - case IMPL: { + case IMPL: + { std::unique_ptr item ( parse_vis_item (std::move (outer_attrs))); return ExprOrStmt (std::move (item)); } - /* TODO: implement union keyword but not really because of - * context-dependence crappy hack way to parse a union written below to - * separate it from the good code. */ - // case UNION: - case UNSAFE: { // maybe - unsafe traits are a thing + /* TODO: implement union keyword but not really because of + * context-dependence crappy hack way to parse a union written below to + * separate it from the good code. */ + // case UNION: + case UNSAFE: + { // maybe - unsafe traits are a thing /* if any of these (should be all possible VisItem prefixes), parse a * VisItem - can't parse item because would require reparsing outer * attributes */ const_TokenPtr t2 = lexer.peek_token (1); switch (t2->get_id ()) { - case LEFT_CURLY: { + case LEFT_CURLY: + { // unsafe block: parse as expression expr = parse_expr (std::move (outer_attrs), restrictions); break; } case AUTO: - case TRAIT: { + case TRAIT: + { // unsafe trait std::unique_ptr item ( parse_vis_item (std::move (outer_attrs))); return ExprOrStmt (std::move (item)); } case EXTERN_KW: - case FN_KW: { + case FN_KW: + { // unsafe function std::unique_ptr item ( parse_vis_item (std::move (outer_attrs))); return ExprOrStmt (std::move (item)); } - case IMPL: { + case IMPL: + { // unsafe trait impl std::unique_ptr item ( parse_vis_item (std::move (outer_attrs))); @@ -11556,7 +11699,8 @@ Parser::parse_stmt_or_expr () case SELF_ALIAS: case CRATE: case SCOPE_RESOLUTION: - case DOLLAR_SIGN: { + case DOLLAR_SIGN: + { AST::PathInExpression path = parse_path_in_expression (); std::unique_ptr null_denotation; @@ -11680,7 +11824,8 @@ Parser::parse_struct_expr_field () std::move (outer_attrs), t->get_locus ())); } - case INT_LITERAL: { + case INT_LITERAL: + { // parse tuple index field int index = atoi (t->get_str ().c_str ()); lexer.skip_token (); @@ -11920,7 +12065,7 @@ Parser::skip_after_end_attribute () { const_TokenPtr t = lexer.peek_token (); - while (t->get_id () != RIGHT_SQUARE) + while (t->get_id () != RIGHT_SQUARE && t->get_id () != END_OF_FILE) { lexer.skip_token (); t = lexer.peek_token (); @@ -12050,7 +12195,8 @@ Parser::null_denotation (const_TokenPtr tok, case SELF_ALIAS: case DOLLAR_SIGN: case CRATE: - case SUPER: { + case SUPER: + { // DEBUG rust_debug ("beginning null denotation identifier handling"); @@ -12061,7 +12207,8 @@ Parser::null_denotation (const_TokenPtr tok, return null_denotation_path (std::move (path), std::move (outer_attrs), restrictions); } - case SCOPE_RESOLUTION: { + case SCOPE_RESOLUTION: + { // TODO: fix: this is for global paths, i.e. std::string::whatever Error error (tok->get_locus (), "found null denotation scope resolution operator, and " @@ -12103,7 +12250,8 @@ Parser::null_denotation_path ( // macro return parse_macro_invocation_partial (std::move (path), std::move (outer_attrs)); - case LEFT_CURLY: { + case LEFT_CURLY: + { bool not_a_block = lexer.peek_token (1)->get_id () == IDENTIFIER && (lexer.peek_token (2)->get_id () == COMMA || (lexer.peek_token (2)->get_id () == COLON @@ -12179,7 +12327,8 @@ Parser::null_denotation_not_path ( { // FIXME: Handle in null_denotation_path? case LEFT_SHIFT: - case LEFT_ANGLE: { + case LEFT_ANGLE: + { // qualified path // HACK: add outer attrs to path AST::QualifiedPathInExpression path @@ -12237,23 +12386,24 @@ Parser::null_denotation_not_path ( return parse_grouped_or_tuple_expr (std::move (outer_attrs), tok->get_locus ()); - /*case PLUS: { // unary plus operator - // invoke parse_expr recursively with appropriate priority, etc. for - below AST::Expr* expr = parse_expr(LBP_UNARY_PLUS); + /*case PLUS: { // unary plus operator + // invoke parse_expr recursively with appropriate priority, etc. for + below AST::Expr* expr = parse_expr(LBP_UNARY_PLUS); - if (expr == nullptr) - return nullptr; - // can only apply to integer and float expressions - if (expr->get_type() != integer_type_node || expr->get_type() != - float_type_node) { rust_error_at(tok->get_locus(), "operand of unary - plus must be int or float but it is %s", print_type(expr->get_type())); - return nullptr; - } + if (expr == nullptr) + return nullptr; + // can only apply to integer and float expressions + if (expr->get_type() != integer_type_node || expr->get_type() != + float_type_node) { rust_error_at(tok->get_locus(), "operand of unary + plus must be int or float but it is %s", print_type(expr->get_type())); + return nullptr; + } - return Tree(expr, tok->get_locus()); - }*/ - // Rust has no unary plus operator - case MINUS: { // unary minus + return Tree(expr, tok->get_locus()); + }*/ + // Rust has no unary plus operator + case MINUS: + { // unary minus ParseRestrictions entered_from_unary; entered_from_unary.entered_from_unary = true; if (!restrictions.can_be_struct_expr) @@ -12280,7 +12430,8 @@ Parser::null_denotation_not_path ( new AST::NegationExpr (std::move (expr), NegationOperator::NEGATE, std::move (outer_attrs), tok->get_locus ())); } - case EXCLAM: { // logical or bitwise not + case EXCLAM: + { // logical or bitwise not ParseRestrictions entered_from_unary; entered_from_unary.entered_from_unary = true; if (!restrictions.can_be_struct_expr) @@ -12305,7 +12456,8 @@ Parser::null_denotation_not_path ( new AST::NegationExpr (std::move (expr), NegationOperator::NOT, std::move (outer_attrs), tok->get_locus ())); } - case ASTERISK: { + case ASTERISK: + { /* pointer dereference only - HACK: as struct expressions should * always be value expressions, cannot be dereferenced */ ParseRestrictions entered_from_unary; @@ -12318,7 +12470,8 @@ Parser::null_denotation_not_path ( new AST::DereferenceExpr (std::move (expr), std::move (outer_attrs), tok->get_locus ())); } - case AMP: { + case AMP: + { // (single) "borrow" expression - shared (mutable) or immutable std::unique_ptr expr = nullptr; Mutability mutability = Mutability::Imm; @@ -12375,7 +12528,8 @@ Parser::null_denotation_not_path ( new AST::BorrowExpr (std::move (expr), mutability, raw_borrow, false, std::move (outer_attrs), tok->get_locus ())); } - case LOGICAL_AND: { + case LOGICAL_AND: + { // (double) "borrow" expression - shared (mutable) or immutable std::unique_ptr expr = nullptr; Mutability mutability = Mutability::Imm; @@ -12414,6 +12568,9 @@ Parser::null_denotation_not_path ( case RETURN_KW: // FIXME: is this really a null denotation expression? return parse_return_expr (std::move (outer_attrs), tok->get_locus ()); + case TRY: + // FIXME: is this really a null denotation expression? + return parse_try_expr (std::move (outer_attrs), tok->get_locus ()); case BREAK: // FIXME: is this really a null denotation expression? return parse_break_expr (std::move (outer_attrs), tok->get_locus ()); @@ -12469,6 +12626,9 @@ Parser::null_denotation_not_path ( "use of %qs is not allowed on the right-side of an assignment", tok->get_token_description ())); return nullptr; + case CONST: + return parse_const_block_expr (std::move (outer_attrs), + tok->get_locus ()); default: if (!restrictions.expr_can_be_null) add_error (Error (tok->get_locus (), @@ -12491,8 +12651,9 @@ Parser::left_denotation (const_TokenPtr tok, // Token passed in has already been skipped, so peek gives "next" token switch (tok->get_id ()) { - // FIXME: allow for outer attributes to be applied - case QUESTION_MARK: { + // FIXME: allow for outer attributes to be applied + case QUESTION_MARK: + { location_t left_locus = left->get_locus (); // error propagation expression - unary postfix return std::unique_ptr ( @@ -12746,7 +12907,8 @@ Parser::left_denotation (const_TokenPtr tok, "function - this should probably be handled elsewhere")); return nullptr; - case DOT: { + case DOT: + { /* field expression or method call - relies on parentheses after next * identifier or await if token after is "await" (unary postfix) or * tuple index if token after is a decimal int literal */ @@ -14062,7 +14224,8 @@ Parser::parse_struct_expr_struct_partial ( * algorithm should work too. As such, AST type not happening. */ case IDENTIFIER: case HASH: - case INT_LITERAL: { + case INT_LITERAL: + { // struct with struct expr fields // parse struct expr fields @@ -14359,7 +14522,8 @@ Parser::parse_closure_expr_pratt (const_TokenPtr tok, case OR: // no parameters, don't skip token break; - case PIPE: { + case PIPE: + { // actually may have parameters // don't skip token const_TokenPtr t = lexer.peek_token (); diff --git a/gcc/rust/parse/rust-parse.cc b/gcc/rust/parse/rust-parse.cc index 43d15aa2bb9e..860fd11612ad 100644 --- a/gcc/rust/parse/rust-parse.cc +++ b/gcc/rust/parse/rust-parse.cc @@ -42,8 +42,7 @@ extract_module_path (const AST::AttrVec &inner_attrs, { rust_error_at ( path_attr.get_locus (), - // Split the format string so that -Wformat-diag does not complain... - "path attributes must contain a filename: '%s'", "#![path = \"file\"]"); + "path attributes must contain a filename: %<#[path = \"file\"]%>"); return name; } @@ -67,8 +66,7 @@ extract_module_path (const AST::AttrVec &inner_attrs, { rust_error_at ( path_attr.get_locus (), - // Split the format string so that -Wformat-diag does not complain... - "path attributes must contain a filename: '%s'", "#[path = \"file\"]"); + "path attributes must contain a filename: %<#[path = \"file\"]%>"); return name; } @@ -80,6 +78,15 @@ extract_module_path (const AST::AttrVec &inner_attrs, // a character that is not an equal sign or whitespace auto filename_begin = path_value.find_first_not_of ("=\t "); + // If the path consists of only whitespace, then we have an error + if (filename_begin == std::string::npos) + { + rust_error_at ( + path_attr.get_locus (), + "path attributes must contain a filename: %<#[path = \"file\"]%>"); + return name; + } + auto path = path_value.substr (filename_begin); // On windows, the path might mix '/' and '\' separators. Replace the @@ -144,10 +151,9 @@ peculiar_fragment_match_compatible_fragment ( = contains (fragment_follow_set[last_spec.get_kind ()], spec.get_kind ()); if (!is_valid) - rust_error_at ( - match_locus, - "fragment specifier %qs is not allowed after %qs fragments", - spec.as_string ().c_str (), last_spec.as_string ().c_str ()); + rust_error_at (match_locus, + "fragment specifier %qs is not allowed after %qs fragments", + spec.as_string ().c_str (), last_spec.as_string ().c_str ()); return is_valid; } @@ -244,7 +250,8 @@ peculiar_fragment_match_compatible (const AST::MacroMatchFragment &last_match, // the error. switch (match.get_macro_match_type ()) { - case AST::MacroMatch::Tok: { + case AST::MacroMatch::Tok: + { auto tok = static_cast (&match); if (contains (allowed_toks, tok->get_id ())) return true; @@ -254,7 +261,8 @@ peculiar_fragment_match_compatible (const AST::MacroMatchFragment &last_match, break; } break; - case AST::MacroMatch::Repetition: { + case AST::MacroMatch::Repetition: + { auto repetition = static_cast (&match); auto &matches = repetition->get_matches (); @@ -263,7 +271,8 @@ peculiar_fragment_match_compatible (const AST::MacroMatchFragment &last_match, return peculiar_fragment_match_compatible (last_match, *first_frag); break; } - case AST::MacroMatch::Matcher: { + case AST::MacroMatch::Matcher: + { auto matcher = static_cast (&match); auto first_token = matcher->get_delim_type (); TokenId delim_id; @@ -289,7 +298,8 @@ peculiar_fragment_match_compatible (const AST::MacroMatchFragment &last_match, error_locus = matcher->get_match_locus (); break; } - case AST::MacroMatch::Fragment: { + case AST::MacroMatch::Fragment: + { auto last_spec = last_match.get_frag_spec (); auto fragment = static_cast (&match); if (last_spec.has_follow_set_fragment_restrictions ()) @@ -328,10 +338,11 @@ is_match_compatible (const AST::MacroMatch &last_match, switch (last_match.get_macro_match_type ()) { - // This is our main stop condition: When we are finally looking at the - // last match (or its actual last component), and it is a fragment, it - // may contain some follow up restrictions. - case AST::MacroMatch::Fragment: { + // This is our main stop condition: When we are finally looking at the + // last match (or its actual last component), and it is a fragment, it + // may contain some follow up restrictions. + case AST::MacroMatch::Fragment: + { auto fragment = static_cast (&last_match); if (fragment->get_frag_spec ().has_follow_set_restrictions ()) @@ -339,7 +350,8 @@ is_match_compatible (const AST::MacroMatch &last_match, else return true; } - case AST::MacroMatch::Repetition: { + case AST::MacroMatch::Repetition: + { // A repetition on the left hand side means we want to make sure the // last match of the repetition is compatible with the new match auto repetition diff --git a/gcc/rust/parse/rust-parse.h b/gcc/rust/parse/rust-parse.h index 827d91d6cbb1..63bbf8ebf0fb 100644 --- a/gcc/rust/parse/rust-parse.h +++ b/gcc/rust/parse/rust-parse.h @@ -17,6 +17,7 @@ along with GCC; see the file COPYING3. If not see #ifndef RUST_PARSE_H #define RUST_PARSE_H +#include "rust-ast.h" #include "rust-item.h" #include "rust-lex.h" #include "rust-ast-full.h" @@ -33,12 +34,19 @@ class ParseLifetimeParamError class ParseLifetimeError { }; + +enum class AnonConstError +{ + InvalidSizeExpr, +}; + enum class ParseLoopLabelError { NOT_LOOP_LABEL, MISSING_COLON, }; -enum ParseSelfError + +enum class ParseSelfError { SELF_PTR, PARSING, @@ -165,6 +173,12 @@ template class Parser tl::optional = tl::nullopt, location_t pratt_parsed_loc = UNKNOWN_LOCATION); + tl::expected parse_anon_const (); + + std::unique_ptr + parse_const_block_expr (AST::AttrVec outer_attrs = AST::AttrVec (), + location_t loc = UNKNOWN_LOCATION); + bool is_macro_rules_def (const_TokenPtr t); std::unique_ptr parse_item (bool called_from_statement); std::unique_ptr parse_pattern (); @@ -222,7 +236,7 @@ template class Parser // Path-related AST::SimplePath parse_simple_path (); - AST::SimplePathSegment parse_simple_path_segment (); + AST::SimplePathSegment parse_simple_path_segment (int base_peek = 0); AST::TypePath parse_type_path (); std::unique_ptr parse_type_path_segment (); AST::PathIdentSegment parse_path_ident_segment (); @@ -644,6 +658,9 @@ template class Parser std::unique_ptr parse_return_expr (AST::AttrVec outer_attrs = AST::AttrVec (), location_t pratt_parsed_loc = UNKNOWN_LOCATION); + std::unique_ptr + parse_try_expr (AST::AttrVec outer_attrs = AST::AttrVec (), + location_t pratt_parsed_loc = UNKNOWN_LOCATION); std::unique_ptr parse_break_expr (AST::AttrVec outer_attrs = AST::AttrVec (), location_t pratt_parsed_loc = UNKNOWN_LOCATION); @@ -764,9 +781,9 @@ template class Parser }; }; -std::string -extract_module_path (const AST::AttrVec &inner_attrs, - const AST::AttrVec &outer_attrs, const std::string &name); +std::string extract_module_path (const AST::AttrVec &inner_attrs, + const AST::AttrVec &outer_attrs, + const std::string &name); /** * Check if a MacroMatch is allowed to follow the last parsed MacroMatch. @@ -776,9 +793,8 @@ extract_module_path (const AST::AttrVec &inner_attrs, * * @return true if the follow-up is valid, false otherwise */ -bool -is_match_compatible (const AST::MacroMatch &last_match, - const AST::MacroMatch ¤t_match); +bool is_match_compatible (const AST::MacroMatch &last_match, + const AST::MacroMatch ¤t_match); } // namespace Rust // as now template, include implementations of all methods diff --git a/gcc/rust/resolve/rust-ast-resolve-base.cc b/gcc/rust/resolve/rust-ast-resolve-base.cc index b781ce33f3f4..05f34bc3f874 100644 --- a/gcc/rust/resolve/rust-ast-resolve-base.cc +++ b/gcc/rust/resolve/rust-ast-resolve-base.cc @@ -231,6 +231,14 @@ void ResolverBase::visit (AST::BlockExpr &) {} +void +ResolverBase::visit (AST::AnonConst &) +{} + +void +ResolverBase::visit (AST::ConstBlock &) +{} + void ResolverBase::visit (AST::ClosureExprInnerTyped &) {} @@ -275,6 +283,10 @@ void ResolverBase::visit (AST::ReturnExpr &) {} +void +ResolverBase::visit (AST::TryExpr &) +{} + void ResolverBase::visit (AST::UnsafeBlockExpr &) {} diff --git a/gcc/rust/resolve/rust-ast-resolve-base.h b/gcc/rust/resolve/rust-ast-resolve-base.h index 5bb9e4f18226..0cbf78e39abc 100644 --- a/gcc/rust/resolve/rust-ast-resolve-base.h +++ b/gcc/rust/resolve/rust-ast-resolve-base.h @@ -21,6 +21,7 @@ #include "rust-ast-visitor.h" #include "rust-ast.h" +#include "rust-expr.h" #include "rust-name-resolver.h" #include "rust-diagnostics.h" #include "rust-location.h" @@ -85,6 +86,8 @@ class ResolverBase : public AST::ASTVisitor void visit (AST::FieldAccessExpr &); void visit (AST::ClosureExprInner &); void visit (AST::BlockExpr &); + void visit (AST::AnonConst &); + void visit (AST::ConstBlock &); void visit (AST::ClosureExprInnerTyped &); void visit (AST::ContinueExpr &); void visit (AST::BreakExpr &); @@ -96,6 +99,7 @@ class ResolverBase : public AST::ASTVisitor void visit (AST::RangeToInclExpr &); void visit (AST::BoxExpr &); void visit (AST::ReturnExpr &); + void visit (AST::TryExpr &); void visit (AST::UnsafeBlockExpr &); void visit (AST::LoopExpr &); void visit (AST::WhileLoopExpr &); diff --git a/gcc/rust/resolve/rust-ast-resolve-expr.cc b/gcc/rust/resolve/rust-ast-resolve-expr.cc index 6242235a1bb1..ffce8ba76007 100644 --- a/gcc/rust/resolve/rust-ast-resolve-expr.cc +++ b/gcc/rust/resolve/rust-ast-resolve-expr.cc @@ -314,6 +314,18 @@ ResolveExpr::visit (AST::BlockExpr &expr) resolver->get_label_scope ().pop (); } +void +ResolveExpr::visit (AST::AnonConst &expr) +{ + ResolveExpr::go (expr.get_inner_expr (), prefix, canonical_prefix); +} + +void +ResolveExpr::visit (AST::ConstBlock &expr) +{ + ResolveExpr::go (expr.get_const_expr (), prefix, canonical_prefix); +} + void translate_operand (AST::InlineAsm &expr, const CanonicalPath &prefix, const CanonicalPath &canonical_prefix) @@ -324,38 +336,46 @@ translate_operand (AST::InlineAsm &expr, const CanonicalPath &prefix, { switch (operand.get_register_type ()) { - case RegisterType::In: { + case RegisterType::In: + { auto in = operand.get_in (); ResolveExpr::go (*in.expr, prefix, canonical_prefix); break; } - case RegisterType::Out: { + case RegisterType::Out: + { auto out = operand.get_out (); ResolveExpr::go (*out.expr, prefix, canonical_prefix); break; } - case RegisterType::InOut: { + case RegisterType::InOut: + { auto in_out = operand.get_in_out (); ResolveExpr::go (*in_out.expr, prefix, canonical_prefix); break; } - case RegisterType::SplitInOut: { + case RegisterType::SplitInOut: + { auto split_in_out = operand.get_split_in_out (); ResolveExpr::go (*split_in_out.in_expr, prefix, canonical_prefix); ResolveExpr::go (*split_in_out.out_expr, prefix, canonical_prefix); break; } - case RegisterType::Const: { + case RegisterType::Const: + { auto anon_const = operand.get_const ().anon_const; - ResolveExpr::go (*anon_const.expr, prefix, canonical_prefix); + ResolveExpr::go (anon_const.get_inner_expr (), prefix, + canonical_prefix); break; } - case RegisterType::Sym: { + case RegisterType::Sym: + { auto sym = operand.get_sym (); ResolveExpr::go (*sym.expr, prefix, canonical_prefix); break; } - case RegisterType::Label: { + case RegisterType::Label: + { auto label = operand.get_label (); ResolveExpr::go (*label.expr, prefix, canonical_prefix); break; @@ -766,7 +786,7 @@ ResolveExpr::visit (AST::ClosureExprInnerTyped &expr) resolver->push_closure_context (expr.get_node_id ()); - ResolveExpr::go (expr.get_definition_block (), prefix, canonical_prefix); + ResolveExpr::go (expr.get_definition_expr (), prefix, canonical_prefix); resolver->pop_closure_context (); diff --git a/gcc/rust/resolve/rust-ast-resolve-expr.h b/gcc/rust/resolve/rust-ast-resolve-expr.h index b296d669cb7c..aad160504174 100644 --- a/gcc/rust/resolve/rust-ast-resolve-expr.h +++ b/gcc/rust/resolve/rust-ast-resolve-expr.h @@ -56,6 +56,8 @@ class ResolveExpr : public ResolverBase void visit (AST::IfLetExpr &expr) override; void visit (AST::IfLetExprConseqElse &expr) override; void visit (AST::BlockExpr &expr) override; + void visit (AST::AnonConst &expr) override; + void visit (AST::ConstBlock &expr) override; void visit (AST::InlineAsm &expr) override; void visit (AST::LlvmInlineAsm &expr) override; void visit (AST::UnsafeBlockExpr &expr) override; diff --git a/gcc/rust/resolve/rust-ast-resolve-item.cc b/gcc/rust/resolve/rust-ast-resolve-item.cc index 30f6d430b861..1d5ebed99696 100644 --- a/gcc/rust/resolve/rust-ast-resolve-item.cc +++ b/gcc/rust/resolve/rust-ast-resolve-item.cc @@ -453,7 +453,8 @@ ResolveItem::visit (AST::ConstantItem &constant) resolve_visibility (constant.get_visibility ()); ResolveType::go (constant.get_type ()); - ResolveExpr::go (constant.get_expr (), path, cpath); + if (constant.has_expr ()) + ResolveExpr::go (constant.get_expr (), path, cpath); } void @@ -608,10 +609,7 @@ ResolveItem::visit (AST::InherentImpl &impl_block) } else { - std::string seg_buf = ""; - CanonicalPath seg - = CanonicalPath::new_seg (impl_block.get_node_id (), seg_buf); - cpath = canonical_prefix.append (seg); + cpath = canonical_prefix.append (impl_type_seg); } // done setup paths @@ -732,13 +730,7 @@ ResolveItem::visit (AST::TraitImpl &impl_block) } else { - std::string projection_str = canonical_projection.get (); - std::string seg_buf - = ""; - CanonicalPath seg - = CanonicalPath::new_seg (impl_block.get_node_id (), seg_buf); - cpath = canonical_prefix.append (seg); + cpath = canonical_prefix.append (canonical_projection); } // DONE setup canonical-path @@ -838,29 +830,32 @@ ResolveItem::resolve_extern_item (AST::ExternalItem &item) ResolveExternItem::go (item, prefix, canonical_prefix); } -static void -flatten_glob (const AST::UseTreeGlob &glob, std::vector &imports); -static void -flatten_rebind (const AST::UseTreeRebind &glob, std::vector &imports); -static void -flatten_list (const AST::UseTreeList &glob, std::vector &imports); +static void flatten_glob (const AST::UseTreeGlob &glob, + std::vector &imports); +static void flatten_rebind (const AST::UseTreeRebind &glob, + std::vector &imports); +static void flatten_list (const AST::UseTreeList &glob, + std::vector &imports); static void flatten (const AST::UseTree *tree, std::vector &imports) { switch (tree->get_kind ()) { - case AST::UseTree::Glob: { + case AST::UseTree::Glob: + { auto glob = static_cast (tree); flatten_glob (*glob, imports); break; } - case AST::UseTree::Rebind: { + case AST::UseTree::Rebind: + { auto rebind = static_cast (tree); flatten_rebind (*rebind, imports); break; } - case AST::UseTree::List: { + case AST::UseTree::List: + { auto list = static_cast (tree); flatten_list (*list, imports); break; diff --git a/gcc/rust/resolve/rust-ast-resolve-item.h b/gcc/rust/resolve/rust-ast-resolve-item.h index 776dd5338a51..d31f910c4b18 100644 --- a/gcc/rust/resolve/rust-ast-resolve-item.h +++ b/gcc/rust/resolve/rust-ast-resolve-item.h @@ -153,8 +153,7 @@ class Import #if CHECKING_P namespace selftest { -extern void -rust_simple_path_resolve_test (void); +extern void rust_simple_path_resolve_test (void); } // namespace selftest #endif // CHECKING_P diff --git a/gcc/rust/resolve/rust-ast-resolve-pattern.cc b/gcc/rust/resolve/rust-ast-resolve-pattern.cc index ee84be8942bc..fce45bcf1e62 100644 --- a/gcc/rust/resolve/rust-ast-resolve-pattern.cc +++ b/gcc/rust/resolve/rust-ast-resolve-pattern.cc @@ -62,6 +62,11 @@ PatternDeclaration::go (AST::Pattern &pattern, Rib::ItemType type, void PatternDeclaration::visit (AST::IdentifierPattern &pattern) { + if (pattern.has_subpattern ()) + { + pattern.get_subpattern ().accept_vis (*this); + } + Mutability mut = pattern.get_is_mut () ? Mutability::Mut : Mutability::Imm; add_new_binding (pattern.get_ident (), pattern.get_node_id (), BindingTypeInfo (mut, pattern.get_is_ref (), @@ -94,13 +99,15 @@ PatternDeclaration::visit (AST::TupleStructPattern &pattern) AST::TupleStructItems &items = pattern.get_items (); switch (items.get_item_type ()) { - case AST::TupleStructItems::RANGE: { + case AST::TupleStructItems::RANGE: + { // TODO rust_unreachable (); } break; - case AST::TupleStructItems::NO_RANGE: { + case AST::TupleStructItems::NO_RANGE: + { auto &items_no_range = static_cast (items); @@ -123,7 +130,8 @@ PatternDeclaration::visit (AST::StructPattern &pattern) { switch (field->get_item_type ()) { - case AST::StructPatternField::ItemType::TUPLE_PAT: { + case AST::StructPatternField::ItemType::TUPLE_PAT: + { AST::StructPatternFieldTuplePat &tuple = static_cast (*field); @@ -131,7 +139,8 @@ PatternDeclaration::visit (AST::StructPattern &pattern) } break; - case AST::StructPatternField::ItemType::IDENT_PAT: { + case AST::StructPatternField::ItemType::IDENT_PAT: + { AST::StructPatternFieldIdentPat &ident = static_cast (*field); @@ -139,7 +148,8 @@ PatternDeclaration::visit (AST::StructPattern &pattern) } break; - case AST::StructPatternField::ItemType::IDENT: { + case AST::StructPatternField::ItemType::IDENT: + { auto &ident = static_cast (*field); Mutability mut @@ -160,7 +170,8 @@ PatternDeclaration::visit (AST::TuplePattern &pattern) auto &items = pattern.get_items (); switch (items.get_pattern_type ()) { - case AST::TuplePatternItems::TuplePatternItemType::MULTIPLE: { + case AST::TuplePatternItems::TuplePatternItemType::MULTIPLE: + { auto &ref = static_cast ( pattern.get_items ()); @@ -169,7 +180,8 @@ PatternDeclaration::visit (AST::TuplePattern &pattern) } break; - case AST::TuplePatternItems::TuplePatternItemType::RANGED: { + case AST::TuplePatternItems::TuplePatternItemType::RANGED: + { auto &ref = static_cast (pattern.get_items ()); @@ -348,14 +360,16 @@ resolve_range_pattern_bound (AST::RangePatternBound &bound) // Nothing to resolve for a literal. break; - case AST::RangePatternBound::RangePatternBoundType::PATH: { + case AST::RangePatternBound::RangePatternBoundType::PATH: + { auto &ref = static_cast (bound); ResolvePath::go (ref.get_path ()); } break; - case AST::RangePatternBound::RangePatternBoundType::QUALPATH: { + case AST::RangePatternBound::RangePatternBoundType::QUALPATH: + { auto &ref = static_cast (bound); ResolvePath::go (ref.get_qualified_path ()); diff --git a/gcc/rust/resolve/rust-ast-resolve-stmt.h b/gcc/rust/resolve/rust-ast-resolve-stmt.h index d413a7c17ae6..d7145112c823 100644 --- a/gcc/rust/resolve/rust-ast-resolve-stmt.h +++ b/gcc/rust/resolve/rust-ast-resolve-stmt.h @@ -67,7 +67,8 @@ class ResolveStmt : public ResolverBase }); ResolveType::go (constant.get_type ()); - ResolveExpr::go (constant.get_expr (), prefix, canonical_prefix); + if (constant.has_expr ()) + ResolveExpr::go (constant.get_expr (), prefix, canonical_prefix); } void visit (AST::LetStmt &stmt) override diff --git a/gcc/rust/resolve/rust-ast-resolve-type.cc b/gcc/rust/resolve/rust-ast-resolve-type.cc index 8fd69c3ead6a..a0402289afc4 100644 --- a/gcc/rust/resolve/rust-ast-resolve-type.cc +++ b/gcc/rust/resolve/rust-ast-resolve-type.cc @@ -140,7 +140,7 @@ ResolveType::visit (AST::ImplTraitType &type) void ResolveType::visit (AST::ImplTraitTypeOneBound &type) { - ResolveTypeBound::go (type.get_trait_bound ()); + ResolveTypeBound::go (*type.get_trait_bound ().get ()); } // resolve relative type-paths @@ -210,7 +210,8 @@ ResolveRelativeTypePath::go (AST::TypePath &path, NodeId &resolved_node_id) switch (segment->get_type ()) { - case AST::TypePathSegment::SegmentType::GENERIC: { + case AST::TypePathSegment::SegmentType::GENERIC: + { AST::TypePathSegmentGeneric *s = static_cast (segment.get ()); if (s->has_generic_args ()) @@ -509,7 +510,8 @@ ResolveTypeToCanonicalPath::visit (AST::TypePath &path) auto &final_seg = path.get_segments ().back (); switch (final_seg->get_type ()) { - case AST::TypePathSegment::SegmentType::GENERIC: { + case AST::TypePathSegment::SegmentType::GENERIC: + { AST::TypePathSegmentGeneric *s = static_cast (final_seg.get ()); @@ -651,7 +653,8 @@ ResolveTypeToCanonicalPath::visit (AST::TraitObjectType &type) switch (additional_bound->get_bound_type ()) { - case AST::TypeParamBound::TRAIT: { + case AST::TypeParamBound::TRAIT: + { auto bound_path = CanonicalPath::create_empty (); auto &bound_type_path diff --git a/gcc/rust/resolve/rust-ast-resolve.cc b/gcc/rust/resolve/rust-ast-resolve.cc index 3e3c992e76ac..2208f7046a7e 100644 --- a/gcc/rust/resolve/rust-ast-resolve.cc +++ b/gcc/rust/resolve/rust-ast-resolve.cc @@ -24,8 +24,7 @@ #include "rust-ast-resolve-expr.h" #include "rust-ast-resolve-struct-expr-field.h" -extern bool -saw_errors (void); +extern bool saw_errors (void); namespace Rust { namespace Resolver { diff --git a/gcc/rust/resolve/rust-default-resolver.cc b/gcc/rust/resolve/rust-default-resolver.cc index 480034c89741..588caa4e6f0c 100644 --- a/gcc/rust/resolve/rust-default-resolver.cc +++ b/gcc/rust/resolve/rust-default-resolver.cc @@ -24,6 +24,21 @@ namespace Rust { namespace Resolver2_0 { +void +DefaultResolver::visit (AST::Crate &crate) +{ + auto inner_fn = [this, &crate] () { AST::DefaultASTVisitor::visit (crate); }; + + auto &mappings = Analysis::Mappings::get (); + + auto crate_num = mappings.lookup_crate_num (crate.get_node_id ()); + rust_assert (crate_num.has_value ()); + auto crate_name = mappings.get_crate_name (*crate_num); + rust_assert (crate_name.has_value ()); + + ctx.canonical_ctx.scope_crate (crate.get_node_id (), *crate_name, inner_fn); +} + void DefaultResolver::visit (AST::BlockExpr &expr) { @@ -38,19 +53,32 @@ DefaultResolver::visit (AST::BlockExpr &expr) void DefaultResolver::visit (AST::Module &module) { - auto item_fn = [this, &module] () { AST::DefaultASTVisitor::visit (module); }; + auto item_fn_1 + = [this, &module] () { AST::DefaultASTVisitor::visit (module); }; + + auto item_fn_2 = [this, &module, &item_fn_1] () { + ctx.canonical_ctx.scope (module.get_node_id (), module.get_name (), + std::move (item_fn_1)); + }; - ctx.scoped (Rib::Kind::Module, module.get_node_id (), item_fn, + ctx.scoped (Rib::Kind::Module, module.get_node_id (), item_fn_2, module.get_name ()); } void DefaultResolver::visit (AST::Function &function) { - auto def_fn + auto def_fn_1 = [this, &function] () { AST::DefaultASTVisitor::visit (function); }; - ctx.scoped (Rib::Kind::Function, function.get_node_id (), def_fn); + auto def_fn_2 = [this, &function, &def_fn_1] () { + ctx.canonical_ctx.scope (function.get_node_id (), + function.get_function_name (), + std::move (def_fn_1)); + }; + + ctx.scoped (Rib::Kind::Function, function.get_node_id (), def_fn_2, + function.get_function_name ()); } void @@ -61,73 +89,245 @@ DefaultResolver::visit (AST::ForLoopExpr &expr) } void -DefaultResolver::visit (AST::Trait &trait) +DefaultResolver::visit_if_let_patterns (AST::IfLetExpr &expr) { - auto inner_fn = [this, &trait] () { AST::DefaultASTVisitor::visit (trait); }; + for (auto &pattern : expr.get_patterns ()) + visit (pattern); +} - ctx.scoped (Rib::Kind::TraitOrImpl, trait.get_node_id (), inner_fn, +void +DefaultResolver::visit (AST::IfLetExpr &expr) +{ + auto inner_vis = [this, &expr] () { + visit_if_let_patterns (expr); + visit (expr.get_if_block ()); + }; + + visit_outer_attrs (expr); + + visit (expr.get_value_expr ()); + + ctx.scoped (Rib::Kind::Normal, expr.get_node_id (), inner_vis); +} + +void +DefaultResolver::visit (AST::Trait &trait) +{ + visit_outer_attrs (trait); + visit (trait.get_visibility ()); + visit_inner_attrs (trait); + + auto inner_fn_1 = [this, &trait] () { + for (auto &item : trait.get_trait_items ()) + visit (item); + }; + + auto inner_fn_2 = [this, &trait, &inner_fn_1] () { + visit (trait.get_implicit_self ()); + for (auto &generic : trait.get_generic_params ()) + visit (generic); + if (trait.has_where_clause ()) + visit (trait.get_where_clause ()); + for (auto &bound : trait.get_type_param_bounds ()) + visit (bound); + + ctx.scoped (Rib::Kind::TraitOrImpl, trait.get_node_id (), inner_fn_1); + }; + + auto inner_fn_3 = [this, &trait, &inner_fn_2] () { + ctx.canonical_ctx.scope (trait.get_node_id (), trait.get_identifier (), + std::move (inner_fn_2)); + }; + + ctx.scoped (Rib::Kind::Generics, trait.get_node_id (), inner_fn_3, trait.get_identifier () /* FIXME: Is that valid?*/); } void DefaultResolver::visit (AST::InherentImpl &impl) { - auto inner_fn = [this, &impl] () { AST::DefaultASTVisitor::visit (impl); }; - - ctx.scoped (Rib::Kind::TraitOrImpl, impl.get_node_id (), inner_fn); + visit_outer_attrs (impl); + visit (impl.get_visibility ()); + visit_inner_attrs (impl); + + auto inner_fn_1 = [this, &impl] () { + for (auto &item : impl.get_impl_items ()) + visit (item); + }; + + auto inner_fn_2 = [this, &impl, &inner_fn_1] () { + maybe_insert_big_self (impl); + for (auto &generic : impl.get_generic_params ()) + visit (generic); + if (impl.has_where_clause ()) + visit (impl.get_where_clause ()); + visit_impl_type (impl.get_type ()); + + ctx.scoped (Rib::Kind::TraitOrImpl, impl.get_node_id (), inner_fn_1); + }; + + auto inner_fn_3 = [this, &impl, &inner_fn_2] () { + ctx.canonical_ctx.scope_impl (impl, std::move (inner_fn_2)); + }; + + ctx.scoped (Rib::Kind::Generics, impl.get_node_id (), inner_fn_3); } void DefaultResolver::visit (AST::TraitImpl &impl) { - auto inner_fn = [this, &impl] () { AST::DefaultASTVisitor::visit (impl); }; - - ctx.scoped (Rib::Kind::TraitOrImpl, impl.get_node_id (), inner_fn); + visit_outer_attrs (impl); + visit (impl.get_visibility ()); + visit_inner_attrs (impl); + + auto inner_fn_1 = [this, &impl] () { + for (auto &item : impl.get_impl_items ()) + visit (item); + }; + + auto inner_fn_2 = [this, &impl, &inner_fn_1] () { + maybe_insert_big_self (impl); + for (auto &generic : impl.get_generic_params ()) + visit (generic); + if (impl.has_where_clause ()) + visit (impl.get_where_clause ()); + visit_impl_type (impl.get_type ()); + visit (impl.get_trait_path ()); + + ctx.scoped (Rib::Kind::TraitOrImpl, impl.get_node_id (), inner_fn_1); + }; + + auto inner_fn_3 = [this, &impl, &inner_fn_2] () { + ctx.canonical_ctx.scope_impl (impl, std::move (inner_fn_2)); + }; + + ctx.scoped (Rib::Kind::Generics, impl.get_node_id (), inner_fn_3); } void DefaultResolver::visit (AST::StructStruct &type) { - auto inner_fn = [this, &type] () { AST::DefaultASTVisitor::visit (type); }; + auto inner_fn_1 = [this, &type] () { AST::DefaultASTVisitor::visit (type); }; + + auto inner_fn_2 = [this, &type, &inner_fn_1] () { + ctx.canonical_ctx.scope (type.get_node_id (), type.get_struct_name (), + std::move (inner_fn_1)); + }; ctx.scoped (Rib::Kind::Item /* FIXME: Correct? */, type.get_node_id (), - inner_fn, type.get_struct_name ()); + inner_fn_2, type.get_struct_name ()); } void DefaultResolver::visit (AST::TupleStruct &type) { - auto inner_fn = [this, &type] () { AST::DefaultASTVisitor::visit (type); }; + auto inner_fn_1 = [this, &type] () { AST::DefaultASTVisitor::visit (type); }; + + auto inner_fn_2 = [this, &type, &inner_fn_1] () { + ctx.canonical_ctx.scope (type.get_node_id (), type.get_struct_name (), + std::move (inner_fn_1)); + }; ctx.scoped (Rib::Kind::Item /* FIXME: Correct? */, type.get_node_id (), - inner_fn, type.get_struct_name ()); + inner_fn_2, type.get_struct_name ()); +} + +void +DefaultResolver::visit (AST::EnumItem &item) +{ + auto inner_fn = [this, &item] () { AST::DefaultASTVisitor::visit (item); }; + + ctx.canonical_ctx.scope (item.get_node_id (), item.get_identifier (), + inner_fn); +} + +void +DefaultResolver::visit (AST::EnumItemTuple &item) +{ + auto inner_fn = [this, &item] () { AST::DefaultASTVisitor::visit (item); }; + + ctx.canonical_ctx.scope (item.get_node_id (), item.get_identifier (), + inner_fn); +} + +void +DefaultResolver::visit (AST::EnumItemStruct &item) +{ + auto inner_fn = [this, &item] () { AST::DefaultASTVisitor::visit (item); }; + + ctx.canonical_ctx.scope (item.get_node_id (), item.get_identifier (), + inner_fn); +} + +void +DefaultResolver::visit (AST::EnumItemDiscriminant &item) +{ + auto inner_fn = [this, &item] () { AST::DefaultASTVisitor::visit (item); }; + + ctx.canonical_ctx.scope (item.get_node_id (), item.get_identifier (), + inner_fn); } void DefaultResolver::visit (AST::Enum &type) { - auto variant_fn = [this, &type] () { AST::DefaultASTVisitor::visit (type); }; + auto inner_fn_1 = [this, &type] () { AST::DefaultASTVisitor::visit (type); }; + + auto inner_fn_2 = [this, &type, &inner_fn_1] () { + ctx.canonical_ctx.scope (type.get_node_id (), type.get_identifier (), + std::move (inner_fn_1)); + }; ctx.scoped (Rib::Kind::Item /* FIXME: Correct? */, type.get_node_id (), - variant_fn, type.get_identifier ()); + inner_fn_2, type.get_identifier ()); } void DefaultResolver::visit (AST::Union &type) { - auto inner_fn = [this, &type] () { AST::DefaultASTVisitor::visit (type); }; + auto inner_fn_1 = [this, &type] () { AST::DefaultASTVisitor::visit (type); }; + + auto inner_fn_2 = [this, &type, &inner_fn_1] () { + ctx.canonical_ctx.scope (type.get_node_id (), type.get_identifier (), + std::move (inner_fn_1)); + }; ctx.scoped (Rib::Kind::Item /* FIXME: Correct? */, type.get_node_id (), - inner_fn, type.get_identifier ()); + inner_fn_2, type.get_identifier ()); } void DefaultResolver::visit (AST::TypeAlias &type) { - auto inner_fn = [this, &type] () { AST::DefaultASTVisitor::visit (type); }; + auto inner_fn_1 = [this, &type] () { AST::DefaultASTVisitor::visit (type); }; + + auto inner_fn_2 = [this, &type, &inner_fn_1] () { + ctx.canonical_ctx.scope (type.get_node_id (), type.get_new_type_name (), + std::move (inner_fn_1)); + }; ctx.scoped (Rib::Kind::Item /* FIXME: Correct? */, type.get_node_id (), - inner_fn, type.get_new_type_name ()); + inner_fn_2, type.get_new_type_name ()); +} + +void +DefaultResolver::visit_closure_params (AST::ClosureExpr &expr) +{ + for (auto ¶m : expr.get_params ()) + visit (param); +} + +void +DefaultResolver::visit (AST::ClosureExpr &expr) +{ + auto expr_fn = [this, &expr] () { + visit_closure_params (expr); + visit (expr.get_definition_expr ()); + }; + + visit_outer_attrs (expr); + + ctx.scoped (Rib::Kind::Normal, expr.get_node_id (), expr_fn); } void @@ -136,7 +336,7 @@ DefaultResolver::visit (AST::ClosureExprInner &expr) if (expr.is_marked_for_strip ()) return; - AST::DefaultASTVisitor::visit (expr); + visit (static_cast (expr)); } void @@ -145,7 +345,8 @@ DefaultResolver::visit (AST::ClosureExprInnerTyped &expr) if (expr.is_marked_for_strip ()) return; - AST::DefaultASTVisitor::visit (expr); + visit (static_cast (expr)); + visit (expr.get_return_type ()); } void @@ -160,23 +361,29 @@ DefaultResolver::visit (AST::MatchExpr &expr) void DefaultResolver::visit (AST::ConstantItem &item) { - if (item.has_expr ()) - { - auto expr_vis - = [this, &item] () { AST::DefaultASTVisitor::visit (item); }; + auto expr_vis_1 = [this, &item] () { AST::DefaultASTVisitor::visit (item); }; - // FIXME: Why do we need a Rib here? - ctx.scoped (Rib::Kind::ConstantItem, item.get_node_id (), expr_vis); - } + auto expr_vis_2 = [this, &item, &expr_vis_1] () { + ctx.canonical_ctx.scope (item.get_node_id (), item.get_identifier (), + std::move (expr_vis_1)); + }; + + // FIXME: Why do we need a Rib here? + ctx.scoped (Rib::Kind::ConstantItem, item.get_node_id (), expr_vis_2); } void DefaultResolver::visit (AST::StaticItem &item) { - auto expr_vis = [this, &item] () { AST::DefaultASTVisitor::visit (item); }; + auto expr_vis_1 = [this, &item] () { AST::DefaultASTVisitor::visit (item); }; + + auto expr_vis_2 = [this, &item, &expr_vis_1] () { + ctx.canonical_ctx.scope (item.get_node_id (), item.get_identifier (), + std::move (expr_vis_1)); + }; // FIXME: Why do we need a Rib here? - ctx.scoped (Rib::Kind::ConstantItem, item.get_node_id (), expr_vis); + ctx.scoped (Rib::Kind::ConstantItem, item.get_node_id (), expr_vis_2); } void @@ -187,5 +394,46 @@ DefaultResolver::visit (AST::TypeParam ¶m) ctx.scoped (Rib::Kind::ForwardTypeParamBan, param.get_node_id (), expr_vis); } +void +DefaultResolver::visit_extern_crate (AST::ExternCrate &extern_crate, + AST::Crate &crate, CrateNum num) +{ + visit (crate); +} + +void +DefaultResolver::visit (AST::ExternCrate &crate) +{ + auto &mappings = Analysis::Mappings::get (); + auto num_opt = mappings.lookup_crate_name (crate.get_referenced_crate ()); + + if (!num_opt) + { + rust_error_at (crate.get_locus (), "unknown crate %qs", + crate.get_referenced_crate ().c_str ()); + return; + } + + CrateNum num = *num_opt; + + AST::Crate &referenced_crate = mappings.get_ast_crate (num); + + auto sub_visitor_1 + = [&, this] () { visit_extern_crate (crate, referenced_crate, num); }; + + auto sub_visitor_2 = [&] () { + ctx.canonical_ctx.scope_crate (referenced_crate.get_node_id (), + crate.get_referenced_crate (), + std::move (sub_visitor_1)); + }; + + if (crate.has_as_clause ()) + ctx.scoped (Rib::Kind::Module, referenced_crate.get_node_id (), + sub_visitor_2, crate.get_as_clause ()); + else + ctx.scoped (Rib::Kind::Module, referenced_crate.get_node_id (), + sub_visitor_2, crate.get_referenced_crate ()); +} + } // namespace Resolver2_0 } // namespace Rust diff --git a/gcc/rust/resolve/rust-default-resolver.h b/gcc/rust/resolve/rust-default-resolver.h index 2a987efdf5c4..3fa037911075 100644 --- a/gcc/rust/resolve/rust-default-resolver.h +++ b/gcc/rust/resolve/rust-default-resolver.h @@ -39,6 +39,7 @@ class DefaultResolver : public AST::DefaultASTVisitor virtual ~DefaultResolver () {} + void visit (AST::Crate &) override; // First, our lexical scope expressions - these visit their sub nodes, always // these nodes create new scopes and ribs - they are often used to declare new // variables, such as a for loop's iterator, or a function's arguments @@ -46,20 +47,34 @@ class DefaultResolver : public AST::DefaultASTVisitor void visit (AST::Module &) override; void visit (AST::Function &) override; void visit (AST::ForLoopExpr &expr) override; + virtual void visit_if_let_patterns (AST::IfLetExpr &expr); + void visit (AST::IfLetExpr &expr) override; void visit (AST::Trait &) override; + // used to handle Self insertion in TopLevel + virtual void maybe_insert_big_self (AST::Impl &) {} + virtual void visit_impl_type (AST::Type &type) { visit (type); } void visit (AST::InherentImpl &) override; void visit (AST::TraitImpl &) override; void visit (AST::TypeParam &) override; + virtual void visit_extern_crate (AST::ExternCrate &, AST::Crate &, CrateNum); + void visit (AST::ExternCrate &) override; + // type dec nodes, which visit their fields or variants by default void visit (AST::StructStruct &) override; void visit (AST::TupleStruct &) override; + void visit (AST::EnumItem &) override; + void visit (AST::EnumItemTuple &) override; + void visit (AST::EnumItemStruct &) override; + void visit (AST::EnumItemDiscriminant &) override; void visit (AST::Enum &) override; void visit (AST::Union &) override; void visit (AST::TypeAlias &) override; // Visitors that visit their expression node(s) + virtual void visit_closure_params (AST::ClosureExpr &); + virtual void visit (AST::ClosureExpr &); void visit (AST::ClosureExprInner &) override; void visit (AST::ClosureExprInnerTyped &) override; void visit (AST::MatchExpr &) override; diff --git a/gcc/rust/resolve/rust-early-name-resolver-2.0.cc b/gcc/rust/resolve/rust-early-name-resolver-2.0.cc index 3390f09e2916..fa746d770fba 100644 --- a/gcc/rust/resolve/rust-early-name-resolver-2.0.cc +++ b/gcc/rust/resolve/rust-early-name-resolver-2.0.cc @@ -17,8 +17,11 @@ // . #include "rust-early-name-resolver-2.0.h" +#include "optional.h" #include "rust-ast-full.h" #include "rust-diagnostics.h" +#include "rust-hir-map.h" +#include "rust-item.h" #include "rust-toplevel-name-resolver-2.0.h" #include "rust-attributes.h" #include "rust-finalize-imports-2.0.h" @@ -62,8 +65,9 @@ Early::go (AST::Crate &crate) // We now proceed with resolving macros, which can be nested in almost any // items textual_scope.push (); - for (auto &item : crate.items) - item->accept_vis (*this); + + visit (crate); + textual_scope.pop (); } @@ -74,8 +78,9 @@ Early::resolve_glob_import (NodeId use_dec_id, TopLevel::ImportKind &&glob) if (!resolved.has_value ()) return false; - auto result - = Analysis::Mappings::get ().lookup_ast_module (resolved->get_node_id ()); + auto result = Analysis::Mappings::get ().lookup_glob_container ( + resolved->get_node_id ()); + if (!result) return false; @@ -249,7 +254,7 @@ Early::visit (AST::Module &module) void Early::visit (AST::MacroInvocation &invoc) { - auto path = invoc.get_invoc_data ().get_path (); + auto &path = invoc.get_invoc_data ().get_path (); if (invoc.get_kind () == AST::MacroInvocation::InvocKind::Builtin) for (auto &pending_invoc : invoc.get_pending_eager_invocations ()) @@ -272,7 +277,7 @@ Early::visit (AST::MacroInvocation &invoc) // we won't have changed `definition` from `nullopt` if there are more // than one segments in our path if (!definition.has_value ()) - definition = ctx.resolve_path (path.get_segments (), Namespace::Macros); + definition = ctx.resolve_path (path, Namespace::Macros); // if the definition still does not have a value, then it's an error if (!definition.has_value ()) @@ -314,8 +319,8 @@ Early::visit_attributes (std::vector &attrs) auto traits = attr.get_traits_to_derive (); for (auto &trait : traits) { - auto definition = ctx.resolve_path (trait.get ().get_segments (), - Namespace::Macros); + auto definition + = ctx.resolve_path (trait.get (), Namespace::Macros); if (!definition.has_value ()) { // FIXME: Change to proper error message @@ -337,8 +342,8 @@ Early::visit_attributes (std::vector &attrs) ->lookup_builtin (name) .is_error ()) // Do not resolve builtins { - auto definition = ctx.resolve_path (attr.get_path ().get_segments (), - Namespace::Macros); + auto definition + = ctx.resolve_path (attr.get_path (), Namespace::Macros); if (!definition.has_value ()) { // FIXME: Change to proper error message @@ -350,7 +355,8 @@ Early::visit_attributes (std::vector &attrs) auto pm_def = mappings.lookup_attribute_proc_macro_def ( definition->get_node_id ()); - rust_assert (pm_def.has_value ()); + if (!pm_def.has_value ()) + return; mappings.insert_attribute_proc_macro_invocation (attr.get_path (), pm_def.value ()); @@ -392,12 +398,12 @@ void Early::finalize_glob_import (NameResolutionContext &ctx, const Early::ImportPair &mapping) { - auto module = Analysis::Mappings::get ().lookup_ast_module ( - mapping.data.module ().get_node_id ()); - rust_assert (module); + auto container = Analysis::Mappings::get ().lookup_glob_container ( + mapping.data.container ().get_node_id ()); - GlobbingVisitor glob_visitor (ctx); - glob_visitor.go (module.value ()); + rust_assert (container); + + GlobbingVisitor (ctx).go (container.value ()); } void @@ -419,7 +425,8 @@ Early::finalize_rebind_import (const Early::ImportPair &mapping) declared_name = rebind.get_identifier ().as_string (); locus = rebind.get_identifier ().get_locus (); break; - case AST::UseTreeRebind::NewBindType::NONE: { + case AST::UseTreeRebind::NewBindType::NONE: + { const auto &segments = path.get_segments (); // We don't want to insert `self` with `use module::self` if (path.get_final_segment ().is_lower_self_seg ()) diff --git a/gcc/rust/resolve/rust-early-name-resolver-2.0.h b/gcc/rust/resolve/rust-early-name-resolver-2.0.h index e78bec0199a8..960de0e4c791 100644 --- a/gcc/rust/resolve/rust-early-name-resolver-2.0.h +++ b/gcc/rust/resolve/rust-early-name-resolver-2.0.h @@ -83,15 +83,15 @@ class Early : public DefaultResolver return ImportData (Kind::Rebind, std::move (definitions)); } - static ImportData Glob (Rib::Definition module) + static ImportData Glob (Rib::Definition container) { - return ImportData (Kind::Glob, module); + return ImportData (Kind::Glob, container); } - Rib::Definition module () const + Rib::Definition container () const { rust_assert (kind == Kind::Glob); - return glob_module; + return glob_container; } std::vector> definitions () const @@ -107,8 +107,8 @@ class Early : public DefaultResolver : kind (kind), resolved_definitions (std::move (definitions)) {} - ImportData (Kind kind, Rib::Definition module) - : kind (kind), glob_module (module) + ImportData (Kind kind, Rib::Definition container) + : kind (kind), glob_container (container) {} // TODO: Should this be a union? @@ -117,7 +117,7 @@ class Early : public DefaultResolver std::vector> resolved_definitions; // For Glob - Rib::Definition glob_module; + Rib::Definition glob_container; }; struct ImportPair diff --git a/gcc/rust/resolve/rust-finalize-imports-2.0.cc b/gcc/rust/resolve/rust-finalize-imports-2.0.cc index b0e86512ac20..317acb0c3123 100644 --- a/gcc/rust/resolve/rust-finalize-imports-2.0.cc +++ b/gcc/rust/resolve/rust-finalize-imports-2.0.cc @@ -21,18 +21,43 @@ #include "rust-hir-map.h" #include "rust-name-resolution-context.h" #include "rust-rib.h" +#include "rust-system.h" #include "rust-toplevel-name-resolver-2.0.h" namespace Rust { namespace Resolver2_0 { void -GlobbingVisitor::go (AST::Module *module) +GlobbingVisitor::go (AST::Item *container) { - for (auto &i : module->get_items ()) + switch (container->get_item_kind ()) + { + case AST::Item::Kind::Module: + visit_module_container (static_cast (*container)); + break; + case AST::Item::Kind::Enum: + visit_enum_container (static_cast (*container)); + break; + default: + rust_unreachable (); + } +} + +void +GlobbingVisitor::visit_module_container (AST::Module &module) +{ + for (auto &i : module.get_items ()) visit (i); } +void +GlobbingVisitor::visit_enum_container (AST::Enum &item) +{ + for (auto &variant : item.get_variants ()) + ctx.insert_globbed (variant->get_identifier (), variant->get_node_id (), + Namespace::Types); +} + void GlobbingVisitor::visit (AST::Module &module) { diff --git a/gcc/rust/resolve/rust-finalize-imports-2.0.h b/gcc/rust/resolve/rust-finalize-imports-2.0.h index d587a5e5c46e..4ae1d6d4d904 100644 --- a/gcc/rust/resolve/rust-finalize-imports-2.0.h +++ b/gcc/rust/resolve/rust-finalize-imports-2.0.h @@ -18,6 +18,7 @@ #include "rust-ast.h" #include "rust-expr.h" +#include "rust-item.h" #include "rust-name-resolution-context.h" #include "rust-toplevel-name-resolver-2.0.h" #include "rust-early-name-resolver-2.0.h" @@ -32,7 +33,11 @@ class GlobbingVisitor : public AST::DefaultASTVisitor public: GlobbingVisitor (NameResolutionContext &ctx) : ctx (ctx) {} - void go (AST::Module *module); + void go (AST::Item *container); + + void visit_module_container (AST::Module &module); + void visit_enum_container (AST::Enum &item); + void visit (AST::Module &module) override; void visit (AST::MacroRulesDefinition ¯o) override; void visit (AST::Function &function) override; diff --git a/gcc/rust/resolve/rust-forever-stack.h b/gcc/rust/resolve/rust-forever-stack.h index 81468e5c386f..75dd87395bef 100644 --- a/gcc/rust/resolve/rust-forever-stack.h +++ b/gcc/rust/resolve/rust-forever-stack.h @@ -543,6 +543,13 @@ class ForeverStackStore Node root; }; +enum class ResolutionMode +{ + Normal, + FromRoot, + FromExtern, // extern prelude +}; + template class ForeverStack { public: @@ -672,13 +679,10 @@ template class ForeverStack */ template tl::optional resolve_path ( - const std::vector &segments, bool has_opening_scope_resolution, + const std::vector &segments, ResolutionMode mode, std::function insert_segment_resolution, std::vector &collect_errors); - // FIXME: Documentation - tl::optional to_canonical_path (NodeId id) const; - // FIXME: Documentation tl::optional to_rib (NodeId rib_id); tl::optional to_rib (NodeId rib_id) const; @@ -739,6 +743,9 @@ template class ForeverStack tl::optional parent; // `None` only if the node is a root }; + // private overload which allows specifying a starting point + tl::optional get (Node &start, const Identifier &name); + /* Should we keep going upon seeing a Rib? */ enum class KeepGoing { diff --git a/gcc/rust/resolve/rust-forever-stack.hxx b/gcc/rust/resolve/rust-forever-stack.hxx index 069111eeb0e0..1ed87b3d55b4 100644 --- a/gcc/rust/resolve/rust-forever-stack.hxx +++ b/gcc/rust/resolve/rust-forever-stack.hxx @@ -291,12 +291,16 @@ ForeverStack::update_cursor (Node &new_cursor) template tl::optional -ForeverStack::get (const Identifier &name) +ForeverStack::get (Node &start, const Identifier &name) { tl::optional resolved_definition = tl::nullopt; // TODO: Can we improve the API? have `reverse_iter` return an optional? - reverse_iter ([&resolved_definition, &name] (Node ¤t) { + reverse_iter (start, [&resolved_definition, &name] (Node ¤t) { + // we can't reference associated types/functions like this + if (current.rib.kind == Rib::Kind::TraitOrImpl) + return KeepGoing::Yes; + auto candidate = current.rib.get (name.as_string ()); return candidate.map_or ( @@ -318,6 +322,13 @@ ForeverStack::get (const Identifier &name) return resolved_definition; } +template +tl::optional +ForeverStack::get (const Identifier &name) +{ + return get (cursor (), name); +} + template tl::optional ForeverStack::get_lang_prelude (const Identifier &name) @@ -542,6 +553,14 @@ ForeverStack::resolve_segments ( bool searched_prelude = false; while (true) { + if (is_start (iterator, segments) + && current_node->rib.kind == Rib::Kind::TraitOrImpl) + { + // we can't reference associated types/functions like this + current_node = ¤t_node->parent.value (); + continue; + } + // may set the value of child for (auto &kv : current_node->children) { @@ -625,88 +644,158 @@ template template tl::optional ForeverStack::resolve_path ( - const std::vector &segments, bool has_opening_scope_resolution, + const std::vector &segments, ResolutionMode mode, std::function insert_segment_resolution, std::vector &collect_errors) { - // TODO: What to do if segments.empty() ? + rust_assert (!segments.empty ()); - // handle paths with opening scopes - std::function cleanup_current = [] () {}; - if (has_opening_scope_resolution) + std::reference_wrapper starting_point = cursor (); + switch (mode) { - Node *last_current = &cursor_reference.get (); - if (get_rust_edition () == Edition::E2015) - cursor_reference = root; - else - cursor_reference = extern_prelude; - cleanup_current - = [this, last_current] () { cursor_reference = *last_current; }; + case ResolutionMode::Normal: + break; // default + case ResolutionMode::FromRoot: + starting_point = root; + break; + case ResolutionMode::FromExtern: + starting_point = extern_prelude; + break; + default: + rust_unreachable (); } // if there's only one segment, we just use `get` if (segments.size () == 1) { - auto &seg = segments.front (); - if (auto lang_item = unwrap_segment_get_lang_item (seg)) + auto &outer_seg = segments.front (); + if (auto lang_item = unwrap_segment_get_lang_item (outer_seg)) { NodeId seg_id = Analysis::Mappings::get ().get_lang_item_node ( lang_item.value ()); - insert_segment_resolution (seg, seg_id); - cleanup_current (); + insert_segment_resolution (outer_seg, seg_id); // TODO: does NonShadowable matter? return Rib::Definition::NonShadowable (seg_id); } + auto &seg = unwrap_type_segment (outer_seg); + tl::optional res - = get (unwrap_type_segment (segments.back ()).as_string ()); + = get (starting_point.get (), seg.as_string ()); if (!res) - res = get_lang_prelude ( - unwrap_type_segment (segments.back ()).as_string ()); + res = get_lang_prelude (seg.as_string ()); + + if (N == Namespace::Types && !res) + { + if (seg.is_crate_path_seg ()) + { + insert_segment_resolution (outer_seg, root.id); + // TODO: does NonShadowable matter? + return Rib::Definition::NonShadowable (root.id); + } + else if (seg.is_lower_self_seg ()) + { + NodeId id = find_closest_module (starting_point.get ()).id; + insert_segment_resolution (outer_seg, id); + // TODO: does NonShadowable matter? + return Rib::Definition::NonShadowable (id); + } + else if (seg.is_super_path_seg ()) + { + Node &closest_module + = find_closest_module (starting_point.get ()); + if (closest_module.is_root ()) + { + rust_error_at (seg.get_locus (), ErrorCode::E0433, + "too many leading % keywords"); + return tl::nullopt; + } + + NodeId id + = find_closest_module (closest_module.parent.value ()).id; + insert_segment_resolution (outer_seg, id); + // TODO: does NonShadowable matter? + return Rib::Definition::NonShadowable (id); + } + else + { + // HACK: check for a module after we check the language prelude + for (auto &kv : + find_closest_module (starting_point.get ()).children) + { + auto &link = kv.first; + + if (link.path.map_or ( + [&seg] (Identifier path) { + auto &path_str = path.as_string (); + return path_str == seg.as_string (); + }, + false)) + { + insert_segment_resolution (outer_seg, kv.second.id); + return Rib::Definition::NonShadowable (kv.second.id); + } + } + } + } if (res && !res->is_ambiguous ()) - insert_segment_resolution (segments.back (), res->get_node_id ()); - cleanup_current (); + insert_segment_resolution (outer_seg, res->get_node_id ()); return res; } - std::reference_wrapper starting_point = cursor (); + return find_starting_point (segments, starting_point, + insert_segment_resolution, collect_errors) + .and_then ( + [this, &segments, &starting_point, &insert_segment_resolution, + &collect_errors] (typename std::vector::const_iterator iterator) { + return resolve_segments (starting_point.get (), segments, iterator, + insert_segment_resolution, collect_errors); + }) + .and_then ([this, &segments, &insert_segment_resolution] ( + Node &final_node) -> tl::optional { + // leave resolution within impl blocks to type checker + if (final_node.rib.kind == Rib::Kind::TraitOrImpl) + return tl::nullopt; + + auto &seg = unwrap_type_segment (segments.back ()); + std::string seg_name = seg.as_string (); + + // assuming this can't be a lang item segment + tl::optional res + = resolve_final_segment (final_node, seg_name, + seg.is_lower_self_seg ()); + // Ok we didn't find it in the rib, Lets try the prelude... + if (!res) + res = get_lang_prelude (seg_name); - auto res - = find_starting_point (segments, starting_point, insert_segment_resolution, - collect_errors) - .and_then ( - [this, &segments, &starting_point, &insert_segment_resolution, - &collect_errors] (typename std::vector::const_iterator iterator) { - return resolve_segments (starting_point.get (), segments, iterator, - insert_segment_resolution, collect_errors); - }) - .and_then ([this, &segments, &insert_segment_resolution] ( - Node &final_node) -> tl::optional { - // leave resolution within impl blocks to type checker - if (final_node.rib.kind == Rib::Kind::TraitOrImpl) - return tl::nullopt; - - auto &seg = unwrap_type_segment (segments.back ()); - std::string seg_name = seg.as_string (); - - // assuming this can't be a lang item segment - tl::optional res - = resolve_final_segment (final_node, seg_name, - seg.is_lower_self_seg ()); - // Ok we didn't find it in the rib, Lets try the prelude... - if (!res) - res = get_lang_prelude (seg_name); - - if (res && !res->is_ambiguous ()) - insert_segment_resolution (segments.back (), res->get_node_id ()); - - return res; - }); - cleanup_current (); - return res; + if (N == Namespace::Types && !res) + { + // HACK: check for a module after we check the language prelude + for (auto &kv : final_node.children) + { + auto &link = kv.first; + + if (link.path.map_or ( + [&seg_name] (Identifier path) { + auto &path_str = path.as_string (); + return path_str == seg_name; + }, + false)) + { + insert_segment_resolution (segments.back (), kv.second.id); + return Rib::Definition::NonShadowable (kv.second.id); + } + } + } + + if (res && !res->is_ambiguous ()) + insert_segment_resolution (segments.back (), res->get_node_id ()); + + return res; + }); } template @@ -770,67 +859,6 @@ ForeverStack::dfs (const ForeverStack::Node &starting_point, return tl::nullopt; } -template -tl::optional -ForeverStack::to_canonical_path (NodeId id) const -{ - // find the id in the current forever stack, starting from the root, - // performing either a BFS or DFS once the Node containing the ID is found, go - // back up to the root (parent().parent().parent()...) accumulate link - // segments reverse them that's your canonical path - - return dfs (root, id).map ([this, id] (ConstDfsResult tuple) { - auto containing_node = tuple.first; - auto name = tuple.second; - - auto segments = std::vector (); - - reverse_iter (containing_node, [&segments] (const Node ¤t) { - if (current.is_root ()) - return KeepGoing::No; - - auto children = current.parent.value ().children; - const Link *outer_link = nullptr; - - for (auto &kv : children) - { - auto &link = kv.first; - auto &child = kv.second; - - if (current.id == child.id) - { - outer_link = &link; - break; - } - } - - rust_assert (outer_link); - - outer_link->path.map ([&segments, outer_link] (Identifier path) { - segments.emplace (segments.begin (), - Resolver::CanonicalPath::new_seg (outer_link->id, - path.as_string ())); - }); - - return KeepGoing::Yes; - }); - - auto &mappings = Analysis::Mappings::get (); - CrateNum crate_num = mappings.lookup_crate_num (root.id).value (); - auto path = Resolver::CanonicalPath::new_seg ( - root.id, mappings.get_crate_name (crate_num).value ()); - path.set_crate_num (crate_num); - - for (const auto &segment : segments) - path = path.append (segment); - - // Finally, append the name - path = path.append (Resolver::CanonicalPath::new_seg (id, name)); - - return path; - }); -} - template tl::optional ForeverStack::dfs_rib (ForeverStack::Node &starting_point, NodeId to_find) diff --git a/gcc/rust/resolve/rust-ice-finalizer.h b/gcc/rust/resolve/rust-ice-finalizer.h index 85ab88ff7146..578084a92cdc 100644 --- a/gcc/rust/resolve/rust-ice-finalizer.h +++ b/gcc/rust/resolve/rust-ice-finalizer.h @@ -54,10 +54,9 @@ namespace Resolver { /* The finalizer for our funny ICE. This prints a custom message instead of the default bug reporting instructions, as there is no bug to report. */ -void ATTRIBUTE_NORETURN -funny_ice_text_finalizer (diagnostic_text_output_format &text_output, - const diagnostic_info *diagnostic, - diagnostic_t diag_kind); +void ATTRIBUTE_NORETURN funny_ice_text_finalizer ( + diagnostic_text_output_format &text_output, const diagnostic_info *diagnostic, + diagnostic_t diag_kind); } // namespace Resolver } // namespace Rust diff --git a/gcc/rust/resolve/rust-late-name-resolver-2.0.cc b/gcc/rust/resolve/rust-late-name-resolver-2.0.cc index 6ec04229c8e7..1b560852418e 100644 --- a/gcc/rust/resolve/rust-late-name-resolver-2.0.cc +++ b/gcc/rust/resolve/rust-late-name-resolver-2.0.cc @@ -19,6 +19,7 @@ #include "optional.h" #include "rust-ast-full.h" #include "rust-diagnostics.h" +#include "rust-expr.h" #include "rust-hir-map.h" #include "rust-late-name-resolver-2.0.h" #include "rust-default-resolver.h" @@ -33,7 +34,9 @@ namespace Rust { namespace Resolver2_0 { -Late::Late (NameResolutionContext &ctx) : DefaultResolver (ctx) {} +Late::Late (NameResolutionContext &ctx) + : DefaultResolver (ctx), funny_error (false), block_big_self (false) +{} static NodeId next_node_id () @@ -114,8 +117,7 @@ Late::go (AST::Crate &crate) { setup_builtin_types (); - for (auto &item : crate.items) - item->accept_vis (*this); + visit (crate); } void @@ -140,24 +142,21 @@ Late::visit (AST::ForLoopExpr &expr) ctx.bindings.exit (); visit (expr.get_iterator_expr ()); - visit (expr.get_loop_label ()); + + if (expr.has_loop_label ()) + visit (expr.get_loop_label ()); + visit (expr.get_loop_block ()); } void -Late::visit (AST::IfLetExpr &expr) +Late::visit_if_let_patterns (AST::IfLetExpr &expr) { - visit_outer_attrs (expr); + ctx.bindings.enter (BindingSource::IfLet); - ctx.bindings.enter (BindingSource::Let); - - for (auto &pattern : expr.get_patterns ()) - visit (pattern); + DefaultResolver::visit_if_let_patterns (expr); ctx.bindings.exit (); - - visit (expr.get_value_expr ()); - visit (expr.get_if_block ()); } void @@ -214,44 +213,79 @@ Late::visit (AST::LetStmt &let) } void -Late::visit (AST::IdentifierPattern &identifier) +Late::visit (AST::WhileLetLoopExpr &while_let) +{ + DefaultASTVisitor::visit_outer_attrs (while_let); + + if (while_let.has_loop_label ()) + visit (while_let.get_loop_label ()); + + // visit expression before pattern + // this makes variable shadowing work properly + visit (while_let.get_scrutinee_expr ()); + + ctx.bindings.enter (BindingSource::WhileLet); + + for (auto &pattern : while_let.get_patterns ()) + visit (pattern); + + ctx.bindings.exit (); + + visit (while_let.get_loop_block ()); +} + +static void +visit_identifier_as_pattern (NameResolutionContext &ctx, + const Identifier &ident, location_t locus, + NodeId node_id, bool is_ref, bool is_mut) { // do we insert in labels or in values // but values does not allow shadowing... since functions cannot shadow // do we insert functions in labels as well? - if (ctx.bindings.peek ().is_and_bound (identifier.get_ident ())) + if (ctx.bindings.peek ().is_and_bound (ident)) { if (ctx.bindings.peek ().get_source () == BindingSource::Param) rust_error_at ( - identifier.get_locus (), ErrorCode::E0415, + locus, ErrorCode::E0415, "identifier %qs is bound more than once in the same parameter list", - identifier.as_string ().c_str ()); + ident.as_string ().c_str ()); else rust_error_at ( - identifier.get_locus (), ErrorCode::E0416, + locus, ErrorCode::E0416, "identifier %qs is bound more than once in the same pattern", - identifier.as_string ().c_str ()); + ident.as_string ().c_str ()); return; } - ctx.bindings.peek ().insert_ident (identifier.get_ident ()); + ctx.bindings.peek ().insert_ident (ident.as_string (), locus, is_ref, is_mut); - if (ctx.bindings.peek ().is_or_bound (identifier.get_ident ())) + if (ctx.bindings.peek ().is_or_bound (ident)) { - // FIXME: map usage instead - std::ignore = ctx.values.insert_shadowable (identifier.get_ident (), - identifier.get_node_id ()); + auto res = ctx.values.get (ident); + rust_assert (res.has_value () && !res->is_ambiguous ()); + ctx.map_usage (Usage (node_id), Definition (res->get_node_id ())); } else { // We do want to ignore duplicated data because some situations rely on // it. - std::ignore = ctx.values.insert_shadowable (identifier.get_ident (), - identifier.get_node_id ()); + std::ignore = ctx.values.insert_shadowable (ident, node_id); } } +void +Late::visit (AST::IdentifierPattern &identifier) +{ + DefaultResolver::visit (identifier); + + visit_identifier_as_pattern (ctx, identifier.get_ident (), + identifier.get_locus (), + identifier.get_node_id (), + identifier.get_is_ref (), + identifier.get_is_mut ()); +} + void Late::visit (AST::AltPattern &pattern) { @@ -279,9 +313,9 @@ Late::visit_function_params (AST::Function &function) void Late::visit (AST::StructPatternFieldIdent &field) { - // We do want to ignore duplicated data because some situations rely on it. - std::ignore = ctx.values.insert_shadowable (field.get_identifier (), - field.get_node_id ()); + visit_identifier_as_pattern (ctx, field.get_identifier (), field.get_locus (), + field.get_node_id (), field.is_ref (), + field.is_mut ()); } void @@ -375,7 +409,8 @@ Late::visit (AST::IdentifierExpr &expr) } else if (funny_error) { - diagnostic_text_finalizer (global_dc) = Resolver::funny_ice_text_finalizer; + diagnostic_text_finalizer (global_dc) + = Resolver::funny_ice_text_finalizer; emit_diagnostic (DK_ICE_NOBT, expr.get_locus (), -1, "are you trying to break %s? how dare you?", expr.as_string ().c_str ()); @@ -476,6 +511,16 @@ Late::visit (AST::PathInExpression &expr) Definition (resolved->get_node_id ())); } +void +Late::visit_impl_type (AST::Type &type) +{ + // TODO: does this have to handle reentrancy? + rust_assert (!block_big_self); + block_big_self = true; + visit (type); + block_big_self = false; +} + void Late::visit (AST::TypePath &type) { @@ -486,6 +531,16 @@ Late::visit (AST::TypePath &type) DefaultResolver::visit (type); + // prevent "impl Self {}" and similar + if (type.get_segments ().size () == 1 + && !type.get_segments ().front ()->is_lang_item () + && type.get_segments ().front ()->is_big_self_seg () && block_big_self) + { + rust_error_at (type.get_locus (), + "% is not valid in the self type of an impl block"); + return; + } + // this *should* mostly work // TODO: make sure typepath-like path resolution (?) is working auto resolved = ctx.resolve_path (type, Namespace::Types); @@ -493,15 +548,16 @@ Late::visit (AST::TypePath &type) if (!resolved.has_value ()) { if (!ctx.lookup (type.get_segments ().front ()->get_node_id ())) - rust_error_at (type.get_locus (), "could not resolve type path %qs", - type.as_string ().c_str ()); + rust_error_at (type.get_locus (), ErrorCode::E0412, + "could not resolve type path %qs", + type.make_debug_string ().c_str ()); return; } if (resolved->is_ambiguous ()) { rust_error_at (type.get_locus (), ErrorCode::E0659, "%qs is ambiguous", - type.as_string ().c_str ()); + type.make_debug_string ().c_str ()); return; } @@ -517,6 +573,62 @@ Late::visit (AST::TypePath &type) Definition (resolved->get_node_id ())); } +void +Late::visit (AST::Visibility &vis) +{ + if (!vis.has_path ()) + return; + + AST::SimplePath &path = vis.get_path (); + + rust_assert (path.get_segments ().size ()); + auto &first_seg = path.get_segments ()[0]; + + auto mode = ResolutionMode::Normal; + + if (path.has_opening_scope_resolution ()) + { + if (get_rust_edition () == Edition::E2015) + mode = ResolutionMode::FromRoot; + else + mode = ResolutionMode::FromExtern; + } + else if (!first_seg.is_crate_path_seg () && !first_seg.is_super_path_seg () + && !first_seg.is_lower_self_seg ()) + { + if (get_rust_edition () == Edition::E2015) + { + mode = ResolutionMode::FromRoot; + } + else + { + rust_error_at (path.get_locus (), + "relative paths are not supported in visibilities in " + "2018 edition or later"); + return; + } + } + + auto res = ctx.resolve_path (path.get_segments (), mode, Namespace::Types); + + if (!res.has_value ()) + { + rust_error_at (path.get_locus (), ErrorCode::E0433, + "could not resolve path %qs", path.as_string ().c_str ()); + return; + } + + // TODO: is this possible? + if (res->is_ambiguous ()) + { + rust_error_at (path.get_locus (), ErrorCode::E0659, "%qs is ambiguous", + path.as_string ().c_str ()); + return; + } + + ctx.map_usage (Usage (path.get_node_id ()), Definition (res->get_node_id ())); +} + void Late::visit (AST::Trait &trait) { @@ -530,13 +642,6 @@ Late::visit (AST::Trait &trait) DefaultResolver::visit (trait); } -void -Late::visit (AST::StructStruct &s) -{ - auto s_vis = [this, &s] () { AST::DefaultASTVisitor::visit (s); }; - ctx.scoped (Rib::Kind::Item, s.get_node_id (), s_vis); -} - void Late::visit (AST::StructExprStruct &s) { @@ -613,51 +718,27 @@ Late::visit (AST::GenericArg &arg) DefaultResolver::visit (arg); } -template -static void -add_captures (Closure &closure, NameResolutionContext &ctx) -{ - auto vals = ctx.values.peek ().get_values (); - for (auto &val : vals) - { - ctx.mappings.add_capture (closure.get_node_id (), - val.second.get_node_id ()); - } -} - void -Late::visit (AST::ClosureExprInner &closure) +Late::visit_closure_params (AST::ClosureExpr &closure) { - add_captures (closure, ctx); - - visit_outer_attrs (closure); - ctx.bindings.enter (BindingSource::Param); - for (auto ¶m : closure.get_params ()) - visit (param); + DefaultResolver::visit_closure_params (closure); ctx.bindings.exit (); - - visit (closure.get_definition_expr ()); } void -Late::visit (AST::ClosureExprInnerTyped &closure) +Late::visit (AST::ClosureExpr &expr) { - add_captures (closure, ctx); - - visit_outer_attrs (closure); - - ctx.bindings.enter (BindingSource::Param); - - for (auto ¶m : closure.get_params ()) - visit (param); - - ctx.bindings.exit (); + // add captures + auto vals = ctx.values.peek ().get_values (); + for (auto &val : vals) + { + ctx.mappings.add_capture (expr.get_node_id (), val.second.get_node_id ()); + } - visit (closure.get_return_type ()); - visit (closure.get_definition_block ()); + DefaultResolver::visit (expr); } } // namespace Resolver2_0 diff --git a/gcc/rust/resolve/rust-late-name-resolver-2.0.h b/gcc/rust/resolve/rust-late-name-resolver-2.0.h index 171d9bfe0f6e..95540e340053 100644 --- a/gcc/rust/resolve/rust-late-name-resolver-2.0.h +++ b/gcc/rust/resolve/rust-late-name-resolver-2.0.h @@ -42,6 +42,7 @@ class Late : public DefaultResolver // some more label declarations void visit (AST::LetStmt &) override; + void visit (AST::WhileLetLoopExpr &) override; // TODO: Do we need this? // void visit (AST::Method &) override; void visit (AST::IdentifierPattern &) override; @@ -50,7 +51,7 @@ class Late : public DefaultResolver void visit (AST::SelfParam &) override; void visit (AST::MatchArm &) override; void visit (AST::ForLoopExpr &) override; - void visit (AST::IfLetExpr &) override; + void visit_if_let_patterns (AST::IfLetExpr &) override; // resolutions void visit (AST::IdentifierExpr &) override; @@ -59,16 +60,17 @@ class Late : public DefaultResolver void visit (AST::ContinueExpr &) override; void visit (AST::LoopLabel &) override; void visit (AST::PathInExpression &) override; + void visit_impl_type (AST::Type &) override; void visit (AST::TypePath &) override; + void visit (AST::Visibility &) override; void visit (AST::Trait &) override; void visit (AST::StructExprStruct &) override; void visit (AST::StructExprStructBase &) override; void visit (AST::StructExprStructFields &) override; - void visit (AST::StructStruct &) override; void visit (AST::GenericArgs &) override; void visit (AST::GenericArg &); - void visit (AST::ClosureExprInner &) override; - void visit (AST::ClosureExprInnerTyped &) override; + void visit_closure_params (AST::ClosureExpr &) override; + void visit (AST::ClosureExpr &) override; private: void resolve_label (AST::Lifetime &lifetime); @@ -77,6 +79,9 @@ class Late : public DefaultResolver void setup_builtin_types (); bool funny_error; + + /* used to prevent "impl Self {}", "impl (Self, i32) {}", etc */ + bool block_big_self; }; // TODO: Add missing mappings and data structures diff --git a/gcc/rust/resolve/rust-name-resolution-context.cc b/gcc/rust/resolve/rust-name-resolution-context.cc index f098e4880e59..1b84f1d7cfa3 100644 --- a/gcc/rust/resolve/rust-name-resolution-context.cc +++ b/gcc/rust/resolve/rust-name-resolution-context.cc @@ -33,7 +33,8 @@ BindingLayer::bind_test (Identifier ident, Binding::Kind kind) { for (auto &bind : bindings) { - if (bind.set.find (ident) != bind.set.cend () && bind.kind == kind) + if (bind.idents.find (ident.as_string ()) != bind.idents.cend () + && bind.kind == kind) { return true; } @@ -60,20 +61,66 @@ BindingLayer::is_or_bound (Identifier ident) } void -BindingLayer::insert_ident (Identifier ident) +BindingLayer::insert_ident (std::string ident, location_t locus, bool is_ref, + bool is_mut) { - bindings.back ().set.insert (ident); + bindings.back ().idents.emplace ( + std::move (ident), std::make_pair (locus, IdentifierMode (is_ref, is_mut))); } void BindingLayer::merge () { - auto last_binding = bindings.back (); + auto last_binding = std::move (bindings.back ()); bindings.pop_back (); - for (auto &value : last_binding.set) + + if (bindings.back ().has_expected_bindings) + { + for (auto &value : bindings.back ().idents) + { + auto ident = value.first; + if (last_binding.idents.find (ident) == last_binding.idents.end ()) + { + location_t locus = value.second.first; + rust_error_at (locus, ErrorCode::E0408, + "variable %qs is not bound in all patterns", + ident.c_str ()); + } + } + } + + for (auto &value : last_binding.idents) { - bindings.back ().set.insert (value); + auto res = bindings.back ().idents.emplace (value); + if (res.second) + { + if (bindings.back ().has_expected_bindings) + { + auto &ident = value.first; + location_t locus = value.second.first; + rust_error_at (locus, ErrorCode::E0408, + "variable %qs is not bound in all patterns", + ident.c_str ()); + } + } + else + { + auto this_mode = value.second.second; + auto other_mode = res.first->second.second; + if (this_mode != other_mode) + { + auto &ident = value.first; + location_t locus = value.second.first; + rust_error_at (locus, ErrorCode::E0409, + "variable %qs is bound inconsistently across " + "pattern alternatives", + ident.c_str ()); + } + } } + + if (bindings.back ().kind == Binding::Kind::Or) + bindings.back ().has_expected_bindings = true; } BindingSource @@ -82,8 +129,63 @@ BindingLayer::get_source () const return source; } +Resolver::CanonicalPath +CanonicalPathRecordCrateRoot::as_path (const NameResolutionContext &) +{ + auto ret = Resolver::CanonicalPath::new_seg (node_id, seg); + ret.set_crate_num (crate_num); + return ret; +} + +Resolver::CanonicalPath +CanonicalPathRecordNormal::as_path (const NameResolutionContext &ctx) +{ + auto parent_path = get_parent ().as_path (ctx); + return parent_path.append (Resolver::CanonicalPath::new_seg (node_id, seg)); +} + +Resolver::CanonicalPath +CanonicalPathRecordLookup::as_path (const NameResolutionContext &ctx) +{ + if (!cache) + { + auto res = ctx.lookup (lookup_id).and_then ( + [&ctx] (NodeId id) { return ctx.canonical_ctx.get_record_opt (id); }); + + if (!res) + { + // HACK: use a dummy value + // this should bring us roughly to parity with nr1.0 + // since nr1.0 doesn't seem to handle canonical paths for generics + // quite right anyways + return Resolver::CanonicalPath::new_seg (UNKNOWN_NODEID, "XXX"); + } + + cache = res.value (); + } + return cache->as_path (ctx); +} + +Resolver::CanonicalPath +CanonicalPathRecordImpl::as_path (const NameResolutionContext &ctx) +{ + auto parent_path = get_parent ().as_path (ctx); + return parent_path.append ( + Resolver::CanonicalPath::inherent_impl_seg (impl_id, + type_record.as_path (ctx))); +} + +Resolver::CanonicalPath +CanonicalPathRecordTraitImpl::as_path (const NameResolutionContext &ctx) +{ + auto parent_path = get_parent ().as_path (ctx); + return parent_path.append ( + Resolver::CanonicalPath::trait_impl_projection_seg ( + impl_id, trait_path_record.as_path (ctx), type_record.as_path (ctx))); +} + NameResolutionContext::NameResolutionContext () - : mappings (Analysis::Mappings::get ()) + : mappings (Analysis::Mappings::get ()), canonical_ctx (*this) {} tl::expected diff --git a/gcc/rust/resolve/rust-name-resolution-context.h b/gcc/rust/resolve/rust-name-resolution-context.h index 19ba75076869..558b3cab6647 100644 --- a/gcc/rust/resolve/rust-name-resolution-context.h +++ b/gcc/rust/resolve/rust-name-resolution-context.h @@ -24,6 +24,7 @@ #include "rust-hir-map.h" #include "rust-rib.h" #include "rust-stacked-contexts.h" +#include "rust-item.h" namespace Rust { namespace Resolver2_0 { @@ -157,6 +158,22 @@ class Definition NodeId id; }; +struct IdentifierMode +{ + bool is_ref; + bool is_mut; + + IdentifierMode (bool is_ref, bool is_mut) : is_ref (is_ref), is_mut (is_mut) + {} + + bool operator== (const IdentifierMode &other) + { + return other.is_ref == is_ref && other.is_mut == is_mut; + } + + bool operator!= (const IdentifierMode &other) { return !(*this == other); } +}; + struct Binding { enum class Kind @@ -165,9 +182,12 @@ struct Binding Or, } kind; - std::unordered_set set; + // used to check the correctness of or-bindings + bool has_expected_bindings; - Binding (Binding::Kind kind) : kind (kind) {} + std::unordered_map> idents; + + Binding (Binding::Kind kind) : kind (kind), has_expected_bindings (false) {} }; /** @@ -177,6 +197,8 @@ enum class BindingSource { Match, Let, + IfLet, + WhileLet, For, /* Closure param or function param */ Param @@ -206,13 +228,256 @@ class BindingLayer */ bool is_or_bound (Identifier ident); - void insert_ident (Identifier ident); + void insert_ident (std::string ident, location_t locus, bool is_ref, + bool is_mut); void merge (); BindingSource get_source () const; }; +class NameResolutionContext; +/* + * Used to handle canonical paths + * Similar to ForeverStack, but namespace independent and more specialized + */ +class CanonicalPathRecord +{ +public: + virtual Resolver::CanonicalPath as_path (const NameResolutionContext &) = 0; + + virtual bool is_root () const = 0; + + virtual ~CanonicalPathRecord () = default; +}; + +class CanonicalPathRecordWithParent : public CanonicalPathRecord +{ +public: + CanonicalPathRecordWithParent (CanonicalPathRecord &parent) : parent (&parent) + {} + + CanonicalPathRecord &get_parent () { return *parent; } + + bool is_root () const override final { return false; } + +private: + CanonicalPathRecord *parent; +}; + +class CanonicalPathRecordCrateRoot : public CanonicalPathRecord +{ +public: + CanonicalPathRecordCrateRoot (NodeId node_id, std::string seg) + : node_id (node_id), seg (std::move (seg)) + { + rust_assert (Analysis::Mappings::get ().node_is_crate (node_id)); + crate_num = Analysis::Mappings::get ().lookup_crate_num (node_id).value (); + } + + Resolver::CanonicalPath as_path (const NameResolutionContext &) override; + + bool is_root () const override final { return true; } + +private: + NodeId node_id; + CrateNum crate_num; + std::string seg; +}; + +class CanonicalPathRecordNormal : public CanonicalPathRecordWithParent +{ +public: + CanonicalPathRecordNormal (CanonicalPathRecord &parent, NodeId node_id, + std::string seg) + : CanonicalPathRecordWithParent (parent), node_id (node_id), + seg (std::move (seg)) + { + rust_assert (!Analysis::Mappings::get ().node_is_crate (node_id)); + } + + Resolver::CanonicalPath as_path (const NameResolutionContext &) override; + +private: + NodeId node_id; + std::string seg; +}; + +class CanonicalPathRecordLookup : public CanonicalPathRecord +{ +public: + CanonicalPathRecordLookup (NodeId lookup_id) + : lookup_id (lookup_id), cache (nullptr) + {} + + Resolver::CanonicalPath as_path (const NameResolutionContext &) override; + + bool is_root () const override final { return true; } + +private: + NodeId lookup_id; + CanonicalPathRecord *cache; +}; + +class CanonicalPathRecordImpl : public CanonicalPathRecordWithParent +{ +public: + CanonicalPathRecordImpl (CanonicalPathRecord &parent, NodeId impl_id, + NodeId type_id) + : CanonicalPathRecordWithParent (parent), impl_id (impl_id), + type_record (type_id) + {} + + Resolver::CanonicalPath as_path (const NameResolutionContext &) override; + +private: + NodeId impl_id; + CanonicalPathRecordLookup type_record; +}; + +class CanonicalPathRecordTraitImpl : public CanonicalPathRecordWithParent +{ +public: + CanonicalPathRecordTraitImpl (CanonicalPathRecord &parent, NodeId impl_id, + NodeId type_id, NodeId trait_path_id) + : CanonicalPathRecordWithParent (parent), impl_id (impl_id), + type_record (type_id), trait_path_record (trait_path_id) + {} + + Resolver::CanonicalPath as_path (const NameResolutionContext &) override; + +private: + NodeId impl_id; + CanonicalPathRecordLookup type_record; + CanonicalPathRecordLookup trait_path_record; +}; + +class CanonicalPathCtx +{ +public: + CanonicalPathCtx (const NameResolutionContext &ctx) + : current_record (nullptr), nr_ctx (&ctx) + {} + + Resolver::CanonicalPath get_path (NodeId id) const + { + return get_record (id).as_path (*nr_ctx); + } + + CanonicalPathRecord &get_record (NodeId id) const + { + auto it = records.find (id); + rust_assert (it != records.end ()); + return *it->second; + } + + tl::optional get_record_opt (NodeId id) const + { + auto it = records.find (id); + if (it == records.end ()) + return tl::nullopt; + else + return it->second.get (); + } + + void insert_record (NodeId id, const Identifier &ident) + { + insert_record (id, ident.as_string ()); + } + + void insert_record (NodeId id, std::string seg) + { + rust_assert (current_record != nullptr); + + auto it = records.find (id); + if (it == records.end ()) + { + auto record = new CanonicalPathRecordNormal (*current_record, id, + std::move (seg)); + bool ok + = records.emplace (id, std::unique_ptr (record)) + .second; + rust_assert (ok); + } + } + + template void scope (NodeId id, const Identifier &ident, F &&f) + { + scope (id, ident.as_string (), std::forward (f)); + } + + template void scope (NodeId id, std::string seg, F &&f) + { + rust_assert (current_record != nullptr); + + scope_inner (id, std::forward (f), [this, id, &seg] () { + return new CanonicalPathRecordNormal (*current_record, id, + std::move (seg)); + }); + } + + template void scope_impl (AST::InherentImpl &impl, F &&f) + { + rust_assert (current_record != nullptr); + + NodeId id = impl.get_node_id (); + scope_inner (id, std::forward (f), [this, id, &impl] () { + return new CanonicalPathRecordImpl (*current_record, id, + impl.get_type ().get_node_id ()); + }); + } + + template void scope_impl (AST::TraitImpl &impl, F &&f) + { + rust_assert (current_record != nullptr); + + NodeId id = impl.get_node_id (); + scope_inner (id, std::forward (f), [this, id, &impl] () { + return new CanonicalPathRecordTraitImpl ( + *current_record, id, impl.get_type ().get_node_id (), + impl.get_trait_path ().get_node_id ()); + }); + } + + template + void scope_crate (NodeId node_id, std::string crate_name, F &&f) + { + scope_inner (node_id, std::forward (f), [node_id, &crate_name] () { + return new CanonicalPathRecordCrateRoot (node_id, std::move (crate_name)); + }); + } + +private: + template + void scope_inner (NodeId id, FCallback &&f_callback, FCreate &&f_create) + { + auto it = records.find (id); + if (it == records.end ()) + { + CanonicalPathRecord *record = std::forward (f_create) (); + it = records.emplace (id, std::unique_ptr (record)) + .first; + } + + rust_assert (it->second->is_root () + || &static_cast (*it->second) + .get_parent () + == current_record); + + CanonicalPathRecord *stash = it->second.get (); + std::swap (stash, current_record); + + std::forward (f_callback) (); + + std::swap (stash, current_record); + } + + std::unordered_map> records; + CanonicalPathRecord *current_record; + + const NameResolutionContext *nr_ctx; +}; + // Now our resolver, which keeps track of all the `ForeverStack`s we could want class NameResolutionContext { @@ -271,16 +536,22 @@ class NameResolutionContext Analysis::Mappings &mappings; StackedContexts bindings; + CanonicalPathCtx canonical_ctx; + // TODO: Rename // TODO: Use newtype pattern for Usage and Definition void map_usage (Usage usage, Definition definition); tl::optional lookup (NodeId usage) const; + Resolver::CanonicalPath to_canonical_path (NodeId id) const + { + return canonical_ctx.get_path (id); + } + template tl::optional - resolve_path (const std::vector &segments, - bool has_opening_scope_resolution, + resolve_path (const std::vector &segments, ResolutionMode mode, std::vector &collect_errors, Namespace ns) { std::function insert_segment_resolution @@ -292,17 +563,17 @@ class NameResolutionContext switch (ns) { case Namespace::Values: - return values.resolve_path (segments, has_opening_scope_resolution, - insert_segment_resolution, collect_errors); + return values.resolve_path (segments, mode, insert_segment_resolution, + collect_errors); case Namespace::Types: - return types.resolve_path (segments, has_opening_scope_resolution, - insert_segment_resolution, collect_errors); + return types.resolve_path (segments, mode, insert_segment_resolution, + collect_errors); case Namespace::Macros: - return macros.resolve_path (segments, has_opening_scope_resolution, - insert_segment_resolution, collect_errors); + return macros.resolve_path (segments, mode, insert_segment_resolution, + collect_errors); case Namespace::Labels: - return labels.resolve_path (segments, has_opening_scope_resolution, - insert_segment_resolution, collect_errors); + return labels.resolve_path (segments, mode, insert_segment_resolution, + collect_errors); default: rust_unreachable (); } @@ -310,8 +581,7 @@ class NameResolutionContext template tl::optional - resolve_path (const std::vector &segments, - bool has_opening_scope_resolution, + resolve_path (const std::vector &segments, ResolutionMode mode, tl::optional &> collect_errors, Namespace ns_first, Args... ns_args) { @@ -320,8 +590,7 @@ class NameResolutionContext for (auto ns : namespaces) { std::vector collect_errors_inner; - if (auto ret = resolve_path (segments, has_opening_scope_resolution, - collect_errors_inner, ns)) + if (auto ret = resolve_path (segments, mode, collect_errors_inner, ns)) return ret; if (!collect_errors_inner.empty ()) { @@ -343,52 +612,68 @@ class NameResolutionContext return tl::nullopt; } - template + template tl::optional - resolve_path (const AST::SimplePath &path, + resolve_path (const std::vector &path_segments, + bool has_opening_scope_resolution, tl::optional &> collect_errors, Namespace ns_first, Args... ns_args) { - return resolve_path (path.get_segments (), - path.has_opening_scope_resolution (), collect_errors, - ns_first, ns_args...); + auto mode = ResolutionMode::Normal; + if (has_opening_scope_resolution) + { + if (get_rust_edition () == Edition::E2015) + mode = ResolutionMode::FromRoot; + else + mode = ResolutionMode::FromExtern; + } + return resolve_path (path_segments, mode, collect_errors, ns_first, + ns_args...); } - template + template tl::optional - resolve_path (const AST::PathInExpression &path, - tl::optional &> collect_errors, - Namespace ns_first, Args... ns_args) + resolve_path (const std::vector &path_segments, + bool has_opening_scope_resolution, Namespace ns_first, + Args... ns_args) { - return resolve_path (path.get_segments (), path.opening_scope_resolution (), - collect_errors, ns_first, ns_args...); + return resolve_path (path_segments, has_opening_scope_resolution, + tl::nullopt, ns_first, ns_args...); } - template + template tl::optional - resolve_path (const AST::TypePath &path, - tl::optional &> collect_errors, + resolve_path (const std::vector &path_segments, ResolutionMode mode, Namespace ns_first, Args... ns_args) + { + return resolve_path (path_segments, mode, tl::nullopt, ns_first, + ns_args...); + } + + template + tl::optional resolve_path (const AST::SimplePath &path, + Args &&...args) { return resolve_path (path.get_segments (), - path.has_opening_scope_resolution_op (), - collect_errors, ns_first, ns_args...); + path.has_opening_scope_resolution (), + std::forward (args)...); } - template - tl::optional resolve_path (const P &path, Namespace ns_first, - Args... ns_args) + template + tl::optional resolve_path (const AST::PathInExpression &path, + Args &&...args) { - return resolve_path (path, tl::nullopt, ns_first, ns_args...); + return resolve_path (path.get_segments (), path.opening_scope_resolution (), + std::forward (args)...); } - template - tl::optional - resolve_path (const P &path_segments, bool has_opening_scope_resolution, - Namespace ns_first, Args... ns_args) + template + tl::optional resolve_path (const AST::TypePath &path, + Args &&...args) { - return resolve_path (path_segments, has_opening_scope_resolution, - tl::nullopt, ns_first, ns_args...); + return resolve_path (path.get_segments (), + path.has_opening_scope_resolution_op (), + std::forward (args)...); } private: diff --git a/gcc/rust/resolve/rust-rib.h b/gcc/rust/resolve/rust-rib.h index c498328a8087..140c991e2ab5 100644 --- a/gcc/rust/resolve/rust-rib.h +++ b/gcc/rust/resolve/rust-rib.h @@ -188,6 +188,8 @@ class Rib * restriction that you cannot `use` items from the Prelude */ Prelude, + /* Generic rib, used to store generics */ + Generics, } kind; static std::string kind_to_string (Rib::Kind kind) @@ -214,9 +216,13 @@ class Rib return "Forward type param ban"; case Rib::Kind::ConstParamType: return "Const Param Type"; - default: - rust_unreachable (); + case Kind::Prelude: + return "Prelude"; + case Kind::Generics: + return "Generics"; } + + rust_unreachable (); } Rib (Kind kind); diff --git a/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc b/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc index 2f036fe40b3f..0930f966e202 100644 --- a/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc +++ b/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc @@ -95,41 +95,17 @@ TopLevel::go (AST::Crate &crate) // times in a row in a fixed-point fashion, so it would make the code // responsible for this ugly and perfom a lot of error checking. - for (auto &item : crate.items) - item->accept_vis (*this); + visit (crate); } void TopLevel::visit (AST::Module &module) { - insert_or_error_out (module.get_name (), module, Namespace::Types); - - // Parse the module's items if they haven't been expanded and the file - // should be parsed (i.e isn't hidden behind an untrue or impossible cfg - // directive - // TODO: make sure this is right - // TODO: avoid loading items if cfg attributes are present? - // might not be needed if this runs after early resolution? - // This was copied from the old early resolver method - // 'accumulate_escaped_macros' - if (module.get_kind () == AST::Module::UNLOADED) - { - module.load_items (); - - // If the module was previously unloaded, then we don't want to visit it - // this time around as the CfgStrip hasn't run on its inner items yet. - // Skip it for now, mark the visitor as dirty and try again - - dirty = true; - - return; - } - DefaultResolver::visit (module); - if (Analysis::Mappings::get ().lookup_ast_module (module.get_node_id ()) + if (Analysis::Mappings::get ().lookup_glob_container (module.get_node_id ()) == tl::nullopt) - Analysis::Mappings::get ().insert_ast_module (&module); + Analysis::Mappings::get ().insert_glob_container (&module); } void @@ -141,33 +117,10 @@ TopLevel::visit (AST::Trait &trait) } void -TopLevel::visit (AST::InherentImpl &impl) -{ - auto inner_fn = [this, &impl] () { - insert_or_error_out (Identifier ("Self", impl.get_type ().get_locus ()), - impl.get_type (), Namespace::Types); - - // We do want to visit with the default visitor instead of default resolver - // because we don't want to insert the scope twice. - AST::DefaultASTVisitor::visit (impl); - }; - - ctx.scoped (Rib::Kind::TraitOrImpl, impl.get_node_id (), inner_fn); -} - -void -TopLevel::visit (AST::TraitImpl &impl) +TopLevel::maybe_insert_big_self (AST::Impl &impl) { - auto inner_fn = [this, &impl] () { - insert_or_error_out (Identifier ("Self", impl.get_type ().get_locus ()), - impl.get_type (), Namespace::Types); - - // We do want to visit using the default visitor instead of default resolver - // because we don't want to insert the scope twice. - AST::DefaultASTVisitor::visit (impl); - }; - - ctx.scoped (Rib::Kind::TraitOrImpl, impl.get_node_id (), inner_fn); + insert_or_error_out (Identifier ("Self", impl.get_type ().get_locus ()), + impl.get_type (), Namespace::Types); } void @@ -197,19 +150,10 @@ insert_macros (std::vector ¯os, NameResolutionContext &ctx) } void -TopLevel::visit (AST::ExternCrate &crate) +TopLevel::visit_extern_crate (AST::ExternCrate &extern_crate, AST::Crate &crate, + CrateNum num) { auto &mappings = Analysis::Mappings::get (); - auto num_opt = mappings.lookup_crate_name (crate.get_referenced_crate ()); - - if (!num_opt) - { - rust_error_at (crate.get_locus (), "unknown crate %qs", - crate.get_referenced_crate ().c_str ()); - return; - } - - CrateNum num = *num_opt; auto attribute_macros = mappings.lookup_attribute_proc_macros (num); @@ -217,34 +161,27 @@ TopLevel::visit (AST::ExternCrate &crate) auto derive_macros = mappings.lookup_derive_proc_macros (num); - auto sub_visitor = [&] () { - // TODO: Find a way to keep this part clean without the double dispatch. - if (derive_macros.has_value ()) - { - insert_macros (derive_macros.value (), ctx); - for (auto ¯o : derive_macros.value ()) - mappings.insert_derive_proc_macro_def (macro); - } - if (attribute_macros.has_value ()) - { - insert_macros (attribute_macros.value (), ctx); - for (auto ¯o : attribute_macros.value ()) - mappings.insert_attribute_proc_macro_def (macro); - } - if (bang_macros.has_value ()) - { - insert_macros (bang_macros.value (), ctx); - for (auto ¯o : bang_macros.value ()) - mappings.insert_bang_proc_macro_def (macro); - } - }; + // TODO: Find a way to keep this part clean without the double dispatch. + if (derive_macros.has_value ()) + { + insert_macros (derive_macros.value (), ctx); + for (auto ¯o : derive_macros.value ()) + mappings.insert_derive_proc_macro_def (macro); + } + if (attribute_macros.has_value ()) + { + insert_macros (attribute_macros.value (), ctx); + for (auto ¯o : attribute_macros.value ()) + mappings.insert_attribute_proc_macro_def (macro); + } + if (bang_macros.has_value ()) + { + insert_macros (bang_macros.value (), ctx); + for (auto ¯o : bang_macros.value ()) + mappings.insert_bang_proc_macro_def (macro); + } - if (crate.has_as_clause ()) - ctx.scoped (Rib::Kind::Module, crate.get_node_id (), sub_visitor, - crate.get_as_clause ()); - else - ctx.scoped (Rib::Kind::Module, crate.get_node_id (), sub_visitor, - crate.get_referenced_crate ()); + visit (crate); } static bool @@ -321,14 +258,7 @@ TopLevel::visit (AST::ExternalStaticItem &static_item) void TopLevel::visit (AST::StructStruct &struct_item) { - auto generic_vis = [this, &struct_item] () { - for (auto &g : struct_item.get_generic_params ()) - { - g->accept_vis (*this); - } - }; - - ctx.scoped (Rib::Kind::Item, struct_item.get_node_id (), generic_vis); + DefaultResolver::visit (struct_item); insert_or_error_out (struct_item.get_struct_name (), struct_item, Namespace::Types); @@ -374,24 +304,32 @@ void TopLevel::visit (AST::EnumItem &variant) { insert_enum_variant_or_error_out (variant.get_identifier (), variant); + + DefaultResolver::visit (variant); } void TopLevel::visit (AST::EnumItemTuple &variant) { insert_enum_variant_or_error_out (variant.get_identifier (), variant); + + DefaultResolver::visit (variant); } void TopLevel::visit (AST::EnumItemStruct &variant) { insert_enum_variant_or_error_out (variant.get_identifier (), variant); + + DefaultResolver::visit (variant); } void TopLevel::visit (AST::EnumItemDiscriminant &variant) { insert_or_error_out (variant.get_identifier (), variant, Namespace::Types); + + DefaultResolver::visit (variant); } void @@ -401,6 +339,13 @@ TopLevel::visit (AST::Enum &enum_item) Namespace::Types); DefaultResolver::visit (enum_item); + + // Since enums can be containers for imports, we need to insert them like we + // do for modules + if (Analysis::Mappings::get ().lookup_glob_container ( + enum_item.get_node_id ()) + == tl::nullopt) + Analysis::Mappings::get ().insert_glob_container (&enum_item); } void @@ -430,21 +375,18 @@ TopLevel::visit (AST::TypeAlias &type_item) DefaultResolver::visit (type_item); } -static void -flatten_rebind ( +static void flatten_rebind ( const AST::UseTreeRebind &glob, std::vector> &rebind_paths); -static void -flatten_list ( +static void flatten_list ( const AST::UseTreeList &glob, std::vector &paths, std::vector &glob_paths, std::vector> &rebind_paths, NameResolutionContext &ctx); -static void -flatten_glob (const AST::UseTreeGlob &glob, - std::vector &glob_paths, - NameResolutionContext &ctx); +static void flatten_glob (const AST::UseTreeGlob &glob, + std::vector &glob_paths, + NameResolutionContext &ctx); static void flatten ( @@ -455,17 +397,20 @@ flatten ( { switch (tree->get_kind ()) { - case AST::UseTree::Rebind: { + case AST::UseTree::Rebind: + { auto rebind = static_cast (tree); flatten_rebind (*rebind, rebind_paths); break; } - case AST::UseTree::List: { + case AST::UseTree::List: + { auto list = static_cast (tree); flatten_list (*list, paths, glob_paths, rebind_paths, ctx); break; } - case AST::UseTree::Glob: { + case AST::UseTree::Glob: + { auto glob = static_cast (tree); flatten_glob (*glob, glob_paths, ctx); break; diff --git a/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.h b/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.h index 3ff37eda16d1..8d3da92961ad 100644 --- a/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.h +++ b/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.h @@ -160,8 +160,7 @@ class TopLevel : public DefaultResolver void visit (AST::Module &module) override; void visit (AST::Trait &trait) override; - void visit (AST::InherentImpl &impl) override; - void visit (AST::TraitImpl &impl) override; + void maybe_insert_big_self (AST::Impl &impl) override; void visit (AST::TraitItemType &trait_item) override; void visit (AST::MacroRulesDefinition ¯o) override; void visit (AST::Function &function) override; @@ -177,7 +176,7 @@ class TopLevel : public DefaultResolver void visit (AST::Union &union_item) override; void visit (AST::ConstantItem &const_item) override; void visit (AST::TypeAlias &type_item) override; - void visit (AST::ExternCrate &crate) override; + void visit_extern_crate (AST::ExternCrate &, AST::Crate &, CrateNum) override; void visit (AST::TypeParam &type_param) override; void visit (AST::ConstGenericParam &const_param) override; diff --git a/gcc/rust/rust-attribs.cc b/gcc/rust/rust-attribs.cc index 74cb2aff90fc..a98c1fab0403 100644 --- a/gcc/rust/rust-attribs.cc +++ b/gcc/rust/rust-attribs.cc @@ -38,35 +38,27 @@ along with GCC; see the file COPYING3. If not see * future. */ -extern const attribute_spec grs_langhook_common_attribute_table[]; +extern const struct scoped_attribute_specs grs_langhook_gnu_attribute_table; +extern const struct scoped_attribute_specs grs_langhook_common_attribute_table; /* Internal attribute handlers for built-in functions. */ -static tree -handle_noreturn_attribute (tree *, tree, tree, int, bool *); -static tree -handle_leaf_attribute (tree *, tree, tree, int, bool *); -static tree -handle_const_attribute (tree *, tree, tree, int, bool *); -static tree -handle_malloc_attribute (tree *, tree, tree, int, bool *); -static tree -handle_pure_attribute (tree *, tree, tree, int, bool *); -static tree -handle_novops_attribute (tree *, tree, tree, int, bool *); -static tree -handle_nonnull_attribute (tree *, tree, tree, int, bool *); -static tree -handle_nothrow_attribute (tree *, tree, tree, int, bool *); -static tree -handle_type_generic_attribute (tree *, tree, tree, int, bool *); -static tree -handle_transaction_pure_attribute (tree *, tree, tree, int, bool *); -static tree -handle_returns_twice_attribute (tree *, tree, tree, int, bool *); -static tree -handle_fnspec_attribute (tree *, tree, tree, int, bool *); -static tree -handle_omp_declare_simd_attribute (tree *, tree, tree, int, bool *); +static tree handle_noreturn_attribute (tree *, tree, tree, int, bool *); +static tree handle_leaf_attribute (tree *, tree, tree, int, bool *); +static tree handle_const_attribute (tree *, tree, tree, int, bool *); +static tree handle_malloc_attribute (tree *, tree, tree, int, bool *); +static tree handle_pure_attribute (tree *, tree, tree, int, bool *); +static tree handle_novops_attribute (tree *, tree, tree, int, bool *); +static tree handle_nonnull_attribute (tree *, tree, tree, int, bool *); +static tree handle_nothrow_attribute (tree *, tree, tree, int, bool *); +static tree handle_type_generic_attribute (tree *, tree, tree, int, bool *); +static tree handle_transaction_pure_attribute (tree *, tree, tree, int, bool *); +static tree handle_returns_twice_attribute (tree *, tree, tree, int, bool *); +static tree handle_fnspec_attribute (tree *, tree, tree, int, bool *); +static tree handle_omp_declare_simd_attribute (tree *, tree, tree, int, bool *); + +/* Rust attribute handlers for user defined attributes. */ +static tree handle_cold_attribute (tree *, tree, tree, int, bool *); +static tree handle_hot_attribute (tree *, tree, tree, int, bool *); /* Helper to define attribute exclusions. */ #define ATTR_EXCL(name, function, type, variable) \ @@ -74,6 +66,10 @@ handle_omp_declare_simd_attribute (tree *, tree, tree, int, bool *); name, function, type, variable \ } +// clang-format off +// Disabling clang-format because it insists in having several ATTR_EXCL() on a +// single line. + static const struct attribute_spec::exclusions attr_noreturn_exclusions[] = { // ATTR_EXCL ("alloc_size", true, true, true), ATTR_EXCL ("const", true, true, true), @@ -89,11 +85,22 @@ static const struct attribute_spec::exclusions attr_returns_twice_exclusions[] ATTR_EXCL (NULL, false, false, false), }; +extern const struct attribute_spec::exclusions attr_cold_hot_exclusions[] = { + + ATTR_EXCL ("cold", true, true, true), + ATTR_EXCL ("hot", true, true, true), + ATTR_EXCL (NULL, false, false, false) +}; + static const struct attribute_spec::exclusions attr_const_pure_exclusions[] = { // ATTR_EXCL ("alloc_size", true, true, true), ATTR_EXCL ("const", true, true, true), ATTR_EXCL ("noreturn", true, true, true), - ATTR_EXCL ("pure", true, true, true), ATTR_EXCL (NULL, false, false, false)}; + ATTR_EXCL ("pure", true, true, true), + ATTR_EXCL (NULL, false, false, false) +}; + +// clang-format on /* Helper to define an attribute. */ #define ATTR_SPEC(name, min_len, max_len, decl_req, type_req, fn_type_req, \ @@ -105,7 +112,7 @@ static const struct attribute_spec::exclusions attr_const_pure_exclusions[] = { /* Table of machine-independent attributes. For internal use (marking of built-ins) only. */ -const attribute_spec grs_langhook_common_attribute_table[] = { +static const attribute_spec grs_langhook_common_attributes[] = { ATTR_SPEC ("noreturn", 0, 0, true, false, false, false, handle_noreturn_attribute, attr_noreturn_exclusions), ATTR_SPEC ("leaf", 0, 0, true, false, false, false, handle_leaf_attribute, @@ -132,9 +139,21 @@ const attribute_spec grs_langhook_common_attribute_table[] = { NULL), ATTR_SPEC ("omp declare simd", 0, -1, true, false, false, false, handle_omp_declare_simd_attribute, NULL), - ATTR_SPEC (NULL, 0, 0, false, false, false, false, NULL, NULL), }; +const scoped_attribute_specs grs_langhook_common_attribute_table + = {"gnu", {grs_langhook_common_attributes}}; + +static const attribute_spec grs_langhook_gnu_attributes[] = { + ATTR_SPEC ("cold", 0, 0, true, false, false, false, handle_cold_attribute, + attr_cold_hot_exclusions), + ATTR_SPEC ("hot", 0, 0, true, false, false, false, handle_hot_attribute, + attr_cold_hot_exclusions), +}; + +const scoped_attribute_specs grs_langhook_gnu_attribute_table + = {"gnu", {grs_langhook_gnu_attributes}}; + /* Built-in attribute handlers. These functions take the arguments: (tree *node, tree name, tree args, int flags, bool *no_add_attrs) */ @@ -204,7 +223,7 @@ handle_const_attribute (tree *node, tree, tree, int, bool *) /* Handle a "malloc" attribute; arguments as in struct attribute_spec.handler. */ -tree +static tree handle_malloc_attribute (tree *node, tree, tree, int, bool *) { gcc_assert (TREE_CODE (*node) == FUNCTION_DECL @@ -217,9 +236,14 @@ handle_malloc_attribute (tree *node, tree, tree, int, bool *) struct attribute_spec.handler. */ static tree -handle_pure_attribute (tree *node, tree, tree, int, bool *) +handle_pure_attribute (tree *node, tree name, tree, int, bool *no_add_attrs) { - gcc_assert (TREE_CODE (*node) == FUNCTION_DECL); + if (TREE_CODE (*node) != FUNCTION_DECL) + { + warning (OPT_Wattributes, "%qE attribute ignored", name); + *no_add_attrs = true; + } + DECL_PURE_P (*node) = 1; return NULL_TREE; } @@ -228,9 +252,14 @@ handle_pure_attribute (tree *node, tree, tree, int, bool *) struct attribute_spec.handler. */ static tree -handle_novops_attribute (tree *node, tree, tree, int, bool *) +handle_novops_attribute (tree *node, tree name, tree, int, bool *no_add_attrs) { - gcc_assert (TREE_CODE (*node) == FUNCTION_DECL); + if (TREE_CODE (*node) != FUNCTION_DECL) + { + warning (OPT_Wattributes, "%qE attribute ignored", name); + *no_add_attrs = true; + } + DECL_IS_NOVOPS (*node) = 1; return NULL_TREE; } @@ -301,9 +330,14 @@ handle_nonnull_attribute (tree *node, tree, tree args, int, bool *) struct attribute_spec.handler. */ static tree -handle_nothrow_attribute (tree *node, tree, tree, int, bool *) +handle_nothrow_attribute (tree *node, tree name, tree, int, bool *no_add_attrs) { - gcc_assert (TREE_CODE (*node) == FUNCTION_DECL); + if (TREE_CODE (*node) != FUNCTION_DECL) + { + warning (OPT_Wattributes, "%qE attribute ignored", name); + *no_add_attrs = true; + } + TREE_NOTHROW (*node) = 1; return NULL_TREE; } @@ -339,9 +373,14 @@ handle_transaction_pure_attribute (tree *node, tree, tree, int, bool *) struct attribute_spec.handler. */ static tree -handle_returns_twice_attribute (tree *node, tree, tree, int, bool *) +handle_returns_twice_attribute (tree *node, tree name, tree, int, + bool *no_add_attrs) { - gcc_assert (TREE_CODE (*node) == FUNCTION_DECL); + if (TREE_CODE (*node) != FUNCTION_DECL) + { + warning (OPT_Wattributes, "%qE attribute ignored", name); + *no_add_attrs = true; + } DECL_IS_RETURNS_TWICE (*node) = 1; @@ -351,7 +390,7 @@ handle_returns_twice_attribute (tree *node, tree, tree, int, bool *) /* Handle a "fn spec" attribute; arguments as in struct attribute_spec.handler. */ -tree +static tree handle_fnspec_attribute (tree *, tree, tree args, int, bool *) { gcc_assert (args && TREE_CODE (TREE_VALUE (args)) == STRING_CST @@ -362,9 +401,46 @@ handle_fnspec_attribute (tree *, tree, tree args, int, bool *) /* Handle an "omp declare simd" attribute; arguments as in struct attribute_spec.handler. */ -tree -handle_omp_declare_simd_attribute (tree *node, tree, tree, int, bool *) +static tree +handle_omp_declare_simd_attribute (tree *node, tree name, tree, int, + bool *no_add_attrs) { - gcc_assert (TREE_CODE (*node) == FUNCTION_DECL); + if (TREE_CODE (*node) != FUNCTION_DECL) + { + warning (OPT_Wattributes, "%qE attribute ignored", name); + *no_add_attrs = true; + } + + return NULL_TREE; +} + +/* Language specific attribute handlers. + These functions take the arguments: + (tree *node, tree name, tree args, int flags, bool *no_add_attrs) */ + +/* Handle a "cold" and attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_cold_attribute (tree *node, tree name, tree, int, bool *no_add_attrs) +{ + if (TREE_CODE (*node) != FUNCTION_DECL) + { + warning (OPT_Wattributes, "%qE attribute ignored", name); + *no_add_attrs = true; + } + + return NULL_TREE; +} + +static tree +handle_hot_attribute (tree *node, tree name, tree, int, bool *no_add_attrs) +{ + if (TREE_CODE (*node) != FUNCTION_DECL) + { + warning (OPT_Wattributes, "%qE attribute ignored", name); + *no_add_attrs = true; + } + return NULL_TREE; } diff --git a/gcc/rust/rust-backend.h b/gcc/rust/rust-backend.h index 414799edefee..8a77d96de835 100644 --- a/gcc/rust/rust-backend.h +++ b/gcc/rust/rust-backend.h @@ -27,6 +27,8 @@ #include "rust-linemap.h" #include "rust-diagnostics.h" #include "util/rust-operators.h" +#include "util/rust-ggc.h" +#include "util/optional.h" #include "tree.h" #include "rust-gcc.h" @@ -42,69 +44,60 @@ class Bvariable; namespace Backend { -void -init (); +namespace GGC { + +using Rust::GGC::Ident; + +} // namespace GGC + +void init (); // Name/type/location. Used for function parameters, struct fields, // interface methods. struct typed_identifier { - std::string name; + GGC::Ident name; tree type; location_t location; - typed_identifier () : name (), type (NULL_TREE), location (UNKNOWN_LOCATION) - {} - - typed_identifier (const std::string &a_name, tree a_type, - location_t a_location) + typed_identifier (GGC::Ident a_name, tree a_type, location_t a_location) : name (a_name), type (a_type), location (a_location) {} }; // debug void debug (tree); -void -debug (Bvariable *); +void debug (Bvariable *); -tree -get_identifier_node (const std::string &str); +tree get_identifier_node (const std::string &str); // Types. // Get the wchar type -tree -wchar_type (); +tree wchar_type (); // Get the Host pointer size in bits -int -get_pointer_size (); +int get_pointer_size (); // Get the raw str type const char* -tree -raw_str_type (); +tree raw_str_type (); // Get an unnamed integer type with the given signedness and number // of bits. -tree -integer_type (bool is_unsigned, int bits); +tree integer_type (bool is_unsigned, int bits); // Get an unnamed floating point type with the given number of bits // (32 or 64). -tree -float_type (int bits); +tree float_type (int bits); // Get a pointer type. -tree -pointer_type (tree to_type); +tree pointer_type (tree to_type); // Get a reference type. -tree -reference_type (tree to_type); +tree reference_type (tree to_type); // make type immutable -tree -immutable_type (tree base); +tree immutable_type (tree base); // Get a function type. The receiver, parameter, and results are // generated from the types in the Function_type. The Function_type @@ -115,41 +108,36 @@ immutable_type (tree base); // one result, RESULT_STRUCT is a struct type to hold the results, // and RESULTS may be ignored; if there are zero or one results, // RESULT_STRUCT is NULL. -tree -function_type (const typed_identifier &receiver, - const std::vector ¶meters, - const std::vector &results, tree result_struct, - location_t location); - -tree -function_type_variadic (const typed_identifier &receiver, - const std::vector ¶meters, - const std::vector &results, - tree result_struct, location_t location); - -tree -function_ptr_type (tree result, const std::vector &praameters, - location_t location); +tree function_type (const typed_identifier &receiver, + const std::vector ¶meters, + const std::vector &results, + tree result_struct, location_t location); + +tree function_type_variadic (const typed_identifier &receiver, + const std::vector ¶meters, + const std::vector &results, + tree result_struct, location_t location); + +tree function_ptr_type (tree result, const std::vector &praameters, + location_t location); // Get a struct type. -tree -struct_type (const std::vector &fields, bool layout = true); +tree struct_type (const std::vector &fields, + bool layout = true); // Get a union type. -tree -union_type (const std::vector &fields, bool layout = true); +tree union_type (const std::vector &fields, + bool layout = true); // Get an array type. -tree -array_type (tree element_type, tree length); +tree array_type (tree element_type, tree length); // Return a named version of a type. The location is the location // of the type definition. This will not be called for a type // created via placeholder_pointer_type, placeholder_struct_type, or // placeholder_array_type.. (It may be called for a pointer, // struct, or array type in a case like "type P *byte; type Q P".) -tree -named_type (const std::string &name, tree, location_t); +tree named_type (GGC::Ident name, tree, location_t); // Return the size of a type. int64_t type_size (tree); @@ -164,8 +152,7 @@ int64_t type_field_alignment (tree); // Return the offset of field INDEX in a struct type. INDEX is the // entry in the FIELDS std::vector parameter of struct_type or // set_placeholder_struct_type. -int64_t -type_field_offset (tree, size_t index); +int64_t type_field_offset (tree, size_t index); // Expressions. @@ -175,155 +162,131 @@ type_field_offset (tree, size_t index); tree zero_expression (tree); // Create a reference to a variable. -tree -var_expression (Bvariable *var, location_t); +tree var_expression (Bvariable *var, location_t); // Return an expression for the floating point value VAL in BTYPE. -tree -float_constant_expression (tree btype, mpfr_t val); +tree float_constant_expression (tree btype, mpfr_t val); // Return an expression for the string value VAL. -tree -string_constant_expression (const std::string &val); +tree string_constant_expression (const std::string &val); // Get a char literal -tree -char_constant_expression (char c); +tree char_constant_expression (char c); // Get a char literal -tree -wchar_constant_expression (wchar_t c); +tree wchar_constant_expression (wchar_t c); + +// Get a size literal +tree size_constant_expression (size_t val); // Return an expression for the boolean value VAL. -tree -boolean_constant_expression (bool val); +tree boolean_constant_expression (bool val); // Return an expression that converts EXPR to TYPE. -tree -convert_expression (tree type, tree expr, location_t); +tree convert_expression (tree type, tree expr, location_t); // Return an expression for the field at INDEX in BSTRUCT. -tree -struct_field_expression (tree bstruct, size_t index, location_t); +tree struct_field_expression (tree bstruct, size_t index, location_t); // Create an expression that executes BSTAT before BEXPR. -tree -compound_expression (tree bstat, tree bexpr, location_t); +tree compound_expression (tree bstat, tree bexpr, location_t); // Return an expression that executes THEN_EXPR if CONDITION is true, or // ELSE_EXPR otherwise and returns the result as type BTYPE, within the // specified function FUNCTION. ELSE_EXPR may be NULL. BTYPE may be NULL. -tree -conditional_expression (tree function, tree btype, tree condition, - tree then_expr, tree else_expr, location_t); +tree conditional_expression (tree function, tree btype, tree condition, + tree then_expr, tree else_expr, location_t); // Return an expression for the negation operation OP EXPR. // Supported values of OP are enumerated in NegationOperator. -tree -negation_expression (NegationOperator op, tree expr, location_t); +tree negation_expression (NegationOperator op, tree expr, location_t); // Return an expression for the operation LEFT OP RIGHT. // Supported values of OP are enumerated in ArithmeticOrLogicalOperator. -tree -arithmetic_or_logical_expression (ArithmeticOrLogicalOperator op, tree left, - tree right, location_t loc); +tree arithmetic_or_logical_expression (ArithmeticOrLogicalOperator op, + tree left, tree right, location_t loc); // Return an expression for the operation LEFT OP RIGHT. // Supported values of OP are enumerated in ArithmeticOrLogicalOperator. // This function adds overflow checking and returns a list of statements to // add to the current function context. The `receiver` variable refers to the // variable which will contain the result of that operation. -tree -arithmetic_or_logical_expression_checked (ArithmeticOrLogicalOperator op, - tree left, tree right, location_t loc, - Bvariable *receiver); +tree arithmetic_or_logical_expression_checked (ArithmeticOrLogicalOperator op, + tree left, tree right, + location_t loc, + Bvariable *receiver); // Return an expression for the operation LEFT OP RIGHT. // Supported values of OP are enumerated in ComparisonOperator. -tree -comparison_expression (ComparisonOperator op, tree left, tree right, - location_t loc); +tree comparison_expression (ComparisonOperator op, tree left, tree right, + location_t loc); // Return an expression for the operation LEFT OP RIGHT. // Supported values of OP are enumerated in LazyBooleanOperator. -tree -lazy_boolean_expression (LazyBooleanOperator op, tree left, tree right, - location_t); +tree lazy_boolean_expression (LazyBooleanOperator op, tree left, tree right, + location_t); // Return an expression that constructs BTYPE with VALS. BTYPE must be the // backend representation a of struct. VALS must be in the same order as the // corresponding fields in BTYPE. -tree -constructor_expression (tree btype, bool is_variant, - const std::vector &vals, int, location_t); +tree constructor_expression (tree btype, bool is_variant, + const std::vector &vals, int, location_t); // Return an expression that constructs an array of BTYPE with INDEXES and // VALS. INDEXES and VALS must have the same amount of elements. Each index // in INDEXES must be in the same order as the corresponding value in VALS. -tree -array_constructor_expression (tree btype, - const std::vector &indexes, - const std::vector &vals, location_t); +tree array_constructor_expression (tree btype, + const std::vector &indexes, + const std::vector &vals, location_t); -tree -array_initializer (tree, tree, tree, tree, tree, tree *, location_t); +tree array_initializer (tree, tree, tree, tree, tree, tree *, location_t); // Return an expression for ARRAY[INDEX] as an l-value. ARRAY is a valid // fixed-length array, not a slice. -tree -array_index_expression (tree array, tree index, location_t); +tree array_index_expression (tree array, tree index, location_t); // Create an expression for a call to FN with ARGS, taking place within // caller CALLER. -tree -call_expression (tree fn, const std::vector &args, tree static_chain, - location_t); +tree call_expression (tree fn, const std::vector &args, tree static_chain, + location_t); // Statements. // Create a variable initialization statement in the specified // function. This initializes a local variable at the point in the // program flow where it is declared. -tree -init_statement (tree, Bvariable *var, tree init); +tree init_statement (tree, Bvariable *var, tree init); // Create an assignment statement within the specified function. -tree -assignment_statement (tree lhs, tree rhs, location_t); +tree assignment_statement (tree lhs, tree rhs, location_t); // Create return statement for an decl for a value (can be NULL_TREE) at a // location -tree -return_statement (tree fndecl, tree val, location_t); +tree return_statement (tree fndecl, tree val, location_t); // Create an if statement within a function. ELSE_BLOCK may be NULL. -tree -if_statement (tree, tree condition, tree then_block, tree else_block, - location_t); +tree if_statement (tree, tree condition, tree then_block, tree else_block, + location_t); // infinite loop expressions -tree -loop_expression (tree body, location_t); +tree loop_expression (tree body, location_t); // exit expressions -tree -exit_expression (tree condition, location_t); +tree exit_expression (tree condition, location_t); // Create a single statement from two statements. tree compound_statement (tree, tree); // Create a single statement from a list of statements. -tree -statement_list (const std::vector &); +tree statement_list (const std::vector &); // Create a statement that attempts to execute BSTAT and calls EXCEPT_STMT if // an exception occurs. EXCEPT_STMT may be NULL. FINALLY_STMT may be NULL and // if not NULL, it will always be executed. This is used for handling defers // in Go functions. In C++, the resulting code is of this form: // try { BSTAT; } catch { EXCEPT_STMT; } finally { FINALLY_STMT; } -tree -exception_handler_statement (tree bstat, tree except_stmt, tree finally_stmt, - location_t); +tree exception_handler_statement (tree bstat, tree except_stmt, + tree finally_stmt, location_t); // Blocks. @@ -337,16 +300,14 @@ exception_handler_statement (tree bstat, tree except_stmt, tree finally_stmt, // the initial curly brace. END_LOCATION is the location of the end // of the block, more or less the location of the final curly brace. // The statements will be added after the block is created. -tree -block (tree function, tree enclosing, const std::vector &vars, - location_t start_location, location_t end_location); +tree block (tree function, tree enclosing, const std::vector &vars, + location_t start_location, location_t end_location); // Add the statements to a block. The block is created first. Then // the statements are created. Then the statements are added to the // block. This will called exactly once per block. The vector may // be empty if there are no statements. -void -block_add_statements (tree, const std::vector &); +void block_add_statements (tree, const std::vector &); // Variables. @@ -360,10 +321,9 @@ block_add_statements (tree, const std::vector &); // be put into a unique section if possible; this is intended to // permit the linker to garbage collect the variable if it is not // referenced. LOCATION is where the variable was defined. -Bvariable * -global_variable (const std::string &name, const std::string &asm_name, - tree btype, bool is_external, bool is_hidden, - bool in_unique_section, location_t location); +Bvariable *global_variable (GGC::Ident name, GGC::Ident asm_name, tree btype, + bool is_external, bool is_hidden, + bool in_unique_section, location_t location); // A global variable will 1) be initialized to zero, or 2) be // initialized to a constant value, or 3) be initialized in the init @@ -371,8 +331,7 @@ global_variable (const std::string &name, const std::string &asm_name, // global_variable_set_init to set the initial value. If this is // not called, the backend should initialize a global variable to 0. // The init function may then assign a value to it. -void -global_variable_set_init (Bvariable *, tree); +void global_variable_set_init (Bvariable *, tree); // Create a local variable. The frontend will create the local // variables first, and then create the block which contains them. @@ -386,21 +345,18 @@ global_variable_set_init (Bvariable *, tree); // the function, as otherwise the variable would be on the heap). // LOCATION is where the variable is defined. For each local variable // the frontend will call init_statement to set the initial value. -Bvariable * -local_variable (tree function, const std::string &name, tree type, - Bvariable *decl_var, location_t location); +Bvariable *local_variable (tree function, GGC::Ident name, tree type, + Bvariable *decl_var, location_t location); // Create a function parameter. This is an incoming parameter, not // a result parameter (result parameters are treated as local // variables). The arguments are as for local_variable. -Bvariable * -parameter_variable (tree function, const std::string &name, tree type, - location_t location); +Bvariable *parameter_variable (tree function, GGC::Ident name, tree type, + location_t location); // Create a static chain parameter. This is the closure parameter. -Bvariable * -static_chain_variable (tree function, const std::string &name, tree type, - location_t location); +Bvariable *static_chain_variable (tree function, GGC::Ident name, tree type, + location_t location); // Create a temporary variable. A temporary variable has no name, // just a type. We pass in FUNCTION and BLOCK in case they are @@ -413,18 +369,16 @@ static_chain_variable (tree function, const std::string &name, tree type, // variable, and may not be very useful. This function should // return a variable which can be referenced later and should set // *PSTATEMENT to a statement which initializes the variable. -Bvariable * -temporary_variable (tree fndecl, tree bind_tree, tree type, tree init, - bool address_is_taken, location_t location, - tree *pstatement); +Bvariable *temporary_variable (tree fndecl, tree bind_tree, tree type, + tree init, bool address_is_taken, + location_t location, tree *pstatement); // Labels. -// Create a new label. NAME will be empty if this is a label +// Create a new label. NAME will be tl::nullopt if this is a label // created by the frontend for a loop construct. The location is // where the label is defined. -tree -label (tree, const std::string &name, location_t); +tree label (tree, tl::optional name, location_t); // Create a statement which defines a label. This statement will be // put into the codestream at the point where the label should be @@ -460,43 +414,38 @@ static const unsigned int function_does_not_return = 1 << 2; static const unsigned int function_in_unique_section = 1 << 3; // Declare or define a function of FNTYPE. -// NAME is the Go name of the function. ASM_NAME, if not the empty -// string, is the name that should be used in the symbol table; this +// NAME is the Go name of the function. ASM_NAME, if not tl::nullopt, +// is the name that should be used in the symbol table; this // will be non-empty if a magic extern comment is used. FLAGS is // bit flags described above. -tree -function (tree fntype, const std::string &name, const std::string &asm_name, - unsigned int flags, location_t); +tree function (tree fntype, GGC::Ident name, tl::optional asm_name, + unsigned int flags, location_t); // Create a statement that runs all deferred calls for FUNCTION. This should // be a statement that looks like this in C++: // finish: // try { DEFER_RETURN; } catch { CHECK_DEFER; goto finish; } -tree -function_defer_statement (tree function, tree undefer, tree check_defer, - location_t); +tree function_defer_statement (tree function, tree undefer, tree check_defer, + location_t); // Record PARAM_VARS as the variables to use for the parameters of FUNCTION. // This will only be called for a function definition. Returns true on // success, false on failure. -bool -function_set_parameters (tree function, - const std::vector ¶m_vars); +bool function_set_parameters (tree function, + const std::vector ¶m_vars); // Utility. // Write the definitions for all TYPE_DECLS, CONSTANT_DECLS, // FUNCTION_DECLS, and VARIABLE_DECLS declared globally. -void -write_global_definitions (const std::vector &type_decls, - const std::vector &constant_decls, - const std::vector &function_decls, - const std::vector &variable_decls); +void write_global_definitions (const std::vector &type_decls, + const std::vector &constant_decls, + const std::vector &function_decls, + const std::vector &variable_decls); // TODO: make static -tree -fill_in_fields (tree, const std::vector &, bool); +tree fill_in_fields (tree, const std::vector &, bool); tree fill_in_array (tree, tree, tree); diff --git a/gcc/rust/rust-diagnostics.cc b/gcc/rust/rust-diagnostics.cc index 0c0ef6ed7e23..7b2d7570d1e3 100644 --- a/gcc/rust/rust-diagnostics.cc +++ b/gcc/rust/rust-diagnostics.cc @@ -48,27 +48,33 @@ expand_format (const char *fmt) c++; switch (*c) { - case '\0': { + case '\0': + { // malformed format string rust_unreachable (); } - case '%': { + case '%': + { ss << "%"; break; } - case 'm': { + case 'm': + { ss << mformat_value (); break; } - case '<': { + case '<': + { ss << rust_open_quote (); break; } - case '>': { + case '>': + { ss << rust_close_quote (); break; } - case 'q': { + case 'q': + { ss << rust_open_quote (); c++; if (*c == 'm') @@ -82,7 +88,8 @@ expand_format (const char *fmt) ss << rust_close_quote (); break; } - default: { + default: + { ss << "%" << *c; } } @@ -104,8 +111,8 @@ expand_format (const char *fmt) // calling function must need to have attribute gnu_printf as well, even // though there is already an attribute declaration for it. -static std::string -expand_message (const char *fmt, va_list ap) RUST_ATTRIBUTE_GCC_DIAG (1, 0); +static std::string expand_message (const char *fmt, va_list ap) + RUST_ATTRIBUTE_GCC_DIAG (1, 0); #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wsuggest-attribute=format" @@ -420,24 +427,24 @@ namespace Rust { */ // simple location -static Error -va_constructor (Error::Kind kind, location_t locus, const char *fmt, - va_list args) RUST_ATTRIBUTE_GCC_DIAG (3, 0); +static Error va_constructor (Error::Kind kind, location_t locus, + const char *fmt, va_list args) + RUST_ATTRIBUTE_GCC_DIAG (3, 0); // simple location + error code -static Error -va_constructor (Error::Kind kind, location_t locus, const ErrorCode code, - const char *fmt, va_list args) RUST_ATTRIBUTE_GCC_DIAG (4, 0); +static Error va_constructor (Error::Kind kind, location_t locus, + const ErrorCode code, const char *fmt, + va_list args) RUST_ATTRIBUTE_GCC_DIAG (4, 0); // rich location -static Error -va_constructor (Error::Kind kind, rich_location *r_locus, const char *fmt, - va_list args) RUST_ATTRIBUTE_GCC_DIAG (3, 0); +static Error va_constructor (Error::Kind kind, rich_location *r_locus, + const char *fmt, va_list args) + RUST_ATTRIBUTE_GCC_DIAG (3, 0); // rich location + error code -static Error -va_constructor (Error::Kind kind, rich_location *r_locus, const ErrorCode code, - const char *fmt, va_list args) RUST_ATTRIBUTE_GCC_DIAG (4, 0); +static Error va_constructor (Error::Kind kind, rich_location *r_locus, + const ErrorCode code, const char *fmt, + va_list args) RUST_ATTRIBUTE_GCC_DIAG (4, 0); // simple location static Error diff --git a/gcc/rust/rust-diagnostics.h b/gcc/rust/rust-diagnostics.h index a13dc6a2eaf8..0b83e8ca2d81 100644 --- a/gcc/rust/rust-diagnostics.h +++ b/gcc/rust/rust-diagnostics.h @@ -31,7 +31,7 @@ #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) #define RUST_ATTRIBUTE_GCC_DIAG(m, n) \ __attribute__ ((__format__ (__gcc_tdiag__, m, n))) \ - __attribute__ ((__nonnull__ (m))) + __attribute__ ((__nonnull__ (m))) #else #define RUST_ATTRIBUTE_GCC_DIAG(m, n) #endif @@ -119,10 +119,8 @@ rust_error_at(rich_location *richloc, const ErrorCode, const char *fmt, ...) // These interfaces provide a way for the front end to ask for // the open/close quote characters it should use when formatting // diagnostics (warnings, errors). -extern const char * -rust_open_quote (); -extern const char * -rust_close_quote (); +extern const char *rust_open_quote (); +extern const char *rust_close_quote (); // These interfaces are used by utilities above to pass warnings and // errors (once format specifiers have been expanded) to the back end, @@ -306,8 +304,7 @@ struct Error #define rust_sorry_at(location, ...) sorry_at (location, __VA_ARGS__) -void -rust_debug_loc (const location_t location, const char *fmt, - ...) ATTRIBUTE_PRINTF_2; +void rust_debug_loc (const location_t location, const char *fmt, + ...) ATTRIBUTE_PRINTF_2; #endif // !defined(RUST_DIAGNOSTICS_H) diff --git a/gcc/rust/rust-gcc.cc b/gcc/rust/rust-gcc.cc index e5319d320800..c5fda5c7a9ca 100644 --- a/gcc/rust/rust-gcc.cc +++ b/gcc/rust/rust-gcc.cc @@ -91,12 +91,6 @@ Bvariable::error_variable () // A helper function to create a GCC identifier from a C++ string. -static inline tree -get_identifier_from_string (const std::string &str) -{ - return get_identifier_with_length (str.data (), str.length ()); -} - namespace Backend { // Define the built-in functions that are exposed to GCCRust. @@ -609,7 +603,7 @@ fill_in_fields (tree fill, const std::vector &fields, tree *pp = &field_trees; for (const auto &p : fields) { - tree name_tree = get_identifier_from_string (p.name); + tree name_tree = p.name.as_tree (); tree type_tree = p.type; if (error_operand_p (type_tree)) return error_mark_node; @@ -675,7 +669,7 @@ fill_in_array (tree fill, tree element_type, tree length_tree) // Return a named version of a type. tree -named_type (const std::string &name, tree type, location_t location) +named_type (GGC::Ident name, tree type, location_t location) { if (error_operand_p (type)) return error_mark_node; @@ -688,15 +682,14 @@ named_type (const std::string &name, tree type, location_t location) || TREE_CODE (type) == COMPLEX_TYPE || TREE_CODE (type) == BOOLEAN_TYPE)) { - tree decl = build_decl (BUILTINS_LOCATION, TYPE_DECL, - get_identifier_from_string (name), type); + tree decl + = build_decl (BUILTINS_LOCATION, TYPE_DECL, name.as_tree (), type); TYPE_NAME (type) = decl; return type; } tree copy = build_variant_type_copy (type); - tree decl - = build_decl (location, TYPE_DECL, get_identifier_from_string (name), copy); + tree decl = build_decl (location, TYPE_DECL, name.as_tree (), copy); DECL_ORIGINAL_TYPE (decl) = type; TYPE_NAME (copy) = decl; return copy; @@ -825,6 +818,12 @@ char_constant_expression (char c) return build_int_cst (char_type_node, c); } +tree +size_constant_expression (size_t val) +{ + return size_int (val); +} + // Make a constant boolean expression. tree @@ -1876,7 +1875,8 @@ non_zero_size_type (tree type) } return rust_non_zero_struct; - case ARRAY_TYPE: { + case ARRAY_TYPE: + { tree element_type = non_zero_size_type (TREE_TYPE (type)); return build_array_type_nelts (element_type, 1); } @@ -1923,9 +1923,9 @@ convert_tree (tree type_tree, tree expr_tree, location_t location) // Make a global variable. Bvariable * -global_variable (const std::string &var_name, const std::string &asm_name, - tree type_tree, bool is_external, bool is_hidden, - bool in_unique_section, location_t location) +global_variable (GGC::Ident var_name, GGC::Ident asm_name, tree type_tree, + bool is_external, bool is_hidden, bool in_unique_section, + location_t location) { if (error_operand_p (type_tree)) return Bvariable::error_variable (); @@ -1935,8 +1935,7 @@ global_variable (const std::string &var_name, const std::string &asm_name, if ((is_external || !is_hidden) && int_size_in_bytes (type_tree) == 0) type_tree = non_zero_size_type (type_tree); - tree decl = build_decl (location, VAR_DECL, - get_identifier_from_string (var_name), type_tree); + tree decl = build_decl (location, VAR_DECL, var_name.as_tree (), type_tree); if (is_external) DECL_EXTERNAL (decl) = 1; else @@ -1944,11 +1943,11 @@ global_variable (const std::string &var_name, const std::string &asm_name, if (!is_hidden) { TREE_PUBLIC (decl) = 1; - SET_DECL_ASSEMBLER_NAME (decl, get_identifier_from_string (asm_name)); + SET_DECL_ASSEMBLER_NAME (decl, asm_name.as_tree ()); } else { - SET_DECL_ASSEMBLER_NAME (decl, get_identifier_from_string (asm_name)); + SET_DECL_ASSEMBLER_NAME (decl, asm_name.as_tree ()); } TREE_USED (decl) = 1; @@ -1988,13 +1987,12 @@ global_variable_set_init (Bvariable *var, tree expr_tree) // Make a local variable. Bvariable * -local_variable (tree function, const std::string &name, tree type_tree, +local_variable (tree function, GGC::Ident name, tree type_tree, Bvariable *decl_var, location_t location) { if (error_operand_p (type_tree)) return Bvariable::error_variable (); - tree decl = build_decl (location, VAR_DECL, get_identifier_from_string (name), - type_tree); + tree decl = build_decl (location, VAR_DECL, name.as_tree (), type_tree); DECL_CONTEXT (decl) = function; if (decl_var != NULL) @@ -2009,13 +2007,12 @@ local_variable (tree function, const std::string &name, tree type_tree, // Make a function parameter variable. Bvariable * -parameter_variable (tree function, const std::string &name, tree type_tree, +parameter_variable (tree function, GGC::Ident name, tree type_tree, location_t location) { if (error_operand_p (type_tree)) return Bvariable::error_variable (); - tree decl = build_decl (location, PARM_DECL, - get_identifier_from_string (name), type_tree); + tree decl = build_decl (location, PARM_DECL, name.as_tree (), type_tree); DECL_CONTEXT (decl) = function; DECL_ARG_TYPE (decl) = type_tree; @@ -2026,13 +2023,12 @@ parameter_variable (tree function, const std::string &name, tree type_tree, // Make a static chain variable. Bvariable * -static_chain_variable (tree fndecl, const std::string &name, tree type_tree, +static_chain_variable (tree fndecl, GGC::Ident name, tree type_tree, location_t location) { if (error_operand_p (type_tree)) return Bvariable::error_variable (); - tree decl = build_decl (location, PARM_DECL, - get_identifier_from_string (name), type_tree); + tree decl = build_decl (location, PARM_DECL, name.as_tree (), type_tree); DECL_CONTEXT (decl) = fndecl; DECL_ARG_TYPE (decl) = type_tree; TREE_USED (decl) = 1; @@ -2123,10 +2119,10 @@ temporary_variable (tree fndecl, tree bind_tree, tree type_tree, tree init_tree, // Make a label. tree -label (tree func_tree, const std::string &name, location_t location) +label (tree func_tree, tl::optional name, location_t location) { tree decl; - if (name.empty ()) + if (!name.has_value ()) { if (DECL_STRUCT_FUNCTION (func_tree) == NULL) push_struct_function (func_tree); @@ -2139,7 +2135,7 @@ label (tree func_tree, const std::string &name, location_t location) } else { - tree id = get_identifier_from_string (name); + tree id = name->as_tree (); decl = build_decl (location, LABEL_DECL, id, void_type_node); DECL_CONTEXT (decl) = func_tree; } @@ -2178,7 +2174,7 @@ label_address (tree label, location_t location) // Declare or define a new function. tree -function (tree functype, const std::string &name, const std::string &asm_name, +function (tree functype, GGC::Ident name, tl::optional asm_name, unsigned int flags, location_t location) { if (error_operand_p (functype)) @@ -2186,13 +2182,13 @@ function (tree functype, const std::string &name, const std::string &asm_name, gcc_assert (FUNCTION_POINTER_TYPE_P (functype)); functype = TREE_TYPE (functype); - tree id = get_identifier_from_string (name); + tree id = name.as_tree (); if (error_operand_p (id)) return error_mark_node; tree decl = build_decl (location, FUNCTION_DECL, id, functype); - if (!asm_name.empty ()) - SET_DECL_ASSEMBLER_NAME (decl, get_identifier_from_string (asm_name)); + if (asm_name.has_value ()) + SET_DECL_ASSEMBLER_NAME (decl, asm_name->as_tree ()); if ((flags & function_is_declaration) != 0) DECL_EXTERNAL (decl) = 1; @@ -2235,7 +2231,7 @@ function_defer_statement (tree function, tree undefer_tree, tree defer_tree, push_cfun (DECL_STRUCT_FUNCTION (function)); tree stmt_list = NULL; - tree label = Backend::label (function, "", location); + tree label = Backend::label (function, tl::nullopt, location); tree label_def = label_definition_statement (label); append_to_statement_list (label_def, &stmt_list); diff --git a/gcc/rust/rust-lang.cc b/gcc/rust/rust-lang.cc index f3a155dbad1f..93ce041c2529 100644 --- a/gcc/rust/rust-lang.cc +++ b/gcc/rust/rust-lang.cc @@ -51,10 +51,10 @@ // FIXME: test saving intellisense #include "options.h" -// version check to stop compiling if c++ isn't c++11 or higher -#if __cplusplus < 201103 +// version check to stop compiling if c++ isn't c++14 or higher +#if __cplusplus < 201402 #error \ - "GCC Rust frontend requires C++11 or higher. You can compile the g++ frontend first and then compile the Rust frontend using that." + "GCC Rust frontend requires C++14 or higher. You can compile the g++ frontend first and then compile the Rust frontend using that." #endif // TODO: is this best way to do it? Is it allowed? (should be) @@ -373,7 +373,13 @@ rust_localize_identifier (const char *ident) return identifier_to_locale (ident); } -extern const attribute_spec grs_langhook_common_attribute_table[]; +extern const struct scoped_attribute_specs grs_langhook_gnu_attribute_table; +extern const struct scoped_attribute_specs grs_langhook_common_attribute_table; + +const scoped_attribute_specs *const grs_langhook_attribute_table[] = { + &grs_langhook_gnu_attribute_table, + &grs_langhook_common_attribute_table, +}; /* The language hooks data structure. This is the main interface between the GCC * front-end and the GCC middle-end/back-end. A list of language hooks could be @@ -394,8 +400,7 @@ extern const attribute_spec grs_langhook_common_attribute_table[]; #undef LANG_HOOKS_WRITE_GLOBALS #undef LANG_HOOKS_GIMPLIFY_EXPR #undef LANG_HOOKS_EH_PERSONALITY - -#undef LANG_HOOKS_COMMON_ATTRIBUTE_TABLE +#undef LANG_HOOKS_ATTRIBUTE_TABLE #define LANG_HOOKS_NAME "GNU Rust" #define LANG_HOOKS_INIT grs_langhook_init @@ -417,7 +422,7 @@ extern const attribute_spec grs_langhook_common_attribute_table[]; #define LANG_HOOKS_GIMPLIFY_EXPR grs_langhook_gimplify_expr #define LANG_HOOKS_EH_PERSONALITY grs_langhook_eh_personality -#define LANG_HOOKS_COMMON_ATTRIBUTE_TABLE grs_langhook_common_attribute_table +#define LANG_HOOKS_ATTRIBUTE_TABLE grs_langhook_attribute_table #if CHECKING_P diff --git a/gcc/rust/rust-object-export.h b/gcc/rust/rust-object-export.h index fe055c3ec057..784fef31f391 100644 --- a/gcc/rust/rust-object-export.h +++ b/gcc/rust/rust-object-export.h @@ -21,13 +21,10 @@ #include "rust-system.h" -extern unsigned int -rust_field_alignment (tree t); - -extern const char * -rust_read_export_data (int fd, off_t offset, char **pbuf, size_t *plen, - int *perr); -extern void -rust_write_export_data (const char *bytes, unsigned int size); +extern unsigned int rust_field_alignment (tree t); + +extern const char *rust_read_export_data (int fd, off_t offset, char **pbuf, + size_t *plen, int *perr); +extern void rust_write_export_data (const char *bytes, unsigned int size); #endif // RUST_OBJECT_EXPORT_H diff --git a/gcc/rust/rust-session-manager.cc b/gcc/rust/rust-session-manager.cc index 48acbf342222..12cdc2e5dba9 100644 --- a/gcc/rust/rust-session-manager.cc +++ b/gcc/rust/rust-session-manager.cc @@ -20,6 +20,7 @@ #include "rust-collect-lang-items.h" #include "rust-desugar-for-loops.h" #include "rust-desugar-question-mark.h" +#include "rust-desugar-apit.h" #include "rust-diagnostics.h" #include "rust-hir-pattern-analysis.h" #include "rust-immutable-name-resolution-context.h" @@ -61,11 +62,9 @@ #include "tm.h" #include "rust-target.h" -extern bool -saw_errors (void); +extern bool saw_errors (void); -extern Linemap * -rust_get_linemap (); +extern Linemap *rust_get_linemap (); namespace Rust { @@ -150,9 +149,9 @@ validate_crate_name (const std::string &crate_name, Error &error) { if (!(is_alphabetic (c.value) || is_numeric (c.value) || c.value == '_')) { - error = Error (UNDEF_LOCATION, - "invalid character %qs in crate name: %qs", - c.as_string ().c_str (), crate_name.c_str ()); + error + = Error (UNDEF_LOCATION, "invalid character %qs in crate name: %qs", + c.as_string ().c_str (), crate_name.c_str ()); return false; } } @@ -203,14 +202,16 @@ Session::handle_option ( switch (code) { case OPT_I: - case OPT_L: { + case OPT_L: + { // TODO: add search path const std::string p = std::string (arg); add_search_path (p); } break; - case OPT_frust_extern_: { + case OPT_frust_extern_: + { std::string input (arg); ret = handle_extern_option (input); } @@ -251,7 +252,8 @@ Session::handle_option ( Compile::Mangler::set_mangling (flag_rust_mangling); break; - case OPT_frust_cfg_: { + case OPT_frust_cfg_: + { auto string_arg = std::string (arg); ret = handle_cfg_option (string_arg); break; @@ -617,9 +619,6 @@ Session::compile_crate (const char *filename) expansion (parsed_crate, name_resolution_ctx); - AST::DesugarForLoops ().go (parsed_crate); - AST::DesugarQuestionMark ().go (parsed_crate); - rust_debug ("\033[0;31mSUCCESSFULLY FINISHED EXPANSION \033[0m"); if (options.dump_option_enabled (CompileOptions::EXPANSION_DUMP)) { @@ -682,6 +681,7 @@ Session::compile_crate (const char *filename) Resolver2_0::ImmutableNameResolutionContext::init (name_resolution_ctx); // type resolve + Compile::Context *ctx = Compile::Context::get (); Resolver::TypeResolution::Resolve (hir); Resolver::TypeCheckContext::get ()->get_variance_analysis_ctx ().solve (); @@ -729,16 +729,15 @@ Session::compile_crate (const char *filename) return; // do compile to gcc generic - Compile::Context ctx; - Compile::CompileCrate::Compile (hir, &ctx); + Compile::CompileCrate::Compile (hir, ctx); // we can't do static analysis if there are errors to worry about if (!saw_errors ()) { // lints Analysis::ScanDeadcode::Scan (hir); - Analysis::UnusedVariables::Lint (ctx); - Analysis::ReadonlyCheck::Lint (ctx); + Analysis::UnusedVariables::Lint (*ctx); + Analysis::ReadonlyCheck::Lint (*ctx); // metadata bool specified_emit_metadata @@ -759,7 +758,7 @@ Session::compile_crate (const char *filename) } // pass to GCC middle-end - ctx.write_to_backend (); + ctx->write_to_backend (); } void @@ -983,6 +982,20 @@ Session::expansion (AST::Crate &crate, Resolver2_0::NameResolutionContext &ctx) rust_error_at (range, "reached recursion limit"); } + // handle AST desugaring + if (!saw_errors ()) + { + AST::DesugarForLoops ().go (crate); + AST::DesugarQuestionMark ().go (crate); + AST::DesugarApit ().go (crate); + + // HACK: we may need a final TopLevel pass + // however, this should not count towards the recursion limit + // and we don't need a full Early pass + if (flag_name_resolution_2_0) + Resolver2_0::TopLevel (ctx).go (crate); + } + // error reporting - check unused macros, get missing fragment specifiers // build test harness @@ -1108,8 +1121,7 @@ Session::load_extern_crate (const std::string &crate_name, location_t locus) if (stream == NULL // No stream and && proc_macros.empty ()) // no proc macros { - rust_error_at (locus, "failed to locate crate %qs", - import_name.c_str ()); + rust_error_at (locus, "failed to locate crate %qs", import_name.c_str ()); return UNKNOWN_NODEID; } @@ -1177,16 +1189,13 @@ Session::load_extern_crate (const std::string &crate_name, location_t locus) mappings.insert_bang_proc_macros (crate_num, bang_macros); mappings.insert_derive_proc_macros (crate_num, derive_macros); - // name resolve it - Resolver::NameResolution::Resolve (parsed_crate); - - // perform hir lowering - std::unique_ptr lowered - = HIR::ASTLowering::Resolve (parsed_crate); - HIR::Crate &hir = mappings.insert_hir_crate (std::move (lowered)); - - // perform type resolution - Resolver::TypeResolution::Resolve (hir); + // if flag_name_resolution_2_0 is enabled + // then we perform resolution later + if (!flag_name_resolution_2_0) + { + // name resolve it + Resolver::NameResolution::Resolve (parsed_crate); + } // always restore the crate_num mappings.set_current_crate (saved_crate_num); diff --git a/gcc/rust/rust-session-manager.h b/gcc/rust/rust-session-manager.h index 83ba121e4116..9af103cbd732 100644 --- a/gcc/rust/rust-session-manager.h +++ b/gcc/rust/rust-session-manager.h @@ -441,8 +441,7 @@ struct Session #if CHECKING_P namespace selftest { -extern void -rust_crate_name_validation_test (void); +extern void rust_crate_name_validation_test (void); } #endif // CHECKING_P diff --git a/gcc/rust/rust-system.h b/gcc/rust/rust-system.h index 986428b08195..a4551239f3ab 100644 --- a/gcc/rust/rust-system.h +++ b/gcc/rust/rust-system.h @@ -88,10 +88,8 @@ constexpr static const char *file_separator = "/"; */ #define rust_unreachable() (fancy_abort (__FILE__, __LINE__, __FUNCTION__)) -extern void -rust_preserve_from_gc (tree t); +extern void rust_preserve_from_gc (tree t); -extern const char * -rust_localize_identifier (const char *ident); +extern const char *rust_localize_identifier (const char *ident); #endif // !defined(RUST_SYSTEM_H) diff --git a/gcc/rust/rust-target.h b/gcc/rust/rust-target.h index dbc2baff29bd..e61ea5112c15 100644 --- a/gcc/rust/rust-target.h +++ b/gcc/rust/rust-target.h @@ -26,8 +26,7 @@ #include "rust-target.def" /* Used by target to add target-related info. */ -extern void -rust_add_target_info (const char *, const char *); +extern void rust_add_target_info (const char *, const char *); /* Each target can provide their own. */ extern struct gcc_targetrustm targetrustm; diff --git a/gcc/rust/typecheck/rust-autoderef.cc b/gcc/rust/typecheck/rust-autoderef.cc index 6aa20a8c9414..825607431f07 100644 --- a/gcc/rust/typecheck/rust-autoderef.cc +++ b/gcc/rust/typecheck/rust-autoderef.cc @@ -26,8 +26,7 @@ namespace Rust { namespace Resolver { -static bool -resolve_operator_overload_fn ( +static bool resolve_operator_overload_fn ( LangItem::Kind lang_item_type, TyTy::BaseType *ty, TyTy::FnType **resolved_fn, Adjustment::AdjustmentType *requires_ref_adjustment); diff --git a/gcc/rust/typecheck/rust-casts.cc b/gcc/rust/typecheck/rust-casts.cc index 90bdef1fd3c1..f06d9ed24e8e 100644 --- a/gcc/rust/typecheck/rust-casts.cc +++ b/gcc/rust/typecheck/rust-casts.cc @@ -17,6 +17,7 @@ // . #include "rust-casts.h" +#include "rust-tyty-util.h" namespace Rust { namespace Resolver { @@ -28,15 +29,20 @@ TypeCastRules::TypeCastRules (location_t locus, TyTy::TyWithLocation from, TypeCoercionRules::CoercionResult TypeCastRules::resolve (location_t locus, TyTy::TyWithLocation from, - TyTy::TyWithLocation to) + TyTy::TyWithLocation to, bool emit_error) { TypeCastRules cast_rules (locus, from, to); - return cast_rules.check (); + return cast_rules.check (emit_error); } TypeCoercionRules::CoercionResult -TypeCastRules::check () +TypeCastRules::check (bool emit_error) { + // try the simple cast rules + auto simple_cast = cast_rules (); + if (!simple_cast.is_error ()) + return simple_cast; + // https://github.com/rust-lang/rust/blob/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/compiler/rustc_typeck/src/check/cast.rs#L565-L582 auto possible_coercion = TypeCoercionRules::TryCoerce (from.get_ty (), to.get_ty (), locus, @@ -51,13 +57,9 @@ TypeCastRules::check () true /*is_cast_site*/); } - // try the simple cast rules - auto simple_cast = cast_rules (); - if (!simple_cast.is_error ()) - return simple_cast; + if (emit_error) + TypeCastRules::emit_cast_error (locus, from, to); - // failed to cast - emit_cast_error (); return TypeCoercionRules::CoercionResult::get_error (); } @@ -73,7 +75,8 @@ TypeCastRules::cast_rules () to.get_ty ()->debug_str ().c_str ()); switch (from_type->get_kind ()) { - case TyTy::TypeKind::INFER: { + case TyTy::TypeKind::INFER: + { TyTy::InferType *from_infer = static_cast (from_type); switch (from_infer->get_infer_kind ()) @@ -85,7 +88,8 @@ TypeCastRules::cast_rules () case TyTy::InferType::InferTypeKind::INTEGRAL: switch (to.get_ty ()->get_kind ()) { - case TyTy::TypeKind::CHAR: { + case TyTy::TypeKind::CHAR: + { // only u8 and char bool was_uint = from.get_ty ()->get_kind () == TyTy::TypeKind::UINT; @@ -108,7 +112,8 @@ TypeCastRules::cast_rules () return TypeCoercionRules::CoercionResult{ {}, to.get_ty ()->clone ()}; - case TyTy::TypeKind::INFER: { + case TyTy::TypeKind::INFER: + { TyTy::InferType *to_infer = static_cast (to.get_ty ()); @@ -140,7 +145,8 @@ TypeCastRules::cast_rules () return TypeCoercionRules::CoercionResult{ {}, to.get_ty ()->clone ()}; - case TyTy::TypeKind::INFER: { + case TyTy::TypeKind::INFER: + { TyTy::InferType *to_infer = static_cast (to.get_ty ()); @@ -187,7 +193,8 @@ TypeCastRules::cast_rules () case TyTy::TypeKind::INT: switch (to.get_ty ()->get_kind ()) { - case TyTy::TypeKind::CHAR: { + case TyTy::TypeKind::CHAR: + { // only u8 and char bool was_uint = from.get_ty ()->get_kind () == TyTy::TypeKind::UINT; bool was_u8 = was_uint @@ -200,7 +207,8 @@ TypeCastRules::cast_rules () } break; - case TyTy::TypeKind::FLOAT: { + case TyTy::TypeKind::FLOAT: + { // can only do this for number types not char bool from_char = from.get_ty ()->get_kind () == TyTy::TypeKind::CHAR; @@ -210,7 +218,8 @@ TypeCastRules::cast_rules () } break; - case TyTy::TypeKind::POINTER: { + case TyTy::TypeKind::POINTER: + { // char can't be casted as a ptr bool from_char = from.get_ty ()->get_kind () == TyTy::TypeKind::CHAR; @@ -244,7 +253,8 @@ TypeCastRules::cast_rules () case TyTy::TypeKind::FLOAT: return TypeCoercionRules::CoercionResult{{}, to.get_ty ()->clone ()}; - case TyTy::TypeKind::INFER: { + case TyTy::TypeKind::INFER: + { TyTy::InferType *to_infer = static_cast (to.get_ty ()); @@ -273,7 +283,8 @@ TypeCastRules::cast_rules () case TyTy::TypeKind::USIZE: case TyTy::TypeKind::ISIZE: case TyTy::TypeKind::UINT: - case TyTy::TypeKind::INT: { + case TyTy::TypeKind::INT: + { // refs should not cast to numeric type bool from_ptr = from.get_ty ()->get_kind () == TyTy::TypeKind::POINTER; @@ -320,7 +331,27 @@ TypeCastRules::check_ptr_ptr_cast () } else if (from_is_ref && to_is_ref) { - // mutability must be coercedable + const auto &from_ref = *from.get_ty ()->as (); + const auto &to_ref = *to.get_ty ()->as (); + + if (from_ref.is_dyn_object () != to_ref.is_dyn_object ()) + { + // this needs to be handled by coercion logic + return TypeCoercionRules::CoercionResult::get_error (); + } + + // are the underlying types safely simple castable? + const auto to_underly = to_ref.get_base (); + const auto from_underly = from_ref.get_base (); + auto res = resolve (locus, TyTy::TyWithLocation (from_underly), + TyTy::TyWithLocation (to_underly), false); + if (res.is_error ()) + { + // this needs to be handled by coercion logic + return TypeCoercionRules::CoercionResult::get_error (); + } + + // mutability must be coerceable TyTy::ReferenceType &f = static_cast (*from.get_ty ()); TyTy::ReferenceType &t @@ -337,7 +368,8 @@ TypeCastRules::check_ptr_ptr_cast () } void -TypeCastRules::emit_cast_error () const +TypeCastRules::emit_cast_error (location_t locus, TyTy::TyWithLocation from, + TyTy::TyWithLocation to) { rich_location r (line_table, locus); r.add_range (from.get_locus ()); diff --git a/gcc/rust/typecheck/rust-casts.h b/gcc/rust/typecheck/rust-casts.h index 0d6ed689e420..10bb006f0376 100644 --- a/gcc/rust/typecheck/rust-casts.h +++ b/gcc/rust/typecheck/rust-casts.h @@ -30,15 +30,17 @@ class TypeCastRules public: static TypeCoercionRules::CoercionResult resolve (location_t locus, TyTy::TyWithLocation from, - TyTy::TyWithLocation to); + TyTy::TyWithLocation to, + bool emit_error = true); + + static void emit_cast_error (location_t locus, TyTy::TyWithLocation from, + TyTy::TyWithLocation to); protected: - TypeCoercionRules::CoercionResult check (); + TypeCoercionRules::CoercionResult check (bool emit_error); TypeCoercionRules::CoercionResult cast_rules (); TypeCoercionRules::CoercionResult check_ptr_ptr_cast (); - void emit_cast_error () const; - protected: TypeCastRules (location_t locus, TyTy::TyWithLocation from, TyTy::TyWithLocation to); diff --git a/gcc/rust/typecheck/rust-coercion.cc b/gcc/rust/typecheck/rust-coercion.cc index 5905992426c2..50c74ed689d3 100644 --- a/gcc/rust/typecheck/rust-coercion.cc +++ b/gcc/rust/typecheck/rust-coercion.cc @@ -125,13 +125,15 @@ TypeCoercionRules::do_coercion (TyTy::BaseType *receiver) // pointers switch (expected->get_kind ()) { - case TyTy::TypeKind::POINTER: { + case TyTy::TypeKind::POINTER: + { TyTy::PointerType *ptr = static_cast (expected); try_result = coerce_unsafe_ptr (receiver, ptr, ptr->mutability ()); return !try_result.is_error (); } - case TyTy::TypeKind::REF: { + case TyTy::TypeKind::REF: + { TyTy::ReferenceType *ptr = static_cast (expected); try_result @@ -147,7 +149,8 @@ TypeCoercionRules::do_coercion (TyTy::BaseType *receiver) // https://github.com/rust-lang/rust/blob/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/compiler/rustc_typeck/src/check/coercion.rs#L210 switch (receiver->get_kind ()) { - default: { + default: + { rust_debug ( "do_coercion default unify and infer expected: %s receiver %s", receiver->debug_str ().c_str (), expected->debug_str ().c_str ()); @@ -182,7 +185,8 @@ TypeCoercionRules::coerce_unsafe_ptr (TyTy::BaseType *receiver, TyTy::BaseType *element = nullptr; switch (receiver->get_kind ()) { - case TyTy::TypeKind::REF: { + case TyTy::TypeKind::REF: + { TyTy::ReferenceType *ref = static_cast (receiver); from_mutbl = ref->mutability (); @@ -190,14 +194,16 @@ TypeCoercionRules::coerce_unsafe_ptr (TyTy::BaseType *receiver, } break; - case TyTy::TypeKind::POINTER: { + case TyTy::TypeKind::POINTER: + { TyTy::PointerType *ref = static_cast (receiver); from_mutbl = ref->mutability (); element = ref->get_base (); } break; - default: { + default: + { // FIXME this can probably turn into a unify_and if (receiver->can_eq (expected, false)) return CoercionResult{{}, expected->clone ()}; @@ -264,14 +270,16 @@ TypeCoercionRules::coerce_borrowed_pointer (TyTy::BaseType *receiver, Mutability from_mutbl = Mutability::Imm; switch (receiver->get_kind ()) { - case TyTy::TypeKind::REF: { + case TyTy::TypeKind::REF: + { TyTy::ReferenceType *from = static_cast (receiver); from_mutbl = from->mutability (); } break; - default: { + default: + { // FIXME // we might be able to replace this with a can_eq because we default // back to a final unity anyway @@ -393,7 +401,7 @@ TypeCoercionRules::coerce_unsized (TyTy::BaseType *source, if (expect_dyn && need_unsize) { - bool bounds_compatible = b->bounds_compatible (*a, locus, true); + bool bounds_compatible = b->bounds_compatible (*a, locus, false); if (!bounds_compatible) { unsafe_error = true; diff --git a/gcc/rust/typecheck/rust-hir-dot-operator.cc b/gcc/rust/typecheck/rust-hir-dot-operator.cc index c1165e9e5b17..7b7944c508dd 100644 --- a/gcc/rust/typecheck/rust-hir-dot-operator.cc +++ b/gcc/rust/typecheck/rust-hir-dot-operator.cc @@ -102,26 +102,16 @@ MethodResolver::try_hook (const TyTy::BaseType &r) } } -bool -MethodResolver::select (TyTy::BaseType &receiver) +std::vector +MethodResolver::assemble_inherent_impl_candidates ( + const TyTy::BaseType &receiver) { - rust_debug ("MethodResolver::select reciever=[%s] path=[%s]", - receiver.debug_str ().c_str (), - segment_name.as_string ().c_str ()); - - struct impl_item_candidate - { - HIR::Function *item; - HIR::ImplBlock *impl_block; - TyTy::FnType *ty; - }; - + std::vector inherent_impl_fns; const TyTy::BaseType *raw = receiver.destructure (); bool receiver_is_raw_ptr = raw->get_kind () == TyTy::TypeKind::POINTER; bool receiver_is_ref = raw->get_kind () == TyTy::TypeKind::REF; - // assemble inherent impl items - std::vector inherent_impl_fns; + // Assemble inherent impl items (non-trait impl blocks) mappings.iterate_impl_items ( [&] (HirId id, HIR::ImplItem *item, HIR::ImplBlock *impl) mutable -> bool { bool is_trait_impl = impl->has_trait_ref (); @@ -190,16 +180,19 @@ MethodResolver::select (TyTy::BaseType &receiver) return true; }); - struct trait_item_candidate - { - const HIR::TraitItemFunc *item; - const HIR::Trait *trait; - TyTy::FnType *ty; - const TraitReference *reference; - const TraitItemReference *item_ref; - }; + return inherent_impl_fns; +} + +void +MethodResolver::assemble_trait_impl_candidates ( + const TyTy::BaseType &receiver, + std::vector &impl_candidates, + std::vector &trait_candidates) +{ + const TyTy::BaseType *raw = receiver.destructure (); + bool receiver_is_raw_ptr = raw->get_kind () == TyTy::TypeKind::POINTER; + bool receiver_is_ref = raw->get_kind () == TyTy::TypeKind::REF; - std::vector trait_fns; mappings.iterate_impl_blocks ([&] (HirId id, HIR::ImplBlock *impl) mutable -> bool { bool is_trait_impl = impl->has_trait_ref (); @@ -266,7 +259,7 @@ MethodResolver::select (TyTy::BaseType &receiver) continue; } - inherent_impl_fns.push_back ({func, impl, fnty}); + impl_candidates.push_back ({func, impl, fnty}); return true; } @@ -293,26 +286,15 @@ MethodResolver::select (TyTy::BaseType &receiver) TyTy::FnType *fnty = static_cast (ty); trait_item_candidate candidate{func, trait, fnty, trait_ref, item_ref}; - trait_fns.push_back (candidate); + trait_candidates.push_back (candidate); return true; }); +} - // lookup specified bounds for an associated item - struct precdicate_candidate - { - TyTy::TypeBoundPredicateItem lookup; - TyTy::FnType *fntype; - }; - - // https://github.com/rust-lang/rust/blob/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/compiler/rustc_typeck/src/check/method/probe.rs#L580-L694 - - rust_debug ("inherent_impl_fns found {%lu}, trait_fns found {%lu}, " - "predicate_items found {%lu}", - (unsigned long) inherent_impl_fns.size (), - (unsigned long) trait_fns.size (), - (unsigned long) predicate_items.size ()); - +bool +MethodResolver::try_select_predicate_candidates (TyTy::BaseType &receiver) +{ bool found_possible_candidate = false; for (const auto &predicate : predicate_items) { @@ -346,60 +328,33 @@ MethodResolver::select (TyTy::BaseType &receiver) found_possible_candidate = true; } } - if (found_possible_candidate) - { - return true; - } + return found_possible_candidate; +} - for (auto &impl_item : inherent_impl_fns) +bool +MethodResolver::try_select_inherent_impl_candidates ( + TyTy::BaseType &receiver, const std::vector &candidates, + bool trait_impl_blocks_only) +{ + bool found_possible_candidate = false; + for (auto &impl_item : candidates) { bool is_trait_impl_block = impl_item.impl_block->has_trait_ref (); - if (is_trait_impl_block) + if (trait_impl_blocks_only && !is_trait_impl_block) continue; - - TyTy::FnType *fn = impl_item.ty; - rust_assert (fn->is_method ()); - - TyTy::BaseType *fn_self = fn->get_self_type (); - rust_debug ("dot-operator impl_item fn_self={%s} can_eq receiver={%s}", - fn_self->debug_str ().c_str (), - receiver.debug_str ().c_str ()); - - auto res - = TypeCoercionRules::TryCoerce (&receiver, fn_self, UNDEF_LOCATION, - false /*allow-autoderef*/); - bool ok = !res.is_error (); - if (ok) - { - std::vector adjs = append_adjustments (res.adjustments); - PathProbeCandidate::ImplItemCandidate c{impl_item.item, - impl_item.impl_block}; - auto try_result = MethodCandidate{ - PathProbeCandidate (PathProbeCandidate::CandidateType::IMPL_FUNC, - fn, impl_item.item->get_locus (), c), - adjs}; - result.insert (std::move (try_result)); - found_possible_candidate = true; - } - } - if (found_possible_candidate) - { - return true; - } - - for (auto &impl_item : inherent_impl_fns) - { - bool is_trait_impl_block = impl_item.impl_block->has_trait_ref (); - if (!is_trait_impl_block) + if (!trait_impl_blocks_only && is_trait_impl_block) continue; TyTy::FnType *fn = impl_item.ty; rust_assert (fn->is_method ()); TyTy::BaseType *fn_self = fn->get_self_type (); - rust_debug ( - "dot-operator trait_impl_item fn_self={%s} can_eq receiver={%s}", - fn_self->debug_str ().c_str (), receiver.debug_str ().c_str ()); + + const char *debug_prefix + = trait_impl_blocks_only ? "trait_impl_item" : "impl_item"; + rust_debug ("dot-operator %s fn_self={%s} can_eq receiver={%s}", + debug_prefix, fn_self->debug_str ().c_str (), + receiver.debug_str ().c_str ()); auto res = TypeCoercionRules::TryCoerce (&receiver, fn_self, UNDEF_LOCATION, @@ -418,12 +373,15 @@ MethodResolver::select (TyTy::BaseType &receiver) found_possible_candidate = true; } } - if (found_possible_candidate) - { - return true; - } + return found_possible_candidate; +} - for (auto trait_item : trait_fns) +bool +MethodResolver::try_select_trait_impl_candidates ( + TyTy::BaseType &receiver, const std::vector &candidates) +{ + bool found_possible_candidate = false; + for (auto trait_item : candidates) { TyTy::FnType *fn = trait_item.ty; rust_assert (fn->is_method ()); @@ -451,10 +409,53 @@ MethodResolver::select (TyTy::BaseType &receiver) found_possible_candidate = true; } } - return found_possible_candidate; } +bool +MethodResolver::select (TyTy::BaseType &receiver) +{ + rust_debug ("MethodResolver::select reciever=[%s] path=[%s]", + receiver.debug_str ().c_str (), + segment_name.as_string ().c_str ()); + + // Assemble candidates + std::vector inherent_impl_fns + = assemble_inherent_impl_candidates (receiver); + std::vector trait_impl_fns; + std::vector trait_fns; + assemble_trait_impl_candidates (receiver, trait_impl_fns, trait_fns); + + // Combine inherent and trait impl functions + inherent_impl_fns.insert (inherent_impl_fns.end (), trait_impl_fns.begin (), + trait_impl_fns.end ()); + + // https://github.com/rust-lang/rust/blob/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/compiler/rustc_typeck/src/check/method/probe.rs#L580-L694 + + rust_debug ("inherent_impl_fns found {%lu}, trait_fns found {%lu}, " + "predicate_items found {%lu}", + (unsigned long) inherent_impl_fns.size (), + (unsigned long) trait_fns.size (), + (unsigned long) predicate_items.size ()); + + // Try selection in the priority order defined by Rust's method resolution: + + // 1. Try predicate candidates first (highest priority) + if (try_select_predicate_candidates (receiver)) + return true; + + // 2. Try inherent impl functions (non-trait impl blocks) + if (try_select_inherent_impl_candidates (receiver, inherent_impl_fns, false)) + return true; + + // 3. Try inherent impl functions from trait impl blocks + if (try_select_inherent_impl_candidates (receiver, inherent_impl_fns, true)) + return true; + + // 4. Try trait functions (lowest priority) + return try_select_trait_impl_candidates (receiver, trait_fns); +} + std::vector MethodResolver::get_predicate_items ( const HIR::PathIdentSegment &segment_name, const TyTy::BaseType &receiver, diff --git a/gcc/rust/typecheck/rust-hir-dot-operator.h b/gcc/rust/typecheck/rust-hir-dot-operator.h index ab95a5a40c45..cc40472e0faf 100644 --- a/gcc/rust/typecheck/rust-hir-dot-operator.h +++ b/gcc/rust/typecheck/rust-hir-dot-operator.h @@ -65,6 +65,22 @@ class MethodResolver : private TypeCheckBase, protected AutoderefCycle const HIR::PathIdentSegment &segment_name, const TyTy::BaseType &receiver, const std::vector &specified_bounds); + struct impl_item_candidate + { + HIR::Function *item; + HIR::ImplBlock *impl_block; + TyTy::FnType *ty; + }; + + struct trait_item_candidate + { + const HIR::TraitItemFunc *item; + const HIR::Trait *trait; + TyTy::FnType *ty; + const TraitReference *reference; + const TraitItemReference *item_ref; + }; + protected: MethodResolver (bool autoderef_flag, const HIR::PathIdentSegment &segment_name); @@ -77,6 +93,25 @@ class MethodResolver : private TypeCheckBase, protected AutoderefCycle std::vector append_adjustments (const std::vector &adjustments) const; + std::vector + assemble_inherent_impl_candidates (const TyTy::BaseType &receiver); + + void assemble_trait_impl_candidates ( + const TyTy::BaseType &receiver, + std::vector &impl_candidates, + std::vector &trait_candidates); + + bool try_select_predicate_candidates (TyTy::BaseType &receiver); + + bool try_select_inherent_impl_candidates ( + TyTy::BaseType &receiver, + const std::vector &candidates, + bool trait_impl_blocks_only); + + bool try_select_trait_impl_candidates ( + TyTy::BaseType &receiver, + const std::vector &candidates); + private: // search const HIR::PathIdentSegment &segment_name; diff --git a/gcc/rust/typecheck/rust-hir-trait-reference.cc b/gcc/rust/typecheck/rust-hir-trait-reference.cc index 83985f009893..74856f098fa0 100644 --- a/gcc/rust/typecheck/rust-hir-trait-reference.cc +++ b/gcc/rust/typecheck/rust-hir-trait-reference.cc @@ -342,7 +342,15 @@ TraitReference::on_resolved () { for (auto &item : item_refs) { - item.on_resolved (); + if (item.get_trait_item_type () + == TraitItemReference::TraitItemType::TYPE) + item.on_resolved (); + } + for (auto &item : item_refs) + { + if (item.get_trait_item_type () + != TraitItemReference::TraitItemType::TYPE) + item.on_resolved (); } } @@ -424,7 +432,13 @@ TraitReference::trait_has_generics () const return !trait_substs.empty (); } -std::vector +std::vector & +TraitReference::get_trait_substs () +{ + return trait_substs; +} + +const std::vector & TraitReference::get_trait_substs () const { return trait_substs; diff --git a/gcc/rust/typecheck/rust-hir-trait-reference.h b/gcc/rust/typecheck/rust-hir-trait-reference.h index 8b1ac7daf7f1..473513ea75ff 100644 --- a/gcc/rust/typecheck/rust-hir-trait-reference.h +++ b/gcc/rust/typecheck/rust-hir-trait-reference.h @@ -224,7 +224,9 @@ class TraitReference bool trait_has_generics () const; - std::vector get_trait_substs () const; + std::vector &get_trait_substs (); + + const std::vector &get_trait_substs () const; bool satisfies_bound (const TraitReference &reference) const; diff --git a/gcc/rust/typecheck/rust-hir-trait-resolve.cc b/gcc/rust/typecheck/rust-hir-trait-resolve.cc index 032bb5841272..7f224076cd74 100644 --- a/gcc/rust/typecheck/rust-hir-trait-resolve.cc +++ b/gcc/rust/typecheck/rust-hir-trait-resolve.cc @@ -224,7 +224,8 @@ TraitResolver::resolve_trait (HIR::Trait *trait_reference) // handling. break; - case HIR::GenericParam::GenericKind::TYPE: { + case HIR::GenericParam::GenericKind::TYPE: + { auto &typaram = static_cast (*generic_param); bool is_self = typaram.get_type_representation ().as_string ().compare ("Self") @@ -287,7 +288,8 @@ TraitResolver::resolve_trait (HIR::Trait *trait_reference) auto predicate = get_predicate_from_bound ( b->get_path (), - tl::nullopt /*this will setup a PLACEHOLDER for self*/); + tl::nullopt /*this will setup a PLACEHOLDER for self*/, + BoundPolarity::RegularBound, false, true); if (predicate.is_error ()) return &TraitReference::error_node (); @@ -443,11 +445,27 @@ TraitItemReference::associated_type_set (TyTy::BaseType *ty) const { rust_assert (get_trait_item_type () == TraitItemType::TYPE); + // this isnt super safe there are cases like the FnTraits where the type is + // set to the impls placeholder associated type. For example + // + // type Output = F::Output; -- see the fn trait impls in libcore + // + // then this projection ends up resolving back to this placeholder so it just + // ends up being cyclical + TyTy::BaseType *item_ty = get_tyty (); rust_assert (item_ty->get_kind () == TyTy::TypeKind::PLACEHOLDER); TyTy::PlaceholderType *placeholder = static_cast (item_ty); + if (ty->is ()) + { + const auto &projection = *static_cast (ty); + const auto resolved = projection.get (); + if (resolved == item_ty) + return; + } + placeholder->set_associated_type (ty->get_ty_ref ()); } @@ -543,7 +561,8 @@ AssociatedImplTrait::setup_associated_types ( // handling. break; - case HIR::GenericParam::GenericKind::TYPE: { + case HIR::GenericParam::GenericKind::TYPE: + { TyTy::BaseType *l = nullptr; bool ok = context->lookup_type ( generic_param->get_mappings ().get_hirid (), &l); @@ -753,7 +772,8 @@ TraitItemReference::is_object_safe () const // https://doc.rust-lang.org/reference/items/traits.html#object-safety switch (get_trait_item_type ()) { - case TraitItemReference::TraitItemType::FN: { + case TraitItemReference::TraitItemType::FN: + { // lets be boring and just check that this is indeed a method will do // for now const HIR::TraitItem *item = get_hir_trait_item (); diff --git a/gcc/rust/typecheck/rust-hir-type-bounds.h b/gcc/rust/typecheck/rust-hir-type-bounds.h index 82333f18685e..5384700e97fb 100644 --- a/gcc/rust/typecheck/rust-hir-type-bounds.h +++ b/gcc/rust/typecheck/rust-hir-type-bounds.h @@ -37,7 +37,11 @@ class TypeBoundsProbe : public TypeCheckBase private: void scan (); - void assemble_sized_builtin (); + bool + process_impl_block (HirId id, HIR::ImplBlock *impl, + std::vector> + &possible_trait_paths); + void assemble_marker_builtins (); void add_trait_bound (HIR::Trait *trait); void assemble_builtin_candidate (LangItem::Kind item); diff --git a/gcc/rust/typecheck/rust-hir-type-check-base.cc b/gcc/rust/typecheck/rust-hir-type-check-base.cc index 14b8ab8635e1..4bbd52a29f45 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-base.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-base.cc @@ -17,6 +17,7 @@ // . #include "rust-hir-type-check-base.h" +#include "rust-compile-base.h" #include "rust-hir-type-check-expr.h" #include "rust-hir-type-check-type.h" #include "rust-hir-trait-resolve.h" @@ -124,7 +125,8 @@ TypeCheckBase::resolve_literal (const Analysis::NodeMapping &expr_mappings, TyTy::BaseType *infered = nullptr; switch (literal.get_lit_type ()) { - case HIR::Literal::LitType::INT: { + case HIR::Literal::LitType::INT: + { bool ok = false; switch (literal.get_type_hint ()) @@ -191,7 +193,8 @@ TypeCheckBase::resolve_literal (const Analysis::NodeMapping &expr_mappings, } break; - case HIR::Literal::LitType::FLOAT: { + case HIR::Literal::LitType::FLOAT: + { bool ok = false; switch (literal.get_type_hint ()) @@ -216,25 +219,29 @@ TypeCheckBase::resolve_literal (const Analysis::NodeMapping &expr_mappings, } break; - case HIR::Literal::LitType::BOOL: { + case HIR::Literal::LitType::BOOL: + { auto ok = context->lookup_builtin ("bool", &infered); rust_assert (ok); } break; - case HIR::Literal::LitType::CHAR: { + case HIR::Literal::LitType::CHAR: + { auto ok = context->lookup_builtin ("char", &infered); rust_assert (ok); } break; - case HIR::Literal::LitType::BYTE: { + case HIR::Literal::LitType::BYTE: + { auto ok = context->lookup_builtin ("u8", &infered); rust_assert (ok); } break; - case HIR::Literal::LitType::STRING: { + case HIR::Literal::LitType::STRING: + { TyTy::BaseType *base = nullptr; auto ok = context->lookup_builtin ("str", &base); rust_assert (ok); @@ -246,7 +253,8 @@ TypeCheckBase::resolve_literal (const Analysis::NodeMapping &expr_mappings, } break; - case HIR::Literal::LitType::BYTE_STRING: { + case HIR::Literal::LitType::BYTE_STRING: + { /* This is an arraytype of u8 reference (&[u8;size]). It isn't in UTF-8, but really just a byte array. Code to construct the array reference copied from ArrayElemsValues and ArrayType. */ @@ -280,9 +288,11 @@ TypeCheckBase::resolve_literal (const Analysis::NodeMapping &expr_mappings, crate_num), UNKNOWN_LOCAL_DEFID); + auto ctx = Compile::Context::get (); + tree capacity = Compile::HIRCompileBase::query_compile_const_expr ( + ctx, expected_ty, *literal_capacity); TyTy::ArrayType *array - = new TyTy::ArrayType (array_mapping.get_hirid (), locus, - *literal_capacity, + = new TyTy::ArrayType (array_mapping.get_hirid (), locus, capacity, TyTy::TyVar (u8->get_ref ())); context->insert_type (array_mapping, array); @@ -440,7 +450,8 @@ TypeCheckBase::resolve_generic_params ( { switch (generic_param->get_kind ()) { - case HIR::GenericParam::GenericKind::LIFETIME: { + case HIR::GenericParam::GenericKind::LIFETIME: + { auto lifetime_param = static_cast (*generic_param); auto lifetime = lifetime_param.get_lifetime (); @@ -449,7 +460,8 @@ TypeCheckBase::resolve_generic_params ( } break; - case HIR::GenericParam::GenericKind::CONST: { + case HIR::GenericParam::GenericKind::CONST: + { if (is_foreign && abi != Rust::ABI::INTRINSIC) { rust_error_at (generic_param->get_locus (), ErrorCode::E0044, @@ -478,7 +490,8 @@ TypeCheckBase::resolve_generic_params ( } break; - case HIR::GenericParam::GenericKind::TYPE: { + case HIR::GenericParam::GenericKind::TYPE: + { if (is_foreign && abi != Rust::ABI::INTRINSIC) { rust_error_at (generic_param->get_locus (), ErrorCode::E0044, diff --git a/gcc/rust/typecheck/rust-hir-type-check-base.h b/gcc/rust/typecheck/rust-hir-type-check-base.h index 580082a6adfb..a8084f2bf5b8 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-base.h +++ b/gcc/rust/typecheck/rust-hir-type-check-base.h @@ -46,7 +46,7 @@ class TypeCheckBase HIR::TypePath &path, tl::optional> associated_self, BoundPolarity polarity = BoundPolarity::RegularBound, - bool is_qualified_type = false); + bool is_qualified_type = false, bool is_super_trait = false); bool check_for_unconstrained ( const std::vector ¶ms_to_constrain, diff --git a/gcc/rust/typecheck/rust-hir-type-check-enumitem.cc b/gcc/rust/typecheck/rust-hir-type-check-enumitem.cc index c80a12f8f84e..2dbd84d254ae 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-enumitem.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-enumitem.cc @@ -87,7 +87,7 @@ TypeCheckEnumItem::visit (HIR::EnumItem &item) = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); canonical_path - = nr_ctx.types.to_canonical_path (item.get_mappings ().get_nodeid ()); + = nr_ctx.to_canonical_path (item.get_mappings ().get_nodeid ()); } else { @@ -131,7 +131,7 @@ TypeCheckEnumItem::visit (HIR::EnumItemDiscriminant &item) = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); canonical_path - = nr_ctx.types.to_canonical_path (item.get_mappings ().get_nodeid ()); + = nr_ctx.to_canonical_path (item.get_mappings ().get_nodeid ()); } else { @@ -193,7 +193,7 @@ TypeCheckEnumItem::visit (HIR::EnumItemTuple &item) = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); canonical_path - = nr_ctx.types.to_canonical_path (item.get_mappings ().get_nodeid ()); + = nr_ctx.to_canonical_path (item.get_mappings ().get_nodeid ()); } else { @@ -253,7 +253,7 @@ TypeCheckEnumItem::visit (HIR::EnumItemStruct &item) = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); canonical_path - = nr_ctx.types.to_canonical_path (item.get_mappings ().get_nodeid ()); + = nr_ctx.to_canonical_path (item.get_mappings ().get_nodeid ()); } else { diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.cc b/gcc/rust/typecheck/rust-hir-type-check-expr.cc index cbf529a77eb9..9f8d31109b15 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-expr.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-expr.cc @@ -17,6 +17,7 @@ // . #include "optional.h" +#include "rust-common.h" #include "rust-hir-expr.h" #include "rust-system.h" #include "rust-tyty-call.h" @@ -31,6 +32,7 @@ #include "rust-hir-type-check-item.h" #include "rust-type-util.h" #include "rust-immutable-name-resolution-context.h" +#include "rust-compile-base.h" // for flag_name_resolution_2_0 #include "options.h" @@ -58,6 +60,19 @@ TypeCheckExpr::Resolve (HIR::Expr &expr) return resolver.infered; } +TyTy::BaseType * +TypeCheckExpr::ResolveOpOverload (LangItem::Kind lang_item_type, + HIR::OperatorExprMeta expr, + TyTy::BaseType *lhs, TyTy::BaseType *rhs, + HIR::PathIdentSegment specified_segment) +{ + TypeCheckExpr resolver; + + resolver.resolve_operator_overload (lang_item_type, expr, lhs, rhs, + specified_segment); + return resolver.infered; +} + void TypeCheckExpr::visit (HIR::TupleIndexExpr &expr) { @@ -373,7 +388,8 @@ TypeCheckExpr::visit (HIR::ArithmeticOrLogicalExpr &expr) switch (expr.get_expr_type ()) { case ArithmeticOrLogicalOperator::LEFT_SHIFT: - case ArithmeticOrLogicalOperator::RIGHT_SHIFT: { + case ArithmeticOrLogicalOperator::RIGHT_SHIFT: + { TyTy::TyWithLocation from (rhs, expr.get_rhs ().get_locus ()); TyTy::TyWithLocation to (lhs, expr.get_lhs ().get_locus ()); infered = cast_site (expr.get_mappings ().get_hirid (), from, to, @@ -381,7 +397,8 @@ TypeCheckExpr::visit (HIR::ArithmeticOrLogicalExpr &expr) } break; - default: { + default: + { infered = unify_site ( expr.get_mappings ().get_hirid (), TyTy::TyWithLocation (lhs, expr.get_lhs ().get_locus ()), @@ -470,7 +487,8 @@ TypeCheckExpr::visit (HIR::NegationExpr &expr) // https://doc.rust-lang.org/reference/expressions/operator-expr.html#negation-operators switch (expr.get_expr_type ()) { - case NegationOperator::NEGATE: { + case NegationOperator::NEGATE: + { bool valid = (negated_expr_ty->get_kind () == TyTy::TypeKind::INT) || (negated_expr_ty->get_kind () == TyTy::TypeKind::UINT) @@ -492,7 +510,8 @@ TypeCheckExpr::visit (HIR::NegationExpr &expr) } break; - case NegationOperator::NOT: { + case NegationOperator::NOT: + { bool valid = (negated_expr_ty->get_kind () == TyTy::TypeKind::BOOL) || (negated_expr_ty->get_kind () == TyTy::TypeKind::INT) @@ -642,6 +661,22 @@ TypeCheckExpr::visit (HIR::BlockExpr &expr) } } +void +TypeCheckExpr::visit (HIR::AnonConst &expr) +{ + // FIXME: How do we typecheck a deferred inference const? + + rust_assert (!expr.is_deferred ()); + + infered = TypeCheckExpr::Resolve (expr.get_inner_expr ()); +} + +void +TypeCheckExpr::visit (HIR::ConstBlock &expr) +{ + infered = TypeCheckExpr::Resolve (expr.get_const_expr ()); +} + void TypeCheckExpr::visit (HIR::RangeFromToExpr &expr) { @@ -790,38 +825,45 @@ typecheck_inline_asm_operand (HIR::InlineAsm &expr) { switch (operand.get_register_type ()) { - case RegisterType::In: { + case RegisterType::In: + { auto in = operand.get_in (); TypeCheckExpr::Resolve (*in.expr); break; } - case RegisterType::Out: { + case RegisterType::Out: + { auto out = operand.get_out (); TypeCheckExpr::Resolve (*out.expr); break; } - case RegisterType::InOut: { + case RegisterType::InOut: + { auto in_out = operand.get_in_out (); TypeCheckExpr::Resolve (*in_out.expr); break; } - case RegisterType::SplitInOut: { + case RegisterType::SplitInOut: + { auto split_in_out = operand.get_split_in_out (); TypeCheckExpr::Resolve (*split_in_out.in_expr); TypeCheckExpr::Resolve (*split_in_out.out_expr); break; } - case RegisterType::Const: { + case RegisterType::Const: + { auto anon_const = operand.get_const ().anon_const; - TypeCheckExpr::Resolve (*anon_const.expr); + TypeCheckExpr::Resolve (anon_const.get_inner_expr ()); break; } - case RegisterType::Sym: { + case RegisterType::Sym: + { auto sym = operand.get_sym (); TypeCheckExpr::Resolve (*sym.expr); break; } - case RegisterType::Label: { + case RegisterType::Label: + { auto label = operand.get_label (); TypeCheckExpr::Resolve (*label.expr); break; @@ -837,7 +879,7 @@ TypeCheckExpr::visit (HIR::InlineAsm &expr) // NOTE: Hoise out if we have noreturn as an option // to return a never type // TODO : new keyword for memory seems sooooo shaky - if (expr.options.count (AST::InlineAsmOption::NORETURN) == 1) + if (expr.options.count (AST::InlineAsm::Option::NORETURN) == 1) infered = new TyTy::NeverType (expr.get_mappings ().get_hirid ()); else infered = TyTy::TupleType::get_unit_type (); @@ -996,8 +1038,7 @@ TypeCheckExpr::visit (HIR::ArrayIndexExpr &expr) rich_location r (line_table, expr.get_locus ()); r.add_range (expr.get_array_expr ().get_locus ()); r.add_range (expr.get_index_expr ().get_locus ()); - rust_error_at (r, ErrorCode::E0277, - "the type %qs cannot be indexed by %qs", + rust_error_at (r, ErrorCode::E0277, "the type %qs cannot be indexed by %qs", array_expr_ty->get_name ().c_str (), index_expr_ty->get_name ().c_str ()); } @@ -1009,14 +1050,16 @@ TypeCheckExpr::visit (HIR::ArrayExpr &expr) HIR::Expr *capacity_expr = nullptr; TyTy::BaseType *element_type = nullptr; + TyTy::BaseType *capacity_type = nullptr; switch (elements.get_array_expr_type ()) { - case HIR::ArrayElems::ArrayExprType::COPIED: { + case HIR::ArrayElems::ArrayExprType::COPIED: + { HIR::ArrayElemsCopied &elems = static_cast (elements); element_type = TypeCheckExpr::Resolve (elems.get_elem_to_copy ()); - auto capacity_type + auto capacity_expr_ty = TypeCheckExpr::Resolve (elems.get_num_copies_expr ()); TyTy::BaseType *expected_ty = nullptr; @@ -1025,17 +1068,19 @@ TypeCheckExpr::visit (HIR::ArrayExpr &expr) context->insert_type (elems.get_num_copies_expr ().get_mappings (), expected_ty); - unify_site (expr.get_mappings ().get_hirid (), - TyTy::TyWithLocation (expected_ty), - TyTy::TyWithLocation ( - capacity_type, elems.get_num_copies_expr ().get_locus ()), - expr.get_locus ()); + unify_site ( + expr.get_mappings ().get_hirid (), TyTy::TyWithLocation (expected_ty), + TyTy::TyWithLocation (capacity_expr_ty, + elems.get_num_copies_expr ().get_locus ()), + expr.get_locus ()); capacity_expr = &elems.get_num_copies_expr (); + capacity_type = expected_ty; } break; - case HIR::ArrayElems::ArrayExprType::VALUES: { + case HIR::ArrayElems::ArrayExprType::VALUES: + { HIR::ArrayElemsValues &elems = static_cast (elements); @@ -1072,13 +1117,20 @@ TypeCheckExpr::visit (HIR::ArrayExpr &expr) bool ok = context->lookup_builtin ("usize", &expected_ty); rust_assert (ok); context->insert_type (mapping, expected_ty); + capacity_type = expected_ty; } break; } - infered = new TyTy::ArrayType (expr.get_mappings ().get_hirid (), - expr.get_locus (), *capacity_expr, - TyTy::TyVar (element_type->get_ref ())); + rust_assert (capacity_expr); + rust_assert (capacity_type); + auto ctx = Compile::Context::get (); + tree capacity + = Compile::HIRCompileBase::query_compile_const_expr (ctx, capacity_type, + *capacity_expr); + infered + = new TyTy::ArrayType (expr.get_mappings ().get_hirid (), expr.get_locus (), + capacity, TyTy::TyVar (element_type->get_ref ())); } // empty struct @@ -1702,16 +1754,22 @@ TypeCheckExpr::visit (HIR::MatchExpr &expr) void TypeCheckExpr::visit (HIR::ClosureExpr &expr) { - TypeCheckContextItem current_context = context->peek_context (); - TyTy::FnType *current_context_fndecl = current_context.get_context_type (); - + std::vector subst_refs; HirId ref = expr.get_mappings ().get_hirid (); DefId id = expr.get_mappings ().get_defid (); - RustIdent ident{current_context_fndecl->get_ident ().path, expr.get_locus ()}; + RustIdent ident{CanonicalPath::create_empty (), expr.get_locus ()}; - // get from parent context - std::vector subst_refs - = current_context_fndecl->clone_substs (); + if (context->have_function_context ()) + { + TypeCheckContextItem current_context = context->peek_context (); + TyTy::FnType *current_context_fndecl + = current_context.get_context_type (); + + ident = RustIdent{current_context_fndecl->get_ident ().path, + expr.get_locus ()}; + + subst_refs = current_context_fndecl->clone_substs (); + } std::vector parameter_types; for (auto &p : expr.get_params ()) @@ -1826,7 +1884,7 @@ TypeCheckExpr::visit (HIR::ClosureExpr &expr) args.get_type_args ().push_back (std::unique_ptr (implicit_tuple)); // apply the arguments - predicate.apply_generic_arguments (&args, false); + predicate.apply_generic_arguments (&args, false, false); // finally inherit the trait bound infered->inherit_bounds ({predicate}); @@ -1845,7 +1903,16 @@ TypeCheckExpr::resolve_operator_overload ( // probe for the lang-item if (!lang_item_defined) return false; + DefId &respective_lang_item_id = lang_item_defined.value (); + auto def_lookup = mappings.lookup_defid (respective_lang_item_id); + rust_assert (def_lookup.has_value ()); + + HIR::Item *def_item = def_lookup.value (); + rust_assert (def_item->get_item_kind () == HIR::Item::ItemKind::Trait); + HIR::Trait &trait = *static_cast (def_item); + TraitReference *defid_trait_reference = TraitResolver::Resolve (trait); + rust_assert (!defid_trait_reference->is_error ()); // we might be in a static or const context and unknown is fine TypeCheckContextItem current_context = TypeCheckContextItem::get_error (); @@ -1889,15 +1956,49 @@ TypeCheckExpr::resolve_operator_overload ( if (selected_candidates.size () > 1) { - // mutliple candidates - rich_location r (line_table, expr.get_locus ()); - for (auto &c : resolved_candidates) - r.add_range (c.candidate.locus); + auto infer + = TyTy::TyVar::get_implicit_infer_var (expr.get_locus ()).get_tyty (); + auto trait_subst = defid_trait_reference->get_trait_substs (); + rust_assert (trait_subst.size () > 0); - rust_error_at ( - r, "multiple candidates found for possible operator overload"); + TyTy::TypeBoundPredicate pred (respective_lang_item_id, trait_subst, + BoundPolarity::RegularBound, + expr.get_locus ()); - return false; + std::vector mappings; + auto &self_param_mapping = trait_subst[0]; + mappings.push_back (TyTy::SubstitutionArg (&self_param_mapping, lhs)); + + if (rhs != nullptr) + { + rust_assert (trait_subst.size () == 2); + auto &rhs_param_mapping = trait_subst[1]; + mappings.push_back (TyTy::SubstitutionArg (&rhs_param_mapping, lhs)); + } + + std::map binding_args; + binding_args["Output"] = infer; + + TyTy::SubstitutionArgumentMappings arg_mappings (mappings, binding_args, + TyTy::RegionParamList ( + trait_subst.size ()), + expr.get_locus ()); + pred.apply_argument_mappings (arg_mappings, false); + + infer->inherit_bounds ({pred}); + DeferredOpOverload defer (expr.get_mappings ().get_hirid (), + lang_item_type, specified_segment, pred, expr); + context->insert_deferred_operator_overload (std::move (defer)); + + if (rhs != nullptr) + lhs = unify_site (expr.get_mappings ().get_hirid (), + TyTy::TyWithLocation (lhs), + TyTy::TyWithLocation (rhs), expr.get_locus ()); + + infered = unify_site (expr.get_mappings ().get_hirid (), + TyTy::TyWithLocation (lhs), + TyTy::TyWithLocation (infer), expr.get_locus ()); + return true; } // Get the adjusted self @@ -2062,16 +2163,13 @@ TypeCheckExpr::resolve_operator_overload ( HIR::PathIdentSegment TypeCheckExpr::resolve_possible_fn_trait_call_method_name ( - TyTy::BaseType &receiver, TyTy::TypeBoundPredicate *associated_predicate) + const TyTy::BaseType &receiver, + TyTy::TypeBoundPredicate *associated_predicate) { - // Question - // do we need to probe possible bounds here? I think not, i think when we - // support Fn traits they are explicitly specified - // FIXME // the logic to map the FnTrait to their respective call trait-item is // duplicated over in the backend/rust-compile-expr.cc - for (auto &bound : receiver.get_specified_bounds ()) + for (const auto &bound : receiver.get_specified_bounds ()) { bool found_fn = bound.get_name ().compare ("Fn") == 0; bool found_fn_mut = bound.get_name ().compare ("FnMut") == 0; @@ -2094,6 +2192,34 @@ TypeCheckExpr::resolve_possible_fn_trait_call_method_name ( } } + if (receiver.is ()) + { + const auto &ref = static_cast (receiver); + const auto &underlying = *ref.get_base (); + for (const auto &bound : underlying.get_specified_bounds ()) + { + bool found_fn = bound.get_name ().compare ("Fn") == 0; + bool found_fn_mut = bound.get_name ().compare ("FnMut") == 0; + bool found_fn_once = bound.get_name ().compare ("FnOnce") == 0; + + if (found_fn) + { + *associated_predicate = bound; + return HIR::PathIdentSegment ("call"); + } + else if (found_fn_mut) + { + *associated_predicate = bound; + return HIR::PathIdentSegment ("call_mut"); + } + else if (found_fn_once) + { + *associated_predicate = bound; + return HIR::PathIdentSegment ("call_once"); + } + } + } + // nothing *associated_predicate = TyTy::TypeBoundPredicate::error (); return HIR::PathIdentSegment (""); diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.h b/gcc/rust/typecheck/rust-hir-type-check-expr.h index 79121b36b436..48f28c700795 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-expr.h +++ b/gcc/rust/typecheck/rust-hir-type-check-expr.h @@ -31,6 +31,11 @@ class TypeCheckExpr : private TypeCheckBase, private HIR::HIRExpressionVisitor public: static TyTy::BaseType *Resolve (HIR::Expr &expr); + static TyTy::BaseType * + ResolveOpOverload (LangItem::Kind lang_item_type, HIR::OperatorExprMeta expr, + TyTy::BaseType *lhs, TyTy::BaseType *rhs, + HIR::PathIdentSegment specified_segment); + void visit (HIR::TupleIndexExpr &expr) override; void visit (HIR::TupleExpr &expr) override; void visit (HIR::ReturnExpr &expr) override; @@ -46,6 +51,8 @@ class TypeCheckExpr : private TypeCheckBase, private HIR::HIRExpressionVisitor void visit (HIR::IfExpr &expr) override; void visit (HIR::IfExprConseqElse &expr) override; void visit (HIR::BlockExpr &expr) override; + void visit (HIR::AnonConst &expr) override; + void visit (HIR::ConstBlock &expr) override; void visit (HIR::UnsafeBlockExpr &expr) override; void visit (HIR::ArrayIndexExpr &expr) override; void visit (HIR::ArrayExpr &expr) override; @@ -107,7 +114,8 @@ class TypeCheckExpr : private TypeCheckBase, private HIR::HIRExpressionVisitor TyTy::BaseType **result); HIR::PathIdentSegment resolve_possible_fn_trait_call_method_name ( - TyTy::BaseType &receiver, TyTy::TypeBoundPredicate *associated_predicate); + const TyTy::BaseType &receiver, + TyTy::TypeBoundPredicate *associated_predicate); private: TypeCheckExpr (); diff --git a/gcc/rust/typecheck/rust-hir-type-check-implitem.cc b/gcc/rust/typecheck/rust-hir-type-check-implitem.cc index bc7f6dc58c48..00f0cc669747 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-implitem.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-implitem.cc @@ -266,7 +266,8 @@ TypeCheckImplItem::visit (HIR::Function &function) self_type = self->clone (); break; - case HIR::SelfParam::IMM_REF: { + case HIR::SelfParam::IMM_REF: + { tl::optional region; if (self_param.has_lifetime ()) { @@ -290,7 +291,8 @@ TypeCheckImplItem::visit (HIR::Function &function) } break; - case HIR::SelfParam::MUT_REF: { + case HIR::SelfParam::MUT_REF: + { tl::optional region; if (self_param.has_lifetime ()) { @@ -343,8 +345,8 @@ TypeCheckImplItem::visit (HIR::Function &function) auto &nr_ctx = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); - canonical_path = nr_ctx.values.to_canonical_path ( - function.get_mappings ().get_nodeid ()); + canonical_path + = nr_ctx.to_canonical_path (function.get_mappings ().get_nodeid ()); } else { @@ -494,10 +496,9 @@ TypeCheckImplItemWithTrait::visit (HIR::ConstantItem &constant) rich_location r (line_table, constant.get_locus ()); r.add_range (resolved_trait_item.get_locus ()); - rust_error_at ( - r, "constant %qs has an incompatible type for trait %qs", - constant.get_identifier ().as_string ().c_str (), - trait_reference.get_name ().c_str ()); + rust_error_at (r, "constant %qs has an incompatible type for trait %qs", + constant.get_identifier ().as_string ().c_str (), + trait_reference.get_name ().c_str ()); } } @@ -545,10 +546,9 @@ TypeCheckImplItemWithTrait::visit (HIR::TypeAlias &type) rich_location r (line_table, type.get_locus ()); r.add_range (resolved_trait_item.get_locus ()); - rust_error_at ( - r, "type alias %qs has an incompatible type for trait %qs", - type.get_new_type_name ().as_string ().c_str (), - trait_reference.get_name ().c_str ()); + rust_error_at (r, "type alias %qs has an incompatible type for trait %qs", + type.get_new_type_name ().as_string ().c_str (), + trait_reference.get_name ().c_str ()); } // its actually a projection, since we need a way to actually bind the diff --git a/gcc/rust/typecheck/rust-hir-type-check-item.cc b/gcc/rust/typecheck/rust-hir-type-check-item.cc index aaa04af628f4..70622778a1c0 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-item.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-item.cc @@ -203,9 +203,8 @@ TypeCheckItem::visit (HIR::TupleStruct &struct_decl) auto &nr_ctx = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); - path = nr_ctx.values - .to_canonical_path (struct_decl.get_mappings ().get_nodeid ()) - .value (); + path + = nr_ctx.to_canonical_path (struct_decl.get_mappings ().get_nodeid ()); } else { @@ -283,12 +282,8 @@ TypeCheckItem::visit (HIR::StructStruct &struct_decl) { auto &nr_ctx = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); - auto canonical_path = nr_ctx.types.to_canonical_path ( - struct_decl.get_mappings ().get_nodeid ()); - - if (!canonical_path.has_value ()) - rust_unreachable (); - path = canonical_path.value (); + path + = nr_ctx.to_canonical_path (struct_decl.get_mappings ().get_nodeid ()); } else { @@ -375,8 +370,8 @@ TypeCheckItem::visit (HIR::Enum &enum_decl) auto &nr_ctx = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); - canonical_path = nr_ctx.types.to_canonical_path ( - enum_decl.get_mappings ().get_nodeid ()); + canonical_path + = nr_ctx.to_canonical_path (enum_decl.get_mappings ().get_nodeid ()); } else { @@ -439,8 +434,8 @@ TypeCheckItem::visit (HIR::Union &union_decl) auto &nr_ctx = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); - canonical_path = nr_ctx.types.to_canonical_path ( - union_decl.get_mappings ().get_nodeid ()); + canonical_path + = nr_ctx.to_canonical_path (union_decl.get_mappings ().get_nodeid ()); } else { @@ -614,10 +609,7 @@ TypeCheckItem::visit (HIR::Function &function) { auto &nr_ctx = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); - auto canonical_path = nr_ctx.values.to_canonical_path ( - function.get_mappings ().get_nodeid ()); - - path = canonical_path.value (); + path = nr_ctx.to_canonical_path (function.get_mappings ().get_nodeid ()); } else { @@ -745,6 +737,25 @@ TypeCheckItem::visit (HIR::ExternBlock &extern_block) } } +void +TypeCheckItem::visit (HIR::ExternCrate &extern_crate) +{ + if (extern_crate.references_self ()) + return; + + auto &mappings = Analysis::Mappings::get (); + CrateNum num + = mappings.lookup_crate_name (extern_crate.get_referenced_crate ()) + .value (); + HIR::Crate &crate = mappings.get_hir_crate (num); + + CrateNum saved_crate_num = mappings.get_current_crate (); + mappings.set_current_crate (num); + for (auto &item : crate.get_items ()) + TypeCheckItem::Resolve (*item); + mappings.set_current_crate (saved_crate_num); +} + std::pair, TyTy::RegionConstraints> TypeCheckItem::resolve_impl_block_substitutions (HIR::ImplBlock &impl_block, bool &failure_flag) diff --git a/gcc/rust/typecheck/rust-hir-type-check-item.h b/gcc/rust/typecheck/rust-hir-type-check-item.h index 56832e75ccdb..414694be2790 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-item.h +++ b/gcc/rust/typecheck/rust-hir-type-check-item.h @@ -51,9 +51,9 @@ class TypeCheckItem : private TypeCheckBase, private HIR::HIRVisItemVisitor void visit (HIR::ImplBlock &impl_block) override; void visit (HIR::ExternBlock &extern_block) override; void visit (HIR::Trait &trait_block) override; + void visit (HIR::ExternCrate &extern_crate) override; // nothing to do - void visit (HIR::ExternCrate &) override {} void visit (HIR::UseDeclaration &) override {} protected: diff --git a/gcc/rust/typecheck/rust-hir-type-check-pattern.cc b/gcc/rust/typecheck/rust-hir-type-check-pattern.cc index bd13f7a56185..bb0e27bb2a6c 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-pattern.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-pattern.cc @@ -213,13 +213,15 @@ TypeCheckPattern::visit (HIR::TupleStructPattern &pattern) auto &items = pattern.get_items (); switch (items.get_item_type ()) { - case HIR::TupleStructItems::RANGED: { + case HIR::TupleStructItems::RANGED: + { // TODO rust_unreachable (); } break; - case HIR::TupleStructItems::MULTIPLE: { + case HIR::TupleStructItems::MULTIPLE: + { HIR::TupleStructItemsNoRange &items_no_range = static_cast (items); @@ -333,13 +335,15 @@ TypeCheckPattern::visit (HIR::StructPattern &pattern) { switch (field->get_item_type ()) { - case HIR::StructPatternField::ItemType::TUPLE_PAT: { + case HIR::StructPatternField::ItemType::TUPLE_PAT: + { // TODO rust_unreachable (); } break; - case HIR::StructPatternField::ItemType::IDENT_PAT: { + case HIR::StructPatternField::ItemType::IDENT_PAT: + { HIR::StructPatternFieldIdentPat &ident = static_cast (*field); @@ -358,7 +362,8 @@ TypeCheckPattern::visit (HIR::StructPattern &pattern) } break; - case HIR::StructPatternField::ItemType::IDENT: { + case HIR::StructPatternField::ItemType::IDENT: + { HIR::StructPatternFieldIdent &ident = static_cast (*field); @@ -397,7 +402,8 @@ TypeCheckPattern::visit (HIR::StructPattern &pattern) case HIR::StructPatternField::ItemType::IDENT: case HIR::StructPatternField::ItemType::IDENT_PAT: break; - default: { + default: + { auto first_elem = struct_pattern_elems.get_struct_pattern_fields () .at (0) @@ -457,25 +463,27 @@ void TypeCheckPattern::visit (HIR::TuplePattern &pattern) { std::unique_ptr items; + + // Check whether parent is tuple + auto resolved_parent = parent->destructure (); + if (resolved_parent->get_kind () != TyTy::TUPLE) + { + rust_error_at (pattern.get_locus (), "expected %s, found tuple", + parent->as_string ().c_str ()); + return; + } + TyTy::TupleType &par = *static_cast (resolved_parent); + switch (pattern.get_items ().get_item_type ()) { - case HIR::TuplePatternItems::ItemType::MULTIPLE: { + case HIR::TuplePatternItems::ItemType::MULTIPLE: + { auto &ref = static_cast ( pattern.get_items ()); - auto resolved_parent = parent->destructure (); - if (resolved_parent->get_kind () != TyTy::TUPLE) - { - rust_error_at (pattern.get_locus (), "expected %s, found tuple", - parent->as_string ().c_str ()); - break; - } - const auto &patterns = ref.get_patterns (); size_t nitems_to_resolve = patterns.size (); - TyTy::TupleType &par - = *static_cast (resolved_parent); if (patterns.size () != par.get_fields ().size ()) { emit_pattern_size_error (pattern, par.get_fields ().size (), @@ -498,12 +506,55 @@ TypeCheckPattern::visit (HIR::TuplePattern &pattern) } break; - case HIR::TuplePatternItems::ItemType::RANGED: { - // HIR::TuplePatternItemsRanged &ref - // = *static_cast ( - // pattern.get_items ().get ()); - // TODO - rust_unreachable (); + case HIR::TuplePatternItems::ItemType::RANGED: + { + HIR::TuplePatternItemsRanged &ref + = static_cast (pattern.get_items ()); + + const auto &lower = ref.get_lower_patterns (); + const auto &upper = ref.get_upper_patterns (); + size_t min_size_required = lower.size () + upper.size (); + + // Ensure that size of lower and upper patterns <= parent size + if (min_size_required > par.get_fields ().size ()) + { + emit_pattern_size_error (pattern, par.get_fields ().size (), + min_size_required); + // TODO attempt to continue to do typechecking even after wrong size + break; + } + + // Resolve lower patterns + std::vector pattern_elems; + for (size_t i = 0; i < lower.size (); i++) + { + auto &p = lower[i]; + TyTy::BaseType *par_type = par.get_field (i); + + TyTy::BaseType *elem = TypeCheckPattern::Resolve (*p, par_type); + pattern_elems.push_back (TyTy::TyVar (elem->get_ref ())); + } + + // Pad pattern_elems until needing to resolve upper patterns + size_t rest_end = par.get_fields ().size () - upper.size (); + for (size_t i = lower.size (); i < rest_end; i++) + { + TyTy::BaseType *par_type = par.get_field (i); + pattern_elems.push_back (TyTy::TyVar (par_type->get_ref ())); + } + + // Resolve upper patterns + for (size_t i = 0; i < upper.size (); i++) + { + auto &p = upper[i]; + TyTy::BaseType *par_type = par.get_field (rest_end + i); + + TyTy::BaseType *elem = TypeCheckPattern::Resolve (*p, par_type); + pattern_elems.push_back (TyTy::TyVar (elem->get_ref ())); + } + + infered = new TyTy::TupleType (pattern.get_mappings ().get_hirid (), + pattern.get_locus (), pattern_elems); } break; } @@ -512,8 +563,18 @@ TypeCheckPattern::visit (HIR::TuplePattern &pattern) void TypeCheckPattern::visit (HIR::LiteralPattern &pattern) { - infered = resolve_literal (pattern.get_mappings (), pattern.get_literal (), - pattern.get_locus ()); + TyTy::BaseType *resolved + = resolve_literal (pattern.get_mappings (), pattern.get_literal (), + pattern.get_locus ()); + if (resolved->get_kind () == TyTy::TypeKind::ERROR) + { + infered = resolved; + return; + } + + infered = unify_site (pattern.get_mappings ().get_hirid (), + TyTy::TyWithLocation (parent), + TyTy::TyWithLocation (resolved), pattern.get_locus ()); } void @@ -538,6 +599,11 @@ TypeCheckPattern::visit (HIR::RangePattern &pattern) void TypeCheckPattern::visit (HIR::IdentifierPattern &pattern) { + if (pattern.has_subpattern ()) + { + TypeCheckPattern::Resolve (pattern.get_subpattern (), parent); + } + if (!pattern.get_is_ref ()) { infered = parent; @@ -580,8 +646,58 @@ TypeCheckPattern::visit (HIR::ReferencePattern &pattern) void TypeCheckPattern::visit (HIR::SlicePattern &pattern) { - rust_sorry_at (pattern.get_locus (), - "type checking qualified path patterns not supported"); + auto resolved_parent = parent->destructure (); + TyTy::BaseType *parent_element_ty = nullptr; + switch (resolved_parent->get_kind ()) + { + case TyTy::ARRAY: + { + auto &array_ty_ty = static_cast (*parent); + parent_element_ty = array_ty_ty.get_element_type (); + tree cap = array_ty_ty.get_capacity (); + if (error_operand_p (cap)) + { + rust_error_at (parent->get_locus (), + "capacity of array %qs is not known at compile time", + array_ty_ty.get_name ().c_str ()); + break; + } + auto cap_wi = wi::to_wide (cap).to_uhwi (); + if (cap_wi != pattern.get_items ().size ()) + { + rust_error_at (pattern.get_locus (), ErrorCode::E0527, + "pattern requires %lu elements but array has %lu", + (unsigned long) pattern.get_items ().size (), + (unsigned long) cap_wi); + break; + } + break; + } + case TyTy::SLICE: + { + auto &array_ty_ty = static_cast (*parent); + parent_element_ty = array_ty_ty.get_element_type (); + break; + } + default: + { + rust_error_at (pattern.get_locus (), "expected %s, found slice", + parent->as_string ().c_str ()); + return; + } + } + + rust_assert (parent_element_ty != nullptr); + // infered inherits array/slice typing from parent + infered = parent->clone (); + infered->set_ref (pattern.get_mappings ().get_hirid ()); + + // Type check every item in the SlicePattern against parent's element ty + // TODO update this after adding support for RestPattern in SlicePattern + for (const auto &item : pattern.get_items ()) + { + TypeCheckPattern::Resolve (*item, parent_element_ty); + } } void @@ -608,7 +724,8 @@ TypeCheckPattern::typecheck_range_pattern_bound ( TyTy::BaseType *resolved_bound = nullptr; switch (bound.get_bound_type ()) { - case HIR::RangePatternBound::RangePatternBoundType::LITERAL: { + case HIR::RangePatternBound::RangePatternBoundType::LITERAL: + { auto &ref = static_cast (bound); HIR::Literal lit = ref.get_literal (); @@ -617,14 +734,16 @@ TypeCheckPattern::typecheck_range_pattern_bound ( } break; - case HIR::RangePatternBound::RangePatternBoundType::PATH: { + case HIR::RangePatternBound::RangePatternBoundType::PATH: + { auto &ref = static_cast (bound); resolved_bound = TypeCheckExpr::Resolve (ref.get_path ()); } break; - case HIR::RangePatternBound::RangePatternBoundType::QUALPATH: { + case HIR::RangePatternBound::RangePatternBoundType::QUALPATH: + { auto &ref = static_cast (bound); resolved_bound = TypeCheckExpr::Resolve (ref.get_qualified_path ()); diff --git a/gcc/rust/typecheck/rust-hir-type-check-stmt.cc b/gcc/rust/typecheck/rust-hir-type-check-stmt.cc index 4e53856278f1..87141af509fd 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-stmt.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-stmt.cc @@ -60,6 +60,12 @@ void TypeCheckStmt::visit (HIR::ConstantItem &constant) { TyTy::BaseType *type = TypeCheckType::Resolve (constant.get_type ()); + if (!constant.has_expr ()) + { + infered = type; + return; + } + TyTy::BaseType *expr_type = TypeCheckExpr::Resolve (constant.get_expr ()); infered = coercion_site ( diff --git a/gcc/rust/typecheck/rust-hir-type-check-struct.cc b/gcc/rust/typecheck/rust-hir-type-check-struct.cc index df1636a584a5..4ef83482a536 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-struct.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-struct.cc @@ -329,8 +329,7 @@ TypeCheckStructExpr::visit (HIR::StructExprFieldIndexValue &field) repeat_location.add_range (prev_field_locus); rust_error_at (repeat_location, ErrorCode::E0062, - "field %qs specified more than once", - field_name.c_str ()); + "field %qs specified more than once", field_name.c_str ()); return false; } @@ -363,7 +362,7 @@ TypeCheckStructExpr::visit (HIR::StructExprFieldIdentifier &field) if (!ok) { rust_error_at (field.get_locus (), "unknown field"); - return true; + return false; } auto it = adtFieldIndexToField.find (field_index); diff --git a/gcc/rust/typecheck/rust-hir-type-check-type.cc b/gcc/rust/typecheck/rust-hir-type-check-type.cc index 6919093b0f5f..462b3d487673 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-type.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-type.cc @@ -29,6 +29,7 @@ #include "rust-substitution-mapper.h" #include "rust-type-util.h" #include "rust-system.h" +#include "rust-compile-base.h" namespace Rust { namespace Resolver { @@ -549,8 +550,7 @@ TypeCheckType::resolve_segments ( bool selfResolveOk = false; if (first_segment && tySegIsBigSelf - && context->block_context ().is_in_context () - && context->block_context ().peek ().is_impl_block ()) + && context->block_context ().is_in_context ()) { TypeCheckBlockContextItem ctx = context->block_context ().peek (); TyTy::BaseType *lookup = nullptr; @@ -711,9 +711,14 @@ TypeCheckType::visit (HIR::ArrayType &type) type.get_size_expr ().get_locus ()); TyTy::BaseType *base = TypeCheckType::Resolve (type.get_element_type ()); - translated = new TyTy::ArrayType (type.get_mappings ().get_hirid (), - type.get_locus (), type.get_size_expr (), - TyTy::TyVar (base->get_ref ())); + + auto ctx = Compile::Context::get (); + tree capacity + = Compile::HIRCompileBase::query_compile_const_expr (ctx, capacity_type, + type.get_size_expr ()); + translated + = new TyTy::ArrayType (type.get_mappings ().get_hirid (), type.get_locus (), + capacity, TyTy::TyVar (base->get_ref ())); } void @@ -908,7 +913,8 @@ TypeResolveGenericParam::apply_trait_bounds (HIR::TypeParam ¶m, { switch (bound->get_bound_type ()) { - case HIR::TypeParamBound::BoundType::TRAITBOUND: { + case HIR::TypeParamBound::BoundType::TRAITBOUND: + { HIR::TraitBound &b = static_cast (*bound); TyTy::TypeBoundPredicate predicate = get_predicate_from_bound ( @@ -920,7 +926,8 @@ TypeResolveGenericParam::apply_trait_bounds (HIR::TypeParam ¶m, { switch (predicate.get_polarity ()) { - case BoundPolarity::AntiBound: { + case BoundPolarity::AntiBound: + { bool found = predicates.find (predicate.get_id ()) != predicates.end (); if (found) @@ -937,7 +944,8 @@ TypeResolveGenericParam::apply_trait_bounds (HIR::TypeParam ¶m, } break; - default: { + default: + { if (predicates.find (predicate.get_id ()) == predicates.end ()) { @@ -1033,7 +1041,8 @@ ResolveWhereClauseItem::visit (HIR::TypeBoundWhereClauseItem &item) { switch (bound->get_bound_type ()) { - case HIR::TypeParamBound::BoundType::TRAITBOUND: { + case HIR::TypeParamBound::BoundType::TRAITBOUND: + { auto *b = static_cast (bound.get ()); TyTy::TypeBoundPredicate predicate @@ -1042,7 +1051,8 @@ ResolveWhereClauseItem::visit (HIR::TypeBoundWhereClauseItem &item) specified_bounds.push_back (std::move (predicate)); } break; - case HIR::TypeParamBound::BoundType::LIFETIME: { + case HIR::TypeParamBound::BoundType::LIFETIME: + { if (auto param = binding->try_as ()) { auto *b = static_cast (bound.get ()); diff --git a/gcc/rust/typecheck/rust-hir-type-check.cc b/gcc/rust/typecheck/rust-hir-type-check.cc index fbaf3230d737..27879e3d4e9d 100644 --- a/gcc/rust/typecheck/rust-hir-type-check.cc +++ b/gcc/rust/typecheck/rust-hir-type-check.cc @@ -29,8 +29,7 @@ // for flag_name_resolution_2_0 #include "options.h" -extern bool -saw_errors (void); +extern bool saw_errors (void); namespace Rust { namespace Resolver { @@ -231,7 +230,8 @@ TraitItemReference::get_type_from_fn (/*const*/ HIR::TraitItemFunc &fn) const break; case HIR::SelfParam::IMM_REF: - case HIR::SelfParam::MUT_REF: { + case HIR::SelfParam::MUT_REF: + { auto mutability = self_param.get_self_kind () == HIR::SelfParam::IMM_REF ? Mutability::Imm @@ -284,7 +284,7 @@ TraitItemReference::get_type_from_fn (/*const*/ HIR::TraitItemFunc &fn) const = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); canonical_path - = nr_ctx.values.to_canonical_path (fn.get_mappings ().get_nodeid ()); + = nr_ctx.to_canonical_path (fn.get_mappings ().get_nodeid ()); } else { diff --git a/gcc/rust/typecheck/rust-hir-type-check.h b/gcc/rust/typecheck/rust-hir-type-check.h index 18a65fec0483..80e403448359 100644 --- a/gcc/rust/typecheck/rust-hir-type-check.h +++ b/gcc/rust/typecheck/rust-hir-type-check.h @@ -20,6 +20,7 @@ #define RUST_HIR_TYPE_CHECK #include "rust-hir-map.h" +#include "rust-mapping-common.h" #include "rust-tyty.h" #include "rust-hir-trait-reference.h" #include "rust-stacked-contexts.h" @@ -157,6 +158,39 @@ class Lifetime WARN_UNUSED_RESULT Lifetime next () { return Lifetime (interner_index++); } }; +struct DeferredOpOverload +{ + HirId expr_id; + LangItem::Kind lang_item_type; + HIR::PathIdentSegment specified_segment; + TyTy::TypeBoundPredicate predicate; + HIR::OperatorExprMeta op; + + DeferredOpOverload (HirId expr_id, LangItem::Kind lang_item_type, + HIR::PathIdentSegment specified_segment, + TyTy::TypeBoundPredicate &predicate, + HIR::OperatorExprMeta op) + : expr_id (expr_id), lang_item_type (lang_item_type), + specified_segment (specified_segment), predicate (predicate), op (op) + {} + + DeferredOpOverload (const struct DeferredOpOverload &other) + : expr_id (other.expr_id), lang_item_type (other.lang_item_type), + specified_segment (other.specified_segment), predicate (other.predicate), + op (other.op) + {} + + DeferredOpOverload &operator= (struct DeferredOpOverload const &other) + { + expr_id = other.expr_id; + lang_item_type = other.lang_item_type; + specified_segment = other.specified_segment; + op = other.op; + + return *this; + } +}; + class TypeCheckContext { public: @@ -237,6 +271,13 @@ class TypeCheckContext void insert_operator_overload (HirId id, TyTy::FnType *call_site); bool lookup_operator_overload (HirId id, TyTy::FnType **call); + void insert_deferred_operator_overload (DeferredOpOverload deferred); + bool lookup_deferred_operator_overload (HirId id, + DeferredOpOverload *deferred); + + void iterate_deferred_operator_overloads ( + std::function cb); + void insert_unconstrained_check_marker (HirId id, bool status); bool have_checked_for_unconstrained (HirId id, bool *result); @@ -263,13 +304,16 @@ class TypeCheckContext WARN_UNUSED_RESULT std::vector regions_from_generic_args (const HIR::GenericArgs &args) const; - void compute_inference_variables (bool error); + void compute_inference_variables (bool emit_error); TyTy::VarianceAnalysis::CrateCtx &get_variance_analysis_ctx (); private: TypeCheckContext (); + bool compute_infer_var (HirId id, TyTy::BaseType *ty, bool emit_error); + bool compute_ambigious_op_overload (HirId id, DeferredOpOverload &op); + std::map node_id_refs; std::map resolved; std::vector> builtins; @@ -306,6 +350,9 @@ class TypeCheckContext std::set querys_in_progress; std::set trait_queries_in_progress; + // deferred operator overload + std::map deferred_operator_overloads; + // variance analysis TyTy::VarianceAnalysis::CrateCtx variance_analysis_ctx; diff --git a/gcc/rust/typecheck/rust-substitution-mapper.cc b/gcc/rust/typecheck/rust-substitution-mapper.cc index f0bd1f8bb17f..bdfde55718be 100644 --- a/gcc/rust/typecheck/rust-substitution-mapper.cc +++ b/gcc/rust/typecheck/rust-substitution-mapper.cc @@ -374,7 +374,7 @@ SubstMapperInternal::visit (TyTy::DynamicObjectType &type) void SubstMapperInternal::visit (TyTy::OpaqueType &type) { - resolved = type.handle_substitions (mappings); + resolved = type.clone (); } // SubstMapperFromExisting diff --git a/gcc/rust/typecheck/rust-type-util.cc b/gcc/rust/typecheck/rust-type-util.cc index c6c5b4bb55fa..a549449dcef0 100644 --- a/gcc/rust/typecheck/rust-type-util.cc +++ b/gcc/rust/typecheck/rust-type-util.cc @@ -40,12 +40,12 @@ query_type (HirId reference, TyTy::BaseType **result) auto &resolver = *Resolver::get (); TypeCheckContext *context = TypeCheckContext::get (); - if (context->query_in_progress (reference)) - return false; - if (context->lookup_type (reference, result)) return true; + if (context->query_in_progress (reference)) + return false; + context->insert_query (reference); std::pair enum_candidiate diff --git a/gcc/rust/typecheck/rust-type-util.h b/gcc/rust/typecheck/rust-type-util.h index 03874a48bd8e..dd97f1e989ac 100644 --- a/gcc/rust/typecheck/rust-type-util.h +++ b/gcc/rust/typecheck/rust-type-util.h @@ -25,33 +25,30 @@ namespace Rust { namespace Resolver { -bool -query_type (HirId reference, TyTy::BaseType **result); +bool query_type (HirId reference, TyTy::BaseType **result); -bool -types_compatable (TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs, - location_t unify_locus, bool emit_errors); +bool types_compatable (TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs, + location_t unify_locus, bool emit_errors); -TyTy::BaseType * -unify_site (HirId id, TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs, - location_t unify_locus); +TyTy::BaseType *unify_site (HirId id, TyTy::TyWithLocation lhs, + TyTy::TyWithLocation rhs, location_t unify_locus); -TyTy::BaseType * -unify_site_and (HirId id, TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs, - location_t unify_locus, bool emit_errors, bool commit_if_ok, - bool implicit_infer_vars, bool cleanup); +TyTy::BaseType *unify_site_and (HirId id, TyTy::TyWithLocation lhs, + TyTy::TyWithLocation rhs, + location_t unify_locus, bool emit_errors, + bool commit_if_ok, bool implicit_infer_vars, + bool cleanup); -TyTy::BaseType * -coercion_site (HirId id, TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs, - location_t coercion_locus); +TyTy::BaseType *coercion_site (HirId id, TyTy::TyWithLocation lhs, + TyTy::TyWithLocation rhs, + location_t coercion_locus); -TyTy::BaseType * -try_coercion (HirId id, TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs, - location_t coercion_locus); +TyTy::BaseType *try_coercion (HirId id, TyTy::TyWithLocation lhs, + TyTy::TyWithLocation rhs, + location_t coercion_locus); -TyTy::BaseType * -cast_site (HirId id, TyTy::TyWithLocation from, TyTy::TyWithLocation to, - location_t cast_locus); +TyTy::BaseType *cast_site (HirId id, TyTy::TyWithLocation from, + TyTy::TyWithLocation to, location_t cast_locus); AssociatedImplTrait * lookup_associated_impl_block (const TyTy::TypeBoundPredicate &bound, diff --git a/gcc/rust/typecheck/rust-typecheck-context.cc b/gcc/rust/typecheck/rust-typecheck-context.cc index 9112b998f168..83b17612d5e3 100644 --- a/gcc/rust/typecheck/rust-typecheck-context.cc +++ b/gcc/rust/typecheck/rust-typecheck-context.cc @@ -18,6 +18,7 @@ #include "rust-hir-type-check.h" #include "rust-type-util.h" +#include "rust-hir-type-check-expr.h" namespace Rust { namespace Resolver { @@ -408,6 +409,38 @@ TypeCheckContext::lookup_operator_overload (HirId id, TyTy::FnType **call) return true; } +void +TypeCheckContext::insert_deferred_operator_overload ( + DeferredOpOverload deferred) +{ + HirId expr_id = deferred.expr_id; + deferred_operator_overloads.emplace (std::make_pair (expr_id, deferred)); +} + +bool +TypeCheckContext::lookup_deferred_operator_overload ( + HirId id, DeferredOpOverload *deferred) +{ + auto it = deferred_operator_overloads.find (id); + if (it == deferred_operator_overloads.end ()) + return false; + + *deferred = it->second; + return true; +} + +void +TypeCheckContext::iterate_deferred_operator_overloads ( + std::function cb) +{ + for (auto it = deferred_operator_overloads.begin (); + it != deferred_operator_overloads.end (); it++) + { + if (!cb (it->first, it->second)) + return; + } +} + void TypeCheckContext::insert_unconstrained_check_marker (HirId id, bool status) { @@ -574,44 +607,77 @@ TypeCheckContext::regions_from_generic_args (const HIR::GenericArgs &args) const return regions; } +bool +TypeCheckContext::compute_ambigious_op_overload (HirId id, + DeferredOpOverload &op) +{ + rust_debug ("attempting resolution of op overload: %s", + op.predicate.as_string ().c_str ()); + + TyTy::BaseType *lhs = nullptr; + bool ok = lookup_type (op.op.get_lvalue_mappings ().get_hirid (), &lhs); + rust_assert (ok); + + TyTy::BaseType *rhs = nullptr; + if (op.op.has_rvalue_mappings ()) + { + bool ok = lookup_type (op.op.get_rvalue_mappings ().get_hirid (), &rhs); + rust_assert (ok); + } + + TypeCheckExpr::ResolveOpOverload (op.lang_item_type, op.op, lhs, rhs, + op.specified_segment); + + return true; +} + void -TypeCheckContext::compute_inference_variables (bool error) +TypeCheckContext::compute_inference_variables (bool emit_error) { - auto &mappings = Analysis::Mappings::get (); + iterate_deferred_operator_overloads ( + [&] (HirId id, DeferredOpOverload &op) mutable -> bool { + return compute_ambigious_op_overload (id, op); + }); - // default inference variables if possible iterate ([&] (HirId id, TyTy::BaseType *ty) mutable -> bool { - // nothing to do - if (ty->get_kind () != TyTy::TypeKind::INFER) - return true; + return compute_infer_var (id, ty, emit_error); + }); +} - TyTy::InferType *infer_var = static_cast (ty); - TyTy::BaseType *default_type; - - rust_debug_loc (mappings.lookup_location (id), - "trying to default infer-var: %s", - infer_var->as_string ().c_str ()); - bool ok = infer_var->default_type (&default_type); - if (!ok) - { - if (error) - rust_error_at (mappings.lookup_location (id), ErrorCode::E0282, - "type annotations needed"); - return true; - } - - auto result - = unify_site (id, TyTy::TyWithLocation (ty), - TyTy::TyWithLocation (default_type), UNDEF_LOCATION); - rust_assert (result); - rust_assert (result->get_kind () != TyTy::TypeKind::ERROR); - result->set_ref (id); - insert_type (Analysis::NodeMapping (mappings.get_current_crate (), 0, id, - UNKNOWN_LOCAL_DEFID), - result); +bool +TypeCheckContext::compute_infer_var (HirId id, TyTy::BaseType *ty, + bool emit_error) +{ + auto &mappings = Analysis::Mappings::get (); + // nothing to do + if (ty->get_kind () != TyTy::TypeKind::INFER) return true; - }); + + TyTy::InferType *infer_var = static_cast (ty); + TyTy::BaseType *default_type; + + rust_debug_loc (mappings.lookup_location (id), + "trying to default infer-var: %s", + infer_var->as_string ().c_str ()); + bool ok = infer_var->default_type (&default_type); + if (!ok) + { + if (emit_error) + rust_error_at (mappings.lookup_location (id), ErrorCode::E0282, + "type annotations needed"); + return true; + } + + auto result + = unify_site (id, TyTy::TyWithLocation (ty), + TyTy::TyWithLocation (default_type), UNDEF_LOCATION); + rust_assert (result); + rust_assert (result->get_kind () != TyTy::TypeKind::ERROR); + result->set_ref (id); + insert_implicit_type (id, result); + + return true; } TyTy::VarianceAnalysis::CrateCtx & diff --git a/gcc/rust/typecheck/rust-tyty-bounds.cc b/gcc/rust/typecheck/rust-tyty-bounds.cc index e028a0af80bb..c34d3628895a 100644 --- a/gcc/rust/typecheck/rust-tyty-bounds.cc +++ b/gcc/rust/typecheck/rust-tyty-bounds.cc @@ -61,6 +61,39 @@ TypeBoundsProbe::is_bound_satisfied_for_type (TyTy::BaseType *receiver, return false; } +bool +TypeBoundsProbe::process_impl_block ( + HirId id, HIR::ImplBlock *impl, + std::vector> + &possible_trait_paths) +{ + // we are filtering for trait-impl-blocks + if (!impl->has_trait_ref ()) + return true; + + // can be recursive trait resolution + HIR::Trait *t = TraitResolver::ResolveHirItem (impl->get_trait_ref ()); + if (t == nullptr) + return true; + // DefId trait_id = t->get_mappings ().get_defid (); + // if (context->trait_query_in_progress (trait_id)) + // return true; + + HirId impl_ty_id = impl->get_type ().get_mappings ().get_hirid (); + TyTy::BaseType *impl_type = nullptr; + if (!query_type (impl_ty_id, &impl_type)) + return true; + + if (!receiver->can_eq (impl_type, false)) + { + if (!impl_type->can_eq (receiver, false)) + return true; + } + + possible_trait_paths.push_back ({&impl->get_trait_ref (), impl}); + return true; +} + void TypeBoundsProbe::scan () { @@ -68,31 +101,7 @@ TypeBoundsProbe::scan () possible_trait_paths; mappings.iterate_impl_blocks ( [&] (HirId id, HIR::ImplBlock *impl) mutable -> bool { - // we are filtering for trait-impl-blocks - if (!impl->has_trait_ref ()) - return true; - - // can be recursive trait resolution - HIR::Trait *t = TraitResolver::ResolveHirItem (impl->get_trait_ref ()); - if (t == nullptr) - return true; - DefId trait_id = t->get_mappings ().get_defid (); - if (context->trait_query_in_progress (trait_id)) - return true; - - HirId impl_ty_id = impl->get_type ().get_mappings ().get_hirid (); - TyTy::BaseType *impl_type = nullptr; - if (!query_type (impl_ty_id, &impl_type)) - return true; - - if (!receiver->can_eq (impl_type, false)) - { - if (!impl_type->can_eq (receiver, false)) - return true; - } - - possible_trait_paths.push_back ({&impl->get_trait_ref (), impl}); - return true; + return process_impl_block (id, impl, possible_trait_paths); }); for (auto &path : possible_trait_paths) @@ -105,7 +114,7 @@ TypeBoundsProbe::scan () } // marker traits... - assemble_sized_builtin (); + assemble_marker_builtins (); // add auto trait bounds for (auto *auto_trait : mappings.get_auto_traits ()) @@ -113,7 +122,7 @@ TypeBoundsProbe::scan () } void -TypeBoundsProbe::assemble_sized_builtin () +TypeBoundsProbe::assemble_marker_builtins () { const TyTy::BaseType *raw = receiver->destructure (); @@ -132,7 +141,6 @@ TypeBoundsProbe::assemble_sized_builtin () case TyTy::POINTER: case TyTy::PARAM: case TyTy::FNDEF: - case TyTy::FNPTR: case TyTy::BOOL: case TyTy::CHAR: case TyTy::INT: @@ -140,7 +148,6 @@ TypeBoundsProbe::assemble_sized_builtin () case TyTy::FLOAT: case TyTy::USIZE: case TyTy::ISIZE: - case TyTy::CLOSURE: case TyTy::INFER: case TyTy::NEVER: case TyTy::PLACEHOLDER: @@ -149,6 +156,14 @@ TypeBoundsProbe::assemble_sized_builtin () assemble_builtin_candidate (LangItem::Kind::SIZED); break; + case TyTy::FNPTR: + case TyTy::CLOSURE: + assemble_builtin_candidate (LangItem::Kind::SIZED); + assemble_builtin_candidate (LangItem::Kind::FN_ONCE); + assemble_builtin_candidate (LangItem::Kind::FN); + assemble_builtin_candidate (LangItem::Kind::FN_MUT); + break; + // FIXME str and slice need to be moved and test cases updated case TyTy::SLICE: case TyTy::STR: @@ -206,7 +221,7 @@ TyTy::TypeBoundPredicate TypeCheckBase::get_predicate_from_bound ( HIR::TypePath &type_path, tl::optional> associated_self, - BoundPolarity polarity, bool is_qualified_type_path) + BoundPolarity polarity, bool is_qualified_type_path, bool is_super_trait) { TyTy::TypeBoundPredicate lookup = TyTy::TypeBoundPredicate::error (); bool already_resolved @@ -226,7 +241,8 @@ TypeCheckBase::get_predicate_from_bound ( auto &final_seg = type_path.get_final_segment (); switch (final_seg.get_type ()) { - case HIR::TypePathSegment::SegmentType::GENERIC: { + case HIR::TypePathSegment::SegmentType::GENERIC: + { auto &final_generic_seg = static_cast (final_seg); if (final_generic_seg.has_generic_args ()) @@ -251,7 +267,8 @@ TypeCheckBase::get_predicate_from_bound ( } break; - case HIR::TypePathSegment::SegmentType::FUNCTION: { + case HIR::TypePathSegment::SegmentType::FUNCTION: + { auto &final_function_seg = static_cast (final_seg); auto &fn = final_function_seg.get_function_path (); @@ -327,7 +344,8 @@ TypeCheckBase::get_predicate_from_bound ( if (!args.is_empty () || predicate.requires_generic_args ()) { // this is applying generic arguments to a trait reference - predicate.apply_generic_arguments (&args, associated_self.has_value ()); + predicate.apply_generic_arguments (&args, associated_self.has_value (), + is_super_trait); } context->insert_resolved_predicate (type_path.get_mappings ().get_hirid (), @@ -508,7 +526,8 @@ TypeBoundPredicate::is_object_safe (bool emit_error, location_t locus) const void TypeBoundPredicate::apply_generic_arguments (HIR::GenericArgs *generic_args, - bool has_associated_self) + bool has_associated_self, + bool is_super_trait) { rust_assert (!substitutions.empty ()); if (has_associated_self) @@ -529,23 +548,26 @@ TypeBoundPredicate::apply_generic_arguments (HIR::GenericArgs *generic_args, Resolver::TypeCheckContext::get ()->regions_from_generic_args ( *generic_args)); - apply_argument_mappings (args); + apply_argument_mappings (args, is_super_trait); } void TypeBoundPredicate::apply_argument_mappings ( - SubstitutionArgumentMappings &arguments) + SubstitutionArgumentMappings &arguments, bool is_super_trait) { used_arguments = arguments; error_flag |= used_arguments.is_error (); auto &subst_mappings = used_arguments; + + bool substs_need_bounds_check = !is_super_trait; for (auto &sub : get_substs ()) { SubstitutionArg arg = SubstitutionArg::error (); bool ok = subst_mappings.get_argument_for_symbol (sub.get_param_ty (), &arg); if (ok && arg.get_tyty () != nullptr) - sub.fill_param_ty (subst_mappings, subst_mappings.get_locus ()); + sub.fill_param_ty (subst_mappings, subst_mappings.get_locus (), + substs_need_bounds_check); } // associated argument mappings @@ -566,7 +588,7 @@ TypeBoundPredicate::apply_argument_mappings ( auto adjusted = super_trait.adjust_mappings_for_this (used_arguments, true /*trait mode*/); - super_trait.apply_argument_mappings (adjusted); + super_trait.apply_argument_mappings (adjusted, is_super_trait); } } @@ -746,16 +768,34 @@ size_t TypeBoundPredicate::get_num_associated_bindings () const { size_t count = 0; + + get_trait_hierachy ([&count] (const Resolver::TraitReference &ref) { + for (const auto &trait_item : ref.get_trait_items ()) + { + bool is_associated_type + = trait_item.get_trait_item_type () + == Resolver::TraitItemReference::TraitItemType::TYPE; + if (is_associated_type) + count++; + } + }); + + return count; +} + +void +TypeBoundPredicate::get_trait_hierachy ( + std::function callback) const +{ auto trait_ref = get (); - for (const auto &trait_item : trait_ref->get_trait_items ()) + callback (*trait_ref); + + for (auto &super : super_traits) { - bool is_associated_type - = trait_item.get_trait_item_type () - == Resolver::TraitItemReference::TraitItemType::TYPE; - if (is_associated_type) - count++; + const auto &super_trait_ref = *super.get (); + callback (super_trait_ref); + super.get_trait_hierachy (callback); } - return count; } TypeBoundPredicateItem diff --git a/gcc/rust/typecheck/rust-tyty-call.cc b/gcc/rust/typecheck/rust-tyty-call.cc index 2e0830e4adad..63bb1ff91f80 100644 --- a/gcc/rust/typecheck/rust-tyty-call.cc +++ b/gcc/rust/typecheck/rust-tyty-call.cc @@ -171,7 +171,8 @@ TypeCheckCallExpr::visit (FnType &type) { case TyTy::TypeKind::ERROR: return; - case TyTy::TypeKind::INT: { + case TyTy::TypeKind::INT: + { auto &int_ty = static_cast (*argument_expr_tyty); if ((int_ty.get_int_kind () == TyTy::IntType::IntKind::I8) @@ -186,7 +187,8 @@ TypeCheckCallExpr::visit (FnType &type) } break; } - case TyTy::TypeKind::UINT: { + case TyTy::TypeKind::UINT: + { auto &uint_ty = static_cast (*argument_expr_tyty); if ((uint_ty.get_uint_kind () == TyTy::UintType::UintKind::U8) @@ -202,7 +204,8 @@ TypeCheckCallExpr::visit (FnType &type) } break; } - case TyTy::TypeKind::FLOAT: { + case TyTy::TypeKind::FLOAT: + { if (static_cast (*argument_expr_tyty) .get_float_kind () == TyTy::FloatType::FloatKind::F32) @@ -216,14 +219,16 @@ TypeCheckCallExpr::visit (FnType &type) } break; } - case TyTy::TypeKind::BOOL: { + case TyTy::TypeKind::BOOL: + { rich_location richloc (line_table, arg_locus); richloc.add_fixit_replace ("cast the value to c_int: as c_int"); rust_error_at (arg_locus, ErrorCode::E0617, "expected % variadic argument"); return; } - case TyTy::TypeKind::FNDEF: { + case TyTy::TypeKind::FNDEF: + { rust_error_at ( arg_locus, ErrorCode::E0617, "unexpected function definition type as variadic " @@ -246,7 +251,7 @@ TypeCheckCallExpr::visit (FnType &type) } type.monomorphize (); - resolved = type.get_return_type ()->clone (); + resolved = type.get_return_type ()->monomorphized_clone (); } void diff --git a/gcc/rust/typecheck/rust-tyty-cmp.h b/gcc/rust/typecheck/rust-tyty-cmp.h index c897c1321bde..aeefaa9323b1 100644 --- a/gcc/rust/typecheck/rust-tyty-cmp.h +++ b/gcc/rust/typecheck/rust-tyty-cmp.h @@ -621,7 +621,8 @@ class InferCmp : public BaseCmp ok = true; return; - case InferType::InferTypeKind::INTEGRAL: { + case InferType::InferTypeKind::INTEGRAL: + { if (type.get_infer_kind () == InferType::InferTypeKind::INTEGRAL) { ok = true; @@ -635,7 +636,8 @@ class InferCmp : public BaseCmp } break; - case InferType::InferTypeKind::FLOAT: { + case InferType::InferTypeKind::FLOAT: + { if (type.get_infer_kind () == InferType::InferTypeKind::FLOAT) { ok = true; diff --git a/gcc/rust/typecheck/rust-tyty-subst.cc b/gcc/rust/typecheck/rust-tyty-subst.cc index bdb6474aeeb4..2d5e87e5adda 100644 --- a/gcc/rust/typecheck/rust-tyty-subst.cc +++ b/gcc/rust/typecheck/rust-tyty-subst.cc @@ -72,6 +72,12 @@ SubstitutionParamMapping::get_generic_param () return generic; } +const HIR::TypeParam & +SubstitutionParamMapping::get_generic_param () const +{ + return generic; +} + bool SubstitutionParamMapping::needs_substitution () const { @@ -109,7 +115,8 @@ SubstitutionParamMapping::need_substitution () const bool SubstitutionParamMapping::fill_param_ty ( - SubstitutionArgumentMappings &subst_mappings, location_t locus) + SubstitutionArgumentMappings &subst_mappings, location_t locus, + bool needs_bounds_check) { SubstitutionArg arg = SubstitutionArg::error (); bool ok = subst_mappings.get_argument_for_symbol (get_param_ty (), &arg); @@ -133,8 +140,7 @@ SubstitutionParamMapping::fill_param_ty ( rust_debug_loc (locus, "fill_param_ty bounds_compatible: param %s type %s", param->get_name ().c_str (), type.get_name ().c_str ()); - - if (!param->is_implicit_self_trait ()) + if (needs_bounds_check && !param->is_implicit_self_trait ()) { if (!param->bounds_compatible (type, locus, true)) return false; @@ -618,7 +624,6 @@ SubstitutionRef::get_mappings_from_generic_args ( if (args.get_binding_args ().size () > get_num_associated_bindings ()) { rich_location r (line_table, args.get_locus ()); - rust_error_at (r, "generic item takes at most %lu type binding " "arguments but %lu were supplied", @@ -702,7 +707,19 @@ SubstitutionRef::get_mappings_from_generic_args ( return SubstitutionArgumentMappings::error (); } - SubstitutionArg subst_arg (&substitutions.at (offs), resolved); + const auto ¶m_mapping = substitutions.at (offs); + const auto &type_param = param_mapping.get_generic_param (); + if (type_param.from_impl_trait ()) + { + rich_location r (line_table, arg->get_locus ()); + r.add_fixit_remove (arg->get_locus ()); + rust_error_at (r, ErrorCode::E0632, + "cannot provide explicit generic arguments when " + "% is used in argument position"); + return SubstitutionArgumentMappings::error (); + } + + SubstitutionArg subst_arg (¶m_mapping, resolved); offs++; mappings.push_back (std::move (subst_arg)); } diff --git a/gcc/rust/typecheck/rust-tyty-subst.h b/gcc/rust/typecheck/rust-tyty-subst.h index e6ed1fc42d67..141db3d448b7 100644 --- a/gcc/rust/typecheck/rust-tyty-subst.h +++ b/gcc/rust/typecheck/rust-tyty-subst.h @@ -51,7 +51,7 @@ class SubstitutionParamMapping std::string as_string () const; bool fill_param_ty (SubstitutionArgumentMappings &subst_mappings, - location_t locus); + location_t locus, bool needs_bounds_check = true); SubstitutionParamMapping clone () const; @@ -60,6 +60,7 @@ class SubstitutionParamMapping const ParamType *get_param_ty () const; HIR::TypeParam &get_generic_param (); + const HIR::TypeParam &get_generic_param () const; // this is used for the backend to override the HirId ref of the param to // what the concrete type is for the rest of the context diff --git a/gcc/rust/typecheck/rust-tyty-variance-analysis.h b/gcc/rust/typecheck/rust-tyty-variance-analysis.h index 9059a2f225d3..282c6f305b49 100644 --- a/gcc/rust/typecheck/rust-tyty-variance-analysis.h +++ b/gcc/rust/typecheck/rust-tyty-variance-analysis.h @@ -41,9 +41,10 @@ class CrateCtx std::unique_ptr private_ctx; }; -std::vector -query_field_regions (const ADTType *parent, size_t variant_index, - size_t field_index, const FreeRegions &parent_regions); +std::vector query_field_regions (const ADTType *parent, + size_t variant_index, + size_t field_index, + const FreeRegions &parent_regions); /** Variance semilattice */ class Variance diff --git a/gcc/rust/typecheck/rust-tyty.cc b/gcc/rust/typecheck/rust-tyty.cc index f0f4a07e9660..75370e96c662 100644 --- a/gcc/rust/typecheck/rust-tyty.cc +++ b/gcc/rust/typecheck/rust-tyty.cc @@ -30,9 +30,11 @@ #include "rust-tyty-cmp.h" #include "rust-type-util.h" #include "rust-hir-type-bounds.h" +#include "print-tree.h" #include "options.h" #include "rust-system.h" +#include "tree.h" namespace Rust { namespace TyTy { @@ -230,11 +232,13 @@ BaseType::is_unit () const case NEVER: return true; - case TUPLE: { + case TUPLE: + { return x->as ()->num_fields () == 0; } - case ADT: { + case ADT: + { auto adt = x->as (); if (adt->is_enum ()) return false; @@ -546,17 +550,14 @@ BaseType::destructure () const { x = p->get (); } - // else if (auto p = x->try_as ()) - // { - // auto pr = p->resolve (); - - // rust_debug ("XXXXXX") - - // if (pr == x) - // return pr; + else if (auto p = x->try_as ()) + { + auto pr = p->resolve (); + if (pr == x) + return pr; - // x = pr; - // } + x = pr; + } else { return x; @@ -575,7 +576,7 @@ BaseType::monomorphized_clone () const { TyVar elm = arr->get_var_element_type ().monomorphized_clone (); return new ArrayType (arr->get_ref (), arr->get_ty_ref (), ident.locus, - arr->get_capacity_expr (), elm, + arr->get_capacity (), elm, arr->get_combined_refs ()); } else if (auto slice = x->try_as ()) @@ -894,28 +895,32 @@ BaseType::has_substitutions_defined () const case OPAQUE: return false; - case PROJECTION: { + case PROJECTION: + { const ProjectionType &p = *static_cast (x); const SubstitutionRef &ref = static_cast (p); return ref.has_substitutions (); } break; - case FNDEF: { + case FNDEF: + { const FnType &fn = *static_cast (x); const SubstitutionRef &ref = static_cast (fn); return ref.has_substitutions (); } break; - case ADT: { + case ADT: + { const ADTType &adt = *static_cast (x); const SubstitutionRef &ref = static_cast (adt); return ref.has_substitutions (); } break; - case CLOSURE: { + case CLOSURE: + { const ClosureType &closure = *static_cast (x); const SubstitutionRef &ref = static_cast (closure); @@ -956,28 +961,32 @@ BaseType::needs_generic_substitutions () const case OPAQUE: return false; - case PROJECTION: { + case PROJECTION: + { const ProjectionType &p = *static_cast (x); const SubstitutionRef &ref = static_cast (p); return ref.needs_substitution (); } break; - case FNDEF: { + case FNDEF: + { const FnType &fn = *static_cast (x); const SubstitutionRef &ref = static_cast (fn); return ref.needs_substitution (); } break; - case ADT: { + case ADT: + { const ADTType &adt = *static_cast (x); const SubstitutionRef &ref = static_cast (adt); return ref.needs_substitution (); } break; - case CLOSURE: { + case CLOSURE: + { const ClosureType &closure = *static_cast (x); const SubstitutionRef &ref = static_cast (closure); @@ -996,28 +1005,32 @@ BaseType::get_subst_argument_mappings () const const TyTy::BaseType *x = destructure (); switch (x->get_kind ()) { - case PROJECTION: { + case PROJECTION: + { const auto &p = *static_cast (x); const auto &ref = static_cast (p); return ref.get_substitution_arguments (); } break; - case FNDEF: { + case FNDEF: + { const auto &fn = *static_cast (x); const auto &ref = static_cast (fn); return ref.get_substitution_arguments (); } break; - case ADT: { + case ADT: + { const auto &adt = *static_cast (x); const auto &ref = static_cast (adt); return ref.get_substitution_arguments (); } break; - case CLOSURE: { + case CLOSURE: + { const auto &closure = *static_cast (x); const auto &ref = static_cast (closure); return ref.get_substitution_arguments (); @@ -1140,13 +1153,15 @@ InferType::default_type (BaseType **type) const case GENERAL: return false; - case INTEGRAL: { + case INTEGRAL: + { ok = context->lookup_builtin ("i32", type); rust_assert (ok); return ok; } - case FLOAT: { + case FLOAT: + { ok = context->lookup_builtin ("f64", type); rust_assert (ok); return ok; @@ -1269,7 +1284,8 @@ InferType::apply_primitive_type_hint (const BaseType &hint) default_hint.kind = hint.get_kind (); break; - case INT: { + case INT: + { infer_kind = INTEGRAL; default_hint.kind = hint.get_kind (); default_hint.shint = TypeHint::SignedHint::SIGNED; @@ -1294,7 +1310,8 @@ InferType::apply_primitive_type_hint (const BaseType &hint) } break; - case UINT: { + case UINT: + { infer_kind = INTEGRAL; default_hint.kind = hint.get_kind (); default_hint.shint = TypeHint::SignedHint::UNSIGNED; @@ -1319,7 +1336,8 @@ InferType::apply_primitive_type_hint (const BaseType &hint) } break; - case TypeKind::FLOAT: { + case TypeKind::FLOAT: + { infer_kind = FLOAT; default_hint.shint = TypeHint::SignedHint::SIGNED; default_hint.kind = hint.get_kind (); @@ -1992,7 +2010,7 @@ TupleType::get_name () const std::string fields_buffer; for (const TyVar &field : get_fields ()) { - fields_buffer += field.get_tyty ()->as_string (); + fields_buffer += field.get_tyty ()->get_name (); bool has_next = (i + 1) < get_fields ().size (); fields_buffer += has_next ? ", " : ""; i++; @@ -2470,7 +2488,16 @@ ArrayType::accept_vis (TyConstVisitor &vis) const std::string ArrayType::as_string () const { - return "[" + get_element_type ()->as_string () + ":" + "CAPACITY" + "]"; + std::string capacity_str = ""; + if (!error_operand_p (capacity)) + { + unsigned HOST_WIDE_INT length = wi::to_wide (capacity).to_uhwi (); + + char buf[64]; + snprintf (buf, sizeof (buf), HOST_WIDE_INT_PRINT_UNSIGNED, length); + capacity_str = std::string (buf); + } + return "[" + get_element_type ()->as_string () + "; " + capacity_str + "]"; } bool @@ -2509,7 +2536,7 @@ ArrayType::get_var_element_type () const BaseType * ArrayType::clone () const { - return new ArrayType (get_ref (), get_ty_ref (), ident.locus, capacity_expr, + return new ArrayType (get_ref (), get_ty_ref (), ident.locus, capacity, element_type, get_combined_refs ()); } @@ -3529,12 +3556,12 @@ ParamType::handle_substitions (SubstitutionArgumentMappings &subst_mappings) ParamType *p = static_cast (clone ()); subst_mappings.on_param_subst (*p, arg); - // there are two cases one where we substitute directly to a new PARAM and - // otherwise - if (arg.get_tyty ()->get_kind () == TyTy::TypeKind::PARAM) + const BaseType *resolved = arg.get_tyty (); + if (resolved->get_kind () == TyTy::TypeKind::PARAM) { - p->set_ty_ref (arg.get_tyty ()->get_ref ()); - return p; + const ParamType &pp = *static_cast (resolved); + if (pp.can_resolve ()) + resolved = pp.resolve (); } // this is the new subst that this needs to pass @@ -3624,28 +3651,7 @@ BaseType * OpaqueType::resolve () const { TyVar var (get_ty_ref ()); - BaseType *r = var.get_tyty (); - - while (r->get_kind () == TypeKind::OPAQUE) - { - OpaqueType *rr = static_cast (r); - if (!rr->can_resolve ()) - break; - - TyVar v (rr->get_ty_ref ()); - BaseType *n = v.get_tyty (); - - // fix infinite loop - if (r == n) - break; - - r = n; - } - - if (r->get_kind () == TypeKind::OPAQUE && (r->get_ref () == r->get_ty_ref ())) - return TyVar (r->get_ty_ref ()).get_tyty (); - - return r; + return var.get_tyty (); } bool @@ -3655,41 +3661,9 @@ OpaqueType::is_equal (const BaseType &other) const if (can_resolve () != other2.can_resolve ()) return false; - if (can_resolve ()) - return resolve ()->can_eq (other2.resolve (), false); - return bounds_compatible (other, UNDEF_LOCATION, false); } -OpaqueType * -OpaqueType::handle_substitions (SubstitutionArgumentMappings &subst_mappings) -{ - // SubstitutionArg arg = SubstitutionArg::error (); - // bool ok = subst_mappings.get_argument_for_symbol (this, &arg); - // if (!ok || arg.is_error ()) - // return this; - - // OpaqueType *p = static_cast (clone ()); - // subst_mappings.on_param_subst (*p, arg); - - // // there are two cases one where we substitute directly to a new PARAM and - // // otherwise - // if (arg.get_tyty ()->get_kind () == TyTy::TypeKind::PARAM) - // { - // p->set_ty_ref (arg.get_tyty ()->get_ref ()); - // return p; - // } - - // // this is the new subst that this needs to pass - // p->set_ref (mappings.get_next_hir_id ()); - // p->set_ty_ref (arg.get_tyty ()->get_ref ()); - - // return p; - - rust_unreachable (); - return nullptr; -} - // StrType StrType::StrType (HirId ref, std::set refs) diff --git a/gcc/rust/typecheck/rust-tyty.h b/gcc/rust/typecheck/rust-tyty.h index 1cada9a4030b..13e9184f29d7 100644 --- a/gcc/rust/typecheck/rust-tyty.h +++ b/gcc/rust/typecheck/rust-tyty.h @@ -29,6 +29,7 @@ #include "rust-tyty-region.h" #include "rust-system.h" #include "rust-hir.h" +#include "tree.h" namespace Rust { @@ -78,8 +79,7 @@ enum TypeKind ERROR }; -extern bool -is_primitive_type_kind (TypeKind kind); +extern bool is_primitive_type_kind (TypeKind kind); class TypeKindFormat { @@ -268,8 +268,8 @@ class CallableTypeInterface : public BaseType {} WARN_UNUSED_RESULT virtual size_t get_num_params () const = 0; - WARN_UNUSED_RESULT virtual BaseType * - get_param_type_at (size_t index) const = 0; + WARN_UNUSED_RESULT virtual BaseType *get_param_type_at (size_t index) const + = 0; WARN_UNUSED_RESULT virtual BaseType *get_return_type () const = 0; }; @@ -441,8 +441,6 @@ class OpaqueType : public BaseType std::string get_name () const override final; bool is_equal (const BaseType &other) const override; - - OpaqueType *handle_substitions (SubstitutionArgumentMappings &mappings); }; class StructFieldType @@ -541,14 +539,15 @@ class TypeBoundPredicate : public SubstitutionRef std::string get_name () const; - // check that this predicate is object-safe see: + // check that this is object-safe see: // https://doc.rust-lang.org/reference/items/traits.html#object-safety bool is_object_safe (bool emit_error, location_t locus) const; void apply_generic_arguments (HIR::GenericArgs *generic_args, - bool has_associated_self); + bool has_associated_self, bool is_super_trait); - void apply_argument_mappings (SubstitutionArgumentMappings &arguments); + void apply_argument_mappings (SubstitutionArgumentMappings &arguments, + bool is_super_trait); bool contains_item (const std::string &search) const; @@ -596,6 +595,9 @@ class TypeBoundPredicate : public SubstitutionRef TypeBoundPredicate (mark_is_error); + void get_trait_hierachy ( + std::function callback) const; + DefId reference; location_t locus; bool error_flag; @@ -1156,19 +1158,18 @@ class ArrayType : public BaseType public: static constexpr auto KIND = TypeKind::ARRAY; - ArrayType (HirId ref, location_t locus, HIR::Expr &capacity_expr, TyVar base, + ArrayType (HirId ref, location_t locus, tree capacity, TyVar base, std::set refs = std::set ()) : BaseType (ref, ref, TypeKind::ARRAY, {Resolver::CanonicalPath::create_empty (), locus}, refs), - element_type (base), capacity_expr (capacity_expr) + element_type (base), capacity (capacity) {} - ArrayType (HirId ref, HirId ty_ref, location_t locus, - HIR::Expr &capacity_expr, TyVar base, - std::set refs = std::set ()) + ArrayType (HirId ref, HirId ty_ref, location_t locus, tree capacity, + TyVar base, std::set refs = std::set ()) : BaseType (ref, ty_ref, TypeKind::ARRAY, {Resolver::CanonicalPath::create_empty (), locus}, refs), - element_type (base), capacity_expr (capacity_expr) + element_type (base), capacity (capacity) {} void accept_vis (TyVisitor &vis) override; @@ -1187,15 +1188,13 @@ class ArrayType : public BaseType BaseType *clone () const final override; - HIR::Expr &get_capacity_expr () const { return capacity_expr; } + tree get_capacity () const { return capacity; } ArrayType *handle_substitions (SubstitutionArgumentMappings &mappings); private: TyVar element_type; - // FIXME: I dont think this should be in tyty - tyty should already be const - // evaluated - HIR::Expr &capacity_expr; + tree capacity; }; class SliceType : public BaseType diff --git a/gcc/rust/typecheck/rust-unify.cc b/gcc/rust/typecheck/rust-unify.cc index 294b677ba417..ac9019369826 100644 --- a/gcc/rust/typecheck/rust-unify.cc +++ b/gcc/rust/typecheck/rust-unify.cc @@ -17,6 +17,7 @@ // . #include "rust-unify.h" +#include "tree.h" namespace Rust { namespace Resolver { @@ -52,6 +53,22 @@ UnifyRules::Resolve (TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs, return result; } +TyTy::BaseType * +UnifyRules::resolve_subtype (TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs) +{ + TyTy::BaseType *result + = UnifyRules::Resolve (lhs, rhs, locus, commit_flag, emit_error, infer_flag, + commits, infers); + + // If the recursive call resulted in an error and would have emitted an error + // message, disable error emission for the current level to avoid duplicate + // errors + if (result->get_kind () == TyTy::TypeKind::ERROR && emit_error) + emit_error = false; + + return result; +} + TyTy::BaseType * UnifyRules::get_base () { @@ -69,7 +86,6 @@ UnifyRules::commit (TyTy::BaseType *base, TyTy::BaseType *other, TyTy::BaseType *resolved) { TypeCheckContext &context = *TypeCheckContext::get (); - Analysis::Mappings &mappings = Analysis::Mappings::get (); TyTy::BaseType *b = base->destructure (); TyTy::BaseType *o = other->destructure (); @@ -102,13 +118,8 @@ UnifyRules::commit (TyTy::BaseType *base, TyTy::BaseType *other, continue; // if any of the types are inference variables lets fix them - if (ref_tyty->get_kind () == TyTy::TypeKind::INFER) - { - auto node = Analysis::NodeMapping (mappings.get_current_crate (), - UNKNOWN_NODEID, ref, - UNKNOWN_LOCAL_DEFID); - context.insert_type (node, resolved->clone ()); - } + if (ref_tyty->is ()) + context.insert_implicit_type (ref, resolved); } } } @@ -328,30 +339,33 @@ UnifyRules::expect_inference_variable (TyTy::InferType *ltype, { switch (rtype->get_kind ()) { - case TyTy::INFER: { + case TyTy::INFER: + { TyTy::InferType *r = static_cast (rtype); switch (ltype->get_infer_kind ()) { case TyTy::InferType::InferTypeKind::GENERAL: return rtype->clone (); - case TyTy::InferType::InferTypeKind::INTEGRAL: { + case TyTy::InferType::InferTypeKind::INTEGRAL: + { bool is_valid = r->get_infer_kind () == TyTy::InferType::InferTypeKind::INTEGRAL || r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL; if (is_valid) - return rtype->clone (); + return rtype; } break; - case TyTy::InferType::InferTypeKind::FLOAT: { + case TyTy::InferType::InferTypeKind::FLOAT: + { bool is_valid = r->get_infer_kind () == TyTy::InferType::InferTypeKind::FLOAT || r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL; if (is_valid) - return rtype->clone (); + return rtype; } break; } @@ -361,7 +375,8 @@ UnifyRules::expect_inference_variable (TyTy::InferType *ltype, case TyTy::INT: case TyTy::UINT: case TyTy::USIZE: - case TyTy::ISIZE: { + case TyTy::ISIZE: + { bool is_valid = (ltype->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL) || (ltype->get_infer_kind () @@ -369,12 +384,13 @@ UnifyRules::expect_inference_variable (TyTy::InferType *ltype, if (is_valid) { ltype->apply_primitive_type_hint (*rtype); - return rtype->clone (); + return rtype; } } break; - case TyTy::FLOAT: { + case TyTy::FLOAT: + { bool is_valid = (ltype->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL) || (ltype->get_infer_kind () @@ -382,7 +398,7 @@ UnifyRules::expect_inference_variable (TyTy::InferType *ltype, if (is_valid) { ltype->apply_primitive_type_hint (*rtype); - return rtype->clone (); + return rtype; } } break; @@ -404,7 +420,8 @@ UnifyRules::expect_inference_variable (TyTy::InferType *ltype, case TyTy::PROJECTION: case TyTy::DYNAMIC: case TyTy::CLOSURE: - case TyTy::OPAQUE: { + case TyTy::OPAQUE: + { bool is_valid = (ltype->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL); if (is_valid) @@ -424,7 +441,8 @@ UnifyRules::expect_adt (TyTy::ADTType *ltype, TyTy::BaseType *rtype) { switch (rtype->get_kind ()) { - case TyTy::INFER: { + case TyTy::INFER: + { TyTy::InferType *r = static_cast (rtype); bool is_valid = r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL; @@ -433,7 +451,8 @@ UnifyRules::expect_adt (TyTy::ADTType *ltype, TyTy::BaseType *rtype) } break; - case TyTy::ADT: { + case TyTy::ADT: + { TyTy::ADTType &type = *static_cast (rtype); if (ltype->get_adt_kind () != type.get_adt_kind ()) { @@ -469,11 +488,8 @@ UnifyRules::expect_adt (TyTy::ADTType *ltype, TyTy::BaseType *rtype) TyTy::BaseType *other_field_ty = other_field->get_field_type (); TyTy::BaseType *unified_ty - = UnifyRules::Resolve (TyTy::TyWithLocation (this_field_ty), - TyTy::TyWithLocation (other_field_ty), - locus, commit_flag, - false /* emit_error */, infer_flag, - commits, infers); + = resolve_subtype (TyTy::TyWithLocation (this_field_ty), + TyTy::TyWithLocation (other_field_ty)); if (unified_ty->get_kind () == TyTy::TypeKind::ERROR) { return new TyTy::ErrorType (0); @@ -495,11 +511,8 @@ UnifyRules::expect_adt (TyTy::ADTType *ltype, TyTy::BaseType *rtype) auto pa = a.get_param_ty (); auto pb = b.get_param_ty (); - auto res - = UnifyRules::Resolve (TyTy::TyWithLocation (pa), - TyTy::TyWithLocation (pb), locus, - commit_flag, false /* emit_error */, - infer_flag, commits, infers); + auto res = resolve_subtype (TyTy::TyWithLocation (pa), + TyTy::TyWithLocation (pb)); if (res->get_kind () == TyTy::TypeKind::ERROR) { return new TyTy::ErrorType (0); @@ -544,7 +557,8 @@ UnifyRules::expect_str (TyTy::StrType *ltype, TyTy::BaseType *rtype) { switch (rtype->get_kind ()) { - case TyTy::INFER: { + case TyTy::INFER: + { TyTy::InferType *r = static_cast (rtype); bool is_valid = r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL; @@ -589,7 +603,8 @@ UnifyRules::expect_reference (TyTy::ReferenceType *ltype, TyTy::BaseType *rtype) { switch (rtype->get_kind ()) { - case TyTy::INFER: { + case TyTy::INFER: + { TyTy::InferType *r = static_cast (rtype); bool is_valid = r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL; @@ -598,16 +613,15 @@ UnifyRules::expect_reference (TyTy::ReferenceType *ltype, TyTy::BaseType *rtype) } break; - case TyTy::REF: { + case TyTy::REF: + { TyTy::ReferenceType &type = *static_cast (rtype); auto base_type = ltype->get_base (); auto other_base_type = type.get_base (); TyTy::BaseType *base_resolved - = UnifyRules::Resolve (TyTy::TyWithLocation (base_type), - TyTy::TyWithLocation (other_base_type), locus, - commit_flag, false /* emit_error */, - infer_flag, commits, infers); + = resolve_subtype (TyTy::TyWithLocation (base_type), + TyTy::TyWithLocation (other_base_type)); if (base_resolved->get_kind () == TyTy::TypeKind::ERROR) { return new TyTy::ErrorType (0); @@ -660,7 +674,8 @@ UnifyRules::expect_pointer (TyTy::PointerType *ltype, TyTy::BaseType *rtype) { switch (rtype->get_kind ()) { - case TyTy::INFER: { + case TyTy::INFER: + { TyTy::InferType *r = static_cast (rtype); bool is_valid = r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL; @@ -669,16 +684,15 @@ UnifyRules::expect_pointer (TyTy::PointerType *ltype, TyTy::BaseType *rtype) } break; - case TyTy::POINTER: { + case TyTy::POINTER: + { TyTy::PointerType &type = *static_cast (rtype); auto base_type = ltype->get_base (); auto other_base_type = type.get_base (); TyTy::BaseType *base_resolved - = UnifyRules::Resolve (TyTy::TyWithLocation (base_type), - TyTy::TyWithLocation (other_base_type), locus, - commit_flag, false /* emit_error */, - infer_flag, commits, infers); + = resolve_subtype (TyTy::TyWithLocation (base_type), + TyTy::TyWithLocation (other_base_type)); if (base_resolved->get_kind () == TyTy::TypeKind::ERROR) { return new TyTy::ErrorType (0); @@ -731,7 +745,8 @@ UnifyRules::expect_param (TyTy::ParamType *ltype, TyTy::BaseType *rtype) { switch (rtype->get_kind ()) { - case TyTy::INFER: { + case TyTy::INFER: + { TyTy::InferType *r = static_cast (rtype); bool is_valid = r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL; @@ -740,7 +755,8 @@ UnifyRules::expect_param (TyTy::ParamType *ltype, TyTy::BaseType *rtype) } break; - case TyTy::PARAM: { + case TyTy::PARAM: + { TyTy::ParamType &type = *static_cast (rtype); // bool symbol_matches // = ltype->get_symbol ().compare (type.get_symbol ()) == 0; @@ -793,7 +809,8 @@ UnifyRules::expect_array (TyTy::ArrayType *ltype, TyTy::BaseType *rtype) { switch (rtype->get_kind ()) { - case TyTy::INFER: { + case TyTy::INFER: + { TyTy::InferType *r = static_cast (rtype); bool is_valid = r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL; @@ -802,21 +819,31 @@ UnifyRules::expect_array (TyTy::ArrayType *ltype, TyTy::BaseType *rtype) } break; - case TyTy::ARRAY: { + case TyTy::ARRAY: + { TyTy::ArrayType &type = *static_cast (rtype); - TyTy::BaseType *element_unify = UnifyRules::Resolve ( - TyTy::TyWithLocation (ltype->get_element_type ()), - TyTy::TyWithLocation (type.get_element_type ()), locus, commit_flag, - false /* emit_error*/, infer_flag, commits, infers); - - if (element_unify->get_kind () != TyTy::TypeKind::ERROR) - { - return new TyTy::ArrayType (type.get_ref (), type.get_ty_ref (), - type.get_ident ().locus, - type.get_capacity_expr (), - TyTy::TyVar ( - element_unify->get_ref ())); - } + TyTy::BaseType *element_unify + = resolve_subtype (TyTy::TyWithLocation (ltype->get_element_type ()), + TyTy::TyWithLocation (type.get_element_type ())); + + if (element_unify->get_kind () == TyTy::TypeKind::ERROR) + return new TyTy::ErrorType (0); + + // TODO infer capacity? + tree lcap = ltype->get_capacity (); + tree rcap = type.get_capacity (); + if (error_operand_p (lcap) || error_operand_p (rcap)) + return new TyTy::ErrorType (0); + + auto lc = wi::to_wide (lcap).to_uhwi (); + auto rc = wi::to_wide (rcap).to_uhwi (); + if (lc != rc) + return new TyTy::ErrorType (0); + + return new TyTy::ArrayType (type.get_ref (), type.get_ty_ref (), + type.get_ident ().locus, + type.get_capacity (), + TyTy::TyVar (element_unify->get_ref ())); } break; @@ -853,7 +880,8 @@ UnifyRules::expect_slice (TyTy::SliceType *ltype, TyTy::BaseType *rtype) { switch (rtype->get_kind ()) { - case TyTy::INFER: { + case TyTy::INFER: + { TyTy::InferType *r = static_cast (rtype); bool is_valid = r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL; @@ -862,12 +890,12 @@ UnifyRules::expect_slice (TyTy::SliceType *ltype, TyTy::BaseType *rtype) } break; - case TyTy::SLICE: { + case TyTy::SLICE: + { TyTy::SliceType &type = *static_cast (rtype); - TyTy::BaseType *element_unify = UnifyRules::Resolve ( - TyTy::TyWithLocation (ltype->get_element_type ()), - TyTy::TyWithLocation (type.get_element_type ()), locus, commit_flag, - false /* emit_error*/, infer_flag, commits, infers); + TyTy::BaseType *element_unify + = resolve_subtype (TyTy::TyWithLocation (ltype->get_element_type ()), + TyTy::TyWithLocation (type.get_element_type ())); if (element_unify->get_kind () != TyTy::TypeKind::ERROR) { @@ -912,7 +940,8 @@ UnifyRules::expect_fndef (TyTy::FnType *ltype, TyTy::BaseType *rtype) { switch (rtype->get_kind ()) { - case TyTy::INFER: { + case TyTy::INFER: + { TyTy::InferType *r = static_cast (rtype); bool is_valid = r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL; @@ -921,7 +950,8 @@ UnifyRules::expect_fndef (TyTy::FnType *ltype, TyTy::BaseType *rtype) } break; - case TyTy::FNDEF: { + case TyTy::FNDEF: + { TyTy::FnType &type = *static_cast (rtype); if (ltype->num_params () != type.num_params ()) { @@ -933,21 +963,17 @@ UnifyRules::expect_fndef (TyTy::FnType *ltype, TyTy::BaseType *rtype) auto a = ltype->param_at (i).get_type (); auto b = type.param_at (i).get_type (); - auto unified_param - = UnifyRules::Resolve (TyTy::TyWithLocation (a), - TyTy::TyWithLocation (b), locus, - commit_flag, false /* emit_errors */, - infer_flag, commits, infers); + auto unified_param = resolve_subtype (TyTy::TyWithLocation (a), + TyTy::TyWithLocation (b)); if (unified_param->get_kind () == TyTy::TypeKind::ERROR) { return new TyTy::ErrorType (0); } } - auto unified_return = UnifyRules::Resolve ( - TyTy::TyWithLocation (ltype->get_return_type ()), - TyTy::TyWithLocation (type.get_return_type ()), locus, commit_flag, - false /* emit_errors */, infer_flag, commits, infers); + auto unified_return + = resolve_subtype (TyTy::TyWithLocation (ltype->get_return_type ()), + TyTy::TyWithLocation (type.get_return_type ())); if (unified_return->get_kind () == TyTy::TypeKind::ERROR) { return new TyTy::ErrorType (0); @@ -1003,7 +1029,8 @@ UnifyRules::expect_fnptr (TyTy::FnPtr *ltype, TyTy::BaseType *rtype) { switch (rtype->get_kind ()) { - case TyTy::INFER: { + case TyTy::INFER: + { TyTy::InferType *r = static_cast (rtype); bool is_valid = r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL; @@ -1012,7 +1039,8 @@ UnifyRules::expect_fnptr (TyTy::FnPtr *ltype, TyTy::BaseType *rtype) } break; - case TyTy::FNPTR: { + case TyTy::FNPTR: + { TyTy::FnPtr &type = *static_cast (rtype); if (ltype->num_params () != type.num_params ()) { @@ -1024,21 +1052,17 @@ UnifyRules::expect_fnptr (TyTy::FnPtr *ltype, TyTy::BaseType *rtype) auto a = ltype->get_param_type_at (i); auto b = type.get_param_type_at (i); - auto unified_param - = UnifyRules::Resolve (TyTy::TyWithLocation (a), - TyTy::TyWithLocation (b), locus, - commit_flag, false /* emit_errors */, - infer_flag, commits, infers); + auto unified_param = resolve_subtype (TyTy::TyWithLocation (a), + TyTy::TyWithLocation (b)); if (unified_param->get_kind () == TyTy::TypeKind::ERROR) { return new TyTy::ErrorType (0); } } - auto unified_return = UnifyRules::Resolve ( - TyTy::TyWithLocation (ltype->get_return_type ()), - TyTy::TyWithLocation (type.get_return_type ()), locus, commit_flag, - false /* emit_errors */, infer_flag, commits, infers); + auto unified_return + = resolve_subtype (TyTy::TyWithLocation (ltype->get_return_type ()), + TyTy::TyWithLocation (type.get_return_type ())); if (unified_return->get_kind () == TyTy::TypeKind::ERROR) { return new TyTy::ErrorType (0); @@ -1048,16 +1072,15 @@ UnifyRules::expect_fnptr (TyTy::FnPtr *ltype, TyTy::BaseType *rtype) } break; - case TyTy::FNDEF: { + case TyTy::FNDEF: + { TyTy::FnType &type = *static_cast (rtype); auto this_ret_type = ltype->get_return_type (); auto other_ret_type = type.get_return_type (); auto unified_result - = UnifyRules::Resolve (TyTy::TyWithLocation (this_ret_type), - TyTy::TyWithLocation (other_ret_type), locus, - commit_flag, false /*emit_errors*/, infer_flag, - commits, infers); + = resolve_subtype (TyTy::TyWithLocation (this_ret_type), + TyTy::TyWithLocation (other_ret_type)); if (unified_result->get_kind () == TyTy::TypeKind::ERROR) { return new TyTy::ErrorType (0); @@ -1074,10 +1097,45 @@ UnifyRules::expect_fnptr (TyTy::FnPtr *ltype, TyTy::BaseType *rtype) auto other_param = type.param_at (i).get_type (); auto unified_param - = UnifyRules::Resolve (TyTy::TyWithLocation (this_param), - TyTy::TyWithLocation (other_param), locus, - commit_flag, false /* emit_errors */, - infer_flag, commits, infers); + = resolve_subtype (TyTy::TyWithLocation (this_param), + TyTy::TyWithLocation (other_param)); + if (unified_param->get_kind () == TyTy::TypeKind::ERROR) + { + return new TyTy::ErrorType (0); + } + } + + return ltype->clone (); + } + break; + + case TyTy::CLOSURE: + { + TyTy::ClosureType &type = *static_cast (rtype); + auto this_ret_type = ltype->get_return_type (); + auto other_ret_type = type.get_return_type (); + + auto unified_result + = resolve_subtype (TyTy::TyWithLocation (this_ret_type), + TyTy::TyWithLocation (other_ret_type)); + if (unified_result->get_kind () == TyTy::TypeKind::ERROR) + { + return new TyTy::ErrorType (0); + } + + if (ltype->num_params () != type.get_num_params ()) + { + return new TyTy::ErrorType (0); + } + + for (size_t i = 0; i < ltype->num_params (); i++) + { + auto this_param = ltype->get_param_type_at (i); + auto other_param = type.get_param_type_at (i); + + auto unified_param + = resolve_subtype (TyTy::TyWithLocation (this_param), + TyTy::TyWithLocation (other_param)); if (unified_param->get_kind () == TyTy::TypeKind::ERROR) { return new TyTy::ErrorType (0); @@ -1107,7 +1165,6 @@ UnifyRules::expect_fnptr (TyTy::FnPtr *ltype, TyTy::BaseType *rtype) case TyTy::PLACEHOLDER: case TyTy::PROJECTION: case TyTy::DYNAMIC: - case TyTy::CLOSURE: case TyTy::OPAQUE: case TyTy::ERROR: return new TyTy::ErrorType (0); @@ -1120,7 +1177,8 @@ UnifyRules::expect_tuple (TyTy::TupleType *ltype, TyTy::BaseType *rtype) { switch (rtype->get_kind ()) { - case TyTy::INFER: { + case TyTy::INFER: + { TyTy::InferType *r = static_cast (rtype); bool is_valid = r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL; @@ -1129,7 +1187,8 @@ UnifyRules::expect_tuple (TyTy::TupleType *ltype, TyTy::BaseType *rtype) } break; - case TyTy::TUPLE: { + case TyTy::TUPLE: + { TyTy::TupleType &type = *static_cast (rtype); if (ltype->num_fields () != type.num_fields ()) { @@ -1143,10 +1202,8 @@ UnifyRules::expect_tuple (TyTy::TupleType *ltype, TyTy::BaseType *rtype) TyTy::BaseType *fo = type.get_field (i); TyTy::BaseType *unified_ty - = UnifyRules::Resolve (TyTy::TyWithLocation (bo), - TyTy::TyWithLocation (fo), locus, - commit_flag, false /* emit_errors */, - infer_flag, commits, infers); + = resolve_subtype (TyTy::TyWithLocation (bo), + TyTy::TyWithLocation (fo)); if (unified_ty->get_kind () == TyTy::TypeKind::ERROR) return new TyTy::ErrorType (0); @@ -1191,7 +1248,8 @@ UnifyRules::expect_bool (TyTy::BoolType *ltype, TyTy::BaseType *rtype) { switch (rtype->get_kind ()) { - case TyTy::INFER: { + case TyTy::INFER: + { TyTy::InferType *r = static_cast (rtype); bool is_valid = r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL; @@ -1239,7 +1297,8 @@ UnifyRules::expect_char (TyTy::CharType *ltype, TyTy::BaseType *rtype) { switch (rtype->get_kind ()) { - case TyTy::INFER: { + case TyTy::INFER: + { TyTy::InferType *r = static_cast (rtype); bool is_valid = r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL; @@ -1287,7 +1346,8 @@ UnifyRules::expect_int (TyTy::IntType *ltype, TyTy::BaseType *rtype) { switch (rtype->get_kind ()) { - case TyTy::INFER: { + case TyTy::INFER: + { TyTy::InferType *r = static_cast (rtype); bool is_valid = r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL @@ -1300,7 +1360,8 @@ UnifyRules::expect_int (TyTy::IntType *ltype, TyTy::BaseType *rtype) } break; - case TyTy::INT: { + case TyTy::INT: + { TyTy::IntType &type = *static_cast (rtype); bool is_valid = ltype->get_int_kind () == type.get_int_kind (); if (is_valid) @@ -1342,7 +1403,8 @@ UnifyRules::expect_uint (TyTy::UintType *ltype, TyTy::BaseType *rtype) { switch (rtype->get_kind ()) { - case TyTy::INFER: { + case TyTy::INFER: + { TyTy::InferType *r = static_cast (rtype); bool is_valid = r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL @@ -1355,7 +1417,8 @@ UnifyRules::expect_uint (TyTy::UintType *ltype, TyTy::BaseType *rtype) } break; - case TyTy::UINT: { + case TyTy::UINT: + { TyTy::UintType &type = *static_cast (rtype); bool is_valid = ltype->get_uint_kind () == type.get_uint_kind (); if (is_valid) @@ -1397,7 +1460,8 @@ UnifyRules::expect_float (TyTy::FloatType *ltype, TyTy::BaseType *rtype) { switch (rtype->get_kind ()) { - case TyTy::INFER: { + case TyTy::INFER: + { TyTy::InferType *r = static_cast (rtype); bool is_valid = r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL @@ -1410,7 +1474,8 @@ UnifyRules::expect_float (TyTy::FloatType *ltype, TyTy::BaseType *rtype) } break; - case TyTy::FLOAT: { + case TyTy::FLOAT: + { TyTy::FloatType &type = *static_cast (rtype); bool is_valid = ltype->get_float_kind () == type.get_float_kind (); if (is_valid) @@ -1452,7 +1517,8 @@ UnifyRules::expect_isize (TyTy::ISizeType *ltype, TyTy::BaseType *rtype) { switch (rtype->get_kind ()) { - case TyTy::INFER: { + case TyTy::INFER: + { TyTy::InferType *r = static_cast (rtype); bool is_valid = r->get_infer_kind () != TyTy::InferType::InferTypeKind::FLOAT; @@ -1500,7 +1566,8 @@ UnifyRules::expect_usize (TyTy::USizeType *ltype, TyTy::BaseType *rtype) { switch (rtype->get_kind ()) { - case TyTy::INFER: { + case TyTy::INFER: + { TyTy::InferType *r = static_cast (rtype); bool is_valid = r->get_infer_kind () != TyTy::InferType::InferTypeKind::FLOAT; @@ -1548,7 +1615,8 @@ UnifyRules::expect_never (TyTy::NeverType *ltype, TyTy::BaseType *rtype) { switch (rtype->get_kind ()) { - case TyTy::INFER: { + case TyTy::INFER: + { TyTy::InferType *r = static_cast (rtype); bool is_valid = r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL; @@ -1569,7 +1637,8 @@ UnifyRules::expect_placeholder (TyTy::PlaceholderType *ltype, { switch (rtype->get_kind ()) { - case TyTy::INFER: { + case TyTy::INFER: + { TyTy::InferType *r = static_cast (rtype); bool is_valid = r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL; @@ -1619,7 +1688,8 @@ UnifyRules::expect_projection (TyTy::ProjectionType *ltype, { switch (rtype->get_kind ()) { - case TyTy::INFER: { + case TyTy::INFER: + { TyTy::InferType *r = static_cast (rtype); bool is_valid = r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL; @@ -1666,7 +1736,8 @@ UnifyRules::expect_dyn (TyTy::DynamicObjectType *ltype, TyTy::BaseType *rtype) { switch (rtype->get_kind ()) { - case TyTy::INFER: { + case TyTy::INFER: + { TyTy::InferType *r = static_cast (rtype); bool is_valid = r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL; @@ -1675,7 +1746,8 @@ UnifyRules::expect_dyn (TyTy::DynamicObjectType *ltype, TyTy::BaseType *rtype) } break; - case TyTy::DYNAMIC: { + case TyTy::DYNAMIC: + { TyTy::DynamicObjectType &type = *static_cast (rtype); if (ltype->num_specified_bounds () != type.num_specified_bounds ()) @@ -1725,7 +1797,8 @@ UnifyRules::expect_closure (TyTy::ClosureType *ltype, TyTy::BaseType *rtype) { switch (rtype->get_kind ()) { - case TyTy::INFER: { + case TyTy::INFER: + { TyTy::InferType *r = static_cast (rtype); bool is_valid = r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL; @@ -1734,26 +1807,25 @@ UnifyRules::expect_closure (TyTy::ClosureType *ltype, TyTy::BaseType *rtype) } break; - case TyTy::CLOSURE: { + case TyTy::CLOSURE: + { TyTy::ClosureType &type = *static_cast (rtype); if (ltype->get_def_id () != type.get_def_id ()) { return new TyTy::ErrorType (0); } - TyTy::BaseType *args_res = UnifyRules::Resolve ( - TyTy::TyWithLocation (<ype->get_parameters ()), - TyTy::TyWithLocation (&type.get_parameters ()), locus, commit_flag, - false /* emit_error */, infer_flag, commits, infers); + TyTy::BaseType *args_res + = resolve_subtype (TyTy::TyWithLocation (<ype->get_parameters ()), + TyTy::TyWithLocation (&type.get_parameters ())); if (args_res->get_kind () == TyTy::TypeKind::ERROR) { return new TyTy::ErrorType (0); } - TyTy::BaseType *res = UnifyRules::Resolve ( - TyTy::TyWithLocation (<ype->get_result_type ()), - TyTy::TyWithLocation (&type.get_result_type ()), locus, commit_flag, - false /* emit_error */, infer_flag, commits, infers); + TyTy::BaseType *res + = resolve_subtype (TyTy::TyWithLocation (<ype->get_result_type ()), + TyTy::TyWithLocation (&type.get_result_type ())); if (res == nullptr || res->get_kind () == TyTy::TypeKind::ERROR) { return new TyTy::ErrorType (0); @@ -1794,59 +1866,47 @@ UnifyRules::expect_closure (TyTy::ClosureType *ltype, TyTy::BaseType *rtype) TyTy::BaseType * UnifyRules::expect_opaque (TyTy::OpaqueType *ltype, TyTy::BaseType *rtype) { - switch (rtype->get_kind ()) + if (rtype->is ()) { - case TyTy::INFER: { - TyTy::InferType *r = static_cast (rtype); - bool is_valid - = r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL; - if (is_valid) - return ltype->clone (); - } - break; + TyTy::OpaqueType *ro = rtype->as (); + if (!ltype->is_equal (*ro)) + return new TyTy::ErrorType (0); - case TyTy::OPAQUE: { - auto &type = *static_cast (rtype); - if (ltype->num_specified_bounds () != type.num_specified_bounds ()) - { - return new TyTy::ErrorType (0); - } + if (ltype->can_resolve () && ro->can_resolve ()) + { + auto lr = ltype->resolve (); + auto rr = ro->resolve (); - if (!ltype->bounds_compatible (type, locus, true)) - { + auto res = resolve_subtype (TyTy::TyWithLocation (lr), + TyTy::TyWithLocation (rr)); + if (res->get_kind () == TyTy::TypeKind::ERROR) return new TyTy::ErrorType (0); - } - - return ltype->clone (); - } - break; - - case TyTy::CLOSURE: - case TyTy::SLICE: - case TyTy::PARAM: - case TyTy::POINTER: - case TyTy::STR: - case TyTy::ADT: - case TyTy::REF: - case TyTy::ARRAY: - case TyTy::FNDEF: - case TyTy::FNPTR: - case TyTy::TUPLE: - case TyTy::BOOL: - case TyTy::CHAR: - case TyTy::INT: - case TyTy::UINT: - case TyTy::FLOAT: - case TyTy::USIZE: - case TyTy::ISIZE: - case TyTy::NEVER: - case TyTy::PLACEHOLDER: - case TyTy::PROJECTION: - case TyTy::DYNAMIC: - case TyTy::ERROR: - return new TyTy::ErrorType (0); + } + else if (ltype->can_resolve ()) + { + auto lr = ltype->resolve (); + ro->set_ty_ref (lr->get_ref ()); + } + else if (ro->can_resolve ()) + { + auto rr = ro->resolve (); + ltype->set_ty_ref (rr->get_ref ()); + } } - return new TyTy::ErrorType (0); + else if (ltype->can_resolve ()) + { + auto underly = ltype->resolve (); + auto res = resolve_subtype (TyTy::TyWithLocation (underly), + TyTy::TyWithLocation (rtype)); + if (res->get_kind () == TyTy::TypeKind::ERROR) + return new TyTy::ErrorType (0); + } + else + { + ltype->set_ty_ref (rtype->get_ref ()); + } + + return ltype; } } // namespace Resolver diff --git a/gcc/rust/typecheck/rust-unify.h b/gcc/rust/typecheck/rust-unify.h index 5ff3b7c48dbe..f64f0ed27b82 100644 --- a/gcc/rust/typecheck/rust-unify.h +++ b/gcc/rust/typecheck/rust-unify.h @@ -91,6 +91,9 @@ class UnifyRules std::vector &commits, std::vector &infers); + TyTy::BaseType *resolve_subtype (TyTy::TyWithLocation lhs, + TyTy::TyWithLocation rhs); + void emit_type_mismatch () const; void emit_abi_mismatch (const TyTy::FnType &expected, const TyTy::FnType &got) const; diff --git a/gcc/rust/util/rust-abi.h b/gcc/rust/util/rust-abi.h index a0180ed4d951..357a5db95ffc 100644 --- a/gcc/rust/util/rust-abi.h +++ b/gcc/rust/util/rust-abi.h @@ -34,11 +34,9 @@ enum ABI SYSV64 }; -extern Rust::ABI -get_abi_from_string (const std::string &abi); +extern Rust::ABI get_abi_from_string (const std::string &abi); -extern std::string -get_string_from_abi (Rust::ABI abi); +extern std::string get_string_from_abi (Rust::ABI abi); } // namespace Rust diff --git a/gcc/rust/util/rust-attribute-values.h b/gcc/rust/util/rust-attribute-values.h index 47e6a175396c..09ef56647953 100644 --- a/gcc/rust/util/rust-attribute-values.h +++ b/gcc/rust/util/rust-attribute-values.h @@ -85,6 +85,10 @@ class Attributes static constexpr auto &NON_EXHAUSTIVE = "non_exhaustive"; static constexpr auto &RUSTFMT = "rustfmt"; + + static constexpr auto &TEST = "test"; + + static constexpr auto &SIMD_TEST = "simd_test"; }; } // namespace Values } // namespace Rust diff --git a/gcc/rust/util/rust-attributes.cc b/gcc/rust/util/rust-attributes.cc index c77e99c1ca5a..0c957fb20144 100644 --- a/gcc/rust/util/rust-attributes.cc +++ b/gcc/rust/util/rust-attributes.cc @@ -95,7 +95,10 @@ static const BuiltinAttrDefinition __definitions[] {Attrs::FUNDAMENTAL, TYPE_CHECK}, {Attrs::NON_EXHAUSTIVE, TYPE_CHECK}, - {Attrs::RUSTFMT, EXTERNAL}}; + {Attrs::RUSTFMT, EXTERNAL}, + + {Attrs::TEST, CODE_GENERATION}, + {Attrs::SIMD_TEST, CODE_GENERATION}}; BuiltinAttributeMappings * BuiltinAttributeMappings::get () @@ -221,7 +224,8 @@ check_doc_attribute (const AST::Attribute &attribute) break; // FIXME: Handle them as well - case AST::AttrInput::TOKEN_TREE: { + case AST::AttrInput::TOKEN_TREE: + { // FIXME: This doesn't check for #[doc(alias(...))] const auto &option = static_cast ( attribute.get_attr_input ()); diff --git a/gcc/rust/util/rust-base62.h b/gcc/rust/util/rust-base62.h index e751c95f18f5..5fd7a37292e5 100644 --- a/gcc/rust/util/rust-base62.h +++ b/gcc/rust/util/rust-base62.h @@ -26,8 +26,7 @@ namespace Rust { /** * Get the Base62 representation of an integer */ -std::string -base62_integer (uint64_t value); +std::string base62_integer (uint64_t value); } // namespace Rust diff --git a/gcc/rust/util/rust-canonical-path.h b/gcc/rust/util/rust-canonical-path.h index 4d8f9542c8b1..079ae76eadba 100644 --- a/gcc/rust/util/rust-canonical-path.h +++ b/gcc/rust/util/rust-canonical-path.h @@ -57,10 +57,11 @@ class CanonicalPath return *this; } - static CanonicalPath new_seg (NodeId id, const std::string &path) + static CanonicalPath new_seg (NodeId id, std::string path) { rust_assert (!path.empty ()); - return CanonicalPath ({std::pair (id, path)}, + return CanonicalPath ({std::pair (id, + std::move (path))}, UNKNOWN_CRATENUM); } @@ -68,14 +69,18 @@ class CanonicalPath trait_impl_projection_seg (NodeId id, const CanonicalPath &trait_seg, const CanonicalPath &impl_type_seg) { - return CanonicalPath::new_seg (id, "<" + impl_type_seg.get () + " as " + // https://doc.rust-lang.org/reference/paths.html#canonical-paths + // should be ""? + return CanonicalPath::new_seg (id, ""); } static CanonicalPath inherent_impl_seg (NodeId id, const CanonicalPath &impl_type_seg) { - return CanonicalPath::new_seg (id, "<" + impl_type_seg.get () + ">"); + // https://doc.rust-lang.org/reference/paths.html#canonical-paths + // should be ""? + return CanonicalPath::new_seg (id, ""); } std::string get () const diff --git a/gcc/rust/util/rust-dir-owner.h b/gcc/rust/util/rust-dir-owner.h index dcb45d84278c..fb72bb1551cb 100644 --- a/gcc/rust/util/rust-dir-owner.h +++ b/gcc/rust/util/rust-dir-owner.h @@ -26,8 +26,7 @@ namespace Rust { // extracts the owned subdirectory name from a file name -bool -get_file_subdir (const std::string &filename, std::string &subdir); +bool get_file_subdir (const std::string &filename, std::string &subdir); } // namespace Rust diff --git a/gcc/rust/util/rust-edition.h b/gcc/rust/util/rust-edition.h index d034ea03a6f1..532fedb98799 100644 --- a/gcc/rust/util/rust-edition.h +++ b/gcc/rust/util/rust-edition.h @@ -33,8 +33,7 @@ enum class Edition E2021 }; -Edition -get_rust_edition (); +Edition get_rust_edition (); } // namespace Rust diff --git a/gcc/rust/util/rust-ggc.cc b/gcc/rust/util/rust-ggc.cc new file mode 100644 index 000000000000..0722af2b7188 --- /dev/null +++ b/gcc/rust/util/rust-ggc.cc @@ -0,0 +1,41 @@ +// Copyright (C) 2025 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 +// . + +#include "rust-ggc.h" +#include "stringpool.h" + +namespace Rust { + +namespace GGC { + +Ident::Ident (const char *str) : inner (get_identifier (str)) {} + +Ident::Ident (const std::string &str) + : inner (get_identifier_with_length (str.c_str (), str.length ())) +{} + +bool +Ident::operator== (const std::string &other) const +{ + // maybe_get_identifier_with_length doesn't seem to exist + return maybe_get_identifier (other.c_str ()) == inner; +} + +} // namespace GGC + +} // namespace Rust diff --git a/gcc/rust/util/rust-ggc.h b/gcc/rust/util/rust-ggc.h new file mode 100644 index 000000000000..da28edeffe0b --- /dev/null +++ b/gcc/rust/util/rust-ggc.h @@ -0,0 +1,63 @@ +// Copyright (C) 2025 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 +// . + +#ifndef RUST_GGC_H +#define RUST_GGC_H + +#include "rust-system.h" +#include "tree.h" + +namespace Rust { + +namespace GGC { + +class Ident +{ + tree inner; + +public: + Ident (const char *str); + Ident (const std::string &str); + + bool operator== (const Ident &other) const { return inner == other.inner; } + bool operator== (const std::string &other) const; + + const char *c_str () const { return IDENTIFIER_POINTER (inner); } + size_t size () const { return IDENTIFIER_LENGTH (inner); } + + bool empty () const { return !size (); } + + std::string as_string () const + { + return std::string (c_str (), c_str () + size ()); + } + + tree as_tree () const { return inner; } +}; + +static inline bool +operator== (const std::string &a, const Ident &b) +{ + return b == a; +} + +} // namespace GGC + +} // namespace Rust + +#endif // RUST_GGC_H diff --git a/gcc/rust/util/rust-hir-map.cc b/gcc/rust/util/rust-hir-map.cc index eaa640c06121..4629e6a57026 100644 --- a/gcc/rust/util/rust-hir-map.cc +++ b/gcc/rust/util/rust-hir-map.cc @@ -1148,17 +1148,19 @@ Mappings::lookup_module_children (NodeId module) } void -Mappings::insert_ast_module (AST::Module *module) +Mappings::insert_glob_container (AST::Item *container) { - rust_assert (modules.find (module->get_node_id ()) == modules.end ()); - modules[module->get_node_id ()] = module; + rust_assert (glob_containers.find (container->get_node_id ()) + == glob_containers.end ()); + + glob_containers[container->get_node_id ()] = container; } -tl::optional -Mappings::lookup_ast_module (NodeId id) +tl::optional +Mappings::lookup_glob_container (NodeId id) { - auto it = modules.find (id); - if (it == modules.end ()) + auto it = glob_containers.find (id); + if (it == glob_containers.end ()) return tl::nullopt; return {it->second}; diff --git a/gcc/rust/util/rust-hir-map.h b/gcc/rust/util/rust-hir-map.h index b523a36eb0b4..c8fafa4a35f0 100644 --- a/gcc/rust/util/rust-hir-map.h +++ b/gcc/rust/util/rust-hir-map.h @@ -321,8 +321,8 @@ class Mappings void insert_visibility (NodeId id, Privacy::ModuleVisibility visibility); tl::optional lookup_visibility (NodeId id); - void insert_ast_module (AST::Module *); - tl::optional lookup_ast_module (NodeId id); + void insert_glob_container (AST::Item *); + tl::optional lookup_glob_container (NodeId id); void insert_module_child (NodeId module, NodeId child); tl::optional &> lookup_module_children (NodeId module); @@ -436,7 +436,7 @@ class Mappings std::map> module_child_map; std::map> module_child_items; std::map child_to_parent_module_map; - std::map modules; + std::map glob_containers; // AST mappings std::map ast_item_mappings; diff --git a/gcc/rust/util/rust-punycode.h b/gcc/rust/util/rust-punycode.h index a939f05e886d..75260ce0468a 100644 --- a/gcc/rust/util/rust-punycode.h +++ b/gcc/rust/util/rust-punycode.h @@ -27,8 +27,7 @@ namespace Rust { /* Encode a string as punycode. Returns a string if encoding is successful. * Returns nullopt otherwise. Note that a returned string contains only ASCII * characters and does not start with `xn--`. */ -tl::optional -encode_punycode (const Utf8String &src); +tl::optional encode_punycode (const Utf8String &src); } // namespace Rust @@ -36,8 +35,7 @@ encode_punycode (const Utf8String &src); namespace selftest { -void -rust_punycode_encode_test (); +void rust_punycode_encode_test (); } // namespace selftest diff --git a/gcc/rust/util/rust-token-converter.cc b/gcc/rust/util/rust-token-converter.cc index fc34adb9b195..52172f40cfa6 100644 --- a/gcc/rust/util/rust-token-converter.cc +++ b/gcc/rust/util/rust-token-converter.cc @@ -202,7 +202,8 @@ convert (const std::vector &tokens) case PERCENT_EQ: case SCOPE_RESOLUTION: case NOT_EQUAL: - case EQUAL_EQUAL: { + case EQUAL_EQUAL: + { auto str = token->as_string (); auto it = str.cbegin (); for (; it != str.cend () - 1; it++) @@ -260,9 +261,8 @@ convert (const std::vector &tokens) return trees.back (); } -static void -from_tokenstream (const ProcMacro::TokenStream &ts, - std::vector &result); +static void from_tokenstream (const ProcMacro::TokenStream &ts, + std::vector &result); /** * Append the token corresponding to a given Ident to a vector. diff --git a/gcc/rust/util/rust-token-converter.h b/gcc/rust/util/rust-token-converter.h index 5405d6e59d6e..6e4af50439ef 100644 --- a/gcc/rust/util/rust-token-converter.h +++ b/gcc/rust/util/rust-token-converter.h @@ -23,14 +23,11 @@ namespace Rust { -ProcMacro::TokenStream -convert (const std::vector &tokens); +ProcMacro::TokenStream convert (const std::vector &tokens); -std::vector -convert (const ProcMacro::TokenStream &ts); +std::vector convert (const ProcMacro::TokenStream &ts); -ProcMacro::Literal -convert_literal (const_TokenPtr lit); +ProcMacro::Literal convert_literal (const_TokenPtr lit); } // namespace Rust diff --git a/gcc/rust/util/rust-unicode.h b/gcc/rust/util/rust-unicode.h index 6a6526db3090..6579b806976e 100644 --- a/gcc/rust/util/rust-unicode.h +++ b/gcc/rust/util/rust-unicode.h @@ -59,20 +59,15 @@ class Utf8String Utf8String nfc_normalize () const; }; -bool -is_alphabetic (uint32_t codepoint); +bool is_alphabetic (uint32_t codepoint); -bool -is_ascii_only (const std::string &str); +bool is_ascii_only (const std::string &str); -bool -is_numeric (uint32_t codepoint); +bool is_numeric (uint32_t codepoint); -bool -is_nfc_qc_no (uint32_t codepoint); +bool is_nfc_qc_no (uint32_t codepoint); -bool -is_nfc_qc_maybe (uint32_t codepoint); +bool is_nfc_qc_maybe (uint32_t codepoint); enum class QuickCheckResult { @@ -81,8 +76,7 @@ enum class QuickCheckResult MAYBE }; -QuickCheckResult -nfc_quick_check (const std::vector &s); +QuickCheckResult nfc_quick_check (const std::vector &s); } // namespace Rust @@ -90,14 +84,11 @@ nfc_quick_check (const std::vector &s); namespace selftest { -void -rust_nfc_qc_test (); +void rust_nfc_qc_test (); -void -rust_utf8_normalize_test (); +void rust_utf8_normalize_test (); -void -rust_utf8_property_test (); +void rust_utf8_property_test (); } // namespace selftest diff --git a/gcc/rust/util/rust-unwrap-segment.h b/gcc/rust/util/rust-unwrap-segment.h index bebdc3aadd4d..af3a237ea28e 100644 --- a/gcc/rust/util/rust-unwrap-segment.h +++ b/gcc/rust/util/rust-unwrap-segment.h @@ -83,14 +83,11 @@ template class unwrap_type_segment_inner /* * Used to get the node id of a path segment object */ -NodeId -unwrap_segment_node_id (const AST::TypePathSegment &seg); +NodeId unwrap_segment_node_id (const AST::TypePathSegment &seg); -NodeId -unwrap_segment_node_id (const AST::SimplePathSegment &seg); +NodeId unwrap_segment_node_id (const AST::SimplePathSegment &seg); -NodeId -unwrap_segment_node_id (const AST::PathExprSegment &seg); +NodeId unwrap_segment_node_id (const AST::PathExprSegment &seg); template NodeId diff --git a/gcc/testsuite/lib/rust.exp b/gcc/testsuite/lib/rust.exp index 9513e1c89558..692030cf8832 100644 --- a/gcc/testsuite/lib/rust.exp +++ b/gcc/testsuite/lib/rust.exp @@ -168,10 +168,7 @@ proc rust_target_compile { source dest type options } { global gluefile wrap_flags global ALWAYS_RUSTFLAGS global RUST_UNDER_TEST - global individual_timeout - - # HACK: guard against infinite loops in the compiler - set individual_timeout 10 + if { [target_info needs_status_wrapper] != "" && [info exists gluefile] } { lappend options "libs=${gluefile}" diff --git a/gcc/testsuite/rust/compile/additional-trait-bounds2nr2.rs b/gcc/testsuite/rust/compile/additional-trait-bounds2nr2.rs index 6764f6e80120..1c49b750319a 100644 --- a/gcc/testsuite/rust/compile/additional-trait-bounds2nr2.rs +++ b/gcc/testsuite/rust/compile/additional-trait-bounds2nr2.rs @@ -1,5 +1,3 @@ -// { dg-additional-options "-frust-name-resolution-2.0" } - #![feature(optin_builtin_traits)] pub unsafe auto trait Send {} diff --git a/gcc/testsuite/rust/compile/all-cast.rs b/gcc/testsuite/rust/compile/all-cast.rs index fa24373a6779..6d8576cc84f0 100644 --- a/gcc/testsuite/rust/compile/all-cast.rs +++ b/gcc/testsuite/rust/compile/all-cast.rs @@ -4,7 +4,7 @@ fn main() { 0u32 as char; // { dg-error "cannot cast .u32. as .char., only .u8. can be cast as .char." } - let x = &[1_usize, 2] as [usize]; // { dg-error "cast to unsized type: .& .usize:CAPACITY.. as ..usize.." } + let x = &[1_usize, 2] as [usize]; // { dg-error "cast to unsized type: .& .usize; 2.. as ..usize.." } let a = &0u8; // Here, `x` is a `&u8`. let y: u32 = a as u32; // { dg-error "casting .& u8. as .u32. is invalid" } diff --git a/gcc/testsuite/rust/compile/arrays2.rs b/gcc/testsuite/rust/compile/arrays2.rs index 668bcf0951b1..109005922c34 100644 --- a/gcc/testsuite/rust/compile/arrays2.rs +++ b/gcc/testsuite/rust/compile/arrays2.rs @@ -1,5 +1,4 @@ -// { dg-additional-options "-w" } fn main() { let array: [i32; 5] = [1, 2, 3]; - // { dg-error "mismatched types, expected an array with a fixed size of 5 elements, found one with 3 elements" "" { target *-*-* } .-1 } + // { dg-error "mismatched types, expected ..i32; 5.. but got ...integer.; 3.. .E0308." "" { target *-*-* } .-1 } } diff --git a/gcc/testsuite/rust/compile/bad-rpit1.rs b/gcc/testsuite/rust/compile/bad-rpit1.rs new file mode 100644 index 000000000000..d8c21b11c64a --- /dev/null +++ b/gcc/testsuite/rust/compile/bad-rpit1.rs @@ -0,0 +1,26 @@ +#[lang = "sized"] +trait Sized {} + +trait Foo { + fn id(&self) -> i32; +} + +struct A; +struct B; + +impl Foo for A { + fn id(&self) -> i32 { + 1 + } +} + +impl Foo for B { + fn id(&self) -> i32 { + 2 + } +} + +fn make_foo(cond: bool) -> impl Foo { + if cond { A } else { B } + // { dg-error "mismatched types, expected .A. but got .B. .E0308." "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/bug-with-default-generic.rs b/gcc/testsuite/rust/compile/bug-with-default-generic.rs new file mode 100644 index 000000000000..25f46a09c7dc --- /dev/null +++ b/gcc/testsuite/rust/compile/bug-with-default-generic.rs @@ -0,0 +1,15 @@ +#[lang = "sized"] +pub trait Sized {} + +pub trait MyBinaryTrait { + fn do_something(&self, rhs: &Rhs); +} + +struct Foo { + // { dg-warning "struct is never constructed" "" { target *-*-* } .-1 } + value: T, +} + +impl MyBinaryTrait for Foo { + fn do_something(&self, _rhs: &Self) {} +} diff --git a/gcc/testsuite/rust/compile/const3.rs b/gcc/testsuite/rust/compile/const3.rs index 22dc3d356cac..c1d0f29ae199 100644 --- a/gcc/testsuite/rust/compile/const3.rs +++ b/gcc/testsuite/rust/compile/const3.rs @@ -3,5 +3,5 @@ fn size() -> usize { } fn main() { - let a = [15; size()]; // { dg-error "only functions marked as .const. are allowed to be called from constant contexts" } + let a = [15; size()]; // { dg-error "calls in constants are limited to constant functions, tuple structs and tuple variants" } } diff --git a/gcc/testsuite/rust/compile/const_generics_3.rs b/gcc/testsuite/rust/compile/const_generics_3.rs index 524d48d5bcf5..d8b2ddfedaf0 100644 --- a/gcc/testsuite/rust/compile/const_generics_3.rs +++ b/gcc/testsuite/rust/compile/const_generics_3.rs @@ -1,4 +1,4 @@ -// { dg-additional-options "-w -frust-name-resolution-2.0" } +// { dg-additional-options "-w -frust-compile-until=typecheck" } #[lang = "sized"] trait Sized {} diff --git a/gcc/testsuite/rust/compile/deferred_const_inference.rs b/gcc/testsuite/rust/compile/deferred_const_inference.rs new file mode 100644 index 000000000000..25a3b17096aa --- /dev/null +++ b/gcc/testsuite/rust/compile/deferred_const_inference.rs @@ -0,0 +1,7 @@ +// { dg-additional-options "-frust-compile-until=typecheck" } + +// #![feature(generic_arg_infer)] + +fn main() { + let a: [u32; _] = [15u32]; +} diff --git a/gcc/testsuite/rust/compile/derive_partial_ord1.rs b/gcc/testsuite/rust/compile/derive_partial_ord1.rs new file mode 100644 index 000000000000..eeca62da0784 --- /dev/null +++ b/gcc/testsuite/rust/compile/derive_partial_ord1.rs @@ -0,0 +1,464 @@ +// { dg-additional-options "-w" } + +#![feature(intrinsics)] + +mod core { + mod option { + // #[rustc_diagnostic_item = "option_type"] + #[stable(feature = "rust1", since = "1.0.0")] + pub enum Option { + /// No value + #[lang = "None"] + #[stable(feature = "rust1", since = "1.0.0")] + None, + /// Some value `T` + #[lang = "Some"] + #[stable(feature = "rust1", since = "1.0.0")] + Some(#[stable(feature = "rust1", since = "1.0.0")] T), + } + } + + mod marker { + #[lang = "phantom_data"] + #[stable(feature = "rust1", since = "1.0.0")] + pub struct PhantomData; + + #[unstable(feature = "structural_match", issue = "31434")] + // #[rustc_on_unimplemented(message = "the type `{Self}` does not `#[derive(PartialEq)]`")] + #[lang = "structural_peq"] + pub trait StructuralPartialEq { + // Empty. + } + + #[unstable(feature = "structural_match", issue = "31434")] + // #[rustc_on_unimplemented(message = "the type `{Self}` does not `#[derive(Eq)]`")] + #[lang = "structural_teq"] + pub trait StructuralEq { + // Empty. + } + + #[stable(feature = "rust1", since = "1.0.0")] + #[lang = "sized"] + // #[rustc_on_unimplemented( + // message = "the size for values of type `{Self}` cannot be known at compilation time", + // label = "doesn't have a size known at compile-time" + // )] + // #[fundamental] // for Default, for example, which requires that `[T]: !Default` be evaluatable + // #[rustc_specialization_trait] + pub trait Sized { + // Empty. + } + } + + mod cmp { + use super::marker::Sized; + use super::option::Option; + + // #[derive(Clone, Copy, PartialEq, Debug, Hash)] + #[stable(feature = "rust1", since = "1.0.0")] + pub enum Ordering { + /// An ordering where a compared value is less than another. + #[stable(feature = "rust1", since = "1.0.0")] + Less = -1, + /// An ordering where a compared value is equal to another. + #[stable(feature = "rust1", since = "1.0.0")] + Equal = 0, + /// An ordering where a compared value is greater than another. + #[stable(feature = "rust1", since = "1.0.0")] + Greater = 1, + } + + #[lang = "eq"] + #[stable(feature = "rust1", since = "1.0.0")] + #[doc(alias = "==")] + #[doc(alias = "!=")] + // #[rustc_on_unimplemented( + // message = "can't compare `{Self}` with `{Rhs}`", + // label = "no implementation for `{Self} == {Rhs}`" + // )] + pub trait PartialEq { + /// This method tests for `self` and `other` values to be equal, and is used + /// by `==`. + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn eq(&self, other: &Rhs) -> bool; + + fn ne(&self, other: &Rhs) -> bool { + !self.eq(other) + } + } + + #[doc(alias = "==")] + #[doc(alias = "!=")] + #[stable(feature = "rust1", since = "1.0.0")] + pub trait Eq: PartialEq { + // this method is used solely by #[deriving] to assert + // that every component of a type implements #[deriving] + // itself, the current deriving infrastructure means doing this + // assertion without using a method on this trait is nearly + // impossible. + // + // This should never be implemented by hand. + #[doc(hidden)] + #[stable(feature = "rust1", since = "1.0.0")] + fn assert_receiver_is_total_eq(&self) {} + } + + #[lang = "partial_ord"] + #[stable(feature = "rust1", since = "1.0.0")] + #[doc(alias = ">")] + #[doc(alias = "<")] + #[doc(alias = "<=")] + #[doc(alias = ">=")] + // #[rustc_on_unimplemented( + // message = "can't compare `{Self}` with `{Rhs}`", + // label = "no implementation for `{Self} < {Rhs}` and `{Self} > {Rhs}`" + // )] + pub trait PartialOrd: PartialEq { + /// This method returns an ordering between `self` and `other` values if one exists. + /// + /// # Examples + /// + /// ``` + /// use std::cmp::Ordering; + /// + /// let result = 1.0.partial_cmp(&2.0); + /// assert_eq!(result, Some(Ordering::Less)); + /// + /// let result = 1.0.partial_cmp(&1.0); + /// assert_eq!(result, Some(Ordering::Equal)); + /// + /// let result = 2.0.partial_cmp(&1.0); + /// assert_eq!(result, Some(Ordering::Greater)); + /// ``` + /// + /// When comparison is impossible: + /// + /// ``` + /// let result = f64::NAN.partial_cmp(&1.0); + /// assert_eq!(result, None); + /// ``` + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn partial_cmp(&self, other: &Rhs) -> Option; + + /// This method tests less than (for `self` and `other`) and is used by the `<` operator. + /// + /// # Examples + /// + /// ``` + /// let result = 1.0 < 2.0; + /// assert_eq!(result, true); + /// + /// let result = 2.0 < 1.0; + /// assert_eq!(result, false); + /// ``` + #[inline] + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn lt(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Less) => true, + _ => false, + } + } + + /// This method tests less than or equal to (for `self` and `other`) and is used by the `<=` + /// operator. + /// + /// # Examples + /// + /// ``` + /// let result = 1.0 <= 2.0; + /// assert_eq!(result, true); + /// + /// let result = 2.0 <= 2.0; + /// assert_eq!(result, true); + /// ``` + #[inline] + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn le(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Less | Ordering::Equal) => true, + _ => false, + } + } + + /// This method tests greater than (for `self` and `other`) and is used by the `>` operator. + /// + /// # Examples + /// + /// ``` + /// let result = 1.0 > 2.0; + /// assert_eq!(result, false); + /// + /// let result = 2.0 > 2.0; + /// assert_eq!(result, false); + /// ``` + #[inline] + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn gt(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Greater) => true, + _ => false, + } + } + + /// This method tests greater than or equal to (for `self` and `other`) and is used by the `>=` + /// operator. + /// + /// # Examples + /// + /// ``` + /// let result = 2.0 >= 1.0; + /// assert_eq!(result, true); + /// + /// let result = 2.0 >= 2.0; + /// assert_eq!(result, true); + /// ``` + #[inline] + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn ge(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Greater | Ordering::Equal) => true, + _ => false, + } + } + } + + #[doc(alias = "<")] + #[doc(alias = ">")] + #[doc(alias = "<=")] + #[doc(alias = ">=")] + #[stable(feature = "rust1", since = "1.0.0")] + pub trait Ord: Eq + PartialOrd { + /// This method returns an [`Ordering`] between `self` and `other`. + /// + /// By convention, `self.cmp(&other)` returns the ordering matching the expression + /// `self other` if true. + /// + /// # Examples + /// + /// ``` + /// use std::cmp::Ordering; + /// + /// assert_eq!(5.cmp(&10), Ordering::Less); + /// assert_eq!(10.cmp(&5), Ordering::Greater); + /// assert_eq!(5.cmp(&5), Ordering::Equal); + /// ``` + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn cmp(&self, other: &Self) -> Ordering; + + /// Compares and returns the maximum of two values. + /// + /// Returns the second argument if the comparison determines them to be equal. + /// + /// # Examples + /// + /// ``` + /// assert_eq!(2, 1.max(2)); + /// assert_eq!(2, 2.max(2)); + /// ``` + #[stable(feature = "ord_max_min", since = "1.21.0")] + #[must_use] + fn max(self, other: Self) -> Self + where + Self: Sized, + { + self + } + + /// Compares and returns the minimum of two values. + /// + /// Returns the first argument if the comparison determines them to be equal. + /// + /// # Examples + /// + /// ``` + /// assert_eq!(1, 1.min(2)); + /// assert_eq!(2, 2.min(2)); + /// ``` + #[stable(feature = "ord_max_min", since = "1.21.0")] + #[must_use] + fn min(self, other: Self) -> Self + where + Self: Sized, + { + self + } + + /// Restrict a value to a certain interval. + /// + /// Returns `max` if `self` is greater than `max`, and `min` if `self` is + /// less than `min`. Otherwise this returns `self`. + /// + /// # Panics + /// + /// Panics if `min > max`. + /// + /// # Examples + /// + /// ``` + /// #![feature(clamp)] + /// + /// assert!((-3).clamp(-2, 1) == -2); + /// assert!(0.clamp(-2, 1) == 0); + /// assert!(2.clamp(-2, 1) == 1); + /// ``` + #[must_use] + #[unstable(feature = "clamp", issue = "44095")] + fn clamp(self, min: Self, max: Self) -> Self + where + Self: Sized, + { + if self < min { + min + } else if self > max { + max + } else { + self + } + } + } + } + + pub mod intrinsics { + #[lang = "discriminant_kind"] + pub trait DiscriminantKind { + #[lang = "discriminant_type"] + type Discriminant; + } + + extern "rust-intrinsic" { + pub fn discriminant_value(v: &T) -> ::Discriminant; + } + } +} + +use core::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd}; +use core::marker::Sized; +use core::option::Option; + +// for comparing discriminant_value +impl PartialEq for isize { + fn eq(&self, other: &Self) -> bool { + *self == *other + } +} + +// for comparing discriminant_value +impl PartialOrd for isize { + fn partial_cmp(&self, other: &Self) -> Option { + if *self > *other { + Option::Some(Ordering::Greater) + } else if *self < *other { + Option::Some(Ordering::Less) + } else { + Option::Some(Ordering::Equal) + } + } + + fn lt(&self, other: &Self) -> bool { + *self < *other + } + fn le(&self, other: &Self) -> bool { + *self <= *other + } + fn ge(&self, other: &Self) -> bool { + *self >= *other + } + fn gt(&self, other: &Self) -> bool { + *self > *other + } +} + +impl PartialEq for i32 { + fn eq(&self, other: &Self) -> bool { + *self == *other + } +} + +impl PartialOrd for i32 { + fn partial_cmp(&self, other: &Self) -> Option { + if *self > *other { + Option::Some(Ordering::Greater) + } else if *self < *other { + Option::Some(Ordering::Less) + } else { + Option::Some(Ordering::Equal) + } + } + + fn lt(&self, other: &Self) -> bool { + *self < *other + } + fn le(&self, other: &Self) -> bool { + *self <= *other + } + fn ge(&self, other: &Self) -> bool { + *self >= *other + } + fn gt(&self, other: &Self) -> bool { + *self > *other + } +} + +impl Ord for i32 { + fn cmp(&self, other: &Self) -> Ordering { + if *self > *other { + Ordering::Greater + } else if *self < *other { + Ordering::Less + } else { + Ordering::Equal + } + } +} + +impl Eq for i32 {} + +#[derive(PartialEq, PartialOrd)] +enum Foo { + A, + B(i32, i32, i32), + C { inner: i32, outer: i32 }, +} + +#[derive(Ord, PartialOrd, PartialEq, Eq)] +struct Bar { + a: i32, +} + +#[derive(Ord, PartialOrd, PartialEq, Eq)] +struct BarFull { + a: i32, + b: i32, + c: i32, + d: i32, +} + +extern "C" { + fn puts(s: *const i8); +} + +fn print(s: &str) { + unsafe { + puts(s as *const str as *const i8); + } +} + +fn main() { + let a = Foo::A; + let b = Foo::B(15, 14, 13); + + match a.partial_cmp(&b) { + Option::Some(Ordering::Less) => print("less"), + Option::Some(Ordering::Greater) => print("greater"), + Option::Some(Ordering::Equal) => print("equal"), + _ => print("uuuuh woops lol"), + } +} diff --git a/gcc/testsuite/rust/compile/enum_variant_name.rs b/gcc/testsuite/rust/compile/enum_variant_name.rs index 671fced2bb8c..965acd1a9cd7 100644 --- a/gcc/testsuite/rust/compile/enum_variant_name.rs +++ b/gcc/testsuite/rust/compile/enum_variant_name.rs @@ -1,4 +1,4 @@ -// { dg-additional-options "-w -frust-name-resolution-2.0" } +// { dg-additional-options "-w" } struct E1; enum Test { diff --git a/gcc/testsuite/rust/compile/generics9.rs b/gcc/testsuite/rust/compile/generics9.rs index 56c619833f4f..949fbb1a41cd 100644 --- a/gcc/testsuite/rust/compile/generics9.rs +++ b/gcc/testsuite/rust/compile/generics9.rs @@ -1,4 +1,3 @@ -// { dg-additional-options "-frust-name-resolution-2.0" } struct Foo(A, B); // { dg-error "type parameters with a default cannot use forward declared identifiers" "" { target *-*-* } .-1 } diff --git a/gcc/testsuite/rust/compile/glob_import_enum.rs b/gcc/testsuite/rust/compile/glob_import_enum.rs new file mode 100644 index 000000000000..032a1db4ea84 --- /dev/null +++ b/gcc/testsuite/rust/compile/glob_import_enum.rs @@ -0,0 +1,16 @@ +use self::Ordering::*; +use Ordering::*; + +enum Ordering { + A, + B, +} + +fn foo(_: Ordering) {} + +fn main() { + let a = A; + + foo(a); + foo(B); +} diff --git a/gcc/testsuite/rust/compile/impl_trait_diag.rs b/gcc/testsuite/rust/compile/impl_trait_diag.rs new file mode 100644 index 000000000000..54a0cd220a39 --- /dev/null +++ b/gcc/testsuite/rust/compile/impl_trait_diag.rs @@ -0,0 +1,17 @@ +#[lang = "sized"] +pub trait Sized {} + +trait Foo { + fn method(&self); +} + +struct Bar; +impl Foo for Bar {} + +fn main() { + let x: impl Foo = Bar; // { dg-error ".impl Trait. not allowed outside of function and inherent method return types .E0562." } + + struct Wrapper { + field: impl Foo, // { dg-error ".impl Trait. not allowed outside of function and inherent method return types .E0562." } + } +} diff --git a/gcc/testsuite/rust/compile/impl_trait_generic_arg.rs b/gcc/testsuite/rust/compile/impl_trait_generic_arg.rs new file mode 100644 index 000000000000..ecdb08803b40 --- /dev/null +++ b/gcc/testsuite/rust/compile/impl_trait_generic_arg.rs @@ -0,0 +1,24 @@ +#[lang = "sized"] +trait Sized {} + +trait Foo { + fn id(&self) -> u8; +} + +struct Bar; + +impl Foo for Bar { + fn id(&self) -> u8 { + 1 + } +} + +fn takes(val: impl Foo) -> u8 { + val.id() +} + +fn main() { + let b = Bar; + let x = takes::(b); + // { dg-error "cannot provide explicit generic arguments when .impl Trait. is used in argument position .E0632." "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/invalid_label_name.rs b/gcc/testsuite/rust/compile/invalid_label_name.rs index 66e40a620e09..d1c5a33c62fb 100644 --- a/gcc/testsuite/rust/compile/invalid_label_name.rs +++ b/gcc/testsuite/rust/compile/invalid_label_name.rs @@ -1,4 +1,3 @@ -// { dg-additional-options "-frust-name-resolution-2.0" } pub fn function() { 'continue: loop { // { dg-error "invalid label name .'continue." "" { target *-*-* } .-1 } diff --git a/gcc/testsuite/rust/compile/issue-1048.rs b/gcc/testsuite/rust/compile/issue-1048.rs new file mode 100644 index 000000000000..8d4053a37a1e --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-1048.rs @@ -0,0 +1,8 @@ +macro_rules! maybe_return { ($e:expr) => ($e); } + +fn frob(x: i32) -> i32{ + maybe_return! {x} + // { dg-error "mismatched types. expected .... but got .i32. .E0308." "" { target *-*-* } .-1 } + // should return -1 + -1 +} diff --git a/gcc/testsuite/rust/compile/issue-1485.rs b/gcc/testsuite/rust/compile/issue-1485.rs new file mode 100644 index 000000000000..a0cd5a0f1f92 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-1485.rs @@ -0,0 +1,16 @@ +#[lang = "sized"] +pub trait Sized {} + +#[lang = "fn_once"] +pub trait FnOnce { + #[lang = "fn_once_output"] + type Output; + + extern "rust-call" fn call_once(self, args: Args) -> Self::Output; +} + +struct BinOpInvalid { + lhs: i32, + rhs: i32, + f: impl FnOnce(i32) -> i32, // { dg-error ".impl Trait. not allowed outside of function and inherent method return types .E0562." } +} diff --git a/gcc/testsuite/rust/compile/issue-1487.rs b/gcc/testsuite/rust/compile/issue-1487.rs new file mode 100644 index 000000000000..4a4d759ef2e9 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-1487.rs @@ -0,0 +1,15 @@ +// { dg-options "-w" } +#[lang = "sized"] +trait Sized {} + +trait Printable { + fn print(&self); +} + +struct Foo; + +impl Printable for Foo { + fn print(&self) {} +} + +fn take_printable(_: impl Printable) {} diff --git a/gcc/testsuite/rust/compile/issue-2015.rs b/gcc/testsuite/rust/compile/issue-2015.rs index 7789ecda3763..7e0365163e5a 100644 --- a/gcc/testsuite/rust/compile/issue-2015.rs +++ b/gcc/testsuite/rust/compile/issue-2015.rs @@ -1,4 +1,5 @@ -// { dg-additional-options "-frust-compile-until=lowering" } +#[lang = "sized"] +trait Sized {} macro_rules! impl_foo { () => { impl Foo } diff --git a/gcc/testsuite/rust/compile/issue-2680.rs b/gcc/testsuite/rust/compile/issue-2680.rs new file mode 100644 index 000000000000..d5ae2ff4450b --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-2680.rs @@ -0,0 +1,6 @@ +// { dg-additional-options "-fdump-tree-gimple" } +pub fn test_cast() { + let i = 1; + // { dg-final { scan-tree-dump-times {const i32 i;} 1 gimple } } + let _j = i as i64; +} diff --git a/gcc/testsuite/rust/compile/issue-3144.rs b/gcc/testsuite/rust/compile/issue-3144.rs new file mode 100644 index 000000000000..4e61078a0dcc --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-3144.rs @@ -0,0 +1,29 @@ +#[lang = "sized"] +pub trait Sized {} + +#[lang = "copy"] +trait Copy {} + +#[lang = "clone"] +pub trait Clone { + fn clone(&self) -> Self; +} + +impl Clone for i32 { + fn clone(&self) -> i32 { + *self + } +} + +struct S {} + +#[derive(Clone, Copy)] +// { dg-error {bounds not satisfied for S .Clone. is not satisfied .E0277.} "" { target *-*-* } .-1 } +struct S2 { + a: i32, + s: S, +} + +fn main() -> i32 { + 0 +} diff --git a/gcc/testsuite/rust/compile/issue-3304.rs b/gcc/testsuite/rust/compile/issue-3304.rs index 6ab614fa2d5d..cc376faeb9dc 100644 --- a/gcc/testsuite/rust/compile/issue-3304.rs +++ b/gcc/testsuite/rust/compile/issue-3304.rs @@ -1,4 +1,3 @@ -// { dg-additional-options "-frust-name-resolution-2.0" } #[lang = "sized"] trait Sized {} diff --git a/gcc/testsuite/rust/compile/issue-3454.rs b/gcc/testsuite/rust/compile/issue-3454.rs new file mode 100644 index 000000000000..2a3c0c714606 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-3454.rs @@ -0,0 +1,20 @@ +#[lang = "sized"] +pub trait Sized {} + +macro_rules! impl_foo { + () => { impl Foo } +} + +pub trait Foo {} + +pub trait Bar { + type Baz; +} + +pub fn foo(_value: impl Bar) -> i32 { + 15 +} + +pub fn bar(_value: impl Bar) -> i32 { + 16 +} diff --git a/gcc/testsuite/rust/compile/issue-3524.rs b/gcc/testsuite/rust/compile/issue-3524.rs new file mode 100644 index 000000000000..62c8c3512747 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-3524.rs @@ -0,0 +1,9 @@ +struct A {} +// { dg-warning "struct is never constructed" "" { target *-*-* } .-1 } + +impl A { + fn main() {} + // { dg-warning "associated function is never used: .main." "" { target *-*-* } .-1 } +} + +fn main() {} diff --git a/gcc/testsuite/rust/compile/issue-3525.rs b/gcc/testsuite/rust/compile/issue-3525.rs new file mode 100644 index 000000000000..84a7ebeee116 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-3525.rs @@ -0,0 +1,6 @@ +// { dg-options "-w" } + +struct Foo(usize); + +const B: usize = A.0; +const A: Foo = Foo(123); diff --git a/gcc/testsuite/rust/compile/issue-3551.rs b/gcc/testsuite/rust/compile/issue-3551.rs new file mode 100644 index 000000000000..6d6a8129885d --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-3551.rs @@ -0,0 +1,15 @@ +#[lang = "sized"] +pub trait Sized {} + +#[lang = "fn_once"] +pub trait FnOnce { + #[lang = "fn_once_output"] + type Output; + + extern "rust-call" fn call_once(self, args: Args) -> Self::Output; +} + +struct Bug { + a: [(); (|| 0)()], + // { dg-error "calls in constants are limited to constant functions, tuple structs and tuple variants" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/issue-3599.rs b/gcc/testsuite/rust/compile/issue-3599.rs new file mode 100644 index 000000000000..1d29fac84e93 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-3599.rs @@ -0,0 +1,8 @@ +#[lang = "sized"] +trait Sized {} + +trait Bar {} + +struct S; // { dg-warning "struct is never constructed" } + +pub fn test(foo: impl Bar) {} diff --git a/gcc/testsuite/rust/compile/issue-3618.rs b/gcc/testsuite/rust/compile/issue-3618.rs new file mode 100644 index 000000000000..3bf2c7efd94d --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-3618.rs @@ -0,0 +1,2 @@ +static _X : () + = loop{}; // { dg-error "'loop' is not allowed in const context" } diff --git a/gcc/testsuite/rust/compile/issue-3642.rs b/gcc/testsuite/rust/compile/issue-3642.rs new file mode 100644 index 000000000000..6d9decc8616d --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-3642.rs @@ -0,0 +1,9 @@ +#[lang = "sized"] +trait Sized {} + +pub trait T { + const D: i32 = { + // { dg-error "mismatched types, expected .i32. but got .()." "" { target *-*-* } .-1 } + const C: X; + }; +} diff --git a/gcc/testsuite/rust/compile/issue-3660.rs b/gcc/testsuite/rust/compile/issue-3660.rs new file mode 100644 index 000000000000..1f1c583cb5b6 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-3660.rs @@ -0,0 +1,3 @@ +pub static A: [u32; 2] = [1, 2]; + +pub static B: [u8; 2] = [3, 4]; diff --git a/gcc/testsuite/rust/compile/issue-3661.rs b/gcc/testsuite/rust/compile/issue-3661.rs new file mode 100644 index 000000000000..8d03c3630d56 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-3661.rs @@ -0,0 +1,10 @@ +pub macro m($inner_str:expr) { + #[m = $inner_str] + // { dg-error "macro not found" "" { target *-*-* } .-1 } + + struct S; +} + +fn main() { + m!(stringify!(foo)); +} diff --git a/gcc/testsuite/rust/compile/issue-3671.rs b/gcc/testsuite/rust/compile/issue-3671.rs index e800d536e02c..8015653c0bc5 100644 --- a/gcc/testsuite/rust/compile/issue-3671.rs +++ b/gcc/testsuite/rust/compile/issue-3671.rs @@ -1,2 +1,2 @@ -impl Self<0> {} +impl Foo<0> {} // { dg-error "could not resolve type path" "" { target *-*-* } .-1 } diff --git a/gcc/testsuite/rust/compile/issue-3836.rs b/gcc/testsuite/rust/compile/issue-3836.rs new file mode 100644 index 000000000000..a2287957ad14 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-3836.rs @@ -0,0 +1,67 @@ +// { dg-options "-w" } +mod core { + mod option { + pub enum Option { + #[lang = "None"] + None, + #[lang = "Some"] + Some(T), + } + } + + mod marker { + #[lang = "sized"] + pub trait Sized {} + } + + mod cmp { + use super::marker::Sized; + use super::option::Option; + + pub enum Ordering { + Less = -1, + Equal = 0, + Greater = 1, + } + + #[lang = "eq"] + pub trait PartialEq { + fn eq(&self, other: &Rhs) -> bool; + + fn ne(&self, other: &Rhs) -> bool { + !self.eq(other) + } + } + + #[lang = "partial_ord"] + pub trait PartialOrd: PartialEq { + fn partial_cmp(&self, other: &Rhs) -> Option; + } + } +} + +use core::cmp::{Ordering, PartialEq, PartialOrd}; +use core::marker::Sized; +use core::option::Option; + +impl PartialEq for i32 { + fn eq(&self, other: &Self) -> bool { + false + } +} + +impl PartialOrd for i32 { + fn partial_cmp(&self, other: &Self) -> Option { + Option::Some(Ordering::Equal) + } +} + +struct Foo { + a: i32, +} + +impl PartialEq for Foo { + fn eq(&self, other: &'_ Self) -> bool { + ::core::cmp::PartialEq::eq(&self.a, &other.a) + } +} diff --git a/gcc/testsuite/rust/compile/issue-3874.rs b/gcc/testsuite/rust/compile/issue-3874.rs new file mode 100644 index 000000000000..ebce4b6da87d --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-3874.rs @@ -0,0 +1,4 @@ +fn wow(){ + &#[serde] + // { dg-error "found unexpected token .#. in null denotation" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/issue-3876.rs b/gcc/testsuite/rust/compile/issue-3876.rs new file mode 100644 index 000000000000..17b1590590e0 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-3876.rs @@ -0,0 +1,8 @@ +enum test { + A(i32), +} + +fn fun(x: i32) { + test::A { x } + // { dg-error "unknown field" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/issue-3915.rs b/gcc/testsuite/rust/compile/issue-3915.rs new file mode 100644 index 000000000000..7132036f92ff --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-3915.rs @@ -0,0 +1,28 @@ +// { dg-options "-w" } +#[lang = "sized"] +trait Sized {} + +trait Trait { + fn do_thing(); +} + +struct MyType; + +impl Trait for MyType { + fn do_thing() {} +} + +struct Wrapper { + value: T, +} + +impl Wrapper { + fn call_it() { + T::do_thing(); + } +} + +fn main() { + let _ = Wrapper:: { value: MyType }; + Wrapper::::call_it(); +} diff --git a/gcc/testsuite/rust/compile/issue-3916.rs b/gcc/testsuite/rust/compile/issue-3916.rs new file mode 100644 index 000000000000..59b522b4ed5c --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-3916.rs @@ -0,0 +1,36 @@ +#![feature(rustc_attrs)] + +#[lang = "sized"] +trait Sized {} + +#[lang = "add"] +trait Add { + type Output; + + fn add(self, rhs: Rhs) -> Self::Output; +} + +macro_rules! add_impl { + ($($t:ty)*) => ($( + impl Add for $t { + type Output = $t; + + #[inline] + #[rustc_inherit_overflow_checks] + fn add(self, other: $t) -> $t { self + other } + } + )*) +} + +add_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } + +pub fn test(len: usize) -> u64 { + let mut i = 0; + let mut out = 0; + if i + 3 < len { + out = 123; + } else { + out = 456; + } + out +} diff --git a/gcc/testsuite/rust/compile/issue-3978.rs b/gcc/testsuite/rust/compile/issue-3978.rs new file mode 100644 index 000000000000..4f17d3d4d04a --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-3978.rs @@ -0,0 +1,8 @@ +type Dimension = usize; + +pub fn main() {} + +mod m2 { + fn main() {} + // { dg-warning "function is never used" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/loop_constant_context.rs b/gcc/testsuite/rust/compile/loop_constant_context.rs new file mode 100644 index 000000000000..ed0782b91a6f --- /dev/null +++ b/gcc/testsuite/rust/compile/loop_constant_context.rs @@ -0,0 +1,5 @@ +// { dg-error "'loop' is not allowed in const context" "" { target *-*-* } .+1 } +const CONST_LOOP : () = loop{}; + +// { dg-error "'loop' is not allowed in const context" "" { target *-*-* } .+1 } +static STATIC_LOOP : () = loop{}; \ No newline at end of file diff --git a/gcc/testsuite/rust/compile/macros/builtin/recurse2.rs b/gcc/testsuite/rust/compile/macros/builtin/recurse2.rs index 73e6ab4aa6cd..fbb4b10e6545 100644 --- a/gcc/testsuite/rust/compile/macros/builtin/recurse2.rs +++ b/gcc/testsuite/rust/compile/macros/builtin/recurse2.rs @@ -34,7 +34,7 @@ fn print_str(s: &str) { } } -// { dg-final { scan-assembler {"abheyho"} } } +// { dg-final { scan-assembler {"abheyho(\\0)?"} } } static S: &str = concat!("a", 'b', a!(), a!(b c d e f a!()), '\0'); fn main() { diff --git a/gcc/testsuite/rust/compile/macros/mbe/macro-issue3708.rs b/gcc/testsuite/rust/compile/macros/mbe/macro-issue3708.rs index e5b38bb0da7e..bcbc8dd695af 100644 --- a/gcc/testsuite/rust/compile/macros/mbe/macro-issue3708.rs +++ b/gcc/testsuite/rust/compile/macros/mbe/macro-issue3708.rs @@ -1,4 +1,4 @@ -// { dg-additional-options "-frust-name-resolution-2.0 -frust-compile-until=lowering" } +// { dg-additional-options "-frust-compile-until=lowering" } macro_rules! impl_fn_for_zst { ($( diff --git a/gcc/testsuite/rust/compile/macros/mbe/macro-issue3709-2.rs b/gcc/testsuite/rust/compile/macros/mbe/macro-issue3709-2.rs index cfc8ab460b78..47514f1e998b 100644 --- a/gcc/testsuite/rust/compile/macros/mbe/macro-issue3709-2.rs +++ b/gcc/testsuite/rust/compile/macros/mbe/macro-issue3709-2.rs @@ -1,4 +1,4 @@ -// { dg-additional-options "-frust-name-resolution-2.0 -frust-compile-until=lowering" } +// { dg-additional-options "-frust-compile-until=lowering" } macro_rules! impl_fn_for_zst { ($( diff --git a/gcc/testsuite/rust/compile/macros/mbe/meta-param.rs b/gcc/testsuite/rust/compile/macros/mbe/meta-param.rs new file mode 100644 index 000000000000..ed6e100e5fd0 --- /dev/null +++ b/gcc/testsuite/rust/compile/macros/mbe/meta-param.rs @@ -0,0 +1,7 @@ +macro_rules! foo { + ($x:meta) => {0} +} + +pub fn main() -> i32 { + foo!(Clone) +} diff --git a/gcc/testsuite/rust/compile/match-identifierpattern-enum.rs b/gcc/testsuite/rust/compile/match-identifierpattern-enum.rs new file mode 100644 index 000000000000..c712667e27a4 --- /dev/null +++ b/gcc/testsuite/rust/compile/match-identifierpattern-enum.rs @@ -0,0 +1,12 @@ +enum Foo { + I(i32), +} + +fn main() { + let x = Foo::I(1); + + match x { + a @ Foo::I(b) => {}, + _ => {}, + }; +} diff --git a/gcc/testsuite/rust/compile/match-identifierpattern.rs b/gcc/testsuite/rust/compile/match-identifierpattern.rs new file mode 100644 index 000000000000..6c558ac065b9 --- /dev/null +++ b/gcc/testsuite/rust/compile/match-identifierpattern.rs @@ -0,0 +1,9 @@ +fn main() { + let x = 1; + + match x { + 2 => {}, + a @ 3 => {}, + _ => {}, + } +} diff --git a/gcc/testsuite/rust/compile/match-restpattern-tuple-1.rs b/gcc/testsuite/rust/compile/match-restpattern-tuple-1.rs new file mode 100644 index 000000000000..5cce3c409f0e --- /dev/null +++ b/gcc/testsuite/rust/compile/match-restpattern-tuple-1.rs @@ -0,0 +1,8 @@ +fn main() { + let x = (1, 2, 3, 4); + + match x { + (1, .., 4) => {}, + _ => {} + } +} \ No newline at end of file diff --git a/gcc/testsuite/rust/compile/match-restpattern-tuple-2.rs b/gcc/testsuite/rust/compile/match-restpattern-tuple-2.rs new file mode 100644 index 000000000000..40900a36bece --- /dev/null +++ b/gcc/testsuite/rust/compile/match-restpattern-tuple-2.rs @@ -0,0 +1,8 @@ +fn main() { + let x = (1, 2, 3, 4); + + match x { + (1, .., 2, 3, 4, 5) => {}, // { dg-error "expected a tuple with 4 elements, found one with 5 elements" } + _ => {} + } +} \ No newline at end of file diff --git a/gcc/testsuite/rust/compile/match-slicepattern-array.rs b/gcc/testsuite/rust/compile/match-slicepattern-array.rs new file mode 100644 index 000000000000..e48ca757f5e0 --- /dev/null +++ b/gcc/testsuite/rust/compile/match-slicepattern-array.rs @@ -0,0 +1,8 @@ +fn main() { + let a = [0, 1]; + + match a { + [0, 1] => {}, + _ => {} + } +} diff --git a/gcc/testsuite/rust/compile/match-tuplestructpattern.rs b/gcc/testsuite/rust/compile/match-tuplestructpattern.rs new file mode 100644 index 000000000000..0dae71ea0051 --- /dev/null +++ b/gcc/testsuite/rust/compile/match-tuplestructpattern.rs @@ -0,0 +1,9 @@ +fn main() { + struct A (i32, i32); + let a = A (0, 1); + + match a { + A (0, 1) => {}, + _ => {} + } +} diff --git a/gcc/testsuite/rust/compile/name_resolution10.rs b/gcc/testsuite/rust/compile/name_resolution10.rs index 33643bd1a147..f156f98c968a 100644 --- a/gcc/testsuite/rust/compile/name_resolution10.rs +++ b/gcc/testsuite/rust/compile/name_resolution10.rs @@ -1,4 +1,4 @@ -// { dg-options "-frust-name-resolution-2.0 -frust-compile-until=lowering" } +// { dg-options "-frust-compile-until=lowering" } #![feature(decl_macro)] diff --git a/gcc/testsuite/rust/compile/name_resolution11.rs b/gcc/testsuite/rust/compile/name_resolution11.rs index a464d2a0fd3e..329567afe960 100644 --- a/gcc/testsuite/rust/compile/name_resolution11.rs +++ b/gcc/testsuite/rust/compile/name_resolution11.rs @@ -1,4 +1,4 @@ -// { dg-additional-options "-frust-name-resolution-2.0 -frust-compile-until=lowering" } +// { dg-additional-options "-frust-compile-until=lowering" } fn foo() { let b = 10; fn bar() { diff --git a/gcc/testsuite/rust/compile/name_resolution12.rs b/gcc/testsuite/rust/compile/name_resolution12.rs index 9cce31ceb5c2..0f217aa064d7 100644 --- a/gcc/testsuite/rust/compile/name_resolution12.rs +++ b/gcc/testsuite/rust/compile/name_resolution12.rs @@ -1,4 +1,4 @@ -// { dg-additional-options "-frust-name-resolution-2.0 -frust-compile-until=lowering" } +// { dg-additional-options "-frust-compile-until=lowering" } const TOTO: i32 = 10; diff --git a/gcc/testsuite/rust/compile/name_resolution13.rs b/gcc/testsuite/rust/compile/name_resolution13.rs index 33edbf9312e2..8356cf6d2d3a 100644 --- a/gcc/testsuite/rust/compile/name_resolution13.rs +++ b/gcc/testsuite/rust/compile/name_resolution13.rs @@ -1,5 +1,3 @@ -// { dg-options "-frust-name-resolution-2.0" } - pub mod foo { pub macro bar() {} } diff --git a/gcc/testsuite/rust/compile/name_resolution14.rs b/gcc/testsuite/rust/compile/name_resolution14.rs index eaef6a52f160..44c43aa2c0fd 100644 --- a/gcc/testsuite/rust/compile/name_resolution14.rs +++ b/gcc/testsuite/rust/compile/name_resolution14.rs @@ -1,5 +1,3 @@ -// { dg-options "-frust-name-resolution-2.0" } - pub mod foo { pub macro bar() {} } diff --git a/gcc/testsuite/rust/compile/name_resolution15.rs b/gcc/testsuite/rust/compile/name_resolution15.rs index 45f38da768af..e82c90eafb51 100644 --- a/gcc/testsuite/rust/compile/name_resolution15.rs +++ b/gcc/testsuite/rust/compile/name_resolution15.rs @@ -1,4 +1,3 @@ -// { dg-additional-options "-frust-name-resolution-2.0" } #![feature(decl_macro)] pub mod foo { diff --git a/gcc/testsuite/rust/compile/name_resolution16.rs b/gcc/testsuite/rust/compile/name_resolution16.rs index 230722ef819c..4db7b2ea164b 100644 --- a/gcc/testsuite/rust/compile/name_resolution16.rs +++ b/gcc/testsuite/rust/compile/name_resolution16.rs @@ -1,4 +1,3 @@ -// { dg-additional-options "-frust-name-resolution-2.0" } #![feature(decl_macro)] pub mod foo { diff --git a/gcc/testsuite/rust/compile/name_resolution17.rs b/gcc/testsuite/rust/compile/name_resolution17.rs index 485947647a95..84ad380fd956 100644 --- a/gcc/testsuite/rust/compile/name_resolution17.rs +++ b/gcc/testsuite/rust/compile/name_resolution17.rs @@ -1,5 +1,3 @@ -// { dg-options "-frust-name-resolution-2.0" } - struct Foo; fn Foo() {} // { dg-error ".Foo. defined multiple times" } diff --git a/gcc/testsuite/rust/compile/name_resolution18.rs b/gcc/testsuite/rust/compile/name_resolution18.rs index 5940149d3bbf..17a335280278 100644 --- a/gcc/testsuite/rust/compile/name_resolution18.rs +++ b/gcc/testsuite/rust/compile/name_resolution18.rs @@ -1,5 +1,3 @@ -// { dg-options "-frust-name-resolution-2.0" } - struct Marker; struct Foo { diff --git a/gcc/testsuite/rust/compile/name_resolution20.rs b/gcc/testsuite/rust/compile/name_resolution20.rs index e6c2dd5ea8f9..f131bb41c170 100644 --- a/gcc/testsuite/rust/compile/name_resolution20.rs +++ b/gcc/testsuite/rust/compile/name_resolution20.rs @@ -1,5 +1,3 @@ -// { dg-options "-frust-name-resolution-2.0" } - pub mod foo { pub macro bar() {} } diff --git a/gcc/testsuite/rust/compile/name_resolution22.rs b/gcc/testsuite/rust/compile/name_resolution22.rs index c49331ef38cd..bb5edda6834b 100644 --- a/gcc/testsuite/rust/compile/name_resolution22.rs +++ b/gcc/testsuite/rust/compile/name_resolution22.rs @@ -1,4 +1,3 @@ -// { dg-options "-frust-name-resolution-2.0" } struct Marker; struct Foo(Marker); diff --git a/gcc/testsuite/rust/compile/name_resolution23.rs b/gcc/testsuite/rust/compile/name_resolution23.rs index 50b8e8111525..843be2a8a49a 100644 --- a/gcc/testsuite/rust/compile/name_resolution23.rs +++ b/gcc/testsuite/rust/compile/name_resolution23.rs @@ -1,5 +1,3 @@ -// { dg-options "-frust-name-resolution-2.0" } - mod a { pub mod b { pub fn foo() {} diff --git a/gcc/testsuite/rust/compile/name_resolution24.rs b/gcc/testsuite/rust/compile/name_resolution24.rs index f4eb7b2d38fd..4350cd85bd69 100644 --- a/gcc/testsuite/rust/compile/name_resolution24.rs +++ b/gcc/testsuite/rust/compile/name_resolution24.rs @@ -1,5 +1,3 @@ -// { dg-options "-frust-name-resolution-2.0" } - mod a { pub mod b { pub fn baz() {} diff --git a/gcc/testsuite/rust/compile/name_resolution25.rs b/gcc/testsuite/rust/compile/name_resolution25.rs index 3cacac7f64bd..0cadd9e1c216 100644 --- a/gcc/testsuite/rust/compile/name_resolution25.rs +++ b/gcc/testsuite/rust/compile/name_resolution25.rs @@ -1,5 +1,3 @@ -// { dg-options "-frust-name-resolution-2.0" } - struct Test; // { dg-warning "struct is never constructed: .Test." } impl Test {} diff --git a/gcc/testsuite/rust/compile/name_resolution6.rs b/gcc/testsuite/rust/compile/name_resolution6.rs index e4087e6281ca..b2b5f6bfc98f 100644 --- a/gcc/testsuite/rust/compile/name_resolution6.rs +++ b/gcc/testsuite/rust/compile/name_resolution6.rs @@ -1,4 +1,4 @@ -// { dg-options "-frust-name-resolution-2.0 -frust-compile-until=lowering" } +// { dg-options "-frust-compile-until=lowering" } pub mod foo { pub mod bar { diff --git a/gcc/testsuite/rust/compile/name_resolution7.rs b/gcc/testsuite/rust/compile/name_resolution7.rs index fa84e2ffb839..78cb0b2df708 100644 --- a/gcc/testsuite/rust/compile/name_resolution7.rs +++ b/gcc/testsuite/rust/compile/name_resolution7.rs @@ -1,5 +1,3 @@ -// { dg-options "-frust-name-resolution-2.0" } - // check that macros by example do not get inserted in ribs like regular items pub mod foo { pub mod bar { diff --git a/gcc/testsuite/rust/compile/name_resolution8.rs b/gcc/testsuite/rust/compile/name_resolution8.rs index 6fb517033824..aca19459fd5b 100644 --- a/gcc/testsuite/rust/compile/name_resolution8.rs +++ b/gcc/testsuite/rust/compile/name_resolution8.rs @@ -1,5 +1,3 @@ -// { dg-options "-frust-name-resolution-2.0" } - // check that macros by example get exported to the crate's root with #[macro_export] pub mod foo { pub mod bar { diff --git a/gcc/testsuite/rust/compile/name_resolution9.rs b/gcc/testsuite/rust/compile/name_resolution9.rs index 792b3bdd6b5c..84ba3c5c7258 100644 --- a/gcc/testsuite/rust/compile/name_resolution9.rs +++ b/gcc/testsuite/rust/compile/name_resolution9.rs @@ -1,5 +1,3 @@ -// { dg-options "-frust-name-resolution-2.0" } - pub mod foo { pub mod bar { fn f() { diff --git a/gcc/testsuite/rust/compile/nested_macro_definition.rs b/gcc/testsuite/rust/compile/nested_macro_definition.rs index c0b72506accd..b71afbd7166e 100644 --- a/gcc/testsuite/rust/compile/nested_macro_definition.rs +++ b/gcc/testsuite/rust/compile/nested_macro_definition.rs @@ -1,5 +1,3 @@ -// { dg-options "-frust-name-resolution-2.0" } - macro_rules! toto { () => { macro_rules! tata { diff --git a/gcc/testsuite/rust/compile/nr2/compile.exp b/gcc/testsuite/rust/compile/nr2/compile.exp deleted file mode 100644 index 9e15cdd7253a..000000000000 --- a/gcc/testsuite/rust/compile/nr2/compile.exp +++ /dev/null @@ -1,149 +0,0 @@ -# Copyright (C) 2021-2024 Free Software Foundation, Inc. - -# This program 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 of the License, or -# (at your option) any later version. -# -# This program 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 -# . - -# Run compile tests with name resolution 2.0 enabled - -# Load support procs. -load_lib rust-dg.exp - -# These tests don't run runtest_file_p consistently if it -# doesn't return the same values, so disable parallelization -# of this *.exp file. The first parallel runtest to reach -# this will run all the tests serially. -if ![gcc_parallel_test_run_p compile] { - return -} -gcc_parallel_test_enable 0 - -# Initialize `dg'. -dg-init - -namespace eval rust-nr2-ns { - # Exclude tests which aren't passing yet - # These should be removed from the exclude file over time - - set exclude_fh [open $srcdir/$subdir/exclude r] - set exclude_raw [lsort [split [read $exclude_fh] "\n"]] - close $exclude_fh - unset exclude_fh - - set exclude "" - foreach ent $exclude_raw { - if [regexp {^[^#].*} $ent] { - lappend exclude $ent - } - } - unset exclude_raw - - # Run tests in directories - # Manually specifying these, in case some other test file - # does something weird - set test_dirs {{} {macros builtin} {macros mbe} {macros proc} {torture}} - - set tests_expect_ok "" - set tests_expect_err "" - - set compile_dir [list {*}[file split $srcdir] {*}[file split $subdir]] - set compile_dir [lreplace $compile_dir end end] - - foreach test_dir $test_dirs { - foreach test [lsort [glob -nocomplain -tails -directory [file join {*}$compile_dir {*}$test_dir] *.rs]] { - # use '/' as the path seperator for entries in the exclude file - set test_lbl [join [list {*}$test_dir $test] "/"] - set idx [lsearch -exact -sorted $exclude $test_lbl] - if {$idx == -1} { - if {[runtest_file_p $runtests [file join {*}$compile_dir {*}$test_dir $test]]} { - lappend tests_expect_ok [list {*}$test_dir $test] - } - } else { - if {[runtest_file_p $runtests [file join {*}$compile_dir {*}$test_dir $test]]} { - lappend tests_expect_err [list {*}$test_dir $test] - } - set exclude [lreplace $exclude $idx $idx] - } - } - } - - # Generate failures for unmatched tests in the exclude list - foreach ent $exclude { - fail "$ent: could not exclude test" - } - unset exclude - - # run a test while catching record_test calls - set record_test_out "" - proc try_test { test } { - variable record_test_out - rename ::record_test record_test_old - - proc ::record_test { type msg args } { - namespace eval ::rust-nr2-ns { - set type [uplevel 1 {set type}] - set msg [uplevel 1 {set msg}] - variable record_test_out - switch $type { - FAIL { - lappend record_test_out [list $type $msg] - } - XPASS { - lappend record_test_out [list $type $msg] - } - } - } - } - - namespace eval :: { - set saved-dg-do-what-default ${dg-do-what-default} - set dg-do-what-default "compile" - dg-runtest [list [uplevel 1 {set test}]] "-frust-name-resolution-2.0" "" - set dg-do-what-default ${saved-dg-do-what-default} - } - - rename ::record_test "" - rename record_test_old ::record_test - - set record_test_cache $record_test_out - set record_test_out "" - return $record_test_cache - } - - # check for unexpected failures - foreach test $tests_expect_ok { - set fails [try_test [file join {*}$compile_dir {*}$test]] - if {[llength $fails] != 0} { - foreach ent $fails { - record_test [lindex $ent 0] "on nr2: [lindex $ent 1]" - } - } else { - record_test PASS "[file join {*}$test] on nr2" - } - } - - #check for unexpected successes - foreach test $tests_expect_err { - set fails [try_test [file join {*}$compile_dir {*}$test]] - if {[llength $fails] == 0} { - record_test XPASS "[file join {*}$test] on nr2" - } else { - record_test XFAIL "[file join {*}$test] on nr2 was rightfully excluded" - } - } -} - -# All done. -dg-finish - -gcc_parallel_test_enable 1 diff --git a/gcc/testsuite/rust/compile/nr2/exclude b/gcc/testsuite/rust/compile/nr2/exclude deleted file mode 100644 index c020e36fba4a..000000000000 --- a/gcc/testsuite/rust/compile/nr2/exclude +++ /dev/null @@ -1,17 +0,0 @@ -canonical_paths1.rs -issue-3315-2.rs -privacy5.rs -privacy8.rs -pub_restricted_1.rs -pub_restricted_2.rs -pub_restricted_3.rs -issue-2905-2.rs -derive-default1.rs -derive-eq-invalid.rs -torture/alt_patterns1.rs -torture/name_resolve1.rs -issue-3663.rs -issue-3671.rs -issue-3652.rs -issue-3649.rs -# please don't delete the trailing newline diff --git a/gcc/testsuite/rust/compile/parse_simple_path_fail_1.rs b/gcc/testsuite/rust/compile/parse_simple_path_fail_1.rs new file mode 100644 index 000000000000..c112e4048ed0 --- /dev/null +++ b/gcc/testsuite/rust/compile/parse_simple_path_fail_1.rs @@ -0,0 +1,3 @@ +pub(in crate::) struct S; +// { dg-error "expecting ... but .::. found" "" { target *-*-* } .-1 } +// { dg-error "failed to parse item in crate" "" { target *-*-* } .-2 } diff --git a/gcc/testsuite/rust/compile/parse_simple_path_fail_2.rs b/gcc/testsuite/rust/compile/parse_simple_path_fail_2.rs new file mode 100644 index 000000000000..94c49c381b25 --- /dev/null +++ b/gcc/testsuite/rust/compile/parse_simple_path_fail_2.rs @@ -0,0 +1,9 @@ +mod A { + struct B; +} + +use A{B}; +// { dg-error "unexpected token" "" { target *-*-* } .-1 } +// { dg-error "could not parse use tree" "" { target *-*-* } .-2 } +// { dg-error "failed to parse item in crate" "" { target *-*-* } 10 } +// ^^^ TODO: should the above error happen at line 10? diff --git a/gcc/testsuite/rust/compile/pub_restricted_1.rs b/gcc/testsuite/rust/compile/pub_restricted_1.rs index 9bda96824032..2afbeb419359 100644 --- a/gcc/testsuite/rust/compile/pub_restricted_1.rs +++ b/gcc/testsuite/rust/compile/pub_restricted_1.rs @@ -6,8 +6,8 @@ pub mod foo { } } -pub(in foo::fah::baz) struct A1; // { dg-error "cannot find simple path segment .fah." } -pub(in fro::bulator::saindoux) struct A2; // { dg-error "cannot find simple path segment .fro." } -pub(in foo::bar::saindoux) struct A3; // { dg-error "cannot find simple path segment .saindoux." } +pub(in foo::fah::baz) struct A1; // { dg-error "could not resolve path .foo::fah::baz." } +pub(in fro::bulator::saindoux) struct A2; // { dg-error "could not resolve path .fro::bulator::saindoux." } +pub(in foo::bar::saindoux) struct A3; // { dg-error "could not resolve path .foo::bar::saindoux." } fn main() {} diff --git a/gcc/testsuite/rust/compile/pub_restricted_2.rs b/gcc/testsuite/rust/compile/pub_restricted_2.rs index 8588f2775cac..fea9379bf42a 100644 --- a/gcc/testsuite/rust/compile/pub_restricted_2.rs +++ b/gcc/testsuite/rust/compile/pub_restricted_2.rs @@ -3,16 +3,16 @@ mod foo { mod bar { mod baz { - pub(in baz) struct A0; - pub(in bar::baz) struct A1; + pub(in super::baz) struct A0; + pub(in super::super::bar::baz) struct A1; pub(in foo::bar::baz) struct A2; mod sain { mod doux {} } - pub(in sain) struct A3; // { dg-error "restricted path is not an ancestor of the current module" } - pub(in sain::doux) struct A4; // { dg-error "restricted path is not an ancestor of the current module" } + pub(in self::sain) struct A3; // { dg-error "restricted path is not an ancestor of the current module" } + pub(in self::sain::doux) struct A4; // { dg-error "restricted path is not an ancestor of the current module" } } } } diff --git a/gcc/testsuite/rust/execute/same_field_name.rs b/gcc/testsuite/rust/compile/same_field_name.rs similarity index 76% rename from gcc/testsuite/rust/execute/same_field_name.rs rename to gcc/testsuite/rust/compile/same_field_name.rs index d57562b39a64..8e5b78c74365 100644 --- a/gcc/testsuite/rust/execute/same_field_name.rs +++ b/gcc/testsuite/rust/compile/same_field_name.rs @@ -1,7 +1,7 @@ // https://doc.rust-lang.org/error_codes/E0124.html fn main() { struct Foo { - field1: i32, // { dg-error "field .field1. is already declared" } + field1: i32, field1: i32, // { dg-error "field .field1. is already declared" } field1: i32, // { dg-error "field .field1. is already declared" } } diff --git a/gcc/testsuite/rust/compile/self-in-impl.rs b/gcc/testsuite/rust/compile/self-in-impl.rs new file mode 100644 index 000000000000..a56789753e22 --- /dev/null +++ b/gcc/testsuite/rust/compile/self-in-impl.rs @@ -0,0 +1,15 @@ +// the error message here is what rustc >=1.66 emits +// rustc <1.66 emits a "cycle detected" error when +// trying to calculate the impl type +// +// since we aren't trying to match error messages too closely +// and the >=1.66 error message is nicer +// we may as well mimic that + +impl ((Self, i32)) {} +// { dg-error ".Self. is not valid in the self" "" { target *-*-* } .-1 } + +trait Foo {} + +impl Foo for ((Self, i32)) {} +// { dg-error ".Self. is not valid in the self" "" { target *-*-* } .-1 } diff --git a/gcc/testsuite/rust/compile/self_import_namespace.rs b/gcc/testsuite/rust/compile/self_import_namespace.rs index 2d9b2ed8e0fc..a63c1d715a8d 100644 --- a/gcc/testsuite/rust/compile/self_import_namespace.rs +++ b/gcc/testsuite/rust/compile/self_import_namespace.rs @@ -1,5 +1,3 @@ -// { dg-additional-options "-frust-name-resolution-2.0" } - mod bar { pub mod foo {} pub fn foo() {} diff --git a/gcc/testsuite/rust/compile/silly-order-bug.rs b/gcc/testsuite/rust/compile/silly-order-bug.rs new file mode 100644 index 000000000000..0d9cf1d8a884 --- /dev/null +++ b/gcc/testsuite/rust/compile/silly-order-bug.rs @@ -0,0 +1,8 @@ +#[lang = "sized"] +trait Sized {} + +#[lang = "fn_once"] +pub trait FnOnce { + extern "rust-call" fn call_once(self, args: Args) -> Self::Output; + type Output; +} diff --git a/gcc/testsuite/rust/compile/slicepattern-size-mismatch.rs b/gcc/testsuite/rust/compile/slicepattern-size-mismatch.rs new file mode 100644 index 000000000000..b54b53206044 --- /dev/null +++ b/gcc/testsuite/rust/compile/slicepattern-size-mismatch.rs @@ -0,0 +1,8 @@ +fn main() { + let arr = [0, 1]; + + match arr { + [0, 1, 2] => {} // { dg-error "pattern requires 3 elements but array has 2 .E0527." } + _ => {} + } +} \ No newline at end of file diff --git a/gcc/testsuite/rust/compile/torture/extern_mod2.rs b/gcc/testsuite/rust/compile/torture/extern_mod2.rs index 4984d5dc2c14..f3a4f799c3ee 100644 --- a/gcc/testsuite/rust/compile/torture/extern_mod2.rs +++ b/gcc/testsuite/rust/compile/torture/extern_mod2.rs @@ -12,6 +12,12 @@ mod no_leading_equal; #[path = "modules/valid_path.rs"] mod extra_spaces; +#[path = ""] // { dg-error "path attributes must contain a filename" } +mod empty_path; // { dg-error "no candidate found" } + +#[path = " "] // { dg-error "path attributes must contain a filename" } +mod path_with_spaces; // { dg-error "no candidate found" } + #[path] // { dg-error "path attributes must contain a filename" } mod error; // { dg-error "no candidate found" } diff --git a/gcc/testsuite/rust/compile/torture/unended-raw-byte-string.rs b/gcc/testsuite/rust/compile/torture/unended-raw-byte-string.rs new file mode 100644 index 000000000000..91a3c9a2ff8e --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/unended-raw-byte-string.rs @@ -0,0 +1,6 @@ +// { dg-excess-errors "...." } +fn main() { + // { dg-error "unended raw byte string literal" "" { target *-*-* } .+1 } + let s = br##"123"# +} + diff --git a/gcc/testsuite/rust/compile/traits9.rs b/gcc/testsuite/rust/compile/traits9.rs index bb3034d0f21c..f4308e8ccc17 100644 --- a/gcc/testsuite/rust/compile/traits9.rs +++ b/gcc/testsuite/rust/compile/traits9.rs @@ -11,6 +11,5 @@ fn main() { a = Foo(123); let b: &dyn Bar = &a; - // { dg-error "bounds not satisfied for Foo .Bar. is not satisfied" "" { target *-*-* } .-1 } - // { dg-error "expected" "" { target *-*-* } .-2 } + // { dg-error "bounds not satisfied for Foo .Bar. is not satisfied .E0277." "" { target *-*-* } .-1 } } diff --git a/gcc/testsuite/rust/compile/tuple_mismatch.rs b/gcc/testsuite/rust/compile/tuple_mismatch.rs index 828586b0f09d..1ff358be60a1 100644 --- a/gcc/testsuite/rust/compile/tuple_mismatch.rs +++ b/gcc/testsuite/rust/compile/tuple_mismatch.rs @@ -3,6 +3,7 @@ fn main() { let (_,) = (1, 2); // { dg-error "expected a tuple with 2 elements, found one with 1 element" } let (_, _) = (1, 2, 3); // { dg-error "expected a tuple with 3 elements, found one with 2 elements" } let (_, _) = (1,); // { dg-error "expected a tuple with 1 element, found one with 2 elements" } + let (_, .., _) = (1,); // { dg-error "expected a tuple with 1 element, found one with 2 elements" } } // The lhs and rhs sizes don't match, but we still resolve 'a' to be bool, we don't diff --git a/gcc/testsuite/rust/compile/unify-errors1.rs b/gcc/testsuite/rust/compile/unify-errors1.rs new file mode 100644 index 000000000000..0fe95efd0d7f --- /dev/null +++ b/gcc/testsuite/rust/compile/unify-errors1.rs @@ -0,0 +1,49 @@ +#[lang = "sized"] +trait Sized {} + +#[lang = "copy"] +trait Copy {} + +trait MyTrait {} + +struct Wrapper { + value: T, +} + +struct NotImpl; + +trait A {} +trait B {} + +struct Wrapper2 { + value: T, +} + +struct NotImpl2; + +impl A for NotImpl2 {} + +fn takes_tuple(x: (i32, bool)) {} + +fn requires_copy(value: T) {} + +pub fn test() { + takes_tuple((1, 2)); + // { dg-error "mismatched types, expected .bool. but got .. .E0308." "" { target *-*-* } .-1 } + + takes_tuple((1, 2, 3)); + // { dg-error "mismatched types, expected ..i32, bool.. but got .., , .. .E0308." "" { target *-*-* } .-1 } + + takes_tuple("hello"); + // { dg-error "mismatched types, expected ..i32, bool.. but got .& str. .E0308." "" { target *-*-* } .-1 } + + let x = &mut 5; + requires_copy(x); + // { dg-error "bounds not satisfied for &mut .Copy. is not satisfied .E0277." "" { target *-*-* } .-1 } + + let _x = Wrapper { value: NotImpl }; + // { dg-error "bounds not satisfied for NotImpl .MyTrait. is not satisfied .E0277." "" { target *-*-* } .-1 } + + let _x = Wrapper2 { value: NotImpl2 }; + // { dg-error "bounds not satisfied for NotImpl2 .B. is not satisfied .E0277." "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/use_1.rs b/gcc/testsuite/rust/compile/use_1.rs index e8e2037aac3f..21ee3e17a25e 100644 --- a/gcc/testsuite/rust/compile/use_1.rs +++ b/gcc/testsuite/rust/compile/use_1.rs @@ -1,4 +1,3 @@ -// { dg-additional-options "-frust-name-resolution-2.0" } mod frob {} use foo::bar::baz; // { dg-error "unresolved import .foo::bar::baz." } diff --git a/gcc/testsuite/rust/compile/usize1.rs b/gcc/testsuite/rust/compile/usize1.rs index 36cb99b5574a..08f6c9cf5cb4 100644 --- a/gcc/testsuite/rust/compile/usize1.rs +++ b/gcc/testsuite/rust/compile/usize1.rs @@ -1,5 +1,5 @@ fn main() { let a = [1, 2, 3]; let b: u32 = 1; - let c = a[b]; // { dg-error "the type ...integer..CAPACITY.. cannot be indexed by .u32." } + let c = a[b]; // { dg-error "the type ...integer.; 3.. cannot be indexed by .u32." } } diff --git a/gcc/testsuite/rust/compile/while_let_without_label.rs b/gcc/testsuite/rust/compile/while_let_without_label.rs new file mode 100644 index 000000000000..e04e4b59d1df --- /dev/null +++ b/gcc/testsuite/rust/compile/while_let_without_label.rs @@ -0,0 +1,11 @@ +// { dg-additional-options "-frust-compile-until=lowering" } + +enum Foo { + A(i32), +} + +fn main() { + let b = Foo::A(15); + + while let Foo::A(x) = b {} +} diff --git a/gcc/testsuite/rust/compile/xfail/name_resolution21.rs b/gcc/testsuite/rust/compile/xfail/name_resolution21.rs index df48d0015987..fc8e94b4b2c8 100644 --- a/gcc/testsuite/rust/compile/xfail/name_resolution21.rs +++ b/gcc/testsuite/rust/compile/xfail/name_resolution21.rs @@ -1,5 +1,3 @@ -// { dg-additional-options "-frust-name-resolution-2.0" } - pub mod foo { pub macro bar() {} } diff --git a/gcc/testsuite/rust/execute/black_box.rs b/gcc/testsuite/rust/execute/black_box.rs index 7a9920eba947..58d10a3e4209 100644 --- a/gcc/testsuite/rust/execute/black_box.rs +++ b/gcc/testsuite/rust/execute/black_box.rs @@ -21,10 +21,11 @@ pub fn black_box(mut dummy: T) -> T { dummy } -fn main() { +fn main() -> i32 { let dummy: i32 = 42; let result = black_box(dummy); unsafe { printf("Value is: %i\n\0" as *const str as *const i8, result); } + 0 } diff --git a/gcc/testsuite/rust/execute/execute.exp b/gcc/testsuite/rust/execute/execute.exp new file mode 100644 index 000000000000..3754778bd4cd --- /dev/null +++ b/gcc/testsuite/rust/execute/execute.exp @@ -0,0 +1,33 @@ +# Copyright (C) 2021-2025 Free Software Foundation, Inc. + +# This program 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 of the License, or +# (at your option) any later version. +# +# This program 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 +# . + +# Execute tests. + +# Load support procs. +load_lib rust-dg.exp + +# Initialize `dg'. +dg-init + +# Main loop. +set saved-dg-do-what-default ${dg-do-what-default} + +set dg-do-what-default "run" +dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.rs]] "" "" +set dg-do-what-default ${saved-dg-do-what-default} + +# All done. +dg-finish diff --git a/gcc/testsuite/rust/execute/torture/basic_partial_ord1.rs b/gcc/testsuite/rust/execute/torture/basic_partial_ord1.rs new file mode 100644 index 000000000000..0431629e9ea6 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/basic_partial_ord1.rs @@ -0,0 +1,189 @@ +/* { dg-output "less\r*" }*/ +mod core { + mod option { + pub enum Option { + None, + Some(T), + } + } + + mod marker { + #[lang = "phantom_data"] + pub struct PhantomData; + + #[lang = "structural_peq"] + pub trait StructuralPartialEq {} + + #[lang = "structural_teq"] + pub trait StructuralEq {} + + #[lang = "sized"] + pub trait Sized {} + } + + mod cmp { + use super::marker::Sized; + use super::option::Option; + + pub enum Ordering { + Less = -1, + Equal = 0, + Greater = 1, + } + + #[lang = "eq"] + pub trait PartialEq { + fn eq(&self, other: &Rhs) -> bool; + + fn ne(&self, other: &Rhs) -> bool { + !self.eq(other) + } + } + + pub trait Eq: PartialEq { + fn assert_receiver_is_total_eq(&self) {} + } + + #[lang = "partial_ord"] + pub trait PartialOrd: PartialEq { + fn partial_cmp(&self, other: &Rhs) -> Option; + + fn lt(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Less) => true, + _ => false, + } + } + + fn le(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Less) | Option::Some(Ordering::Equal) => true, + _ => false, + } + } + + fn gt(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Greater) => true, + _ => false, + } + } + + fn ge(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Greater) | Option::Some(Ordering::Equal) => true, + _ => false, + } + } + } + + pub trait Ord: Eq + PartialOrd { + fn cmp(&self, other: &Self) -> Ordering; + } + } +} + +use core::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd}; +use core::option::Option; + +// Needed impls for primitives +impl PartialEq for i32 { + fn eq(&self, other: &Self) -> bool { + *self == *other + } +} + +impl PartialOrd for i32 { + fn partial_cmp(&self, other: &Self) -> Option { + if *self < *other { + Option::Some(Ordering::Less) + } else if *self > *other { + Option::Some(Ordering::Greater) + } else { + Option::Some(Ordering::Equal) + } + } + + fn lt(&self, other: &Self) -> bool { + *self < *other + } + fn le(&self, other: &Self) -> bool { + *self <= *other + } + fn ge(&self, other: &Self) -> bool { + *self >= *other + } + fn gt(&self, other: &Self) -> bool { + *self > *other + } +} + +impl Eq for i32 {} +impl Ord for i32 { + fn cmp(&self, other: &Self) -> Ordering { + if *self < *other { + Ordering::Less + } else if *self > *other { + Ordering::Greater + } else { + Ordering::Equal + } + } +} + +// Manual impl for struct Bar +struct Bar { + a: i32, + b: i32, +} + +impl PartialEq for Bar { + fn eq(&self, other: &Self) -> bool { + self.a.eq(&other.a) && self.b.eq(&other.b) + } +} + +impl Eq for Bar {} + +impl PartialOrd for Bar { + fn partial_cmp(&self, other: &Self) -> Option { + match self.a.partial_cmp(&other.a) { + Option::Some(Ordering::Equal) => self.b.partial_cmp(&other.b), + ord => ord, + } + } +} + +impl Ord for Bar { + fn cmp(&self, other: &Self) -> Ordering { + match self.a.cmp(&other.a) { + Ordering::Equal => self.b.cmp(&other.b), + ord => ord, + } + } +} + +// External print shim +extern "C" { + fn puts(s: *const i8); +} + +fn print(s: &str) { + unsafe { + puts(s as *const str as *const i8); + } +} + +fn main() -> i32 { + let x = Bar { a: 1, b: 2 }; + let y = Bar { a: 1, b: 3 }; + + match x.partial_cmp(&y) { + Option::Some(Ordering::Less) => print("less"), + Option::Some(Ordering::Greater) => print("greater"), + Option::Some(Ordering::Equal) => print("equal"), + _ => print("none"), + } + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/basic_partial_ord2.rs b/gcc/testsuite/rust/execute/torture/basic_partial_ord2.rs new file mode 100644 index 000000000000..b6a96953d4a9 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/basic_partial_ord2.rs @@ -0,0 +1,197 @@ +/* { dg-output "<><=>=\r*" } */ +/* { dg-options "-w" } */ +mod core { + mod option { + pub enum Option { + None, + Some(T), + } + } + + mod marker { + #[lang = "phantom_data"] + pub struct PhantomData; + + #[lang = "structural_peq"] + pub trait StructuralPartialEq {} + + #[lang = "structural_teq"] + pub trait StructuralEq {} + + #[lang = "sized"] + pub trait Sized {} + } + + mod cmp { + use super::marker::Sized; + use super::option::Option; + + pub enum Ordering { + Less = -1, + Equal = 0, + Greater = 1, + } + + #[lang = "eq"] + pub trait PartialEq { + fn eq(&self, other: &Rhs) -> bool; + + fn ne(&self, other: &Rhs) -> bool { + !self.eq(other) + } + } + + pub trait Eq: PartialEq { + fn assert_receiver_is_total_eq(&self) {} + } + + #[lang = "partial_ord"] + pub trait PartialOrd: PartialEq { + fn partial_cmp(&self, other: &Rhs) -> Option; + + fn lt(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Less) => true, + _ => false, + } + } + + fn le(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Less) | Option::Some(Ordering::Equal) => true, + _ => false, + } + } + + fn gt(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Greater) => true, + _ => false, + } + } + + fn ge(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Greater) | Option::Some(Ordering::Equal) => true, + _ => false, + } + } + } + + pub trait Ord: Eq + PartialOrd { + fn cmp(&self, other: &Self) -> Ordering; + } + } +} + +use core::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd}; +use core::option::Option; + +// Needed impls for primitives +impl PartialEq for i32 { + fn eq(&self, other: &Self) -> bool { + *self == *other + } +} + +impl PartialOrd for i32 { + fn partial_cmp(&self, other: &Self) -> Option { + if *self < *other { + Option::Some(Ordering::Less) + } else if *self > *other { + Option::Some(Ordering::Greater) + } else { + Option::Some(Ordering::Equal) + } + } + + fn lt(&self, other: &Self) -> bool { + *self < *other + } + fn le(&self, other: &Self) -> bool { + *self <= *other + } + fn ge(&self, other: &Self) -> bool { + *self >= *other + } + fn gt(&self, other: &Self) -> bool { + *self > *other + } +} + +impl Eq for i32 {} +impl Ord for i32 { + fn cmp(&self, other: &Self) -> Ordering { + if *self < *other { + Ordering::Less + } else if *self > *other { + Ordering::Greater + } else { + Ordering::Equal + } + } +} + +// Manual impl for struct Bar +struct Bar { + a: i32, + b: i32, +} + +impl PartialEq for Bar { + fn eq(&self, other: &Self) -> bool { + self.a.eq(&other.a) && self.b.eq(&other.b) + } +} + +impl Eq for Bar {} + +impl PartialOrd for Bar { + fn partial_cmp(&self, other: &Self) -> Option { + match self.a.partial_cmp(&other.a) { + Option::Some(Ordering::Equal) => self.b.partial_cmp(&other.b), + ord => ord, + } + } +} + +impl Ord for Bar { + fn cmp(&self, other: &Self) -> Ordering { + match self.a.cmp(&other.a) { + Ordering::Equal => self.b.cmp(&other.b), + ord => ord, + } + } +} + +// External print shim +extern "C" { + fn printf(s: *const i8); +} + +fn print(s: &str) { + unsafe { + printf(s as *const str as *const i8); + } +} + +fn main() -> i32 { + let a = Bar { a: 1, b: 2 }; + let b = Bar { a: 1, b: 3 }; + let c = Bar { a: 1, b: 2 }; + + if a < b { + print("<"); + } + if b > a { + print(">"); + } + if a <= c { + print("<="); + } + if b >= c { + print(">="); + } + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/builtin_abort.rs b/gcc/testsuite/rust/execute/torture/builtin_abort.rs index 9f2d8c2d9f38..8c8259adcb7c 100644 --- a/gcc/testsuite/rust/execute/torture/builtin_abort.rs +++ b/gcc/testsuite/rust/execute/torture/builtin_abort.rs @@ -9,6 +9,6 @@ mod intrinsics { } pub fn main () -> i32 { - abort(); + intrinsics::abort(); 0 } diff --git a/gcc/testsuite/rust/execute/torture/const_block1.rs b/gcc/testsuite/rust/execute/torture/const_block1.rs new file mode 100644 index 000000000000..eaf343249d13 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/const_block1.rs @@ -0,0 +1,9 @@ +const X: i32 = const { + let a = 15; + let b = 14; + a + b +}; + +fn main() -> i32 { + X - 29 +} diff --git a/gcc/testsuite/rust/execute/torture/derive-partialeq2.rs b/gcc/testsuite/rust/execute/torture/derive-partialeq2.rs new file mode 100644 index 000000000000..e316017753a2 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/derive-partialeq2.rs @@ -0,0 +1,80 @@ +// { dg-output "true\r*\nfalse\r*\nfalse\r*\nfalse\r*\nfalse\r*\n" } + +#![feature(intrinsics)] + +pub mod core { + pub mod intrinsics { + #[lang = "discriminant_kind"] + pub trait DiscriminantKind { + #[lang = "discriminant_type"] + type Discriminant; + } + + extern "rust-intrinsic" { + pub fn discriminant_value(v: &T) -> ::Discriminant; + } + } +} + +#[lang = "sized"] +trait Sized {} + +#[lang = "copy"] +trait Copy {} + +#[lang = "structural_peq"] +trait StructuralPartialEq {} + +#[lang = "eq"] +pub trait PartialEq { + /// This method tests for `self` and `other` values to be equal, and is used + /// by `==`. + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn eq(&self, other: &Rhs) -> bool; + + /// This method tests for `!=`. + #[inline] + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn ne(&self, other: &Rhs) -> bool { + !self.eq(other) + } +} + +#[derive(PartialEq)] +enum Foo { + A { a: i32, b: i32 }, + B(i32, i32), + C, +} + +extern "C" { + fn puts(s: *const i8); +} + +fn print(b: bool) { + if b { + unsafe { puts("true\0" as *const str as *const i8) } + } else { + unsafe { puts("false\0" as *const str as *const i8) } + } +} + +fn main() -> i32 { + let x = Foo::A { a: 15, b: 14 }; + + let b1 = x == Foo::A { a: 15, b: 14 }; + let b12 = x == Foo::A { a: 15, b: 19 }; + let b13 = x == Foo::A { a: 19, b: 14 }; + let b2 = x == Foo::B(15, 14); + let b3 = x == Foo::C; + + print(b1); + print(b12); + print(b13); + print(b2); + print(b3); + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/for-loop1.rs b/gcc/testsuite/rust/execute/torture/for-loop1.rs index 5a6a70c37d64..334218927b13 100644 --- a/gcc/testsuite/rust/execute/torture/for-loop1.rs +++ b/gcc/testsuite/rust/execute/torture/for-loop1.rs @@ -102,30 +102,30 @@ mod ptr { #[lang = "const_ptr"] impl *const T { pub unsafe fn offset(self, count: isize) -> *const T { - intrinsics::offset(self, count) + crate::intrinsics::offset(self, count) } } #[lang = "mut_ptr"] impl *mut T { pub unsafe fn offset(self, count: isize) -> *mut T { - intrinsics::offset(self, count) as *mut T + crate::intrinsics::offset(self, count) as *mut T } } pub unsafe fn swap_nonoverlapping(x: *mut T, y: *mut T, count: usize) { let x = x as *mut u8; let y = y as *mut u8; - let len = mem::size_of::() * count; + let len = crate::mem::size_of::() * count; swap_nonoverlapping_bytes(x, y, len) } pub unsafe fn swap_nonoverlapping_one(x: *mut T, y: *mut T) { // For types smaller than the block optimization below, // just swap directly to avoid pessimizing codegen. - if mem::size_of::() < 32 { + if crate::mem::size_of::() < 32 { let z = read(x); - intrinsics::copy_nonoverlapping(y, x, 1); + crate::intrinsics::copy_nonoverlapping(y, x, 1); write(y, z); } else { swap_nonoverlapping(x, y, 1); @@ -133,12 +133,12 @@ mod ptr { } pub unsafe fn write(dst: *mut T, src: T) { - intrinsics::move_val_init(&mut *dst, src) + crate::intrinsics::move_val_init(&mut *dst, src) } pub unsafe fn read(src: *const T) -> T { - let mut tmp: T = mem::uninitialized(); - intrinsics::copy_nonoverlapping(src, &mut tmp, 1); + let mut tmp: T = crate::mem::uninitialized(); + crate::intrinsics::copy_nonoverlapping(src, &mut tmp, 1); tmp } @@ -146,7 +146,7 @@ mod ptr { struct Block(u64, u64, u64, u64); struct UnalignedBlock(u64, u64, u64, u64); - let block_size = mem::size_of::(); + let block_size = crate::mem::size_of::(); // Loop through x & y, copying them `Block` at a time // The optimizer should unroll the loop fully for most types @@ -155,31 +155,31 @@ mod ptr { while i + block_size <= len { // Create some uninitialized memory as scratch space // Declaring `t` here avoids aligning the stack when this loop is unused - let mut t: Block = mem::uninitialized(); + let mut t: Block = crate::mem::uninitialized(); let t = &mut t as *mut _ as *mut u8; let x = x.offset(i as isize); let y = y.offset(i as isize); // Swap a block of bytes of x & y, using t as a temporary buffer // This should be optimized into efficient SIMD operations where available - intrinsics::copy_nonoverlapping(x, t, block_size); - intrinsics::copy_nonoverlapping(y, x, block_size); - intrinsics::copy_nonoverlapping(t, y, block_size); + crate::intrinsics::copy_nonoverlapping(x, t, block_size); + crate::intrinsics::copy_nonoverlapping(y, x, block_size); + crate::intrinsics::copy_nonoverlapping(t, y, block_size); i += block_size; } if i < len { // Swap any remaining bytes - let mut t: UnalignedBlock = mem::uninitialized(); + let mut t: UnalignedBlock = crate::mem::uninitialized(); let rem = len - i; let t = &mut t as *mut _ as *mut u8; let x = x.offset(i as isize); let y = y.offset(i as isize); - intrinsics::copy_nonoverlapping(x, t, rem); - intrinsics::copy_nonoverlapping(y, x, rem); - intrinsics::copy_nonoverlapping(t, y, rem); + crate::intrinsics::copy_nonoverlapping(x, t, rem); + crate::intrinsics::copy_nonoverlapping(y, x, rem); + crate::intrinsics::copy_nonoverlapping(t, y, rem); } } } @@ -194,7 +194,7 @@ mod mem { pub fn swap(x: &mut T, y: &mut T) { unsafe { - ptr::swap_nonoverlapping_one(x, y); + crate::ptr::swap_nonoverlapping_one(x, y); } } @@ -204,7 +204,7 @@ mod mem { } pub unsafe fn uninitialized() -> T { - intrinsics::uninit() + crate::intrinsics::uninit() } } diff --git a/gcc/testsuite/rust/execute/torture/for-loop2.rs b/gcc/testsuite/rust/execute/torture/for-loop2.rs index 5ba2cd1351a6..4f5dfe1a0a26 100644 --- a/gcc/testsuite/rust/execute/torture/for-loop2.rs +++ b/gcc/testsuite/rust/execute/torture/for-loop2.rs @@ -101,30 +101,30 @@ mod ptr { #[lang = "const_ptr"] impl *const T { pub unsafe fn offset(self, count: isize) -> *const T { - intrinsics::offset(self, count) + crate::intrinsics::offset(self, count) } } #[lang = "mut_ptr"] impl *mut T { pub unsafe fn offset(self, count: isize) -> *mut T { - intrinsics::offset(self, count) as *mut T + crate::intrinsics::offset(self, count) as *mut T } } pub unsafe fn swap_nonoverlapping(x: *mut T, y: *mut T, count: usize) { let x = x as *mut u8; let y = y as *mut u8; - let len = mem::size_of::() * count; + let len = crate::mem::size_of::() * count; swap_nonoverlapping_bytes(x, y, len) } pub unsafe fn swap_nonoverlapping_one(x: *mut T, y: *mut T) { // For types smaller than the block optimization below, // just swap directly to avoid pessimizing codegen. - if mem::size_of::() < 32 { + if crate::mem::size_of::() < 32 { let z = read(x); - intrinsics::copy_nonoverlapping(y, x, 1); + crate::intrinsics::copy_nonoverlapping(y, x, 1); write(y, z); } else { swap_nonoverlapping(x, y, 1); @@ -132,12 +132,12 @@ mod ptr { } pub unsafe fn write(dst: *mut T, src: T) { - intrinsics::move_val_init(&mut *dst, src) + crate::intrinsics::move_val_init(&mut *dst, src) } pub unsafe fn read(src: *const T) -> T { - let mut tmp: T = mem::uninitialized(); - intrinsics::copy_nonoverlapping(src, &mut tmp, 1); + let mut tmp: T = crate::mem::uninitialized(); + crate::intrinsics::copy_nonoverlapping(src, &mut tmp, 1); tmp } @@ -145,7 +145,7 @@ mod ptr { struct Block(u64, u64, u64, u64); struct UnalignedBlock(u64, u64, u64, u64); - let block_size = mem::size_of::(); + let block_size = crate::mem::size_of::(); // Loop through x & y, copying them `Block` at a time // The optimizer should unroll the loop fully for most types @@ -154,31 +154,31 @@ mod ptr { while i + block_size <= len { // Create some uninitialized memory as scratch space // Declaring `t` here avoids aligning the stack when this loop is unused - let mut t: Block = mem::uninitialized(); + let mut t: Block = crate::mem::uninitialized(); let t = &mut t as *mut _ as *mut u8; let x = x.offset(i as isize); let y = y.offset(i as isize); // Swap a block of bytes of x & y, using t as a temporary buffer // This should be optimized into efficient SIMD operations where available - intrinsics::copy_nonoverlapping(x, t, block_size); - intrinsics::copy_nonoverlapping(y, x, block_size); - intrinsics::copy_nonoverlapping(t, y, block_size); + crate::intrinsics::copy_nonoverlapping(x, t, block_size); + crate::intrinsics::copy_nonoverlapping(y, x, block_size); + crate::intrinsics::copy_nonoverlapping(t, y, block_size); i += block_size; } if i < len { // Swap any remaining bytes - let mut t: UnalignedBlock = mem::uninitialized(); + let mut t: UnalignedBlock = crate::mem::uninitialized(); let rem = len - i; let t = &mut t as *mut _ as *mut u8; let x = x.offset(i as isize); let y = y.offset(i as isize); - intrinsics::copy_nonoverlapping(x, t, rem); - intrinsics::copy_nonoverlapping(y, x, rem); - intrinsics::copy_nonoverlapping(t, y, rem); + crate::intrinsics::copy_nonoverlapping(x, t, rem); + crate::intrinsics::copy_nonoverlapping(y, x, rem); + crate::intrinsics::copy_nonoverlapping(t, y, rem); } } } @@ -193,7 +193,7 @@ mod mem { pub fn swap(x: &mut T, y: &mut T) { unsafe { - ptr::swap_nonoverlapping_one(x, y); + crate::ptr::swap_nonoverlapping_one(x, y); } } @@ -203,7 +203,7 @@ mod mem { } pub unsafe fn uninitialized() -> T { - intrinsics::uninit() + crate::intrinsics::uninit() } } diff --git a/gcc/testsuite/rust/execute/torture/impl_desugar-2.rs b/gcc/testsuite/rust/execute/torture/impl_desugar-2.rs new file mode 100644 index 000000000000..c73ea34c6dab --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/impl_desugar-2.rs @@ -0,0 +1,32 @@ +#[lang = "sized"] +trait Sized {} + +macro_rules! impl_foo { + () => { impl Foo } +} + +pub trait Foo {} + +pub trait Bar { + type Baz; +} + +struct MyBaz; // { dg-warning "struct is never constructed" } +impl Foo for MyBaz {} + +struct MyBar; + +impl Bar for MyBar { + type Baz = MyBaz; +} + +pub fn foo(_value: impl Bar) -> i32 { + 15 +} + +fn main() -> i32 { + let bar = MyBar; + let result: i32 = foo(bar); + + result - 15 +} diff --git a/gcc/testsuite/rust/execute/torture/impl_desugar.rs b/gcc/testsuite/rust/execute/torture/impl_desugar.rs new file mode 100644 index 000000000000..22d39519f305 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/impl_desugar.rs @@ -0,0 +1,32 @@ +#[lang = "sized"] +trait Sized {} + +pub trait Foo {} + +pub trait Bar { + type Baz; +} + +struct MyBaz; // { dg-warning "struct is never constructed" } +impl Foo for MyBaz {} + +struct MyBar; + +impl Bar for MyBar { + type Baz = MyBaz; +} + +pub fn foo(_value: T) -> i32 +where + T: Bar, + U: Foo, +{ + 15 +} + +fn main() -> i32 { + let bar = MyBar; + let result: i32 = foo::(bar); + + result - 15 +} diff --git a/gcc/testsuite/rust/execute/torture/impl_rpit1.rs b/gcc/testsuite/rust/execute/torture/impl_rpit1.rs new file mode 100644 index 000000000000..8ce5f21ef87e --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/impl_rpit1.rs @@ -0,0 +1,28 @@ +#[lang = "sized"] +trait Sized {} + +trait Foo { + fn id(&self) -> i32; +} + +struct Thing(i32); + +impl Foo for Thing { + fn id(&self) -> i32 { + self.0 + } +} + +fn make_thing(a: i32) -> impl Foo { + Thing(a) +} + +fn use_foo(f: impl Foo) -> i32 { + f.id() +} + +fn main() -> i32 { + let value = make_thing(42); + let val = use_foo(value); + val - 42 +} diff --git a/gcc/testsuite/rust/execute/torture/impl_rpit2.rs b/gcc/testsuite/rust/execute/torture/impl_rpit2.rs new file mode 100644 index 000000000000..f7cbbb668649 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/impl_rpit2.rs @@ -0,0 +1,36 @@ +#[lang = "sized"] +trait Sized {} + +trait Foo { + fn id(&self) -> i32; +} + +struct Thing(i32); + +impl Thing { + fn double(&self) -> i32 { + // { dg-warning "associated function is never used: .double." "" { target *-*-* } .-1 } + self.0 * 2 + } +} + +impl Foo for Thing { + fn id(&self) -> i32 { + self.0 + } +} + +fn make_thing(a: i32) -> impl Foo { + Thing(a) +} + +fn use_foo(f: impl Foo) -> i32 { + f.id() +} + +fn main() -> i32 { + let value = make_thing(21); + let id = use_foo(value); + + id - 21 +} diff --git a/gcc/testsuite/rust/execute/torture/impl_rpit3.rs b/gcc/testsuite/rust/execute/torture/impl_rpit3.rs new file mode 100644 index 000000000000..dd68eb29ef96 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/impl_rpit3.rs @@ -0,0 +1,25 @@ +#[lang = "sized"] +trait Sized {} + +trait Foo { + fn id(&self) -> i32; +} + +struct Thing(i32); + +impl Foo for Thing { + fn id(&self) -> i32 { + self.0 + } +} + +fn make_thing() -> impl Foo { + Thing(99) +} + +fn main() -> i32 { + let v = make_thing(); + let r = &v; + let val = r.id(); + val - 99 +} diff --git a/gcc/testsuite/rust/execute/torture/impl_trait1.rs b/gcc/testsuite/rust/execute/torture/impl_trait1.rs new file mode 100644 index 000000000000..33a5c8cf1dbb --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/impl_trait1.rs @@ -0,0 +1,31 @@ +#[lang = "sized"] +trait Sized {} + +pub trait Value { + fn get(&self) -> i32; +} + +struct Foo(i32); +struct Bar(i32); + +impl Value for Foo { + fn get(&self) -> i32 { + self.0 + } +} +impl Value for Bar { + fn get(&self) -> i32 { + self.0 + } +} + +pub fn foo(a: impl Value, b: impl Value) -> i32 { + a.get() + b.get() +} + +fn main() -> i32 { + let a = Foo(1); + let b = Bar(2); + + foo(a, b) - 3 +} diff --git a/gcc/testsuite/rust/execute/torture/impl_trait2.rs b/gcc/testsuite/rust/execute/torture/impl_trait2.rs new file mode 100644 index 000000000000..29f393d679d2 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/impl_trait2.rs @@ -0,0 +1,31 @@ +#[lang = "sized"] +trait Sized {} + +pub trait Value { + fn get(&self) -> i32; +} + +struct Foo(i32); +struct Bar(i32); + +impl Value for Foo { + fn get(&self) -> i32 { + self.0 + } +} +impl Value for Bar { + fn get(&self) -> i32 { + self.0 + } +} + +pub fn foo(a: &impl Value, b: &impl Value) -> i32 { + a.get() + b.get() +} + +fn main() -> i32 { + let a = Foo(1); + let b = Bar(2); + + foo(&a, &b) - 3 +} diff --git a/gcc/testsuite/rust/execute/torture/impl_trait3.rs b/gcc/testsuite/rust/execute/torture/impl_trait3.rs new file mode 100644 index 000000000000..97e2972aeb22 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/impl_trait3.rs @@ -0,0 +1,46 @@ +/* { dg-output "Hello from Message\r*\n" } */ +#[lang = "sized"] +pub trait Sized {} + +extern "C" { + fn printf(s: *const i8, ...); +} + +trait Speak { + fn speak(&self) -> &'static str; +} + +trait Printer { + fn print(&self, input: impl Speak); +} + +struct Console; + +impl Printer for Console { + fn print(&self, input: impl Speak) { + // { dg-warning "unused name .self." "" { target *-*-* } .-1 } + unsafe { + let a = input.speak(); + let b = a as *const str; + let c = b as *const i8; + + printf(c); + } + } +} + +struct Message(&'static str); + +impl Speak for Message { + fn speak(&self) -> &'static str { + self.0 + } +} + +fn main() -> i32 { + let c = Console; + let msg = Message("Hello from Message\n"); + c.print(msg); + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/impl_trait4.rs b/gcc/testsuite/rust/execute/torture/impl_trait4.rs new file mode 100644 index 000000000000..67d00957e3d6 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/impl_trait4.rs @@ -0,0 +1,31 @@ +#[lang = "sized"] +trait Sized {} + +trait Foo { + fn id(&self) -> i32; +} + +struct A(i32); +struct B(i32); + +impl Foo for A { + fn id(&self) -> i32 { + self.0 + } +} + +impl Foo for B { + fn id(&self) -> i32 { + self.0 + } +} + +fn takes_tuple(pair: (impl Foo, impl Foo)) -> i32 { + pair.0.id() + pair.1.id() +} + +fn main() -> i32 { + let a = A(1); + let b = B(2); + takes_tuple((a, b)) - 3 +} diff --git a/gcc/testsuite/rust/execute/torture/issue-1481.rs b/gcc/testsuite/rust/execute/torture/issue-1481.rs new file mode 100644 index 000000000000..2ff78d9b6055 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/issue-1481.rs @@ -0,0 +1,35 @@ +/* { dg-output "called Foo::print\\(\\)\r*" } */ +/* { dg-options "-w" } */ + +#[lang = "sized"] +trait Sized {} + +trait Printable { + fn print(&self); +} + +struct Foo; + +impl Printable for Foo { + fn print(&self) { + // Simulate output + unsafe { + puts("called Foo::print()\0" as *const _ as *const i8); + } + } +} + +fn get_printable() -> impl Printable { + Foo +} + +extern "C" { + fn puts(s: *const i8); +} + +fn main() -> i32 { + let p = get_printable(); + p.print(); + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/issue-1482.rs b/gcc/testsuite/rust/execute/torture/issue-1482.rs new file mode 100644 index 000000000000..ed8dc8146103 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/issue-1482.rs @@ -0,0 +1,23 @@ +#[lang = "sized"] +trait Sized {} + +#[lang = "fn_once"] +pub trait FnOnce { + #[lang = "fn_once_output"] + type Output; + + extern "rust-call" fn call_once(self, args: Args) -> Self::Output; +} + +fn takes_fn(a: i32, f: impl FnOnce(i32) -> i32) -> i32 { + f(a) +} + +pub fn main() -> i32 { + let capture = 2; + let a = |i: i32| { + let b = i + capture; + b + }; + takes_fn(1, a) - 3 +} diff --git a/gcc/testsuite/rust/execute/torture/issue-2005.rs b/gcc/testsuite/rust/execute/torture/issue-2005.rs new file mode 100644 index 000000000000..87edb95988dc --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/issue-2005.rs @@ -0,0 +1,465 @@ +// { dg-additional-options "-w" } +/* { dg-output "WORKS\r?\n" } */ +#![feature(intrinsics)] + +mod core { + mod option { + // #[rustc_diagnostic_item = "option_type"] + #[stable(feature = "rust1", since = "1.0.0")] + pub enum Option { + /// No value + #[lang = "None"] + #[stable(feature = "rust1", since = "1.0.0")] + None, + /// Some value `T` + #[lang = "Some"] + #[stable(feature = "rust1", since = "1.0.0")] + Some(#[stable(feature = "rust1", since = "1.0.0")] T), + } + } + + mod marker { + #[lang = "phantom_data"] + #[stable(feature = "rust1", since = "1.0.0")] + pub struct PhantomData; + + #[unstable(feature = "structural_match", issue = "31434")] + // #[rustc_on_unimplemented(message = "the type `{Self}` does not `#[derive(PartialEq)]`")] + #[lang = "structural_peq"] + pub trait StructuralPartialEq { + // Empty. + } + + #[unstable(feature = "structural_match", issue = "31434")] + // #[rustc_on_unimplemented(message = "the type `{Self}` does not `#[derive(Eq)]`")] + #[lang = "structural_teq"] + pub trait StructuralEq { + // Empty. + } + + #[stable(feature = "rust1", since = "1.0.0")] + #[lang = "sized"] + // #[rustc_on_unimplemented( + // message = "the size for values of type `{Self}` cannot be known at compilation time", + // label = "doesn't have a size known at compile-time" + // )] + // #[fundamental] // for Default, for example, which requires that `[T]: !Default` be evaluatable + // #[rustc_specialization_trait] + pub trait Sized { + // Empty. + } + } + + mod cmp { + use super::marker::Sized; + use super::option::Option; + + // #[derive(Clone, Copy, PartialEq, Debug, Hash)] + #[stable(feature = "rust1", since = "1.0.0")] + pub enum Ordering { + /// An ordering where a compared value is less than another. + #[stable(feature = "rust1", since = "1.0.0")] + Less = -1, + /// An ordering where a compared value is equal to another. + #[stable(feature = "rust1", since = "1.0.0")] + Equal = 0, + /// An ordering where a compared value is greater than another. + #[stable(feature = "rust1", since = "1.0.0")] + Greater = 1, + } + + #[lang = "eq"] + #[stable(feature = "rust1", since = "1.0.0")] + #[doc(alias = "==")] + #[doc(alias = "!=")] + // #[rustc_on_unimplemented( + // message = "can't compare `{Self}` with `{Rhs}`", + // label = "no implementation for `{Self} == {Rhs}`" + // )] + pub trait PartialEq { + /// This method tests for `self` and `other` values to be equal, and is used + /// by `==`. + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn eq(&self, other: &Rhs) -> bool; + + fn ne(&self, other: &Rhs) -> bool { + !self.eq(other) + } + } + + #[doc(alias = "==")] + #[doc(alias = "!=")] + #[stable(feature = "rust1", since = "1.0.0")] + pub trait Eq: PartialEq { + // this method is used solely by #[deriving] to assert + // that every component of a type implements #[deriving] + // itself, the current deriving infrastructure means doing this + // assertion without using a method on this trait is nearly + // impossible. + // + // This should never be implemented by hand. + #[doc(hidden)] + #[stable(feature = "rust1", since = "1.0.0")] + fn assert_receiver_is_total_eq(&self) {} + } + + #[lang = "partial_ord"] + #[stable(feature = "rust1", since = "1.0.0")] + #[doc(alias = ">")] + #[doc(alias = "<")] + #[doc(alias = "<=")] + #[doc(alias = ">=")] + // #[rustc_on_unimplemented( + // message = "can't compare `{Self}` with `{Rhs}`", + // label = "no implementation for `{Self} < {Rhs}` and `{Self} > {Rhs}`" + // )] + pub trait PartialOrd: PartialEq { + /// This method returns an ordering between `self` and `other` values if one exists. + /// + /// # Examples + /// + /// ``` + /// use std::cmp::Ordering; + /// + /// let result = 1.0.partial_cmp(&2.0); + /// assert_eq!(result, Some(Ordering::Less)); + /// + /// let result = 1.0.partial_cmp(&1.0); + /// assert_eq!(result, Some(Ordering::Equal)); + /// + /// let result = 2.0.partial_cmp(&1.0); + /// assert_eq!(result, Some(Ordering::Greater)); + /// ``` + /// + /// When comparison is impossible: + /// + /// ``` + /// let result = f64::NAN.partial_cmp(&1.0); + /// assert_eq!(result, None); + /// ``` + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn partial_cmp(&self, other: &Rhs) -> Option; + + /// This method tests less than (for `self` and `other`) and is used by the `<` operator. + /// + /// # Examples + /// + /// ``` + /// let result = 1.0 < 2.0; + /// assert_eq!(result, true); + /// + /// let result = 2.0 < 1.0; + /// assert_eq!(result, false); + /// ``` + #[inline] + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn lt(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Less) => true, + _ => false, + } + } + + /// This method tests less than or equal to (for `self` and `other`) and is used by the `<=` + /// operator. + /// + /// # Examples + /// + /// ``` + /// let result = 1.0 <= 2.0; + /// assert_eq!(result, true); + /// + /// let result = 2.0 <= 2.0; + /// assert_eq!(result, true); + /// ``` + #[inline] + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn le(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Less | Ordering::Equal) => true, + _ => false, + } + } + + /// This method tests greater than (for `self` and `other`) and is used by the `>` operator. + /// + /// # Examples + /// + /// ``` + /// let result = 1.0 > 2.0; + /// assert_eq!(result, false); + /// + /// let result = 2.0 > 2.0; + /// assert_eq!(result, false); + /// ``` + #[inline] + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn gt(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Greater) => true, + _ => false, + } + } + + /// This method tests greater than or equal to (for `self` and `other`) and is used by the `>=` + /// operator. + /// + /// # Examples + /// + /// ``` + /// let result = 2.0 >= 1.0; + /// assert_eq!(result, true); + /// + /// let result = 2.0 >= 2.0; + /// assert_eq!(result, true); + /// ``` + #[inline] + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn ge(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Greater | Ordering::Equal) => true, + _ => false, + } + } + } + + #[doc(alias = "<")] + #[doc(alias = ">")] + #[doc(alias = "<=")] + #[doc(alias = ">=")] + #[stable(feature = "rust1", since = "1.0.0")] + pub trait Ord: Eq + PartialOrd { + /// This method returns an [`Ordering`] between `self` and `other`. + /// + /// By convention, `self.cmp(&other)` returns the ordering matching the expression + /// `self other` if true. + /// + /// # Examples + /// + /// ``` + /// use std::cmp::Ordering; + /// + /// assert_eq!(5.cmp(&10), Ordering::Less); + /// assert_eq!(10.cmp(&5), Ordering::Greater); + /// assert_eq!(5.cmp(&5), Ordering::Equal); + /// ``` + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn cmp(&self, other: &Self) -> Ordering; + + /// Compares and returns the maximum of two values. + /// + /// Returns the second argument if the comparison determines them to be equal. + /// + /// # Examples + /// + /// ``` + /// assert_eq!(2, 1.max(2)); + /// assert_eq!(2, 2.max(2)); + /// ``` + #[stable(feature = "ord_max_min", since = "1.21.0")] + #[must_use] + fn max(self, other: Self) -> Self + where + Self: Sized, + { + self + } + + /// Compares and returns the minimum of two values. + /// + /// Returns the first argument if the comparison determines them to be equal. + /// + /// # Examples + /// + /// ``` + /// assert_eq!(1, 1.min(2)); + /// assert_eq!(2, 2.min(2)); + /// ``` + #[stable(feature = "ord_max_min", since = "1.21.0")] + #[must_use] + fn min(self, other: Self) -> Self + where + Self: Sized, + { + self + } + + /// Restrict a value to a certain interval. + /// + /// Returns `max` if `self` is greater than `max`, and `min` if `self` is + /// less than `min`. Otherwise this returns `self`. + /// + /// # Panics + /// + /// Panics if `min > max`. + /// + /// # Examples + /// + /// ``` + /// #![feature(clamp)] + /// + /// assert!((-3).clamp(-2, 1) == -2); + /// assert!(0.clamp(-2, 1) == 0); + /// assert!(2.clamp(-2, 1) == 1); + /// ``` + #[must_use] + #[unstable(feature = "clamp", issue = "44095")] + fn clamp(self, min: Self, max: Self) -> Self + where + Self: Sized, + { + if self < min { + min + } else if self > max { + max + } else { + self + } + } + } + } + + pub mod intrinsics { + #[lang = "discriminant_kind"] + pub trait DiscriminantKind { + #[lang = "discriminant_type"] + type Discriminant; + } + + extern "rust-intrinsic" { + pub fn discriminant_value(v: &T) -> ::Discriminant; + } + } +} + +use core::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd}; +use core::marker::Sized; +use core::option::Option; + +// -------------- + +impl PartialEq for isize { + fn eq(&self, other: &Self) -> bool { + *self == *other + } +} + +impl PartialOrd for isize { + fn partial_cmp(&self, other: &Self) -> Option { + if *self > *other { + Option::Some(Ordering::Greater) + } else if *self < *other { + Option::Some(Ordering::Less) + } else { + Option::Some(Ordering::Equal) + } + } + + fn lt(&self, other: &Self) -> bool { + *self < *other + } + fn le(&self, other: &Self) -> bool { + *self <= *other + } + fn ge(&self, other: &Self) -> bool { + *self >= *other + } + fn gt(&self, other: &Self) -> bool { + *self > *other + } +} + +impl Eq for isize {} + +impl Ord for isize { + fn cmp(&self, other: &Self) -> Ordering { + if *self > *other { + Ordering::Greater + } else if *self < *other { + Ordering::Less + } else { + Ordering::Equal + } + } +} + +// ---------------------------------- + +impl PartialEq for i32 { + fn eq(&self, other: &Self) -> bool { + *self == *other + } +} + +impl PartialOrd for i32 { + fn partial_cmp(&self, other: &Self) -> Option { + if *self > *other { + Option::Some(Ordering::Greater) + } else if *self < *other { + Option::Some(Ordering::Less) + } else { + Option::Some(Ordering::Equal) + } + } + + fn lt(&self, other: &Self) -> bool { + *self < *other + } + fn le(&self, other: &Self) -> bool { + *self <= *other + } + fn ge(&self, other: &Self) -> bool { + *self >= *other + } + fn gt(&self, other: &Self) -> bool { + *self > *other + } +} + +impl Ord for i32 { + fn cmp(&self, other: &Self) -> Ordering { + if *self > *other { + Ordering::Greater + } else if *self < *other { + Ordering::Less + } else { + Ordering::Equal + } + } +} + +impl Eq for i32 {} + +#[derive(Ord, PartialOrd, PartialEq, Eq)] +enum Foo { + A, + B(i32), +} + +extern "C" { + fn puts(s: *const i8); +} + +fn print(s: &str) { + unsafe { + puts(s as *const str as *const i8); + } +} + +fn main() -> i32 { + let a = Foo::A; + let b = Foo::B(15); + + if (a != b) { + print("WORKS"); + } + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/issue-3836.rs b/gcc/testsuite/rust/execute/torture/issue-3836.rs new file mode 100644 index 000000000000..61ad42492e74 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/issue-3836.rs @@ -0,0 +1,454 @@ +// { dg-options "-w" } +// { dg-output "less\r*\n" } + +#![feature(intrinsics)] + +mod core { + mod option { + // #[rustc_diagnostic_item = "option_type"] + #[stable(feature = "rust1", since = "1.0.0")] + pub enum Option { + /// No value + #[lang = "None"] + #[stable(feature = "rust1", since = "1.0.0")] + None, + /// Some value `T` + #[lang = "Some"] + #[stable(feature = "rust1", since = "1.0.0")] + Some(#[stable(feature = "rust1", since = "1.0.0")] T), + } + } + + mod marker { + #[lang = "phantom_data"] + #[stable(feature = "rust1", since = "1.0.0")] + pub struct PhantomData; + + #[unstable(feature = "structural_match", issue = "31434")] + // #[rustc_on_unimplemented(message = "the type `{Self}` does not `#[derive(PartialEq)]`")] + #[lang = "structural_peq"] + pub trait StructuralPartialEq { + // Empty. + } + + #[unstable(feature = "structural_match", issue = "31434")] + // #[rustc_on_unimplemented(message = "the type `{Self}` does not `#[derive(Eq)]`")] + #[lang = "structural_teq"] + pub trait StructuralEq { + // Empty. + } + + #[stable(feature = "rust1", since = "1.0.0")] + #[lang = "sized"] + // #[rustc_on_unimplemented( + // message = "the size for values of type `{Self}` cannot be known at compilation time", + // label = "doesn't have a size known at compile-time" + // )] + // #[fundamental] // for Default, for example, which requires that `[T]: !Default` be evaluatable + // #[rustc_specialization_trait] + pub trait Sized { + // Empty. + } + } + + mod cmp { + use super::marker::Sized; + use super::option::Option; + + // #[derive(Clone, Copy, PartialEq, Debug, Hash)] + #[stable(feature = "rust1", since = "1.0.0")] + pub enum Ordering { + /// An ordering where a compared value is less than another. + #[stable(feature = "rust1", since = "1.0.0")] + Less = -1, + /// An ordering where a compared value is equal to another. + #[stable(feature = "rust1", since = "1.0.0")] + Equal = 0, + /// An ordering where a compared value is greater than another. + #[stable(feature = "rust1", since = "1.0.0")] + Greater = 1, + } + + #[lang = "eq"] + #[stable(feature = "rust1", since = "1.0.0")] + #[doc(alias = "==")] + #[doc(alias = "!=")] + // #[rustc_on_unimplemented( + // message = "can't compare `{Self}` with `{Rhs}`", + // label = "no implementation for `{Self} == {Rhs}`" + // )] + pub trait PartialEq { + /// This method tests for `self` and `other` values to be equal, and is used + /// by `==`. + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn eq(&self, other: &Rhs) -> bool; + + fn ne(&self, other: &Rhs) -> bool { + !self.eq(other) + } + } + + #[doc(alias = "==")] + #[doc(alias = "!=")] + #[stable(feature = "rust1", since = "1.0.0")] + pub trait Eq: PartialEq { + // this method is used solely by #[deriving] to assert + // that every component of a type implements #[deriving] + // itself, the current deriving infrastructure means doing this + // assertion without using a method on this trait is nearly + // impossible. + // + // This should never be implemented by hand. + #[doc(hidden)] + #[stable(feature = "rust1", since = "1.0.0")] + fn assert_receiver_is_total_eq(&self) {} + } + + #[lang = "partial_ord"] + #[stable(feature = "rust1", since = "1.0.0")] + #[doc(alias = ">")] + #[doc(alias = "<")] + #[doc(alias = "<=")] + #[doc(alias = ">=")] + // #[rustc_on_unimplemented( + // message = "can't compare `{Self}` with `{Rhs}`", + // label = "no implementation for `{Self} < {Rhs}` and `{Self} > {Rhs}`" + // )] + pub trait PartialOrd: PartialEq { + /// This method returns an ordering between `self` and `other` values if one exists. + /// + /// # Examples + /// + /// ``` + /// use std::cmp::Ordering; + /// + /// let result = 1.0.partial_cmp(&2.0); + /// assert_eq!(result, Some(Ordering::Less)); + /// + /// let result = 1.0.partial_cmp(&1.0); + /// assert_eq!(result, Some(Ordering::Equal)); + /// + /// let result = 2.0.partial_cmp(&1.0); + /// assert_eq!(result, Some(Ordering::Greater)); + /// ``` + /// + /// When comparison is impossible: + /// + /// ``` + /// let result = f64::NAN.partial_cmp(&1.0); + /// assert_eq!(result, None); + /// ``` + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn partial_cmp(&self, other: &Rhs) -> Option; + + /// This method tests less than (for `self` and `other`) and is used by the `<` operator. + /// + /// # Examples + /// + /// ``` + /// let result = 1.0 < 2.0; + /// assert_eq!(result, true); + /// + /// let result = 2.0 < 1.0; + /// assert_eq!(result, false); + /// ``` + #[inline] + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn lt(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Less) => true, + _ => false, + } + } + + /// This method tests less than or equal to (for `self` and `other`) and is used by the `<=` + /// operator. + /// + /// # Examples + /// + /// ``` + /// let result = 1.0 <= 2.0; + /// assert_eq!(result, true); + /// + /// let result = 2.0 <= 2.0; + /// assert_eq!(result, true); + /// ``` + #[inline] + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn le(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Less | Ordering::Equal) => true, + _ => false, + } + } + + /// This method tests greater than (for `self` and `other`) and is used by the `>` operator. + /// + /// # Examples + /// + /// ``` + /// let result = 1.0 > 2.0; + /// assert_eq!(result, false); + /// + /// let result = 2.0 > 2.0; + /// assert_eq!(result, false); + /// ``` + #[inline] + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn gt(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Greater) => true, + _ => false, + } + } + + /// This method tests greater than or equal to (for `self` and `other`) and is used by the `>=` + /// operator. + /// + /// # Examples + /// + /// ``` + /// let result = 2.0 >= 1.0; + /// assert_eq!(result, true); + /// + /// let result = 2.0 >= 2.0; + /// assert_eq!(result, true); + /// ``` + #[inline] + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn ge(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Greater | Ordering::Equal) => true, + _ => false, + } + } + } + + #[doc(alias = "<")] + #[doc(alias = ">")] + #[doc(alias = "<=")] + #[doc(alias = ">=")] + #[stable(feature = "rust1", since = "1.0.0")] + pub trait Ord: Eq + PartialOrd { + /// This method returns an [`Ordering`] between `self` and `other`. + /// + /// By convention, `self.cmp(&other)` returns the ordering matching the expression + /// `self other` if true. + /// + /// # Examples + /// + /// ``` + /// use std::cmp::Ordering; + /// + /// assert_eq!(5.cmp(&10), Ordering::Less); + /// assert_eq!(10.cmp(&5), Ordering::Greater); + /// assert_eq!(5.cmp(&5), Ordering::Equal); + /// ``` + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn cmp(&self, other: &Self) -> Ordering; + + /// Compares and returns the maximum of two values. + /// + /// Returns the second argument if the comparison determines them to be equal. + /// + /// # Examples + /// + /// ``` + /// assert_eq!(2, 1.max(2)); + /// assert_eq!(2, 2.max(2)); + /// ``` + #[stable(feature = "ord_max_min", since = "1.21.0")] + #[must_use] + fn max(self, other: Self) -> Self + where + Self: Sized, + { + self + } + + /// Compares and returns the minimum of two values. + /// + /// Returns the first argument if the comparison determines them to be equal. + /// + /// # Examples + /// + /// ``` + /// assert_eq!(1, 1.min(2)); + /// assert_eq!(2, 2.min(2)); + /// ``` + #[stable(feature = "ord_max_min", since = "1.21.0")] + #[must_use] + fn min(self, other: Self) -> Self + where + Self: Sized, + { + self + } + + /// Restrict a value to a certain interval. + /// + /// Returns `max` if `self` is greater than `max`, and `min` if `self` is + /// less than `min`. Otherwise this returns `self`. + /// + /// # Panics + /// + /// Panics if `min > max`. + /// + /// # Examples + /// + /// ``` + /// #![feature(clamp)] + /// + /// assert!((-3).clamp(-2, 1) == -2); + /// assert!(0.clamp(-2, 1) == 0); + /// assert!(2.clamp(-2, 1) == 1); + /// ``` + #[must_use] + #[unstable(feature = "clamp", issue = "44095")] + fn clamp(self, min: Self, max: Self) -> Self + where + Self: Sized, + { + if self < min { + min + } else if self > max { + max + } else { + self + } + } + } + } + + pub mod intrinsics { + #[lang = "discriminant_kind"] + pub trait DiscriminantKind { + #[lang = "discriminant_type"] + type Discriminant; + } + + extern "rust-intrinsic" { + pub fn discriminant_value(v: &T) -> ::Discriminant; + } + } +} + +use core::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd}; +use core::marker::Sized; +use core::option::Option; + +// for comparing discriminant_value +impl PartialEq for isize { + fn eq(&self, other: &Self) -> bool { + *self == *other + } +} + +// for comparing discriminant_value +impl PartialOrd for isize { + fn partial_cmp(&self, other: &Self) -> Option { + if *self > *other { + Option::Some(Ordering::Greater) + } else if *self < *other { + Option::Some(Ordering::Less) + } else { + Option::Some(Ordering::Equal) + } + } + + fn lt(&self, other: &Self) -> bool { + *self < *other + } + fn le(&self, other: &Self) -> bool { + *self <= *other + } + fn ge(&self, other: &Self) -> bool { + *self >= *other + } + fn gt(&self, other: &Self) -> bool { + *self > *other + } +} + +impl PartialEq for i32 { + fn eq(&self, other: &Self) -> bool { + *self == *other + } +} +impl Eq for i32 {} + +impl PartialOrd for i32 { + fn partial_cmp(&self, other: &Self) -> Option { + if *self > *other { + Option::Some(Ordering::Greater) + } else if *self < *other { + Option::Some(Ordering::Less) + } else { + Option::Some(Ordering::Equal) + } + } + + fn lt(&self, other: &Self) -> bool { + *self < *other + } + fn le(&self, other: &Self) -> bool { + *self <= *other + } + fn ge(&self, other: &Self) -> bool { + *self >= *other + } + fn gt(&self, other: &Self) -> bool { + *self > *other + } +} + +impl Ord for i32 { + fn cmp(&self, other: &Self) -> Ordering { + if *self > *other { + Ordering::Greater + } else if *self < *other { + Ordering::Less + } else { + Ordering::Equal + } + } +} + +// ------------ + +#[derive(Ord, PartialOrd, PartialEq, Eq)] +struct Bar { + a: i32, + b: i32, +} + +extern "C" { + fn puts(s: *const i8); +} + +fn print(s: &str) { + unsafe { + puts(s as *const str as *const i8); + } +} + +fn main() -> i32 { + let x = Bar { a: 1, b: 2 }; + let y = Bar { a: 1, b: 3 }; + + match x.partial_cmp(&y) { + Option::Some(Ordering::Less) => print("less"), + Option::Some(Ordering::Greater) => print("greater"), + Option::Some(Ordering::Equal) => print("equal"), + _ => print("none"), + } + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/iter1.rs b/gcc/testsuite/rust/execute/torture/iter1.rs index c3b6c7bc3f89..233eb60383b3 100644 --- a/gcc/testsuite/rust/execute/torture/iter1.rs +++ b/gcc/testsuite/rust/execute/torture/iter1.rs @@ -99,30 +99,30 @@ mod ptr { #[lang = "const_ptr"] impl *const T { pub unsafe fn offset(self, count: isize) -> *const T { - intrinsics::offset(self, count) + crate::intrinsics::offset(self, count) } } #[lang = "mut_ptr"] impl *mut T { pub unsafe fn offset(self, count: isize) -> *mut T { - intrinsics::offset(self, count) as *mut T + crate::intrinsics::offset(self, count) as *mut T } } pub unsafe fn swap_nonoverlapping(x: *mut T, y: *mut T, count: usize) { let x = x as *mut u8; let y = y as *mut u8; - let len = mem::size_of::() * count; + let len = crate::mem::size_of::() * count; swap_nonoverlapping_bytes(x, y, len) } pub unsafe fn swap_nonoverlapping_one(x: *mut T, y: *mut T) { // For types smaller than the block optimization below, // just swap directly to avoid pessimizing codegen. - if mem::size_of::() < 32 { + if crate::mem::size_of::() < 32 { let z = read(x); - intrinsics::copy_nonoverlapping(y, x, 1); + crate::intrinsics::copy_nonoverlapping(y, x, 1); write(y, z); } else { swap_nonoverlapping(x, y, 1); @@ -130,12 +130,12 @@ mod ptr { } pub unsafe fn write(dst: *mut T, src: T) { - intrinsics::move_val_init(&mut *dst, src) + crate::intrinsics::move_val_init(&mut *dst, src) } pub unsafe fn read(src: *const T) -> T { - let mut tmp: T = mem::uninitialized(); - intrinsics::copy_nonoverlapping(src, &mut tmp, 1); + let mut tmp: T = crate::mem::uninitialized(); + crate::intrinsics::copy_nonoverlapping(src, &mut tmp, 1); tmp } @@ -143,7 +143,7 @@ mod ptr { struct Block(u64, u64, u64, u64); struct UnalignedBlock(u64, u64, u64, u64); - let block_size = mem::size_of::(); + let block_size = crate::mem::size_of::(); // Loop through x & y, copying them `Block` at a time // The optimizer should unroll the loop fully for most types @@ -152,31 +152,31 @@ mod ptr { while i + block_size <= len { // Create some uninitialized memory as scratch space // Declaring `t` here avoids aligning the stack when this loop is unused - let mut t: Block = mem::uninitialized(); + let mut t: Block = crate::mem::uninitialized(); let t = &mut t as *mut _ as *mut u8; let x = x.offset(i as isize); let y = y.offset(i as isize); // Swap a block of bytes of x & y, using t as a temporary buffer // This should be optimized into efficient SIMD operations where available - intrinsics::copy_nonoverlapping(x, t, block_size); - intrinsics::copy_nonoverlapping(y, x, block_size); - intrinsics::copy_nonoverlapping(t, y, block_size); + crate::intrinsics::copy_nonoverlapping(x, t, block_size); + crate::intrinsics::copy_nonoverlapping(y, x, block_size); + crate::intrinsics::copy_nonoverlapping(t, y, block_size); i += block_size; } if i < len { // Swap any remaining bytes - let mut t: UnalignedBlock = mem::uninitialized(); + let mut t: UnalignedBlock = crate::mem::uninitialized(); let rem = len - i; let t = &mut t as *mut _ as *mut u8; let x = x.offset(i as isize); let y = y.offset(i as isize); - intrinsics::copy_nonoverlapping(x, t, rem); - intrinsics::copy_nonoverlapping(y, x, rem); - intrinsics::copy_nonoverlapping(t, y, rem); + crate::intrinsics::copy_nonoverlapping(x, t, rem); + crate::intrinsics::copy_nonoverlapping(y, x, rem); + crate::intrinsics::copy_nonoverlapping(t, y, rem); } } } @@ -191,7 +191,7 @@ mod mem { pub fn swap(x: &mut T, y: &mut T) { unsafe { - ptr::swap_nonoverlapping_one(x, y); + crate::ptr::swap_nonoverlapping_one(x, y); } } @@ -201,7 +201,7 @@ mod mem { } pub unsafe fn uninitialized() -> T { - intrinsics::uninit() + crate::intrinsics::uninit() } } diff --git a/gcc/testsuite/rust/execute/torture/match-identifierpattern.rs b/gcc/testsuite/rust/execute/torture/match-identifierpattern.rs new file mode 100644 index 000000000000..b102ad1ec417 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/match-identifierpattern.rs @@ -0,0 +1,10 @@ +fn main() -> i32 { + let mut x = 2; + + match x { + a @ 2 => { x = a + 1 }, + _ => {} + } + + x - 3 +} diff --git a/gcc/testsuite/rust/execute/torture/match-restpattern-tuple.rs b/gcc/testsuite/rust/execute/torture/match-restpattern-tuple.rs new file mode 100644 index 000000000000..2c1418c551d0 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/match-restpattern-tuple.rs @@ -0,0 +1,27 @@ +// { dg-output "correct\r*" } +extern "C" { + fn puts(s: *const i8); +} + +fn main() -> i32 { + let x = (1, 2, 3, 4); + let mut ret = 1; + + match x { + (1, .., 2, 4) => { + /* should not take this path */ + unsafe { puts("wrong\0" as *const str as *const i8) } + }, + (2, ..) => { + /* should not take this path */ + unsafe { puts("wrong\0" as *const str as *const i8) } + }, + (b, .., 4) => { + ret -= b; + unsafe { puts("correct\0" as *const str as *const i8) } + }, + _ => {} + } + + ret +} \ No newline at end of file diff --git a/gcc/testsuite/rust/execute/torture/match-slicepattern-array-1.rs b/gcc/testsuite/rust/execute/torture/match-slicepattern-array-1.rs new file mode 100644 index 000000000000..95c55d8f9d5e --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/match-slicepattern-array-1.rs @@ -0,0 +1,23 @@ +// { dg-output "correct\r*" } +extern "C" { + fn puts(s: *const i8); +} + +fn main() -> i32 { + let a = [0, 1]; + let mut ret = 1; + + match a { + [0, 0] => { + /* should not take this path */ + unsafe { puts("wrong\0" as *const str as *const i8) } + }, + [0, b] => { + ret -= b; + unsafe { puts("correct\0" as *const str as *const i8) } + }, + _ => {} + } + + ret +} diff --git a/gcc/testsuite/rust/execute/torture/match-tuplestructpattern.rs b/gcc/testsuite/rust/execute/torture/match-tuplestructpattern.rs new file mode 100644 index 000000000000..323109cd4963 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/match-tuplestructpattern.rs @@ -0,0 +1,12 @@ +fn main() -> i32 { + struct A (i32, i32); + let a = A (0, 1); + let mut ret = 1; + + match a { + A (0, b) => { ret -= b }, + _ => {} + } + + ret +} diff --git a/gcc/testsuite/rust/execute/torture/name_resolution.rs b/gcc/testsuite/rust/execute/torture/name_resolution.rs index 749218352d64..a2eaf4867239 100644 --- a/gcc/testsuite/rust/execute/torture/name_resolution.rs +++ b/gcc/testsuite/rust/execute/torture/name_resolution.rs @@ -1,4 +1,3 @@ -// { dg-additional-options "-frust-name-resolution-2.0" } // { dg-output "Value is 10\r*\n" } const BAZ: i32 = 10; diff --git a/gcc/testsuite/rust/execute/torture/partial-eq-1.rs b/gcc/testsuite/rust/execute/torture/partial-eq-1.rs new file mode 100644 index 000000000000..db123a1b5e7d --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/partial-eq-1.rs @@ -0,0 +1,103 @@ +/* { dg-output "a == b\r*\na != c\r*\n" }*/ +/* { dg-options "-w" } */ + +mod core { + mod marker { + #[lang = "phantom_data"] + #[stable(feature = "rust1", since = "1.0.0")] + pub struct PhantomData; + + #[unstable(feature = "structural_match", issue = "31434")] + #[lang = "structural_peq"] + pub trait StructuralPartialEq { + // Empty. + } + + #[unstable(feature = "structural_match", issue = "31434")] + #[lang = "structural_teq"] + pub trait StructuralEq { + // Empty. + } + + #[lang = "sized"] + pub trait Sized {} + } + + pub mod cmp { + use super::marker::Sized; + + #[lang = "eq"] + pub trait PartialEq { + fn eq(&self, other: &Rhs) -> bool; + + fn ne(&self, other: &Rhs) -> bool { + !self.eq(other) + } + } + + pub trait Eq: PartialEq { + fn assert_receiver_is_total_eq(&self) {} + } + } +} + +use core::cmp::{Eq, PartialEq}; + +// PartialEq for i32 and u32 so we can compare across types +impl PartialEq for i32 { + fn eq(&self, other: &u32) -> bool { + *self >= 0 && (*self as u32) == *other + } +} +impl PartialEq for u32 { + fn eq(&self, other: &i32) -> bool { + *other >= 0 && *self == *other as u32 + } +} + +// Our generic struct +struct Foo { + value: T, +} + +// Manual impl of PartialEq for different generic params +impl PartialEq> for Foo +where + T: PartialEq, +{ + fn eq(&self, other: &Foo) -> bool { + self.value.eq(&other.value) + } +} + +impl Eq for Foo {} + +extern "C" { + fn puts(s: *const i8); +} + +fn print(s: &str) { + unsafe { + puts(s as *const str as *const i8); + } +} + +fn main() -> i32 { + let a = Foo { value: 42i32 }; + let b = Foo { value: 42u32 }; + let c = Foo { value: 7u32 }; + + if a == b { + print("a == b"); + } else { + print("a != b"); + } + + if a == c { + print("a == c"); + } else { + print("a != c"); + } + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/partial-eq-2.rs b/gcc/testsuite/rust/execute/torture/partial-eq-2.rs new file mode 100644 index 000000000000..debed8c83f32 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/partial-eq-2.rs @@ -0,0 +1,60 @@ +/* { dg-output "a == b\r*\na != c\r*\n" }*/ +/* { dg-options "-w" } */ + +#[lang = "sized"] +pub trait Sized {} + +#[lang = "eq"] +pub trait PartialEq { + fn eq(&self, other: &Rhs) -> bool; + + fn ne(&self, other: &Rhs) -> bool { + !self.eq(other) + } +} + +impl PartialEq for i32 { + fn eq(&self, other: &Self) -> bool { + *self == *other + } +} + +struct Foo { + value: T, +} + +impl PartialEq for Foo { + fn eq(&self, other: &Self) -> bool { + self.value.eq(&other.value) + } +} + +extern "C" { + fn puts(s: *const i8); +} + +fn print(s: &str) { + unsafe { + puts(s as *const str as *const i8); + } +} + +fn main() -> i32 { + let a = Foo { value: 42i32 }; + let b = Foo { value: 42i32 }; + let c = Foo { value: 99i32 }; + + if a == b { + print("a == b"); + } else { + print("a != b"); + } + + if a == c { + print("a == c"); + } else { + print("a != c"); + } + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/partial-eq-3.rs b/gcc/testsuite/rust/execute/torture/partial-eq-3.rs new file mode 100644 index 000000000000..849910afc832 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/partial-eq-3.rs @@ -0,0 +1,457 @@ +/* { dg-output "a == b\r*\na != c\r*\n" }*/ +/* { dg-options "-w" } */ + +#![feature(intrinsics)] + +mod core { + mod option { + // #[rustc_diagnostic_item = "option_type"] + #[stable(feature = "rust1", since = "1.0.0")] + pub enum Option { + /// No value + #[lang = "None"] + #[stable(feature = "rust1", since = "1.0.0")] + None, + /// Some value `T` + #[lang = "Some"] + #[stable(feature = "rust1", since = "1.0.0")] + Some(#[stable(feature = "rust1", since = "1.0.0")] T), + } + } + + mod marker { + #[lang = "phantom_data"] + #[stable(feature = "rust1", since = "1.0.0")] + pub struct PhantomData; + + #[unstable(feature = "structural_match", issue = "31434")] + // #[rustc_on_unimplemented(message = "the type `{Self}` does not `#[derive(PartialEq)]`")] + #[lang = "structural_peq"] + pub trait StructuralPartialEq { + // Empty. + } + + #[unstable(feature = "structural_match", issue = "31434")] + // #[rustc_on_unimplemented(message = "the type `{Self}` does not `#[derive(Eq)]`")] + #[lang = "structural_teq"] + pub trait StructuralEq { + // Empty. + } + + #[stable(feature = "rust1", since = "1.0.0")] + #[lang = "sized"] + // #[rustc_on_unimplemented( + // message = "the size for values of type `{Self}` cannot be known at compilation time", + // label = "doesn't have a size known at compile-time" + // )] + // #[fundamental] // for Default, for example, which requires that `[T]: !Default` be evaluatable + // #[rustc_specialization_trait] + pub trait Sized { + // Empty. + } + } + + mod cmp { + use super::marker::Sized; + use super::option::Option; + + // #[derive(Clone, Copy, PartialEq, Debug, Hash)] + #[stable(feature = "rust1", since = "1.0.0")] + pub enum Ordering { + /// An ordering where a compared value is less than another. + #[stable(feature = "rust1", since = "1.0.0")] + Less = -1, + /// An ordering where a compared value is equal to another. + #[stable(feature = "rust1", since = "1.0.0")] + Equal = 0, + /// An ordering where a compared value is greater than another. + #[stable(feature = "rust1", since = "1.0.0")] + Greater = 1, + } + + #[lang = "eq"] + #[stable(feature = "rust1", since = "1.0.0")] + #[doc(alias = "==")] + #[doc(alias = "!=")] + // #[rustc_on_unimplemented( + // message = "can't compare `{Self}` with `{Rhs}`", + // label = "no implementation for `{Self} == {Rhs}`" + // )] + pub trait PartialEq { + /// This method tests for `self` and `other` values to be equal, and is used + /// by `==`. + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn eq(&self, other: &Rhs) -> bool; + + fn ne(&self, other: &Rhs) -> bool { + !self.eq(other) + } + } + + #[doc(alias = "==")] + #[doc(alias = "!=")] + #[stable(feature = "rust1", since = "1.0.0")] + pub trait Eq: PartialEq { + // this method is used solely by #[deriving] to assert + // that every component of a type implements #[deriving] + // itself, the current deriving infrastructure means doing this + // assertion without using a method on this trait is nearly + // impossible. + // + // This should never be implemented by hand. + #[doc(hidden)] + #[stable(feature = "rust1", since = "1.0.0")] + fn assert_receiver_is_total_eq(&self) {} + } + + #[lang = "partial_ord"] + #[stable(feature = "rust1", since = "1.0.0")] + #[doc(alias = ">")] + #[doc(alias = "<")] + #[doc(alias = "<=")] + #[doc(alias = ">=")] + // #[rustc_on_unimplemented( + // message = "can't compare `{Self}` with `{Rhs}`", + // label = "no implementation for `{Self} < {Rhs}` and `{Self} > {Rhs}`" + // )] + pub trait PartialOrd: PartialEq { + /// This method returns an ordering between `self` and `other` values if one exists. + /// + /// # Examples + /// + /// ``` + /// use std::cmp::Ordering; + /// + /// let result = 1.0.partial_cmp(&2.0); + /// assert_eq!(result, Some(Ordering::Less)); + /// + /// let result = 1.0.partial_cmp(&1.0); + /// assert_eq!(result, Some(Ordering::Equal)); + /// + /// let result = 2.0.partial_cmp(&1.0); + /// assert_eq!(result, Some(Ordering::Greater)); + /// ``` + /// + /// When comparison is impossible: + /// + /// ``` + /// let result = f64::NAN.partial_cmp(&1.0); + /// assert_eq!(result, None); + /// ``` + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn partial_cmp(&self, other: &Rhs) -> Option; + + /// This method tests less than (for `self` and `other`) and is used by the `<` operator. + /// + /// # Examples + /// + /// ``` + /// let result = 1.0 < 2.0; + /// assert_eq!(result, true); + /// + /// let result = 2.0 < 1.0; + /// assert_eq!(result, false); + /// ``` + #[inline] + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn lt(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Less) => true, + _ => false, + } + } + + /// This method tests less than or equal to (for `self` and `other`) and is used by the `<=` + /// operator. + /// + /// # Examples + /// + /// ``` + /// let result = 1.0 <= 2.0; + /// assert_eq!(result, true); + /// + /// let result = 2.0 <= 2.0; + /// assert_eq!(result, true); + /// ``` + #[inline] + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn le(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Less | Ordering::Equal) => true, + _ => false, + } + } + + /// This method tests greater than (for `self` and `other`) and is used by the `>` operator. + /// + /// # Examples + /// + /// ``` + /// let result = 1.0 > 2.0; + /// assert_eq!(result, false); + /// + /// let result = 2.0 > 2.0; + /// assert_eq!(result, false); + /// ``` + #[inline] + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn gt(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Greater) => true, + _ => false, + } + } + + /// This method tests greater than or equal to (for `self` and `other`) and is used by the `>=` + /// operator. + /// + /// # Examples + /// + /// ``` + /// let result = 2.0 >= 1.0; + /// assert_eq!(result, true); + /// + /// let result = 2.0 >= 2.0; + /// assert_eq!(result, true); + /// ``` + #[inline] + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn ge(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Greater | Ordering::Equal) => true, + _ => false, + } + } + } + + #[doc(alias = "<")] + #[doc(alias = ">")] + #[doc(alias = "<=")] + #[doc(alias = ">=")] + #[stable(feature = "rust1", since = "1.0.0")] + pub trait Ord: Eq + PartialOrd { + /// This method returns an [`Ordering`] between `self` and `other`. + /// + /// By convention, `self.cmp(&other)` returns the ordering matching the expression + /// `self other` if true. + /// + /// # Examples + /// + /// ``` + /// use std::cmp::Ordering; + /// + /// assert_eq!(5.cmp(&10), Ordering::Less); + /// assert_eq!(10.cmp(&5), Ordering::Greater); + /// assert_eq!(5.cmp(&5), Ordering::Equal); + /// ``` + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn cmp(&self, other: &Self) -> Ordering; + + /// Compares and returns the maximum of two values. + /// + /// Returns the second argument if the comparison determines them to be equal. + /// + /// # Examples + /// + /// ``` + /// assert_eq!(2, 1.max(2)); + /// assert_eq!(2, 2.max(2)); + /// ``` + #[stable(feature = "ord_max_min", since = "1.21.0")] + #[must_use] + fn max(self, other: Self) -> Self + where + Self: Sized, + { + self + } + + /// Compares and returns the minimum of two values. + /// + /// Returns the first argument if the comparison determines them to be equal. + /// + /// # Examples + /// + /// ``` + /// assert_eq!(1, 1.min(2)); + /// assert_eq!(2, 2.min(2)); + /// ``` + #[stable(feature = "ord_max_min", since = "1.21.0")] + #[must_use] + fn min(self, other: Self) -> Self + where + Self: Sized, + { + self + } + + /// Restrict a value to a certain interval. + /// + /// Returns `max` if `self` is greater than `max`, and `min` if `self` is + /// less than `min`. Otherwise this returns `self`. + /// + /// # Panics + /// + /// Panics if `min > max`. + /// + /// # Examples + /// + /// ``` + /// #![feature(clamp)] + /// + /// assert!((-3).clamp(-2, 1) == -2); + /// assert!(0.clamp(-2, 1) == 0); + /// assert!(2.clamp(-2, 1) == 1); + /// ``` + #[must_use] + #[unstable(feature = "clamp", issue = "44095")] + fn clamp(self, min: Self, max: Self) -> Self + where + Self: Sized, + { + if self < min { + min + } else if self > max { + max + } else { + self + } + } + } + } + + pub mod intrinsics { + #[lang = "discriminant_kind"] + pub trait DiscriminantKind { + #[lang = "discriminant_type"] + type Discriminant; + } + + extern "rust-intrinsic" { + pub fn discriminant_value(v: &T) -> ::Discriminant; + } + } +} + +use core::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd}; +use core::marker::Sized; +use core::option::Option; + +// for comparing discriminant_value +impl PartialEq for isize { + fn eq(&self, other: &Self) -> bool { + *self == *other + } +} + +// for comparing discriminant_value +impl PartialOrd for isize { + fn partial_cmp(&self, other: &Self) -> Option { + if *self > *other { + Option::Some(Ordering::Greater) + } else if *self < *other { + Option::Some(Ordering::Less) + } else { + Option::Some(Ordering::Equal) + } + } + + fn lt(&self, other: &Self) -> bool { + *self < *other + } + fn le(&self, other: &Self) -> bool { + *self <= *other + } + fn ge(&self, other: &Self) -> bool { + *self >= *other + } + fn gt(&self, other: &Self) -> bool { + *self > *other + } +} + +impl PartialEq for i32 { + fn eq(&self, other: &Self) -> bool { + *self == *other + } +} +impl Eq for i32 {} + +impl PartialOrd for i32 { + fn partial_cmp(&self, other: &Self) -> Option { + if *self > *other { + Option::Some(Ordering::Greater) + } else if *self < *other { + Option::Some(Ordering::Less) + } else { + Option::Some(Ordering::Equal) + } + } + + fn lt(&self, other: &Self) -> bool { + *self < *other + } + fn le(&self, other: &Self) -> bool { + *self <= *other + } + fn ge(&self, other: &Self) -> bool { + *self >= *other + } + fn gt(&self, other: &Self) -> bool { + *self > *other + } +} + +impl Ord for i32 { + fn cmp(&self, other: &Self) -> Ordering { + if *self > *other { + Ordering::Greater + } else if *self < *other { + Ordering::Less + } else { + Ordering::Equal + } + } +} + +#[derive(PartialEq)] +struct Foo { + a: i32, +} + +extern "C" { + fn puts(s: *const i8); +} + +fn print(s: &str) { + unsafe { + puts(s as *const str as *const i8); + } +} + +fn main() -> i32 { + let a = Foo { a: 42i32 }; + let b = Foo { a: 42i32 }; + let c = Foo { a: 7i32 }; + + if a == b { + print("a == b"); + } else { + print("a != b"); + } + + if a == c { + print("a == c"); + } else { + print("a != c"); + } + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/partial-eq-4.rs b/gcc/testsuite/rust/execute/torture/partial-eq-4.rs new file mode 100644 index 000000000000..b6997d8592fa --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/partial-eq-4.rs @@ -0,0 +1,457 @@ +/* { dg-output "a == b\r*\na != c\r*\n" }*/ +/* { dg-options "-w" } */ + +#![feature(intrinsics)] + +mod core { + mod option { + // #[rustc_diagnostic_item = "option_type"] + #[stable(feature = "rust1", since = "1.0.0")] + pub enum Option { + /// No value + #[lang = "None"] + #[stable(feature = "rust1", since = "1.0.0")] + None, + /// Some value `T` + #[lang = "Some"] + #[stable(feature = "rust1", since = "1.0.0")] + Some(#[stable(feature = "rust1", since = "1.0.0")] T), + } + } + + mod marker { + #[lang = "phantom_data"] + #[stable(feature = "rust1", since = "1.0.0")] + pub struct PhantomData; + + #[unstable(feature = "structural_match", issue = "31434")] + // #[rustc_on_unimplemented(message = "the type `{Self}` does not `#[derive(PartialEq)]`")] + #[lang = "structural_peq"] + pub trait StructuralPartialEq { + // Empty. + } + + #[unstable(feature = "structural_match", issue = "31434")] + // #[rustc_on_unimplemented(message = "the type `{Self}` does not `#[derive(Eq)]`")] + #[lang = "structural_teq"] + pub trait StructuralEq { + // Empty. + } + + #[stable(feature = "rust1", since = "1.0.0")] + #[lang = "sized"] + // #[rustc_on_unimplemented( + // message = "the size for values of type `{Self}` cannot be known at compilation time", + // label = "doesn't have a size known at compile-time" + // )] + // #[fundamental] // for Default, for example, which requires that `[T]: !Default` be evaluatable + // #[rustc_specialization_trait] + pub trait Sized { + // Empty. + } + } + + mod cmp { + use super::marker::Sized; + use super::option::Option; + + // #[derive(Clone, Copy, PartialEq, Debug, Hash)] + #[stable(feature = "rust1", since = "1.0.0")] + pub enum Ordering { + /// An ordering where a compared value is less than another. + #[stable(feature = "rust1", since = "1.0.0")] + Less = -1, + /// An ordering where a compared value is equal to another. + #[stable(feature = "rust1", since = "1.0.0")] + Equal = 0, + /// An ordering where a compared value is greater than another. + #[stable(feature = "rust1", since = "1.0.0")] + Greater = 1, + } + + #[lang = "eq"] + #[stable(feature = "rust1", since = "1.0.0")] + #[doc(alias = "==")] + #[doc(alias = "!=")] + // #[rustc_on_unimplemented( + // message = "can't compare `{Self}` with `{Rhs}`", + // label = "no implementation for `{Self} == {Rhs}`" + // )] + pub trait PartialEq { + /// This method tests for `self` and `other` values to be equal, and is used + /// by `==`. + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn eq(&self, other: &Rhs) -> bool; + + fn ne(&self, other: &Rhs) -> bool { + !self.eq(other) + } + } + + #[doc(alias = "==")] + #[doc(alias = "!=")] + #[stable(feature = "rust1", since = "1.0.0")] + pub trait Eq: PartialEq { + // this method is used solely by #[deriving] to assert + // that every component of a type implements #[deriving] + // itself, the current deriving infrastructure means doing this + // assertion without using a method on this trait is nearly + // impossible. + // + // This should never be implemented by hand. + #[doc(hidden)] + #[stable(feature = "rust1", since = "1.0.0")] + fn assert_receiver_is_total_eq(&self) {} + } + + #[lang = "partial_ord"] + #[stable(feature = "rust1", since = "1.0.0")] + #[doc(alias = ">")] + #[doc(alias = "<")] + #[doc(alias = "<=")] + #[doc(alias = ">=")] + // #[rustc_on_unimplemented( + // message = "can't compare `{Self}` with `{Rhs}`", + // label = "no implementation for `{Self} < {Rhs}` and `{Self} > {Rhs}`" + // )] + pub trait PartialOrd: PartialEq { + /// This method returns an ordering between `self` and `other` values if one exists. + /// + /// # Examples + /// + /// ``` + /// use std::cmp::Ordering; + /// + /// let result = 1.0.partial_cmp(&2.0); + /// assert_eq!(result, Some(Ordering::Less)); + /// + /// let result = 1.0.partial_cmp(&1.0); + /// assert_eq!(result, Some(Ordering::Equal)); + /// + /// let result = 2.0.partial_cmp(&1.0); + /// assert_eq!(result, Some(Ordering::Greater)); + /// ``` + /// + /// When comparison is impossible: + /// + /// ``` + /// let result = f64::NAN.partial_cmp(&1.0); + /// assert_eq!(result, None); + /// ``` + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn partial_cmp(&self, other: &Rhs) -> Option; + + /// This method tests less than (for `self` and `other`) and is used by the `<` operator. + /// + /// # Examples + /// + /// ``` + /// let result = 1.0 < 2.0; + /// assert_eq!(result, true); + /// + /// let result = 2.0 < 1.0; + /// assert_eq!(result, false); + /// ``` + #[inline] + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn lt(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Less) => true, + _ => false, + } + } + + /// This method tests less than or equal to (for `self` and `other`) and is used by the `<=` + /// operator. + /// + /// # Examples + /// + /// ``` + /// let result = 1.0 <= 2.0; + /// assert_eq!(result, true); + /// + /// let result = 2.0 <= 2.0; + /// assert_eq!(result, true); + /// ``` + #[inline] + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn le(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Less | Ordering::Equal) => true, + _ => false, + } + } + + /// This method tests greater than (for `self` and `other`) and is used by the `>` operator. + /// + /// # Examples + /// + /// ``` + /// let result = 1.0 > 2.0; + /// assert_eq!(result, false); + /// + /// let result = 2.0 > 2.0; + /// assert_eq!(result, false); + /// ``` + #[inline] + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn gt(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Greater) => true, + _ => false, + } + } + + /// This method tests greater than or equal to (for `self` and `other`) and is used by the `>=` + /// operator. + /// + /// # Examples + /// + /// ``` + /// let result = 2.0 >= 1.0; + /// assert_eq!(result, true); + /// + /// let result = 2.0 >= 2.0; + /// assert_eq!(result, true); + /// ``` + #[inline] + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn ge(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Greater | Ordering::Equal) => true, + _ => false, + } + } + } + + #[doc(alias = "<")] + #[doc(alias = ">")] + #[doc(alias = "<=")] + #[doc(alias = ">=")] + #[stable(feature = "rust1", since = "1.0.0")] + pub trait Ord: Eq + PartialOrd { + /// This method returns an [`Ordering`] between `self` and `other`. + /// + /// By convention, `self.cmp(&other)` returns the ordering matching the expression + /// `self other` if true. + /// + /// # Examples + /// + /// ``` + /// use std::cmp::Ordering; + /// + /// assert_eq!(5.cmp(&10), Ordering::Less); + /// assert_eq!(10.cmp(&5), Ordering::Greater); + /// assert_eq!(5.cmp(&5), Ordering::Equal); + /// ``` + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn cmp(&self, other: &Self) -> Ordering; + + /// Compares and returns the maximum of two values. + /// + /// Returns the second argument if the comparison determines them to be equal. + /// + /// # Examples + /// + /// ``` + /// assert_eq!(2, 1.max(2)); + /// assert_eq!(2, 2.max(2)); + /// ``` + #[stable(feature = "ord_max_min", since = "1.21.0")] + #[must_use] + fn max(self, other: Self) -> Self + where + Self: Sized, + { + self + } + + /// Compares and returns the minimum of two values. + /// + /// Returns the first argument if the comparison determines them to be equal. + /// + /// # Examples + /// + /// ``` + /// assert_eq!(1, 1.min(2)); + /// assert_eq!(2, 2.min(2)); + /// ``` + #[stable(feature = "ord_max_min", since = "1.21.0")] + #[must_use] + fn min(self, other: Self) -> Self + where + Self: Sized, + { + self + } + + /// Restrict a value to a certain interval. + /// + /// Returns `max` if `self` is greater than `max`, and `min` if `self` is + /// less than `min`. Otherwise this returns `self`. + /// + /// # Panics + /// + /// Panics if `min > max`. + /// + /// # Examples + /// + /// ``` + /// #![feature(clamp)] + /// + /// assert!((-3).clamp(-2, 1) == -2); + /// assert!(0.clamp(-2, 1) == 0); + /// assert!(2.clamp(-2, 1) == 1); + /// ``` + #[must_use] + #[unstable(feature = "clamp", issue = "44095")] + fn clamp(self, min: Self, max: Self) -> Self + where + Self: Sized, + { + if self < min { + min + } else if self > max { + max + } else { + self + } + } + } + } + + pub mod intrinsics { + #[lang = "discriminant_kind"] + pub trait DiscriminantKind { + #[lang = "discriminant_type"] + type Discriminant; + } + + extern "rust-intrinsic" { + pub fn discriminant_value(v: &T) -> ::Discriminant; + } + } +} + +use core::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd}; +use core::marker::Sized; +use core::option::Option; + +// for comparing discriminant_value +impl PartialEq for isize { + fn eq(&self, other: &Self) -> bool { + *self == *other + } +} + +// for comparing discriminant_value +impl PartialOrd for isize { + fn partial_cmp(&self, other: &Self) -> Option { + if *self > *other { + Option::Some(Ordering::Greater) + } else if *self < *other { + Option::Some(Ordering::Less) + } else { + Option::Some(Ordering::Equal) + } + } + + fn lt(&self, other: &Self) -> bool { + *self < *other + } + fn le(&self, other: &Self) -> bool { + *self <= *other + } + fn ge(&self, other: &Self) -> bool { + *self >= *other + } + fn gt(&self, other: &Self) -> bool { + *self > *other + } +} + +impl PartialEq for i32 { + fn eq(&self, other: &Self) -> bool { + *self == *other + } +} +impl Eq for i32 {} + +impl PartialOrd for i32 { + fn partial_cmp(&self, other: &Self) -> Option { + if *self > *other { + Option::Some(Ordering::Greater) + } else if *self < *other { + Option::Some(Ordering::Less) + } else { + Option::Some(Ordering::Equal) + } + } + + fn lt(&self, other: &Self) -> bool { + *self < *other + } + fn le(&self, other: &Self) -> bool { + *self <= *other + } + fn ge(&self, other: &Self) -> bool { + *self >= *other + } + fn gt(&self, other: &Self) -> bool { + *self > *other + } +} + +impl Ord for i32 { + fn cmp(&self, other: &Self) -> Ordering { + if *self > *other { + Ordering::Greater + } else if *self < *other { + Ordering::Less + } else { + Ordering::Equal + } + } +} + +#[derive(PartialEq, Eq)] +struct Foo { + a: i32, +} + +extern "C" { + fn puts(s: *const i8); +} + +fn print(s: &str) { + unsafe { + puts(s as *const str as *const i8); + } +} + +fn main() -> i32 { + let a = Foo { a: 42i32 }; + let b = Foo { a: 42i32 }; + let c = Foo { a: 7i32 }; + + if a == b { + print("a == b"); + } else { + print("a != b"); + } + + if a == c { + print("a == c"); + } else { + print("a != c"); + } + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/partial-ord-1.rs b/gcc/testsuite/rust/execute/torture/partial-ord-1.rs new file mode 100644 index 000000000000..a3558e7cb7a9 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/partial-ord-1.rs @@ -0,0 +1,101 @@ +/* { dg-output "x == y\r*\nx > z\r*\n" }*/ +#[lang = "sized"] +pub trait Sized {} + +pub enum Option { + #[lang = "None"] + None, + #[lang = "Some"] + Some(T), +} + +use Option::{None, Some}; + +#[lang = "eq"] +pub trait PartialEq { + fn eq(&self, other: &Rhs) -> bool; + + fn ne(&self, other: &Rhs) -> bool { + !self.eq(other) + } +} + +pub enum Ordering { + Less = -1, + Equal = 0, + Greater = 1, +} + +#[lang = "partial_ord"] +pub trait PartialOrd: PartialEq { + fn partial_cmp(&self, other: &Rhs) -> Option; +} + +// Implement for i32 +impl PartialEq for i32 { + fn eq(&self, other: &Self) -> bool { + *self == *other + } +} + +// Implement PartialOrd for i32 +impl PartialOrd for i32 { + fn partial_cmp(&self, other: &Self) -> Option { + if *self < *other { + Some(Ordering::Less) + } else if *self > *other { + Some(Ordering::Greater) + } else { + Some(Ordering::Equal) + } + } +} + +// Struct with manual PartialEq +struct Foo { + a: i32, +} + +impl PartialEq for Foo { + fn eq(&self, other: &Self) -> bool { + self.a.eq(&other.a) + } +} + +impl PartialOrd for Foo { + fn partial_cmp(&self, other: &Self) -> Option { + self.a.partial_cmp(&other.a) + } +} + +extern "C" { + fn puts(s: *const i8); +} + +fn print(s: &str) { + unsafe { + puts(s as *const str as *const i8); + } +} + +fn main() -> i32 { + let x = Foo { a: 42 }; + let y = Foo { a: 42 }; + let z = Foo { a: 7 }; + + match x.partial_cmp(&y) { + Some(Ordering::Equal) => print("x == y"), + Some(Ordering::Less) => print("x < y"), + Some(Ordering::Greater) => print("x > y"), + None => print("x ? y"), + } + + match x.partial_cmp(&z) { + Some(Ordering::Equal) => print("x == z"), + Some(Ordering::Less) => print("x < z"), + Some(Ordering::Greater) => print("x > z"), + None => print("x ? z"), + } + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/partial-ord-2.rs b/gcc/testsuite/rust/execute/torture/partial-ord-2.rs new file mode 100644 index 000000000000..d3b713fc5e26 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/partial-ord-2.rs @@ -0,0 +1,469 @@ +/* { dg-output "x == y\r*\nx > z\r*\n" }*/ + +#![feature(intrinsics)] + +mod core { + mod option { + // #[rustc_diagnostic_item = "option_type"] + #[stable(feature = "rust1", since = "1.0.0")] + pub enum Option { + /// No value + #[lang = "None"] + #[stable(feature = "rust1", since = "1.0.0")] + None, + /// Some value `T` + #[lang = "Some"] + #[stable(feature = "rust1", since = "1.0.0")] + Some(#[stable(feature = "rust1", since = "1.0.0")] T), + } + } + + mod marker { + #[lang = "phantom_data"] + #[stable(feature = "rust1", since = "1.0.0")] + pub struct PhantomData; + + #[unstable(feature = "structural_match", issue = "31434")] + // #[rustc_on_unimplemented(message = "the type `{Self}` does not `#[derive(PartialEq)]`")] + #[lang = "structural_peq"] + pub trait StructuralPartialEq { + // Empty. + } + + #[unstable(feature = "structural_match", issue = "31434")] + // #[rustc_on_unimplemented(message = "the type `{Self}` does not `#[derive(Eq)]`")] + #[lang = "structural_teq"] + pub trait StructuralEq { + // Empty. + } + + #[stable(feature = "rust1", since = "1.0.0")] + #[lang = "sized"] + // #[rustc_on_unimplemented( + // message = "the size for values of type `{Self}` cannot be known at compilation time", + // label = "doesn't have a size known at compile-time" + // )] + // #[fundamental] // for Default, for example, which requires that `[T]: !Default` be evaluatable + // #[rustc_specialization_trait] + pub trait Sized { + // Empty. + } + } + + mod cmp { + use super::marker::Sized; + use super::option::Option; + + // #[derive(Clone, Copy, PartialEq, Debug, Hash)] + #[stable(feature = "rust1", since = "1.0.0")] + pub enum Ordering { + /// An ordering where a compared value is less than another. + #[stable(feature = "rust1", since = "1.0.0")] + Less = -1, + /// An ordering where a compared value is equal to another. + #[stable(feature = "rust1", since = "1.0.0")] + Equal = 0, + /// An ordering where a compared value is greater than another. + #[stable(feature = "rust1", since = "1.0.0")] + Greater = 1, + } + + #[lang = "eq"] + #[stable(feature = "rust1", since = "1.0.0")] + #[doc(alias = "==")] + #[doc(alias = "!=")] + // #[rustc_on_unimplemented( + // message = "can't compare `{Self}` with `{Rhs}`", + // label = "no implementation for `{Self} == {Rhs}`" + // )] + pub trait PartialEq { + /// This method tests for `self` and `other` values to be equal, and is used + /// by `==`. + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn eq(&self, other: &Rhs) -> bool; + + fn ne(&self, other: &Rhs) -> bool { + !self.eq(other) + } + } + + #[doc(alias = "==")] + #[doc(alias = "!=")] + #[stable(feature = "rust1", since = "1.0.0")] + pub trait Eq: PartialEq { + // this method is used solely by #[deriving] to assert + // that every component of a type implements #[deriving] + // itself, the current deriving infrastructure means doing this + // assertion without using a method on this trait is nearly + // impossible. + // + // This should never be implemented by hand. + #[doc(hidden)] + #[stable(feature = "rust1", since = "1.0.0")] + fn assert_receiver_is_total_eq(&self) {} + } + + #[lang = "partial_ord"] + #[stable(feature = "rust1", since = "1.0.0")] + #[doc(alias = ">")] + #[doc(alias = "<")] + #[doc(alias = "<=")] + #[doc(alias = ">=")] + // #[rustc_on_unimplemented( + // message = "can't compare `{Self}` with `{Rhs}`", + // label = "no implementation for `{Self} < {Rhs}` and `{Self} > {Rhs}`" + // )] + pub trait PartialOrd: PartialEq { + /// This method returns an ordering between `self` and `other` values if one exists. + /// + /// # Examples + /// + /// ``` + /// use std::cmp::Ordering; + /// + /// let result = 1.0.partial_cmp(&2.0); + /// assert_eq!(result, Some(Ordering::Less)); + /// + /// let result = 1.0.partial_cmp(&1.0); + /// assert_eq!(result, Some(Ordering::Equal)); + /// + /// let result = 2.0.partial_cmp(&1.0); + /// assert_eq!(result, Some(Ordering::Greater)); + /// ``` + /// + /// When comparison is impossible: + /// + /// ``` + /// let result = f64::NAN.partial_cmp(&1.0); + /// assert_eq!(result, None); + /// ``` + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn partial_cmp(&self, other: &Rhs) -> Option; + + /// This method tests less than (for `self` and `other`) and is used by the `<` operator. + /// + /// # Examples + /// + /// ``` + /// let result = 1.0 < 2.0; + /// assert_eq!(result, true); + /// + /// let result = 2.0 < 1.0; + /// assert_eq!(result, false); + /// ``` + #[inline] + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn lt(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Less) => true, + _ => false, + } + } + + /// This method tests less than or equal to (for `self` and `other`) and is used by the `<=` + /// operator. + /// + /// # Examples + /// + /// ``` + /// let result = 1.0 <= 2.0; + /// assert_eq!(result, true); + /// + /// let result = 2.0 <= 2.0; + /// assert_eq!(result, true); + /// ``` + #[inline] + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn le(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Less | Ordering::Equal) => true, + _ => false, + } + } + + /// This method tests greater than (for `self` and `other`) and is used by the `>` operator. + /// + /// # Examples + /// + /// ``` + /// let result = 1.0 > 2.0; + /// assert_eq!(result, false); + /// + /// let result = 2.0 > 2.0; + /// assert_eq!(result, false); + /// ``` + #[inline] + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn gt(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Greater) => true, + _ => false, + } + } + + /// This method tests greater than or equal to (for `self` and `other`) and is used by the `>=` + /// operator. + /// + /// # Examples + /// + /// ``` + /// let result = 2.0 >= 1.0; + /// assert_eq!(result, true); + /// + /// let result = 2.0 >= 2.0; + /// assert_eq!(result, true); + /// ``` + #[inline] + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn ge(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Greater | Ordering::Equal) => true, + _ => false, + } + } + } + + #[doc(alias = "<")] + #[doc(alias = ">")] + #[doc(alias = "<=")] + #[doc(alias = ">=")] + #[stable(feature = "rust1", since = "1.0.0")] + pub trait Ord: Eq + PartialOrd { + /// This method returns an [`Ordering`] between `self` and `other`. + /// + /// By convention, `self.cmp(&other)` returns the ordering matching the expression + /// `self other` if true. + /// + /// # Examples + /// + /// ``` + /// use std::cmp::Ordering; + /// + /// assert_eq!(5.cmp(&10), Ordering::Less); + /// assert_eq!(10.cmp(&5), Ordering::Greater); + /// assert_eq!(5.cmp(&5), Ordering::Equal); + /// ``` + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn cmp(&self, other: &Self) -> Ordering; + + /// Compares and returns the maximum of two values. + /// + /// Returns the second argument if the comparison determines them to be equal. + /// + /// # Examples + /// + /// ``` + /// assert_eq!(2, 1.max(2)); + /// assert_eq!(2, 2.max(2)); + /// ``` + #[stable(feature = "ord_max_min", since = "1.21.0")] + #[must_use] + fn max(self, other: Self) -> Self + where + Self: Sized, + { + self + } + + /// Compares and returns the minimum of two values. + /// + /// Returns the first argument if the comparison determines them to be equal. + /// + /// # Examples + /// + /// ``` + /// assert_eq!(1, 1.min(2)); + /// assert_eq!(2, 2.min(2)); + /// ``` + #[stable(feature = "ord_max_min", since = "1.21.0")] + #[must_use] + fn min(self, other: Self) -> Self + where + Self: Sized, + { + self + } + + /// Restrict a value to a certain interval. + /// + /// Returns `max` if `self` is greater than `max`, and `min` if `self` is + /// less than `min`. Otherwise this returns `self`. + /// + /// # Panics + /// + /// Panics if `min > max`. + /// + /// # Examples + /// + /// ``` + /// #![feature(clamp)] + /// + /// assert!((-3).clamp(-2, 1) == -2); + /// assert!(0.clamp(-2, 1) == 0); + /// assert!(2.clamp(-2, 1) == 1); + /// ``` + #[must_use] + #[unstable(feature = "clamp", issue = "44095")] + fn clamp(self, min: Self, max: Self) -> Self + where + Self: Sized, + { + if self < min { + min + } else if self > max { + max + } else { + self + } + } + } + } + + pub mod intrinsics { + #[lang = "discriminant_kind"] + pub trait DiscriminantKind { + #[lang = "discriminant_type"] + type Discriminant; + } + + extern "rust-intrinsic" { + pub fn discriminant_value(v: &T) -> ::Discriminant; + } + } +} + +use core::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd}; +use core::marker::Sized; +use core::option::Option; + +// for comparing discriminant_value +impl PartialEq for isize { + fn eq(&self, other: &Self) -> bool { + *self == *other + } +} + +// for comparing discriminant_value +impl PartialOrd for isize { + fn partial_cmp(&self, other: &Self) -> Option { + if *self > *other { + Option::Some(Ordering::Greater) + } else if *self < *other { + Option::Some(Ordering::Less) + } else { + Option::Some(Ordering::Equal) + } + } + + fn lt(&self, other: &Self) -> bool { + *self < *other + } + fn le(&self, other: &Self) -> bool { + *self <= *other + } + fn ge(&self, other: &Self) -> bool { + *self >= *other + } + fn gt(&self, other: &Self) -> bool { + *self > *other + } +} + +impl PartialEq for i32 { + fn eq(&self, other: &Self) -> bool { + *self == *other + } +} +impl Eq for i32 {} + +impl PartialOrd for i32 { + fn partial_cmp(&self, other: &Self) -> Option { + if *self > *other { + Option::Some(Ordering::Greater) + } else if *self < *other { + Option::Some(Ordering::Less) + } else { + Option::Some(Ordering::Equal) + } + } + + fn lt(&self, other: &Self) -> bool { + *self < *other + } + fn le(&self, other: &Self) -> bool { + *self <= *other + } + fn ge(&self, other: &Self) -> bool { + *self >= *other + } + fn gt(&self, other: &Self) -> bool { + *self > *other + } +} + +impl Ord for i32 { + fn cmp(&self, other: &Self) -> Ordering { + if *self > *other { + Ordering::Greater + } else if *self < *other { + Ordering::Less + } else { + Ordering::Equal + } + } +} + +struct Foo { + a: i32, +} + +impl PartialEq for Foo { + fn eq(&self, other: &'_ Self) -> bool { + self.a == other.a + } +} + +impl PartialOrd for Foo { + fn partial_cmp(&self, other: &'_ Foo) -> Option<::core::cmp::Ordering> { + self.a.partial_cmp(&other.a) + } +} + +extern "C" { + fn puts(s: *const i8); +} + +fn print(s: &str) { + unsafe { + puts(s as *const str as *const i8); + } +} + +fn main() -> i32 { + let x = Foo { a: 42 }; + let y = Foo { a: 42 }; + let z = Foo { a: 7 }; + + match x.partial_cmp(&y) { + Option::Some(Ordering::Equal) => print("x == y"), + Option::Some(Ordering::Less) => print("x < y"), + Option::Some(Ordering::Greater) => print("x > y"), + Option::None => print("x ? y"), + } + + match x.partial_cmp(&z) { + Option::Some(Ordering::Equal) => print("x == z"), + Option::Some(Ordering::Less) => print("x < z"), + Option::Some(Ordering::Greater) => print("x > z"), + Option::None => print("x ? z"), + } + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/partial-ord-3.rs b/gcc/testsuite/rust/execute/torture/partial-ord-3.rs new file mode 100644 index 000000000000..7aec07c5caaa --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/partial-ord-3.rs @@ -0,0 +1,489 @@ +/* { dg-output "x == y\r*\nx > z\r*\nx < z\r*\nx >= y\r*\nx <= y\r*\n" } */ +/* { dg-options "-w" } */ + +#![feature(intrinsics)] + +mod core { + mod option { + // #[rustc_diagnostic_item = "option_type"] + #[stable(feature = "rust1", since = "1.0.0")] + pub enum Option { + /// No value + #[lang = "None"] + #[stable(feature = "rust1", since = "1.0.0")] + None, + /// Some value `T` + #[lang = "Some"] + #[stable(feature = "rust1", since = "1.0.0")] + Some(#[stable(feature = "rust1", since = "1.0.0")] T), + } + } + + mod marker { + #[lang = "phantom_data"] + #[stable(feature = "rust1", since = "1.0.0")] + pub struct PhantomData; + + #[unstable(feature = "structural_match", issue = "31434")] + // #[rustc_on_unimplemented(message = "the type `{Self}` does not `#[derive(PartialEq)]`")] + #[lang = "structural_peq"] + pub trait StructuralPartialEq { + // Empty. + } + + #[unstable(feature = "structural_match", issue = "31434")] + // #[rustc_on_unimplemented(message = "the type `{Self}` does not `#[derive(Eq)]`")] + #[lang = "structural_teq"] + pub trait StructuralEq { + // Empty. + } + + #[stable(feature = "rust1", since = "1.0.0")] + #[lang = "sized"] + // #[rustc_on_unimplemented( + // message = "the size for values of type `{Self}` cannot be known at compilation time", + // label = "doesn't have a size known at compile-time" + // )] + // #[fundamental] // for Default, for example, which requires that `[T]: !Default` be evaluatable + // #[rustc_specialization_trait] + pub trait Sized { + // Empty. + } + } + + mod cmp { + use super::marker::Sized; + use super::option::Option; + + // #[derive(Clone, Copy, PartialEq, Debug, Hash)] + #[stable(feature = "rust1", since = "1.0.0")] + pub enum Ordering { + /// An ordering where a compared value is less than another. + #[stable(feature = "rust1", since = "1.0.0")] + Less = -1, + /// An ordering where a compared value is equal to another. + #[stable(feature = "rust1", since = "1.0.0")] + Equal = 0, + /// An ordering where a compared value is greater than another. + #[stable(feature = "rust1", since = "1.0.0")] + Greater = 1, + } + + #[lang = "eq"] + #[stable(feature = "rust1", since = "1.0.0")] + #[doc(alias = "==")] + #[doc(alias = "!=")] + // #[rustc_on_unimplemented( + // message = "can't compare `{Self}` with `{Rhs}`", + // label = "no implementation for `{Self} == {Rhs}`" + // )] + pub trait PartialEq { + /// This method tests for `self` and `other` values to be equal, and is used + /// by `==`. + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn eq(&self, other: &Rhs) -> bool; + + fn ne(&self, other: &Rhs) -> bool { + !self.eq(other) + } + } + + #[doc(alias = "==")] + #[doc(alias = "!=")] + #[stable(feature = "rust1", since = "1.0.0")] + pub trait Eq: PartialEq { + // this method is used solely by #[deriving] to assert + // that every component of a type implements #[deriving] + // itself, the current deriving infrastructure means doing this + // assertion without using a method on this trait is nearly + // impossible. + // + // This should never be implemented by hand. + #[doc(hidden)] + #[stable(feature = "rust1", since = "1.0.0")] + fn assert_receiver_is_total_eq(&self) {} + } + + #[lang = "partial_ord"] + #[stable(feature = "rust1", since = "1.0.0")] + #[doc(alias = ">")] + #[doc(alias = "<")] + #[doc(alias = "<=")] + #[doc(alias = ">=")] + // #[rustc_on_unimplemented( + // message = "can't compare `{Self}` with `{Rhs}`", + // label = "no implementation for `{Self} < {Rhs}` and `{Self} > {Rhs}`" + // )] + pub trait PartialOrd: PartialEq { + /// This method returns an ordering between `self` and `other` values if one exists. + /// + /// # Examples + /// + /// ``` + /// use std::cmp::Ordering; + /// + /// let result = 1.0.partial_cmp(&2.0); + /// assert_eq!(result, Some(Ordering::Less)); + /// + /// let result = 1.0.partial_cmp(&1.0); + /// assert_eq!(result, Some(Ordering::Equal)); + /// + /// let result = 2.0.partial_cmp(&1.0); + /// assert_eq!(result, Some(Ordering::Greater)); + /// ``` + /// + /// When comparison is impossible: + /// + /// ``` + /// let result = f64::NAN.partial_cmp(&1.0); + /// assert_eq!(result, None); + /// ``` + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn partial_cmp(&self, other: &Rhs) -> Option; + + /// This method tests less than (for `self` and `other`) and is used by the `<` operator. + /// + /// # Examples + /// + /// ``` + /// let result = 1.0 < 2.0; + /// assert_eq!(result, true); + /// + /// let result = 2.0 < 1.0; + /// assert_eq!(result, false); + /// ``` + #[inline] + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn lt(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Less) => true, + _ => false, + } + } + + /// This method tests less than or equal to (for `self` and `other`) and is used by the `<=` + /// operator. + /// + /// # Examples + /// + /// ``` + /// let result = 1.0 <= 2.0; + /// assert_eq!(result, true); + /// + /// let result = 2.0 <= 2.0; + /// assert_eq!(result, true); + /// ``` + #[inline] + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn le(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Less | Ordering::Equal) => true, + _ => false, + } + } + + /// This method tests greater than (for `self` and `other`) and is used by the `>` operator. + /// + /// # Examples + /// + /// ``` + /// let result = 1.0 > 2.0; + /// assert_eq!(result, false); + /// + /// let result = 2.0 > 2.0; + /// assert_eq!(result, false); + /// ``` + #[inline] + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn gt(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Greater) => true, + _ => false, + } + } + + /// This method tests greater than or equal to (for `self` and `other`) and is used by the `>=` + /// operator. + /// + /// # Examples + /// + /// ``` + /// let result = 2.0 >= 1.0; + /// assert_eq!(result, true); + /// + /// let result = 2.0 >= 2.0; + /// assert_eq!(result, true); + /// ``` + #[inline] + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn ge(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Greater | Ordering::Equal) => true, + _ => false, + } + } + } + + #[doc(alias = "<")] + #[doc(alias = ">")] + #[doc(alias = "<=")] + #[doc(alias = ">=")] + #[stable(feature = "rust1", since = "1.0.0")] + pub trait Ord: Eq + PartialOrd { + /// This method returns an [`Ordering`] between `self` and `other`. + /// + /// By convention, `self.cmp(&other)` returns the ordering matching the expression + /// `self other` if true. + /// + /// # Examples + /// + /// ``` + /// use std::cmp::Ordering; + /// + /// assert_eq!(5.cmp(&10), Ordering::Less); + /// assert_eq!(10.cmp(&5), Ordering::Greater); + /// assert_eq!(5.cmp(&5), Ordering::Equal); + /// ``` + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn cmp(&self, other: &Self) -> Ordering; + + /// Compares and returns the maximum of two values. + /// + /// Returns the second argument if the comparison determines them to be equal. + /// + /// # Examples + /// + /// ``` + /// assert_eq!(2, 1.max(2)); + /// assert_eq!(2, 2.max(2)); + /// ``` + #[stable(feature = "ord_max_min", since = "1.21.0")] + #[must_use] + fn max(self, other: Self) -> Self + where + Self: Sized, + { + self + } + + /// Compares and returns the minimum of two values. + /// + /// Returns the first argument if the comparison determines them to be equal. + /// + /// # Examples + /// + /// ``` + /// assert_eq!(1, 1.min(2)); + /// assert_eq!(2, 2.min(2)); + /// ``` + #[stable(feature = "ord_max_min", since = "1.21.0")] + #[must_use] + fn min(self, other: Self) -> Self + where + Self: Sized, + { + self + } + + /// Restrict a value to a certain interval. + /// + /// Returns `max` if `self` is greater than `max`, and `min` if `self` is + /// less than `min`. Otherwise this returns `self`. + /// + /// # Panics + /// + /// Panics if `min > max`. + /// + /// # Examples + /// + /// ``` + /// #![feature(clamp)] + /// + /// assert!((-3).clamp(-2, 1) == -2); + /// assert!(0.clamp(-2, 1) == 0); + /// assert!(2.clamp(-2, 1) == 1); + /// ``` + #[must_use] + #[unstable(feature = "clamp", issue = "44095")] + fn clamp(self, min: Self, max: Self) -> Self + where + Self: Sized, + { + if self < min { + min + } else if self > max { + max + } else { + self + } + } + } + } + + pub mod intrinsics { + #[lang = "discriminant_kind"] + pub trait DiscriminantKind { + #[lang = "discriminant_type"] + type Discriminant; + } + + extern "rust-intrinsic" { + pub fn discriminant_value(v: &T) -> ::Discriminant; + } + } +} + +use core::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd}; +use core::marker::Sized; +use core::option::Option; + +// for comparing discriminant_value +impl PartialEq for isize { + fn eq(&self, other: &Self) -> bool { + *self == *other + } +} + +// for comparing discriminant_value +impl PartialOrd for isize { + fn partial_cmp(&self, other: &Self) -> Option { + if *self > *other { + Option::Some(Ordering::Greater) + } else if *self < *other { + Option::Some(Ordering::Less) + } else { + Option::Some(Ordering::Equal) + } + } + + fn lt(&self, other: &Self) -> bool { + *self < *other + } + fn le(&self, other: &Self) -> bool { + *self <= *other + } + fn ge(&self, other: &Self) -> bool { + *self >= *other + } + fn gt(&self, other: &Self) -> bool { + *self > *other + } +} + +impl PartialEq for i32 { + fn eq(&self, other: &Self) -> bool { + *self == *other + } +} +impl Eq for i32 {} + +impl PartialOrd for i32 { + fn partial_cmp(&self, other: &Self) -> Option { + if *self > *other { + Option::Some(Ordering::Greater) + } else if *self < *other { + Option::Some(Ordering::Less) + } else { + Option::Some(Ordering::Equal) + } + } + + fn lt(&self, other: &Self) -> bool { + *self < *other + } + fn le(&self, other: &Self) -> bool { + *self <= *other + } + fn ge(&self, other: &Self) -> bool { + *self >= *other + } + fn gt(&self, other: &Self) -> bool { + *self > *other + } +} + +impl Ord for i32 { + fn cmp(&self, other: &Self) -> Ordering { + if *self > *other { + Ordering::Greater + } else if *self < *other { + Ordering::Less + } else { + Ordering::Equal + } + } +} + +struct Foo { + a: i32, +} + +impl PartialEq for Foo { + fn eq(&self, other: &Self) -> bool { + self.a == other.a + } +} +impl Eq for Foo {} + +impl PartialOrd for Foo { + fn partial_cmp(&self, other: &Self) -> Option { + self.a.partial_cmp(&other.a) + } +} + +impl Ord for Foo { + fn cmp(&self, other: &Self) -> Ordering { + self.a.cmp(&other.a) + } +} + +extern "C" { + fn puts(s: *const i8); +} + +fn print(s: &str) { + unsafe { + puts(s as *const str as *const i8); + } +} + +fn main() -> i32 { + let x = Foo { a: 42 }; + let y = Foo { a: 42 }; + let z = Foo { a: 7 }; + + // test direct equality + if x == y { + print("x == y"); + } + + // test PartialOrd via match + match x.partial_cmp(&z) { + Option::Some(Ordering::Greater) => print("x > z"), + _ => print("x ? z"), + } + + // test `<` directly + if z < x { + print("x < z"); + } + + // test `>=` + if x >= y { + print("x >= y"); + } + + // test `<=` + if x <= y { + print("x <= y"); + } + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/partial-ord-4.rs b/gcc/testsuite/rust/execute/torture/partial-ord-4.rs new file mode 100644 index 000000000000..fd52f328c58b --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/partial-ord-4.rs @@ -0,0 +1,115 @@ +/* { dg-output "a == b\r*\na != c\r*\n" }*/ +/* { dg-options "-w" } */ + +#![feature(intrinsics)] + +mod core { + mod option { + pub enum Option { + #[lang = "None"] + None, + #[lang = "Some"] + Some(T), + } + } + + mod marker { + #[lang = "sized"] + pub trait Sized {} + } + + mod cmp { + use super::marker::Sized; + use super::option::Option; + + pub enum Ordering { + Less = -1, + Equal = 0, + Greater = 1, + } + + #[lang = "eq"] + pub trait PartialEq { + fn eq(&self, other: &Rhs) -> bool; + + fn ne(&self, other: &Rhs) -> bool { + !self.eq(other) + } + } + + #[lang = "partial_ord"] + pub trait PartialOrd: PartialEq { + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn partial_cmp(&self, other: &Rhs) -> Option; + } + } +} + +use core::cmp::{Ordering, PartialEq, PartialOrd}; +use core::marker::Sized; +use core::option::Option; + +impl PartialEq for i32 { + fn eq(&self, other: &Self) -> bool { + *self == *other + } +} + +impl PartialOrd for i32 { + fn partial_cmp(&self, other: &Self) -> Option { + if *self > *other { + Option::Some(Ordering::Greater) + } else if *self < *other { + Option::Some(Ordering::Less) + } else { + Option::Some(Ordering::Equal) + } + } +} + +struct Foo { + a: i32, +} + +impl PartialEq for Foo { + fn eq(&self, other: &'_ Self) -> bool { + self.a == other.a + } +} + +impl PartialOrd for Foo { + fn partial_cmp(&self, other: &'_ Foo) -> Option<::core::cmp::Ordering> { + ::core::cmp::PartialOrd::partial_cmp(&self.a, &other.a) + } +} + +extern "C" { + fn puts(s: *const i8); +} + +fn print(s: &str) { + unsafe { + puts(s as *const str as *const i8); + } +} + +fn main() -> i32 { + let a = Foo { a: 42i32 }; + let b = Foo { a: 42i32 }; + let c = Foo { a: 7i32 }; + + if a == b { + print("a == b"); + } else { + print("a != b"); + } + + if a == c { + print("a == c"); + } else { + print("a != c"); + } + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/partial-ord-5.rs b/gcc/testsuite/rust/execute/torture/partial-ord-5.rs new file mode 100644 index 000000000000..721d2aa00655 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/partial-ord-5.rs @@ -0,0 +1,487 @@ +/* { dg-output "a == b\r*\na != c\r*\na >= c\r*\na <= b\r*\na > c\r*\nc < b\r*\n" } */ +/* { dg-options "-w" } */ + +#![feature(intrinsics)] + +mod core { + mod option { + // #[rustc_diagnostic_item = "option_type"] + #[stable(feature = "rust1", since = "1.0.0")] + pub enum Option { + /// No value + #[lang = "None"] + #[stable(feature = "rust1", since = "1.0.0")] + None, + /// Some value `T` + #[lang = "Some"] + #[stable(feature = "rust1", since = "1.0.0")] + Some(#[stable(feature = "rust1", since = "1.0.0")] T), + } + } + + mod marker { + #[lang = "phantom_data"] + #[stable(feature = "rust1", since = "1.0.0")] + pub struct PhantomData; + + #[unstable(feature = "structural_match", issue = "31434")] + // #[rustc_on_unimplemented(message = "the type `{Self}` does not `#[derive(PartialEq)]`")] + #[lang = "structural_peq"] + pub trait StructuralPartialEq { + // Empty. + } + + #[unstable(feature = "structural_match", issue = "31434")] + // #[rustc_on_unimplemented(message = "the type `{Self}` does not `#[derive(Eq)]`")] + #[lang = "structural_teq"] + pub trait StructuralEq { + // Empty. + } + + #[stable(feature = "rust1", since = "1.0.0")] + #[lang = "sized"] + // #[rustc_on_unimplemented( + // message = "the size for values of type `{Self}` cannot be known at compilation time", + // label = "doesn't have a size known at compile-time" + // )] + // #[fundamental] // for Default, for example, which requires that `[T]: !Default` be evaluatable + // #[rustc_specialization_trait] + pub trait Sized { + // Empty. + } + } + + mod cmp { + use super::marker::Sized; + use super::option::Option; + + // #[derive(Clone, Copy, PartialEq, Debug, Hash)] + #[stable(feature = "rust1", since = "1.0.0")] + pub enum Ordering { + /// An ordering where a compared value is less than another. + #[stable(feature = "rust1", since = "1.0.0")] + Less = -1, + /// An ordering where a compared value is equal to another. + #[stable(feature = "rust1", since = "1.0.0")] + Equal = 0, + /// An ordering where a compared value is greater than another. + #[stable(feature = "rust1", since = "1.0.0")] + Greater = 1, + } + + #[lang = "eq"] + #[stable(feature = "rust1", since = "1.0.0")] + #[doc(alias = "==")] + #[doc(alias = "!=")] + // #[rustc_on_unimplemented( + // message = "can't compare `{Self}` with `{Rhs}`", + // label = "no implementation for `{Self} == {Rhs}`" + // )] + pub trait PartialEq { + /// This method tests for `self` and `other` values to be equal, and is used + /// by `==`. + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn eq(&self, other: &Rhs) -> bool; + + fn ne(&self, other: &Rhs) -> bool { + !self.eq(other) + } + } + + #[doc(alias = "==")] + #[doc(alias = "!=")] + #[stable(feature = "rust1", since = "1.0.0")] + pub trait Eq: PartialEq { + // this method is used solely by #[deriving] to assert + // that every component of a type implements #[deriving] + // itself, the current deriving infrastructure means doing this + // assertion without using a method on this trait is nearly + // impossible. + // + // This should never be implemented by hand. + #[doc(hidden)] + #[stable(feature = "rust1", since = "1.0.0")] + fn assert_receiver_is_total_eq(&self) {} + } + + #[lang = "partial_ord"] + #[stable(feature = "rust1", since = "1.0.0")] + #[doc(alias = ">")] + #[doc(alias = "<")] + #[doc(alias = "<=")] + #[doc(alias = ">=")] + // #[rustc_on_unimplemented( + // message = "can't compare `{Self}` with `{Rhs}`", + // label = "no implementation for `{Self} < {Rhs}` and `{Self} > {Rhs}`" + // )] + pub trait PartialOrd: PartialEq { + /// This method returns an ordering between `self` and `other` values if one exists. + /// + /// # Examples + /// + /// ``` + /// use std::cmp::Ordering; + /// + /// let result = 1.0.partial_cmp(&2.0); + /// assert_eq!(result, Some(Ordering::Less)); + /// + /// let result = 1.0.partial_cmp(&1.0); + /// assert_eq!(result, Some(Ordering::Equal)); + /// + /// let result = 2.0.partial_cmp(&1.0); + /// assert_eq!(result, Some(Ordering::Greater)); + /// ``` + /// + /// When comparison is impossible: + /// + /// ``` + /// let result = f64::NAN.partial_cmp(&1.0); + /// assert_eq!(result, None); + /// ``` + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn partial_cmp(&self, other: &Rhs) -> Option; + + /// This method tests less than (for `self` and `other`) and is used by the `<` operator. + /// + /// # Examples + /// + /// ``` + /// let result = 1.0 < 2.0; + /// assert_eq!(result, true); + /// + /// let result = 2.0 < 1.0; + /// assert_eq!(result, false); + /// ``` + #[inline] + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn lt(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Less) => true, + _ => false, + } + } + + /// This method tests less than or equal to (for `self` and `other`) and is used by the `<=` + /// operator. + /// + /// # Examples + /// + /// ``` + /// let result = 1.0 <= 2.0; + /// assert_eq!(result, true); + /// + /// let result = 2.0 <= 2.0; + /// assert_eq!(result, true); + /// ``` + #[inline] + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn le(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Less | Ordering::Equal) => true, + _ => false, + } + } + + /// This method tests greater than (for `self` and `other`) and is used by the `>` operator. + /// + /// # Examples + /// + /// ``` + /// let result = 1.0 > 2.0; + /// assert_eq!(result, false); + /// + /// let result = 2.0 > 2.0; + /// assert_eq!(result, false); + /// ``` + #[inline] + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn gt(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Greater) => true, + _ => false, + } + } + + /// This method tests greater than or equal to (for `self` and `other`) and is used by the `>=` + /// operator. + /// + /// # Examples + /// + /// ``` + /// let result = 2.0 >= 1.0; + /// assert_eq!(result, true); + /// + /// let result = 2.0 >= 2.0; + /// assert_eq!(result, true); + /// ``` + #[inline] + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn ge(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Greater | Ordering::Equal) => true, + _ => false, + } + } + } + + #[doc(alias = "<")] + #[doc(alias = ">")] + #[doc(alias = "<=")] + #[doc(alias = ">=")] + #[stable(feature = "rust1", since = "1.0.0")] + pub trait Ord: Eq + PartialOrd { + /// This method returns an [`Ordering`] between `self` and `other`. + /// + /// By convention, `self.cmp(&other)` returns the ordering matching the expression + /// `self other` if true. + /// + /// # Examples + /// + /// ``` + /// use std::cmp::Ordering; + /// + /// assert_eq!(5.cmp(&10), Ordering::Less); + /// assert_eq!(10.cmp(&5), Ordering::Greater); + /// assert_eq!(5.cmp(&5), Ordering::Equal); + /// ``` + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn cmp(&self, other: &Self) -> Ordering; + + /// Compares and returns the maximum of two values. + /// + /// Returns the second argument if the comparison determines them to be equal. + /// + /// # Examples + /// + /// ``` + /// assert_eq!(2, 1.max(2)); + /// assert_eq!(2, 2.max(2)); + /// ``` + #[stable(feature = "ord_max_min", since = "1.21.0")] + #[must_use] + fn max(self, other: Self) -> Self + where + Self: Sized, + { + self + } + + /// Compares and returns the minimum of two values. + /// + /// Returns the first argument if the comparison determines them to be equal. + /// + /// # Examples + /// + /// ``` + /// assert_eq!(1, 1.min(2)); + /// assert_eq!(2, 2.min(2)); + /// ``` + #[stable(feature = "ord_max_min", since = "1.21.0")] + #[must_use] + fn min(self, other: Self) -> Self + where + Self: Sized, + { + self + } + + /// Restrict a value to a certain interval. + /// + /// Returns `max` if `self` is greater than `max`, and `min` if `self` is + /// less than `min`. Otherwise this returns `self`. + /// + /// # Panics + /// + /// Panics if `min > max`. + /// + /// # Examples + /// + /// ``` + /// #![feature(clamp)] + /// + /// assert!((-3).clamp(-2, 1) == -2); + /// assert!(0.clamp(-2, 1) == 0); + /// assert!(2.clamp(-2, 1) == 1); + /// ``` + #[must_use] + #[unstable(feature = "clamp", issue = "44095")] + fn clamp(self, min: Self, max: Self) -> Self + where + Self: Sized, + { + if self < min { + min + } else if self > max { + max + } else { + self + } + } + } + } + + pub mod intrinsics { + #[lang = "discriminant_kind"] + pub trait DiscriminantKind { + #[lang = "discriminant_type"] + type Discriminant; + } + + extern "rust-intrinsic" { + pub fn discriminant_value(v: &T) -> ::Discriminant; + } + } +} + +use core::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd}; +use core::marker::Sized; +use core::option::Option; + +// for comparing discriminant_value +impl PartialEq for isize { + fn eq(&self, other: &Self) -> bool { + *self == *other + } +} + +// for comparing discriminant_value +impl PartialOrd for isize { + fn partial_cmp(&self, other: &Self) -> Option { + if *self > *other { + Option::Some(Ordering::Greater) + } else if *self < *other { + Option::Some(Ordering::Less) + } else { + Option::Some(Ordering::Equal) + } + } + + fn lt(&self, other: &Self) -> bool { + *self < *other + } + fn le(&self, other: &Self) -> bool { + *self <= *other + } + fn ge(&self, other: &Self) -> bool { + *self >= *other + } + fn gt(&self, other: &Self) -> bool { + *self > *other + } +} + +impl PartialEq for i32 { + fn eq(&self, other: &Self) -> bool { + *self == *other + } +} +impl Eq for i32 {} + +impl PartialOrd for i32 { + fn partial_cmp(&self, other: &Self) -> Option { + if *self > *other { + Option::Some(Ordering::Greater) + } else if *self < *other { + Option::Some(Ordering::Less) + } else { + Option::Some(Ordering::Equal) + } + } + + fn lt(&self, other: &Self) -> bool { + *self < *other + } + fn le(&self, other: &Self) -> bool { + *self <= *other + } + fn ge(&self, other: &Self) -> bool { + *self >= *other + } + fn gt(&self, other: &Self) -> bool { + *self > *other + } +} + +impl Ord for i32 { + fn cmp(&self, other: &Self) -> Ordering { + if *self > *other { + Ordering::Greater + } else if *self < *other { + Ordering::Less + } else { + Ordering::Equal + } + } +} + +#[derive(PartialEq, Eq, Ord)] +struct Foo { + a: i32, +} + +impl PartialOrd for Foo { + fn partial_cmp(&self, other: &'_ Foo) -> Option<::core::cmp::Ordering> { + self.a.partial_cmp(&other.a) + } +} + +extern "C" { + fn puts(s: *const i8); +} + +fn print(s: &str) { + unsafe { + puts(s as *const str as *const i8); + } +} + +fn main() -> i32 { + let a = Foo { a: 42 }; + let b = Foo { a: 42 }; + let c = Foo { a: 7 }; + + if a == b { + print("a == b"); + } else { + print("a != b"); + } + + if a != c { + print("a != c"); + } else { + print("a == c"); + } + + if a < c { + print("a < c"); + } else { + print("a >= c"); + } + + if a <= b { + print("a <= b"); + } else { + print("a > b"); + } + + if a > c { + print("a > c"); + } else { + print("a <= c"); + } + + if c >= b { + print("c >= b"); + } else { + print("c < b"); + } + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/partial-ord-6.rs b/gcc/testsuite/rust/execute/torture/partial-ord-6.rs new file mode 100644 index 000000000000..5d64f8c2f84c --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/partial-ord-6.rs @@ -0,0 +1,518 @@ +// { dg-additional-options "-w" } +/* { dg-output "Foo A < B\r?\nFoo B < C\r?\nFoo C == C\r?\nBar x < y\r?\nBarFull s1 < s2\r?\n" } */ + +#![feature(intrinsics)] + +mod core { + mod option { + // #[rustc_diagnostic_item = "option_type"] + #[stable(feature = "rust1", since = "1.0.0")] + pub enum Option { + /// No value + #[lang = "None"] + #[stable(feature = "rust1", since = "1.0.0")] + None, + /// Some value `T` + #[lang = "Some"] + #[stable(feature = "rust1", since = "1.0.0")] + Some(#[stable(feature = "rust1", since = "1.0.0")] T), + } + } + + mod marker { + #[lang = "phantom_data"] + #[stable(feature = "rust1", since = "1.0.0")] + pub struct PhantomData; + + #[unstable(feature = "structural_match", issue = "31434")] + // #[rustc_on_unimplemented(message = "the type `{Self}` does not `#[derive(PartialEq)]`")] + #[lang = "structural_peq"] + pub trait StructuralPartialEq { + // Empty. + } + + #[unstable(feature = "structural_match", issue = "31434")] + // #[rustc_on_unimplemented(message = "the type `{Self}` does not `#[derive(Eq)]`")] + #[lang = "structural_teq"] + pub trait StructuralEq { + // Empty. + } + + #[stable(feature = "rust1", since = "1.0.0")] + #[lang = "sized"] + // #[rustc_on_unimplemented( + // message = "the size for values of type `{Self}` cannot be known at compilation time", + // label = "doesn't have a size known at compile-time" + // )] + // #[fundamental] // for Default, for example, which requires that `[T]: !Default` be evaluatable + // #[rustc_specialization_trait] + pub trait Sized { + // Empty. + } + } + + mod cmp { + use super::marker::Sized; + use super::option::Option; + + // #[derive(Clone, Copy, PartialEq, Debug, Hash)] + #[stable(feature = "rust1", since = "1.0.0")] + pub enum Ordering { + /// An ordering where a compared value is less than another. + #[stable(feature = "rust1", since = "1.0.0")] + Less = -1, + /// An ordering where a compared value is equal to another. + #[stable(feature = "rust1", since = "1.0.0")] + Equal = 0, + /// An ordering where a compared value is greater than another. + #[stable(feature = "rust1", since = "1.0.0")] + Greater = 1, + } + + #[lang = "eq"] + #[stable(feature = "rust1", since = "1.0.0")] + #[doc(alias = "==")] + #[doc(alias = "!=")] + // #[rustc_on_unimplemented( + // message = "can't compare `{Self}` with `{Rhs}`", + // label = "no implementation for `{Self} == {Rhs}`" + // )] + pub trait PartialEq { + /// This method tests for `self` and `other` values to be equal, and is used + /// by `==`. + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn eq(&self, other: &Rhs) -> bool; + + fn ne(&self, other: &Rhs) -> bool { + !self.eq(other) + } + } + + #[doc(alias = "==")] + #[doc(alias = "!=")] + #[stable(feature = "rust1", since = "1.0.0")] + pub trait Eq: PartialEq { + // this method is used solely by #[deriving] to assert + // that every component of a type implements #[deriving] + // itself, the current deriving infrastructure means doing this + // assertion without using a method on this trait is nearly + // impossible. + // + // This should never be implemented by hand. + #[doc(hidden)] + #[stable(feature = "rust1", since = "1.0.0")] + fn assert_receiver_is_total_eq(&self) {} + } + + #[lang = "partial_ord"] + #[stable(feature = "rust1", since = "1.0.0")] + #[doc(alias = ">")] + #[doc(alias = "<")] + #[doc(alias = "<=")] + #[doc(alias = ">=")] + // #[rustc_on_unimplemented( + // message = "can't compare `{Self}` with `{Rhs}`", + // label = "no implementation for `{Self} < {Rhs}` and `{Self} > {Rhs}`" + // )] + pub trait PartialOrd: PartialEq { + /// This method returns an ordering between `self` and `other` values if one exists. + /// + /// # Examples + /// + /// ``` + /// use std::cmp::Ordering; + /// + /// let result = 1.0.partial_cmp(&2.0); + /// assert_eq!(result, Some(Ordering::Less)); + /// + /// let result = 1.0.partial_cmp(&1.0); + /// assert_eq!(result, Some(Ordering::Equal)); + /// + /// let result = 2.0.partial_cmp(&1.0); + /// assert_eq!(result, Some(Ordering::Greater)); + /// ``` + /// + /// When comparison is impossible: + /// + /// ``` + /// let result = f64::NAN.partial_cmp(&1.0); + /// assert_eq!(result, None); + /// ``` + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn partial_cmp(&self, other: &Rhs) -> Option; + + /// This method tests less than (for `self` and `other`) and is used by the `<` operator. + /// + /// # Examples + /// + /// ``` + /// let result = 1.0 < 2.0; + /// assert_eq!(result, true); + /// + /// let result = 2.0 < 1.0; + /// assert_eq!(result, false); + /// ``` + #[inline] + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn lt(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Less) => true, + _ => false, + } + } + + /// This method tests less than or equal to (for `self` and `other`) and is used by the `<=` + /// operator. + /// + /// # Examples + /// + /// ``` + /// let result = 1.0 <= 2.0; + /// assert_eq!(result, true); + /// + /// let result = 2.0 <= 2.0; + /// assert_eq!(result, true); + /// ``` + #[inline] + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn le(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Less | Ordering::Equal) => true, + _ => false, + } + } + + /// This method tests greater than (for `self` and `other`) and is used by the `>` operator. + /// + /// # Examples + /// + /// ``` + /// let result = 1.0 > 2.0; + /// assert_eq!(result, false); + /// + /// let result = 2.0 > 2.0; + /// assert_eq!(result, false); + /// ``` + #[inline] + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn gt(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Greater) => true, + _ => false, + } + } + + /// This method tests greater than or equal to (for `self` and `other`) and is used by the `>=` + /// operator. + /// + /// # Examples + /// + /// ``` + /// let result = 2.0 >= 1.0; + /// assert_eq!(result, true); + /// + /// let result = 2.0 >= 2.0; + /// assert_eq!(result, true); + /// ``` + #[inline] + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn ge(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Greater | Ordering::Equal) => true, + _ => false, + } + } + } + + #[doc(alias = "<")] + #[doc(alias = ">")] + #[doc(alias = "<=")] + #[doc(alias = ">=")] + #[stable(feature = "rust1", since = "1.0.0")] + pub trait Ord: Eq + PartialOrd { + /// This method returns an [`Ordering`] between `self` and `other`. + /// + /// By convention, `self.cmp(&other)` returns the ordering matching the expression + /// `self other` if true. + /// + /// # Examples + /// + /// ``` + /// use std::cmp::Ordering; + /// + /// assert_eq!(5.cmp(&10), Ordering::Less); + /// assert_eq!(10.cmp(&5), Ordering::Greater); + /// assert_eq!(5.cmp(&5), Ordering::Equal); + /// ``` + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn cmp(&self, other: &Self) -> Ordering; + + /// Compares and returns the maximum of two values. + /// + /// Returns the second argument if the comparison determines them to be equal. + /// + /// # Examples + /// + /// ``` + /// assert_eq!(2, 1.max(2)); + /// assert_eq!(2, 2.max(2)); + /// ``` + #[stable(feature = "ord_max_min", since = "1.21.0")] + #[must_use] + fn max(self, other: Self) -> Self + where + Self: Sized, + { + self + } + + /// Compares and returns the minimum of two values. + /// + /// Returns the first argument if the comparison determines them to be equal. + /// + /// # Examples + /// + /// ``` + /// assert_eq!(1, 1.min(2)); + /// assert_eq!(2, 2.min(2)); + /// ``` + #[stable(feature = "ord_max_min", since = "1.21.0")] + #[must_use] + fn min(self, other: Self) -> Self + where + Self: Sized, + { + self + } + + /// Restrict a value to a certain interval. + /// + /// Returns `max` if `self` is greater than `max`, and `min` if `self` is + /// less than `min`. Otherwise this returns `self`. + /// + /// # Panics + /// + /// Panics if `min > max`. + /// + /// # Examples + /// + /// ``` + /// #![feature(clamp)] + /// + /// assert!((-3).clamp(-2, 1) == -2); + /// assert!(0.clamp(-2, 1) == 0); + /// assert!(2.clamp(-2, 1) == 1); + /// ``` + #[must_use] + #[unstable(feature = "clamp", issue = "44095")] + fn clamp(self, min: Self, max: Self) -> Self + where + Self: Sized, + { + if self < min { + min + } else if self > max { + max + } else { + self + } + } + } + } + + pub mod intrinsics { + #[lang = "discriminant_kind"] + pub trait DiscriminantKind { + #[lang = "discriminant_type"] + type Discriminant; + } + + extern "rust-intrinsic" { + pub fn discriminant_value(v: &T) -> ::Discriminant; + } + } +} + +use core::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd}; +use core::marker::Sized; +use core::option::Option; + +// for comparing discriminant_value +impl PartialEq for isize { + fn eq(&self, other: &Self) -> bool { + *self == *other + } +} + +// for comparing discriminant_value +impl PartialOrd for isize { + fn partial_cmp(&self, other: &Self) -> Option { + if *self > *other { + Option::Some(Ordering::Greater) + } else if *self < *other { + Option::Some(Ordering::Less) + } else { + Option::Some(Ordering::Equal) + } + } + + fn lt(&self, other: &Self) -> bool { + *self < *other + } + fn le(&self, other: &Self) -> bool { + *self <= *other + } + fn ge(&self, other: &Self) -> bool { + *self >= *other + } + fn gt(&self, other: &Self) -> bool { + *self > *other + } +} + +impl PartialEq for i32 { + fn eq(&self, other: &Self) -> bool { + *self == *other + } +} + +impl PartialOrd for i32 { + fn partial_cmp(&self, other: &Self) -> Option { + if *self > *other { + Option::Some(Ordering::Greater) + } else if *self < *other { + Option::Some(Ordering::Less) + } else { + Option::Some(Ordering::Equal) + } + } + + fn lt(&self, other: &Self) -> bool { + *self < *other + } + fn le(&self, other: &Self) -> bool { + *self <= *other + } + fn ge(&self, other: &Self) -> bool { + *self >= *other + } + fn gt(&self, other: &Self) -> bool { + *self > *other + } +} + +impl Ord for i32 { + fn cmp(&self, other: &Self) -> Ordering { + if *self > *other { + Ordering::Greater + } else if *self < *other { + Ordering::Less + } else { + Ordering::Equal + } + } +} + +impl Eq for i32 {} + +#[derive(PartialEq, PartialOrd)] +enum Foo { + A, + B(i32, i32, i32), + C { inner: i32, outer: i32 }, +} + +#[derive(Ord, PartialOrd, PartialEq, Eq)] +struct Bar { + a: i32, +} + +#[derive(Ord, PartialOrd, PartialEq, Eq)] +struct BarFull { + a: i32, + b: i32, + c: i32, + d: i32, +} + +extern "C" { + fn puts(s: *const i8); +} + +fn print(s: &str) { + unsafe { + puts(s as *const str as *const i8); + } +} + +fn main() -> i32 { + // Enum comparison + let a = Foo::A; + let b = Foo::B(15, 14, 13); + let c = Foo::C { + inner: 10, + outer: 20, + }; + + match a.partial_cmp(&b) { + Option::Some(Ordering::Less) => print("Foo A < B"), + Option::Some(Ordering::Greater) => print("Foo A > B"), + Option::Some(Ordering::Equal) => print("Foo A == B"), + _ => print("Foo A ? B"), + } + + match b.partial_cmp(&c) { + Option::Some(Ordering::Less) => print("Foo B < C"), + Option::Some(Ordering::Greater) => print("Foo B > C"), + Option::Some(Ordering::Equal) => print("Foo B == C"), + _ => print("Foo B ? C"), + } + + match c.partial_cmp(&c) { + Option::Some(Ordering::Less) => print("Foo C < C ???"), + Option::Some(Ordering::Greater) => print("Foo C > C ???"), + Option::Some(Ordering::Equal) => print("Foo C == C"), + _ => print("Foo C ? C"), + } + + // Struct comparison: Bar + let x = Bar { a: 10 }; + let y = Bar { a: 20 }; + + if x < y { + print("Bar x < y"); + } else if x > y { + print("Bar x > y"); + } else { + print("Bar x == y"); + } + + // Struct comparison: BarFull + let s1 = BarFull { + a: 1, + b: 2, + c: 3, + d: 4, + }; + let s2 = BarFull { + a: 1, + b: 2, + c: 3, + d: 5, + }; + + match s1.cmp(&s2) { + Ordering::Less => print("BarFull s1 < s2"), + Ordering::Greater => print("BarFull s1 > s2"), + Ordering::Equal => print("BarFull s1 == s2"), + } + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/sip-hasher.rs b/gcc/testsuite/rust/execute/torture/sip-hasher.rs new file mode 100644 index 000000000000..60826a3ed012 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/sip-hasher.rs @@ -0,0 +1,438 @@ +// { dg-skip-if "" { *-*-* } { "-m32" } { "" } } +// { dg-options "-w" } +// { dg-output "Hash: 0x63d53fd2170bbb8c\r*\n" } +#![feature(intrinsics)] +#![feature(rustc_attrs)] + +#[lang = "sized"] +trait Sized {} + +mod intrinsics { + extern "rust-intrinsic" { + pub fn wrapping_add(a: T, b: T) -> T; + pub fn rotate_left(a: T, b: T) -> T; + pub fn offset(ptr: *const T, count: isize) -> *const T; + } +} + +#[lang = "add"] +trait Add { + type Output; + + fn add(self, rhs: Rhs) -> Self::Output; +} + +macro_rules! add_impl { + ($($t:ty)*) => ($( + impl Add for $t { + type Output = $t; + + #[inline] + #[rustc_inherit_overflow_checks] + fn add(self, other: $t) -> $t { self + other } + } + + + )*) +} + +add_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } + +impl *const T { + pub unsafe fn add(self, count: usize) -> Self { + // SAFETY: the caller must uphold the safety contract for `offset`. + unsafe { self.offset(count as isize) } + } + + pub unsafe fn offset(self, count: isize) -> *const T { + // SAFETY: the caller must uphold the safety contract for `offset`. + unsafe { intrinsics::offset(self, count) } + } +} + +macro_rules! impl_uint { + ($($ty:ident = $lang:literal),*) => { + $( + #[lang = $lang] + impl $ty { + pub fn wrapping_add(self, rhs: Self) -> Self { + intrinsics::wrapping_add(self, rhs) + } + + pub fn rotate_left(self, n: u32) -> Self { + intrinsics::rotate_left(self, n as Self) + } + + pub fn to_le(self) -> Self { + #[cfg(target_endian = "little")] + { + self + } + #[cfg(not(target_endian = "little"))] + { + self.swap_bytes() + } + } + } + )* + } +} + +impl_uint!( + u8 = "u8", + u16 = "u16", + u32 = "u32", + u64 = "u64", + u128 = "u128", + usize = "usize" +); + +#[repr(C)] +pub(crate) struct SliceComponents { + pub(crate) data_address: *const (), + pub(crate) metadata: usize, +} + +#[repr(C)] +pub(crate) union SliceRepr { + pub(crate) const_ptr: *const [T], + pub(crate) mut_ptr: *mut [T], + pub(crate) components: SliceComponents, +} + +impl [T] { + pub const fn as_ptr(&self) -> *const T { + self as *const [T] as *const T + } + + pub unsafe fn get_unchecked(&self, index: usize) -> &T { + unsafe { &*self.as_ptr().add(index) } + } + + pub fn len(&self) -> usize { + unsafe { + SliceRepr { + const_ptr: self as *const _, + } + .components + .metadata + } + } +} + +trait HasherTrait { + fn write(&mut self, msg: &[u8]); + fn finish(&self) -> u64; +} + +mod cmp { + pub fn min(a: usize, b: usize) -> usize { + if a < b { + a + } else { + b + } + } +} + +struct PhantomData; + +mod mem { + extern "rust-intrinsic" { + fn transmute(_: T) -> U; + fn size_of() -> usize; + } +} + +mod ptr { + extern "rust-intrinsic" { + fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize); + } +} + +#[repr(C)] +struct State { + v0: u64, + v2: u64, + v1: u64, + v3: u64, +} + +struct Hasher { + k0: u64, + k1: u64, + length: usize, // how many bytes we've processed + state: State, // hash State + tail: u64, // unprocessed bytes le + ntail: usize, // how many bytes in tail are valid + _marker: PhantomData, +} + +macro_rules! compress { + ($state:expr) => {{ + compress!($state.v0, $state.v1, $state.v2, $state.v3) + }}; + ($v0:expr, $v1:expr, $v2:expr, $v3:expr) => {{ + $v0 = $v0.wrapping_add($v1); + $v1 = $v1.rotate_left(13); + $v1 ^= $v0; + $v0 = $v0.rotate_left(32); + $v2 = $v2.wrapping_add($v3); + $v3 = $v3.rotate_left(16); + $v3 ^= $v2; + $v0 = $v0.wrapping_add($v3); + $v3 = $v3.rotate_left(21); + $v3 ^= $v0; + $v2 = $v2.wrapping_add($v1); + $v1 = $v1.rotate_left(17); + $v1 ^= $v2; + $v2 = $v2.rotate_left(32); + }}; +} + +#[doc(hidden)] +trait Sip { + fn c_rounds(_: &mut State); + fn d_rounds(_: &mut State); +} + +struct Sip13Rounds; + +impl Sip for Sip13Rounds { + #[inline] + fn c_rounds(state: &mut State) { + compress!(state); + } + + #[inline] + fn d_rounds(state: &mut State) { + compress!(state); + compress!(state); + compress!(state); + } +} + +struct Sip24Rounds; + +impl Sip for Sip24Rounds { + #[inline] + fn c_rounds(state: &mut State) { + compress!(state); + compress!(state); + } + + #[inline] + fn d_rounds(state: &mut State) { + compress!(state); + compress!(state); + compress!(state); + compress!(state); + } +} + +pub struct SipHasher13 { + hasher: Hasher, +} + +struct SipHasher24 { + hasher: Hasher, +} + +pub struct SipHasher(SipHasher24); + +macro_rules! load_int_le { + ($buf:expr, $i:expr, $int_ty:ident) => {{ + let mut data = 0 as $int_ty; + ptr::copy_nonoverlapping( + $buf.as_ptr().add($i), + &mut data as *mut _ as *mut u8, + mem::size_of::<$int_ty>(), + ); + data.to_le() + }}; +} + +#[inline] +unsafe fn u8to64_le(buf: &[u8], start: usize, len: usize) -> u64 { + let mut i = 0; // current byte index (from LSB) in the output u64 + let mut out = 0; + if i + 3 < len { + // SAFETY: `i` cannot be greater than `len`, and the caller must guarantee + // that the index start..start+len is in bounds. + out = unsafe { load_int_le!(buf, start + i, u32) } as u64; + i += 4; + } + if i + 1 < len { + // SAFETY: same as above. + out |= (unsafe { load_int_le!(buf, start + i, u16) } as u64) << ((i * 8) as u64); + i += 2 + } + if i < len { + // SAFETY: same as above. + out |= (unsafe { *buf.get_unchecked(start + i) } as u64) << ((i * 8) as u64); + i += 1; + } + out +} + +impl SipHasher { + #[inline] + #[must_use] + pub fn new() -> SipHasher { + SipHasher::new_with_keys(0, 0) + } + + #[inline] + #[must_use] + pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher { + SipHasher(SipHasher24 { + hasher: Hasher::new_with_keys(key0, key1), + }) + } +} + +impl SipHasher13 { + #[inline] + pub fn new() -> SipHasher13 { + SipHasher13::new_with_keys(0, 0) + } + + #[inline] + pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher13 { + SipHasher13 { + hasher: Hasher::new_with_keys(key0, key1), + } + } +} + +impl Hasher { + #[inline] + fn new_with_keys(key0: u64, key1: u64) -> Hasher { + let mut state = Hasher { + k0: key0, + k1: key1, + length: 0, + state: State { + v0: 0, + v1: 0, + v2: 0, + v3: 0, + }, + tail: 0, + ntail: 0, + _marker: PhantomData, + }; + state.reset(); + state + } + + #[inline] + fn reset(&mut self) { + self.length = 0; + self.state.v0 = self.k0 ^ 0x736f6d6570736575; + self.state.v1 = self.k1 ^ 0x646f72616e646f6d; + self.state.v2 = self.k0 ^ 0x6c7967656e657261; + self.state.v3 = self.k1 ^ 0x7465646279746573; + self.ntail = 0; + } +} + +impl HasherTrait for SipHasher { + #[inline] + fn write(&mut self, msg: &[u8]) { + self.0.hasher.write(msg) + } + + #[inline] + fn finish(&self) -> u64 { + self.0.hasher.finish() + } +} + +impl HasherTrait for SipHasher13 { + #[inline] + fn write(&mut self, msg: &[u8]) { + self.hasher.write(msg) + } + + #[inline] + fn finish(&self) -> u64 { + self.hasher.finish() + } +} + +impl HasherTrait for Hasher { + #[inline] + fn write(&mut self, msg: &[u8]) { + let length = msg.len(); + self.length += length; + + let mut needed = 0; + + if self.ntail != 0 { + needed = 8 - self.ntail; + // SAFETY: `cmp::min(length, needed)` is guaranteed to not be over `length` + self.tail |= + unsafe { u8to64_le(msg, 0, cmp::min(length, needed)) } << ((8 * self.ntail) as u64); + if length < needed { + self.ntail += length; + return; + } else { + self.state.v3 ^= self.tail; + S::c_rounds(&mut self.state); + self.state.v0 ^= self.tail; + self.ntail = 0; + } + } + + // Buffered tail is now flushed, process new input. + let len = length - needed; + let left = len & 0x7; // len % 8 + + let mut i = needed; + while i < len - left { + let mi = unsafe { load_int_le!(msg, i, u64) }; + + self.state.v3 ^= mi; + S::c_rounds(&mut self.state); + self.state.v0 ^= mi; + + i += 8; + } + + self.tail = unsafe { u8to64_le(msg, i, left) }; + self.ntail = left; + } + + #[inline] + fn finish(&self) -> u64 { + let mut state = self.state; + + let b: u64 = ((self.length as u64 & 0xff) << 56) | self.tail; + + state.v3 ^= b; + S::c_rounds(&mut state); + state.v0 ^= b; + + state.v2 ^= 0xff; + S::d_rounds(&mut state); + + state.v0 ^ state.v1 ^ state.v2 ^ state.v3 + } +} + +extern "C" { + fn printf(fmt: *const u8, ...) -> i32; +} + +fn main() -> i32 { + let mut hasher = SipHasher::new_with_keys(0x0706050403020100, 0x0f0e0d0c0b0a0908); + hasher.write(b"Hello"); + let result = hasher.finish(); + + unsafe { + printf("Hash: 0x%016llx\n\0" as *const str as *const u8, result); + } + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/struct-pattern-match.rs b/gcc/testsuite/rust/execute/torture/struct-pattern-match.rs new file mode 100644 index 000000000000..6aec51f93fe0 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/struct-pattern-match.rs @@ -0,0 +1,13 @@ +enum Foo { + A { x: i32 }, + B { y: i32 } +} + +fn main() -> i32 { + let x = Foo::A { x: 12 }; + match x { + Foo::A { x: 10 } => 1, + Foo::B { y: 11 } => 2, + Foo::A { x: abc } => { abc - 12 } + } +} diff --git a/gcc/testsuite/rust/execute/torture/struct_pattern1.rs b/gcc/testsuite/rust/execute/torture/struct_pattern1.rs new file mode 100644 index 000000000000..7a74092ad50c --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/struct_pattern1.rs @@ -0,0 +1,19 @@ +struct A { + // the two warnings are invalid but this should be fixed by our lint rework + // with this year's GSoC so ok for now + a: i32, // { dg-warning "never read" } + b: i32, // { dg-warning "never read" } +} + +fn main() -> i32 { + let a = A { a: 15, b: 14 }; + + let result = match a { + A { + a: self_a, + b: self_b, + } => self_a + self_b, + }; + + result - 29 +} diff --git a/gcc/testsuite/rust/execute/xfail/match-identifierpattern-enum.rs b/gcc/testsuite/rust/execute/xfail/match-identifierpattern-enum.rs new file mode 100644 index 000000000000..c3a0f65fe710 --- /dev/null +++ b/gcc/testsuite/rust/execute/xfail/match-identifierpattern-enum.rs @@ -0,0 +1,15 @@ +enum Foo { + I(i32), +} + +fn main() -> i32 { + let x = Foo::I(0); + let ret = 1; + + match x { + _ @ Foo::I(b) => { ret = b }, + _ => {}, + }; + + ret +} diff --git a/libgrust/libproc_macro_internal/ffistring.h b/libgrust/libproc_macro_internal/ffistring.h index e176bc299850..b133b35bcb0f 100644 --- a/libgrust/libproc_macro_internal/ffistring.h +++ b/libgrust/libproc_macro_internal/ffistring.h @@ -43,11 +43,9 @@ struct FFIString }; extern "C" { -FFIString -FFIString__new (const unsigned char *data, std::uint64_t len); +FFIString FFIString__new (const unsigned char *data, std::uint64_t len); -void -FFIString__drop (FFIString *str); +void FFIString__drop (FFIString *str); } } // namespace ProcMacro diff --git a/libgrust/libproc_macro_internal/ident.h b/libgrust/libproc_macro_internal/ident.h index cdc9b0d5d95d..839471675a78 100644 --- a/libgrust/libproc_macro_internal/ident.h +++ b/libgrust/libproc_macro_internal/ident.h @@ -47,17 +47,13 @@ struct Ident extern "C" { -Ident -Ident__new (FFIString str, Span span); +Ident Ident__new (FFIString str, Span span); -Ident -Ident__new_raw (FFIString str, Span span); +Ident Ident__new_raw (FFIString str, Span span); -void -Ident__drop (Ident *ident); +void Ident__drop (Ident *ident); -Ident -Ident__clone (const Ident *ident); +Ident Ident__clone (const Ident *ident); } } // namespace ProcMacro diff --git a/libgrust/libproc_macro_internal/literal.h b/libgrust/libproc_macro_internal/literal.h index c8579471b9df..b30c69a2925d 100644 --- a/libgrust/libproc_macro_internal/literal.h +++ b/libgrust/libproc_macro_internal/literal.h @@ -105,8 +105,7 @@ struct Literal }; extern "C" { -bool -Literal__from_string (FFIString str, Literal *lit); +bool Literal__from_string (FFIString str, Literal *lit); } } // namespace ProcMacro diff --git a/libgrust/libproc_macro_internal/proc_macro.h b/libgrust/libproc_macro_internal/proc_macro.h index ce9adb24734d..d5f2e20d8d69 100644 --- a/libgrust/libproc_macro_internal/proc_macro.h +++ b/libgrust/libproc_macro_internal/proc_macro.h @@ -96,8 +96,7 @@ struct ProcmacroArray Procmacro *macros; }; -extern "C" bool -bridge_is_available (); +extern "C" bool bridge_is_available (); } // namespace ProcMacro diff --git a/libgrust/libproc_macro_internal/tokenstream.h b/libgrust/libproc_macro_internal/tokenstream.h index 4e13ce7690d9..f24d4ab68925 100644 --- a/libgrust/libproc_macro_internal/tokenstream.h +++ b/libgrust/libproc_macro_internal/tokenstream.h @@ -51,23 +51,17 @@ struct TokenStream static void drop (TokenStream *stream); }; -extern "C" TokenStream -TokenStream__new (); +extern "C" TokenStream TokenStream__new (); -extern "C" TokenStream -TokenStream__with_capacity (std::uint64_t capacity); +extern "C" TokenStream TokenStream__with_capacity (std::uint64_t capacity); -extern "C" void -TokenSream__push (TokenStream *stream, TokenTree tree); +extern "C" void TokenSream__push (TokenStream *stream, TokenTree tree); -extern "C" bool -TokenStream__from_string (FFIString str, TokenStream *ts); +extern "C" bool TokenStream__from_string (FFIString str, TokenStream *ts); -extern "C" TokenStream -TokenStream__clone (const TokenStream *ts); +extern "C" TokenStream TokenStream__clone (const TokenStream *ts); -extern "C" void -TokenStream__drop (TokenStream *stream); +extern "C" void TokenStream__drop (TokenStream *stream); } // namespace ProcMacro