diff --git a/gcc/rust/Make-lang.in b/gcc/rust/Make-lang.in index 73ec2193f50d..58a5d5f73636 100644 --- a/gcc/rust/Make-lang.in +++ b/gcc/rust/Make-lang.in @@ -131,6 +131,7 @@ GRS_OBJS = \ rust/rust-default-resolver.o \ rust/rust-toplevel-name-resolver-2.0.o \ rust/rust-early-name-resolver-2.0.o \ + rust/rust-finalize-imports-2.0.o \ rust/rust-late-name-resolver-2.0.o \ rust/rust-immutable-name-resolution-context.o \ rust/rust-early-name-resolver.o \ @@ -171,6 +172,7 @@ GRS_OBJS = \ rust/rust-borrow-checker.o \ rust/rust-borrow-checker-diagnostics.o\ rust/rust-bir-builder-expr-stmt.o \ + rust/rust-bir-builder-pattern.o \ rust/rust-bir-dump.o \ rust/rust-polonius.o\ rust/rust-hir-dot-operator.o \ diff --git a/gcc/rust/ast/rust-ast-visitor.h b/gcc/rust/ast/rust-ast-visitor.h index 80214fa7fcec..7d418989c049 100644 --- a/gcc/rust/ast/rust-ast-visitor.h +++ b/gcc/rust/ast/rust-ast-visitor.h @@ -244,7 +244,6 @@ class DefaultASTVisitor : public ASTVisitor public: virtual void visit (AST::Crate &crate); -protected: virtual void visit (AST::Token &tok) override; virtual void visit (AST::DelimTokenTree &delim_tok_tree) override; virtual void visit (AST::AttrInputMetaItemContainer &input) override; diff --git a/gcc/rust/ast/rust-ast.h b/gcc/rust/ast/rust-ast.h index dc0fd8b0e478..35f27e37dcd4 100644 --- a/gcc/rust/ast/rust-ast.h +++ b/gcc/rust/ast/rust-ast.h @@ -1587,7 +1587,7 @@ class GenericParam : public Visitable virtual Kind get_kind () const = 0; - NodeId get_node_id () { return node_id; } + NodeId get_node_id () const { return node_id; } protected: GenericParam () : node_id (Analysis::Mappings::get ().get_next_node_id ()) {} diff --git a/gcc/rust/ast/rust-item.h b/gcc/rust/ast/rust-item.h index 8a156663fa72..f6b29130cb8a 100644 --- a/gcc/rust/ast/rust-item.h +++ b/gcc/rust/ast/rust-item.h @@ -1213,7 +1213,7 @@ class UseTreeRebind : public UseTree std::string as_string () const override; - NewBindType get_new_bind_type () { return bind_type; } + NewBindType get_new_bind_type () const { return bind_type; } void accept_vis (ASTVisitor &vis) override; diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-builder-pattern.cc b/gcc/rust/checks/errors/borrowck/rust-bir-builder-pattern.cc new file mode 100644 index 000000000000..723ff7334b62 --- /dev/null +++ b/gcc/rust/checks/errors/borrowck/rust-bir-builder-pattern.cc @@ -0,0 +1,273 @@ +#include "rust-bir-builder-pattern.h" + +namespace Rust { +namespace BIR { + +void +PatternBindingBuilder::visit_identifier (const Analysis::NodeMapping &node, + bool is_ref, location_t location, + bool is_mut) +{ + if (is_ref) + { + translated = declare_variable ( + node, + new TyTy::ReferenceType (node.get_hirid (), + TyTy::TyVar (node.get_hirid ()), + (is_mut) ? Mutability::Mut : Mutability::Imm)); + } + else + { + translated = declare_variable (node); + } + + if (init.has_value ()) + { + push_assignment (translated, init.value (), location); + } +} + +void +PatternBindingBuilder::visit (HIR::IdentifierPattern &pattern) +{ + // Top-level identifiers are resolved directly to avoid useless temporary + // (for cleaner BIR). + visit_identifier (pattern.get_mappings (), pattern.get_is_ref (), + pattern.get_locus (), pattern.is_mut ()); +} + +void +PatternBindingBuilder::visit (HIR::ReferencePattern &pattern) +{ + SavedState saved (this); + + init = init.map ([&] (PlaceId id) { + return ctx.place_db.lookup_or_add_path (Place::DEREF, lookup_type (pattern), + id); + }); + + type_annotation = type_annotation.map ([&] (TyTy::BaseType *ty) { + return ty->as ()->get_base (); + }); + + pattern.get_referenced_pattern ()->accept_vis (*this); +} + +void +PatternBindingBuilder::visit (HIR::SlicePattern &pattern) +{ + SavedState saved (this); + + // All indexes are supposed to point to the same place for borrow-checking. + // init = ctx.place_db.lookup_or_add_path (Place::INDEX, lookup_type + // (pattern), saved.init); + init = init.map ([&] (PlaceId id) { + return ctx.place_db.lookup_or_add_path (Place::INDEX, lookup_type (pattern), + id); + }); + + type_annotation = type_annotation.map ([&] (TyTy::BaseType *ty) { + return ty->as ()->get_element_type (); + }); + + // Regions are unchnaged. + + for (auto &item : pattern.get_items ()) + { + item->accept_vis (*this); + } +} + +void +PatternBindingBuilder::visit (HIR::AltPattern &pattern) +{ + rust_sorry_at (pattern.get_locus (), + "borrow-checking of alt patterns is not yet implemented"); +} + +void +PatternBindingBuilder::visit (HIR::StructPattern &pattern) +{ + SavedState saved (this); + + auto tyty = ctx.place_db[init.value ()].tyty; + rust_assert (tyty->get_kind () == TyTy::ADT); + auto adt_ty = static_cast (tyty); + rust_assert (adt_ty->is_struct_struct ()); + auto struct_ty = adt_ty->get_variants ().at (0); + + for (auto &field : + pattern.get_struct_pattern_elems ().get_struct_pattern_fields ()) + { + switch (field->get_item_type ()) + { + case HIR::StructPatternField::TUPLE_PAT: { + auto tuple + = static_cast (field.get ()); + + init = init.map ([&] (PlaceId id) { + return ctx.place_db.lookup_or_add_path ( + Place::FIELD, lookup_type (*tuple->get_tuple_pattern ()), id, + tuple->get_index ()); + }); + + type_annotation = type_annotation.map ([&] (TyTy::BaseType *ty) { + return ty->as () + ->get_variants () + .at (0) + ->get_fields () + .at (tuple->get_index ()) + ->get_field_type (); + }); + + tuple->get_tuple_pattern ()->accept_vis (*this); + break; + } + case HIR::StructPatternField::IDENT_PAT: { + auto ident_field + = static_cast (field.get ()); + TyTy::StructFieldType *field_ty = nullptr; + size_t field_index = 0; + auto ok = struct_ty->lookup_field ( + ident_field->get_identifier ().as_string (), &field_ty, + &field_index); + rust_assert (ok); + init = ctx.place_db.lookup_or_add_path (Place::FIELD, + field_ty->get_field_type (), + saved.init.value (), + field_index); + ident_field->get_pattern ()->accept_vis (*this); + break; + } + case HIR::StructPatternField::IDENT: { + auto ident_field + = static_cast (field.get ()); + TyTy::StructFieldType *field_ty = nullptr; + size_t field_index = 0; + auto ok = struct_ty->lookup_field ( + ident_field->get_identifier ().as_string (), &field_ty, + &field_index); + rust_assert (ok); + init = ctx.place_db.lookup_or_add_path (Place::FIELD, + field_ty->get_field_type (), + saved.init.value (), + field_index); + visit_identifier (ident_field->get_mappings (), + ident_field->get_has_ref (), + ident_field->get_locus (), + ident_field->is_mut ()); + break; + } + } + } +} + +void +PatternBindingBuilder::visit_tuple_fields ( + std::vector> &fields, SavedState &saved, + size_t &index) +{ + for (auto &item : fields) + { + auto type = lookup_type (*item); + + init = init.map ([&] (PlaceId id) { + return ctx.place_db.lookup_or_add_path (Place::FIELD, type, id, index); + }); + + type_annotation = type_annotation.map ([&] (TyTy::BaseType *ty) { + return ty->as ()->get_fields ().at (index).get_tyty (); + }); + + regions = regions.map ([&] (FreeRegions regs) { + return bind_regions (Resolver::TypeCheckContext::get () + ->get_variance_analysis_ctx () + .query_type_regions (type), + regs); + }); + + item->accept_vis (*this); + index++; + } +} + +void +PatternBindingBuilder::visit (HIR::TuplePattern &pattern) +{ + SavedState saved (this); + + size_t index = 0; + switch (pattern.get_items ()->get_item_type ()) + { + case HIR::TuplePatternItems::MULTIPLE: { + auto &items = static_cast ( + *pattern.get_items ()); + visit_tuple_fields (items.get_patterns (), saved, index); + break; + } + case HIR::TuplePatternItems::RANGED: { + auto &items + = static_cast (*pattern.get_items ()); + + auto tyty = ctx.place_db[init.value ()].tyty; + rust_assert (tyty->get_kind () == TyTy::TUPLE); + + auto skipped = (static_cast (tyty))->num_fields () + - items.get_lower_patterns ().size () + - items.get_upper_patterns ().size (); + + visit_tuple_fields (items.get_lower_patterns (), saved, index); + index += skipped; + visit_tuple_fields (items.get_upper_patterns (), saved, index); + break; + } + } + init = saved.init; +} + +void +PatternBindingBuilder::visit (HIR::TupleStructPattern &pattern) +{ + SavedState saved (this); + + type_annotation = tl::nullopt; + + auto type = lookup_type (pattern); + + regions = regions.map ([&] (FreeRegions regs) { + return bind_regions (Resolver::TypeCheckContext::get () + ->get_variance_analysis_ctx () + .query_type_regions (type), + regs); + }); + + size_t index = 0; + switch (pattern.get_items ()->get_item_type ()) + { + case HIR::TupleStructItems::RANGED: { + auto &items + = static_cast (*pattern.get_items ()); + + rust_assert (type->get_kind () == TyTy::ADT); + auto adt_ty = static_cast (type); + rust_assert (adt_ty->is_tuple_struct ()); + + auto skipped = adt_ty->get_variants ().at (0)->get_fields ().size () + - items.get_lower_patterns ().size () + - items.get_upper_patterns ().size (); + + visit_tuple_fields (items.get_lower_patterns (), saved, index); + index += skipped; + visit_tuple_fields (items.get_upper_patterns (), saved, index); + break; + } + case HIR::TupleStructItems::MULTIPLE: { + auto &items + = static_cast (*pattern.get_items ()); + visit_tuple_fields (items.get_patterns (), saved, index); + break; + } + } +} +} // namespace BIR +} // namespace Rust diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-builder-pattern.h b/gcc/rust/checks/errors/borrowck/rust-bir-builder-pattern.h index 1bdd1168ad18..698607459f68 100644 --- a/gcc/rust/checks/errors/borrowck/rust-bir-builder-pattern.h +++ b/gcc/rust/checks/errors/borrowck/rust-bir-builder-pattern.h @@ -65,266 +65,24 @@ class PatternBindingBuilder : protected AbstractBuilder, void go (HIR::Pattern &pattern) { pattern.accept_vis (*this); } void visit_identifier (const Analysis::NodeMapping &node, bool is_ref, - location_t location, bool is_mut = false) - { - if (is_ref) - { - translated = declare_variable ( - node, new TyTy::ReferenceType (node.get_hirid (), - TyTy::TyVar (node.get_hirid ()), - (is_mut) ? Mutability::Mut - : Mutability::Imm)); - } - else - { - translated = declare_variable (node); - } - - if (init.has_value ()) - { - push_assignment (translated, init.value (), location); - } - } - - void visit (HIR::IdentifierPattern &pattern) override - { - // Top-level identifiers are resolved directly to avoid useless temporary - // (for cleaner BIR). - visit_identifier (pattern.get_mappings (), pattern.get_is_ref (), - pattern.get_locus (), pattern.is_mut ()); - } - - void visit (HIR::ReferencePattern &pattern) override - { - SavedState saved (this); - - init = init.map ([&] (PlaceId id) { - return ctx.place_db.lookup_or_add_path (Place::DEREF, - lookup_type (pattern), id); - }); - - type_annotation = type_annotation.map ([&] (TyTy::BaseType *ty) { - return ty->as ()->get_base (); - }); - - pattern.get_referenced_pattern ()->accept_vis (*this); - } - - void visit (HIR::SlicePattern &pattern) override - { - SavedState saved (this); - - // All indexes are supposed to point to the same place for borrow-checking. - // init = ctx.place_db.lookup_or_add_path (Place::INDEX, lookup_type - // (pattern), saved.init); - init = init.map ([&] (PlaceId id) { - return ctx.place_db.lookup_or_add_path (Place::INDEX, - lookup_type (pattern), id); - }); - - type_annotation = type_annotation.map ([&] (TyTy::BaseType *ty) { - return ty->as ()->get_element_type (); - }); - - // Regions are unchnaged. - - for (auto &item : pattern.get_items ()) - { - item->accept_vis (*this); - } - } - - void visit (HIR::AltPattern &pattern) override - { - rust_sorry_at (pattern.get_locus (), - "borrow-checking of alt patterns is not yet implemented"); - } - - void visit (HIR::StructPattern &pattern) override - { - SavedState saved (this); + location_t location, bool is_mut = false); - auto tyty = ctx.place_db[init.value ()].tyty; - rust_assert (tyty->get_kind () == TyTy::ADT); - auto adt_ty = static_cast (tyty); - rust_assert (adt_ty->is_struct_struct ()); - auto struct_ty = adt_ty->get_variants ().at (0); + void visit (HIR::IdentifierPattern &pattern) override; - for (auto &field : - pattern.get_struct_pattern_elems ().get_struct_pattern_fields ()) - { - switch (field->get_item_type ()) - { - case HIR::StructPatternField::TUPLE_PAT: { - auto tuple - = static_cast (field.get ()); + void visit (HIR::ReferencePattern &pattern) override; - init = init.map ([&] (PlaceId id) { - return ctx.place_db.lookup_or_add_path ( - Place::FIELD, lookup_type (*tuple->get_tuple_pattern ()), id, - tuple->get_index ()); - }); + void visit (HIR::SlicePattern &pattern) override; - type_annotation = type_annotation.map ([&] (TyTy::BaseType *ty) { - return ty->as () - ->get_variants () - .at (0) - ->get_fields () - .at (tuple->get_index ()) - ->get_field_type (); - }); + void visit (HIR::AltPattern &pattern) override; - tuple->get_tuple_pattern ()->accept_vis (*this); - break; - } - case HIR::StructPatternField::IDENT_PAT: { - auto ident_field - = static_cast (field.get ()); - TyTy::StructFieldType *field_ty = nullptr; - size_t field_index = 0; - auto ok = struct_ty->lookup_field ( - ident_field->get_identifier ().as_string (), &field_ty, - &field_index); - rust_assert (ok); - init - = ctx.place_db.lookup_or_add_path (Place::FIELD, - field_ty->get_field_type (), - saved.init.value (), - field_index); - ident_field->get_pattern ()->accept_vis (*this); - break; - } - case HIR::StructPatternField::IDENT: { - auto ident_field - = static_cast (field.get ()); - TyTy::StructFieldType *field_ty = nullptr; - size_t field_index = 0; - auto ok = struct_ty->lookup_field ( - ident_field->get_identifier ().as_string (), &field_ty, - &field_index); - rust_assert (ok); - init - = ctx.place_db.lookup_or_add_path (Place::FIELD, - field_ty->get_field_type (), - saved.init.value (), - field_index); - visit_identifier (ident_field->get_mappings (), - ident_field->get_has_ref (), - ident_field->get_locus (), - ident_field->is_mut ()); - break; - } - } - } - } + void visit (HIR::StructPattern &pattern) override; void visit_tuple_fields (std::vector> &fields, - SavedState &saved, size_t &index) - { - for (auto &item : fields) - { - auto type = lookup_type (*item); - - init = init.map ([&] (PlaceId id) { - return ctx.place_db.lookup_or_add_path (Place::FIELD, type, id, - index); - }); - - type_annotation = type_annotation.map ([&] (TyTy::BaseType *ty) { - return ty->as () - ->get_fields () - .at (index) - .get_tyty (); - }); - - regions = regions.map ([&] (FreeRegions regs) { - return bind_regions (Resolver::TypeCheckContext::get () - ->get_variance_analysis_ctx () - .query_type_regions (type), - regs); - }); - - item->accept_vis (*this); - index++; - } - } - - void visit (HIR::TuplePattern &pattern) override - { - SavedState saved (this); - - size_t index = 0; - switch (pattern.get_items ()->get_item_type ()) - { - case HIR::TuplePatternItems::MULTIPLE: { - auto &items = static_cast ( - *pattern.get_items ()); - visit_tuple_fields (items.get_patterns (), saved, index); - break; - } - case HIR::TuplePatternItems::RANGED: { - auto &items = static_cast ( - *pattern.get_items ()); - - auto tyty = ctx.place_db[init.value ()].tyty; - rust_assert (tyty->get_kind () == TyTy::TUPLE); - - auto skipped = (static_cast (tyty))->num_fields () - - items.get_lower_patterns ().size () - - items.get_upper_patterns ().size (); - - visit_tuple_fields (items.get_lower_patterns (), saved, index); - index += skipped; - visit_tuple_fields (items.get_upper_patterns (), saved, index); - break; - } - } - init = saved.init; - } - - void visit (HIR::TupleStructPattern &pattern) override - { - SavedState saved (this); - - type_annotation = tl::nullopt; - - auto type = lookup_type (pattern); - - regions = regions.map ([&] (FreeRegions regs) { - return bind_regions (Resolver::TypeCheckContext::get () - ->get_variance_analysis_ctx () - .query_type_regions (type), - regs); - }); - - size_t index = 0; - switch (pattern.get_items ()->get_item_type ()) - { - case HIR::TupleStructItems::RANGED: { - auto &items - = static_cast (*pattern.get_items ()); - - rust_assert (type->get_kind () == TyTy::ADT); - auto adt_ty = static_cast (type); - rust_assert (adt_ty->is_tuple_struct ()); + SavedState &saved, size_t &index); - auto skipped = adt_ty->get_variants ().at (0)->get_fields ().size () - - items.get_lower_patterns ().size () - - items.get_upper_patterns ().size (); + void visit (HIR::TuplePattern &pattern) override; - visit_tuple_fields (items.get_lower_patterns (), saved, index); - index += skipped; - visit_tuple_fields (items.get_upper_patterns (), saved, index); - break; - } - case HIR::TupleStructItems::MULTIPLE: { - auto &items = static_cast ( - *pattern.get_items ()); - visit_tuple_fields (items.get_patterns (), saved, index); - break; - } - } - } + void visit (HIR::TupleStructPattern &pattern) override; void visit (HIR::WildcardPattern &pattern) override {} // Unused for binding. diff --git a/gcc/rust/resolve/rust-default-resolver.cc b/gcc/rust/resolve/rust-default-resolver.cc index 1a9d377aa1ea..5d0f7a0e9303 100644 --- a/gcc/rust/resolve/rust-default-resolver.cc +++ b/gcc/rust/resolve/rust-default-resolver.cc @@ -30,13 +30,7 @@ DefaultResolver::visit (AST::BlockExpr &expr) // extracting the lambda from the `scoped` call otherwise the code looks like // a hot turd thanks to our .clang-format - auto inner_fn = [this, &expr] () { - for (auto &stmt : expr.get_statements ()) - stmt->accept_vis (*this); - - if (expr.has_tail_expr ()) - expr.get_tail_expr ().accept_vis (*this); - }; + auto inner_fn = [this, &expr] () { AST::DefaultASTVisitor::visit (expr); }; ctx.scoped (Rib::Kind::Normal, expr.get_node_id (), inner_fn); } @@ -44,10 +38,7 @@ DefaultResolver::visit (AST::BlockExpr &expr) void DefaultResolver::visit (AST::Module &module) { - auto item_fn = [this, &module] () { - for (auto &item : module.get_items ()) - item->accept_vis (*this); - }; + auto item_fn = [this, &module] () { AST::DefaultASTVisitor::visit (module); }; ctx.scoped (Rib::Kind::Module, module.get_node_id (), item_fn, module.get_name ()); @@ -56,35 +47,8 @@ DefaultResolver::visit (AST::Module &module) void DefaultResolver::visit (AST::Function &function) { - auto def_fn = [this, &function] () { - for (auto &p : function.get_function_params ()) - { - if (p->is_variadic ()) - { - auto ¶m = static_cast (*p); - if (param.has_pattern ()) - param.get_pattern ().accept_vis (*this); - } - else if (p->is_self ()) - { - auto ¶m = static_cast (*p); - param.get_type ().accept_vis (*this); - param.get_lifetime ().accept_vis (*this); - } - else - { - auto ¶m = static_cast (*p); - param.get_pattern ().accept_vis (*this); - param.get_type ().accept_vis (*this); - } - } - - if (function.has_return_type ()) - visit (function.get_return_type ()); - - if (function.has_body ()) - function.get_definition ().value ()->accept_vis (*this); - }; + auto def_fn + = [this, &function] () { AST::DefaultASTVisitor::visit (function); }; ctx.scoped (Rib::Kind::Function, function.get_node_id (), def_fn); } @@ -92,20 +56,14 @@ DefaultResolver::visit (AST::Function &function) void DefaultResolver::visit (AST::ForLoopExpr &expr) { - ctx.scoped (Rib::Kind::Normal, expr.get_node_id (), [this, &expr] () { - expr.get_pattern ().accept_vis (*this); - expr.get_iterator_expr ().accept_vis (*this); - expr.get_loop_block ().accept_vis (*this); - }); + ctx.scoped (Rib::Kind::Normal, expr.get_node_id (), + [this, &expr] () { AST::DefaultASTVisitor::visit (expr); }); } void DefaultResolver::visit (AST::Trait &trait) { - auto inner_fn = [this, &trait] () { - for (auto &item : trait.get_trait_items ()) - item->accept_vis (*this); - }; + auto inner_fn = [this, &trait] () { AST::DefaultASTVisitor::visit (trait); }; ctx.scoped (Rib::Kind::TraitOrImpl, trait.get_node_id (), inner_fn, trait.get_identifier () /* FIXME: Is that valid?*/); @@ -114,11 +72,7 @@ DefaultResolver::visit (AST::Trait &trait) void DefaultResolver::visit (AST::InherentImpl &impl) { - auto inner_fn = [this, &impl] () { - visit (impl.get_type ()); - for (auto &item : impl.get_impl_items ()) - item->accept_vis (*this); - }; + auto inner_fn = [this, &impl] () { AST::DefaultASTVisitor::visit (impl); }; ctx.scoped (Rib::Kind::TraitOrImpl, impl.get_node_id (), inner_fn); } @@ -126,10 +80,7 @@ DefaultResolver::visit (AST::InherentImpl &impl) void DefaultResolver::visit (AST::TraitImpl &impl) { - auto inner_fn = [this, &impl] () { - for (auto &item : impl.get_impl_items ()) - item->accept_vis (*this); - }; + auto inner_fn = [this, &impl] () { AST::DefaultASTVisitor::visit (impl); }; ctx.scoped (Rib::Kind::TraitOrImpl, impl.get_node_id (), inner_fn); } @@ -152,40 +103,19 @@ DefaultResolver::visit (AST::Enum &type) { // FIXME: Do we need to scope anything by default? - auto variant_fn = [this, &type] () { - for (auto &variant : type.get_variants ()) - variant->accept_vis (*this); - }; + auto variant_fn = [this, &type] () { AST::DefaultASTVisitor::visit (type); }; ctx.scoped (Rib::Kind::Item /* FIXME: Correct? */, type.get_node_id (), variant_fn, type.get_identifier ()); } -void -DefaultResolver::visit (AST::StructExprFieldIdentifierValue &) -{} - -void -DefaultResolver::visit (AST::StructExprFieldIndexValue &) -{} - void DefaultResolver::visit (AST::ClosureExprInner &expr) { if (expr.is_marked_for_strip ()) return; - for (auto ¶m : expr.get_params ()) - { - if (param.is_error ()) - continue; - - param.get_pattern ().accept_vis (*this); - if (param.has_type_given ()) - param.get_type ().accept_vis (*this); - } - - expr.get_definition_expr ().accept_vis (*this); + AST::DefaultASTVisitor::visit (expr); } void @@ -194,286 +124,16 @@ DefaultResolver::visit (AST::ClosureExprInnerTyped &expr) if (expr.is_marked_for_strip ()) return; - for (auto ¶m : expr.get_params ()) - { - if (param.is_error ()) - continue; - - param.get_pattern ().accept_vis (*this); - if (param.has_type_given ()) - param.get_type ().accept_vis (*this); - } - - expr.get_definition_block ().accept_vis (*this); - expr.get_return_type ().accept_vis (*this); -} - -void -DefaultResolver::visit (AST::ContinueExpr &expr) -{} - -void -DefaultResolver::visit (AST::RangeFromToExpr &expr) -{} - -void -DefaultResolver::visit (AST::RangeFromExpr &expr) -{} - -void -DefaultResolver::visit (AST::RangeToExpr &expr) -{} - -void -DefaultResolver::visit (AST::RangeFromToInclExpr &expr) -{} - -void -DefaultResolver::visit (AST::RangeToInclExpr &expr) -{} - -void -DefaultResolver::visit (AST::ReturnExpr &expr) -{} - -void -DefaultResolver::visit (AST::CallExpr &expr) -{ - expr.get_function_expr ().accept_vis (*this); - - for (auto ¶m : expr.get_params ()) - param->accept_vis (*this); -} - -void -DefaultResolver::visit (AST::MethodCallExpr &expr) -{ - expr.get_receiver_expr ().accept_vis (*this); - - if (expr.get_method_name ().has_generic_args ()) - { - auto &args = expr.get_method_name ().get_generic_args (); - for (auto &arg : args.get_generic_args ()) - arg.accept_vis (*this); - for (auto &arg : args.get_binding_args ()) - if (!arg.is_error ()) - arg.get_type ().accept_vis (*this); - for (auto &arg : args.get_lifetime_args ()) - arg.accept_vis (*this); - } - - for (auto ¶m : expr.get_params ()) - param->accept_vis (*this); -} - -void -DefaultResolver::visit (AST::LoopExpr &expr) -{} - -void -DefaultResolver::visit (AST::WhileLoopExpr &expr) -{} - -void -DefaultResolver::visit (AST::WhileLetLoopExpr &expr) -{} - -void -DefaultResolver::visit (AST::IfExpr &expr) -{ - expr.get_condition_expr ().accept_vis (*this); - expr.get_if_block ().accept_vis (*this); -} - -void -DefaultResolver::visit (AST::IfExprConseqElse &expr) -{ - expr.get_condition_expr ().accept_vis (*this); - expr.get_if_block ().accept_vis (*this); - expr.get_else_block ().accept_vis (*this); + AST::DefaultASTVisitor::visit (expr); } -void -DefaultResolver::visit (AST::IfLetExpr &expr) -{} - -void -DefaultResolver::visit (AST::IfLetExprConseqElse &) -{} - void DefaultResolver::visit (AST::MatchExpr &expr) { if (expr.is_marked_for_strip ()) return; - expr.get_scrutinee_expr ().accept_vis (*this); - for (auto &arm : expr.get_match_cases ()) - { - arm.get_expr ().accept_vis (*this); - for (auto &pat : arm.get_arm ().get_patterns ()) - pat->accept_vis (*this); - if (arm.get_arm ().has_match_arm_guard ()) - arm.get_arm ().get_guard_expr ().accept_vis (*this); - } -} - -void -DefaultResolver::visit (AST::AwaitExpr &expr) -{} - -void -DefaultResolver::visit (AST::AsyncBlockExpr &expr) -{} - -void -DefaultResolver::visit (AST::DelimTokenTree &) -{} - -void -DefaultResolver::visit (AST::AttrInputMetaItemContainer &) -{} - -void -DefaultResolver::visit (AST::IdentifierExpr &expr) -{} - -void -DefaultResolver::visit (AST::LifetimeParam &) -{} - -void -DefaultResolver::visit (AST::ConstGenericParam &) -{} - -void -DefaultResolver::visit (AST::PathInExpression &expr) -{ - for (auto &seg : expr.get_segments ()) - if (seg.has_generic_args ()) - { - auto &args = seg.get_generic_args (); - for (auto &arg : args.get_generic_args ()) - arg.accept_vis (*this); - for (auto &arg : args.get_binding_args ()) - if (!arg.is_error ()) - arg.get_type ().accept_vis (*this); - for (auto &arg : args.get_lifetime_args ()) - arg.accept_vis (*this); - } -} - -void -DefaultResolver::visit (AST::TypePathSegmentGeneric &) -{} - -void -DefaultResolver::visit (AST::TypePathSegmentFunction &) -{} - -void -DefaultResolver::visit (AST::TypePath &) -{} - -void -DefaultResolver::visit (AST::QualifiedPathInExpression &) -{} - -void -DefaultResolver::visit (AST::QualifiedPathInType &) -{} - -void -DefaultResolver::visit (AST::LiteralExpr &expr) -{} - -void -DefaultResolver::visit (AST::AttrInputLiteral &) -{} - -void -DefaultResolver::visit (AST::AttrInputMacro &) -{} - -void -DefaultResolver::visit (AST::MetaItemLitExpr &expr) -{} - -void -DefaultResolver::visit (AST::MetaItemPathLit &) -{} - -void -DefaultResolver::visit (AST::StructExprStruct &) -{} - -void -DefaultResolver::visit (AST::StructExprStructFields &) -{} - -void -DefaultResolver::visit (AST::StructExprStructBase &) -{} - -void -DefaultResolver::visit (AST::TypeParam &) -{} - -void -DefaultResolver::visit (AST::LifetimeWhereClauseItem &) -{} - -void -DefaultResolver::visit (AST::TypeBoundWhereClauseItem &) -{} - -void -DefaultResolver::visit (AST::ExternCrate &) -{} - -void -DefaultResolver::visit (AST::UseTreeGlob &) -{} - -void -DefaultResolver::visit (AST::UseTreeList &) -{} - -void -DefaultResolver::visit (AST::UseTreeRebind &) -{} - -void -DefaultResolver::visit (AST::UseDeclaration &) -{} - -void -DefaultResolver::visit (AST::TypeAlias &) -{} - -void -DefaultResolver::visit (AST::EnumItem &) -{} - -void -DefaultResolver::visit (AST::EnumItemTuple &item) -{ - for (auto &field : item.get_tuple_fields ()) - field.get_field_type ().accept_vis (*this); -} - -void -DefaultResolver::visit (AST::EnumItemStruct &item) -{ - for (auto &field : item.get_struct_fields ()) - field.get_field_type ().accept_vis (*this); -} - -void -DefaultResolver::visit (AST::EnumItemDiscriminant &item) -{ - if (item.has_expr ()) - item.get_expr ().accept_vis (*this); + AST::DefaultASTVisitor::visit (expr); } void @@ -481,10 +141,8 @@ DefaultResolver::visit (AST::ConstantItem &item) { if (item.has_expr ()) { - auto expr_vis = [this, &item] () { - item.get_expr ().accept_vis (*this); - visit (item.get_type ()); - }; + auto expr_vis + = [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); @@ -494,103 +152,11 @@ DefaultResolver::visit (AST::ConstantItem &item) void DefaultResolver::visit (AST::StaticItem &item) { - auto expr_vis = [this, &item] () { item.get_expr ().accept_vis (*this); }; + auto expr_vis = [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); } -void -DefaultResolver::visit (AST::TraitItemConst &) -{} - -void -DefaultResolver::visit (AST::TraitItemType &) -{} - -void -DefaultResolver::visit (AST::ExternalTypeItem &) -{} - -void -DefaultResolver::visit (AST::ExternalStaticItem &) -{} - -void -DefaultResolver::visit (AST::MacroMatchRepetition &) -{} - -void -DefaultResolver::visit (AST::MacroMatcher &) -{} - -void -DefaultResolver::visit (AST::MacroRulesDefinition &) -{} - -void -DefaultResolver::visit (AST::MacroInvocation &) -{} - -void -DefaultResolver::visit (AST::MetaItemPath &) -{} - -void -DefaultResolver::visit (AST::MetaItemSeq &) -{} - -void -DefaultResolver::visit (AST::MetaListPaths &) -{} - -void -DefaultResolver::visit (AST::MetaListNameValueStr &) -{} - -void -DefaultResolver::visit (AST::AltPattern &) -{} - -void -DefaultResolver::visit (AST::EmptyStmt &) -{} - -void -DefaultResolver::visit (AST::TraitBound &) -{} - -void -DefaultResolver::visit (AST::ImplTraitType &) -{} - -void -DefaultResolver::visit (AST::TraitObjectType &) -{} - -void -DefaultResolver::visit (AST::ImplTraitTypeOneBound &) -{} - -void -DefaultResolver::visit (AST::TraitObjectTypeOneBound &) -{} - -void -DefaultResolver::visit (AST::BareFunctionType &) -{} - -void -DefaultResolver::visit (AST::SelfParam &) -{} - -void -DefaultResolver::visit (AST::FunctionParam &) -{} - -void -DefaultResolver::visit (AST::VariadicParam &) -{} - } // namespace Resolver2_0 } // namespace Rust diff --git a/gcc/rust/resolve/rust-default-resolver.h b/gcc/rust/resolve/rust-default-resolver.h index c554ee8b8e63..21e67d8e5c5e 100644 --- a/gcc/rust/resolve/rust-default-resolver.h +++ b/gcc/rust/resolve/rust-default-resolver.h @@ -42,101 +42,26 @@ class DefaultResolver : public AST::DefaultASTVisitor // 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 - void visit (AST::BlockExpr &); - void visit (AST::Module &); - void visit (AST::Function &); - void visit (AST::ForLoopExpr &); - void visit (AST::Trait &); - void visit (AST::InherentImpl &); - void visit (AST::TraitImpl &); + void visit (AST::BlockExpr &) override; + void visit (AST::Module &) override; + void visit (AST::Function &) override; + void visit (AST::ForLoopExpr &expr) override; + void visit (AST::Trait &) override; + void visit (AST::InherentImpl &) override; + void visit (AST::TraitImpl &) override; // type dec nodes, which visit their fields or variants by default - void visit (AST::StructStruct &); - void visit (AST::Enum &); + void visit (AST::StructStruct &) override; + void visit (AST::Enum &) override; // Visitors that visit their expression node(s) - void visit (AST::StructExprFieldIdentifierValue &); - void visit (AST::StructExprFieldIndexValue &); - void visit (AST::ClosureExprInner &); - void visit (AST::ClosureExprInnerTyped &); - void visit (AST::ContinueExpr &); - void visit (AST::RangeFromToExpr &); - void visit (AST::RangeFromExpr &); - void visit (AST::RangeToExpr &); - void visit (AST::RangeFromToInclExpr &); - void visit (AST::RangeToInclExpr &); - void visit (AST::ReturnExpr &); - void visit (AST::CallExpr &); - void visit (AST::MethodCallExpr &); - void visit (AST::LoopExpr &); - void visit (AST::WhileLoopExpr &); - void visit (AST::WhileLetLoopExpr &); - void visit (AST::IfExpr &); - void visit (AST::IfExprConseqElse &); - void visit (AST::IfLetExpr &); - void visit (AST::IfLetExprConseqElse &); - void visit (AST::MatchExpr &); - void visit (AST::AwaitExpr &); - void visit (AST::AsyncBlockExpr &); + void visit (AST::ClosureExprInner &) override; + void visit (AST::ClosureExprInnerTyped &) override; + void visit (AST::MatchExpr &) override; // Leaf visitors, which do nothing by default - void visit (AST::DelimTokenTree &); - void visit (AST::AttrInputMetaItemContainer &); - void visit (AST::IdentifierExpr &); - void visit (AST::LifetimeParam &); - void visit (AST::ConstGenericParam &); - void visit (AST::PathInExpression &); - void visit (AST::TypePathSegmentGeneric &); - void visit (AST::TypePathSegmentFunction &); - void visit (AST::TypePath &); - void visit (AST::QualifiedPathInExpression &); - void visit (AST::QualifiedPathInType &); - void visit (AST::LiteralExpr &); - void visit (AST::AttrInputLiteral &); - void visit (AST::AttrInputMacro &); - void visit (AST::MetaItemLitExpr &); - void visit (AST::MetaItemPathLit &); - void visit (AST::StructExprStruct &); - void visit (AST::StructExprStructFields &); - void visit (AST::StructExprStructBase &); - void visit (AST::TypeParam &); - void visit (AST::LifetimeWhereClauseItem &); - void visit (AST::TypeBoundWhereClauseItem &); - void visit (AST::ExternCrate &); - void visit (AST::UseTreeGlob &); - void visit (AST::UseTreeList &); - void visit (AST::UseTreeRebind &); - void visit (AST::UseDeclaration &); - void visit (AST::TypeAlias &); - void visit (AST::EnumItem &); - void visit (AST::EnumItemTuple &); - void visit (AST::EnumItemStruct &); - void visit (AST::EnumItemDiscriminant &); - void visit (AST::ConstantItem &); - void visit (AST::StaticItem &); - void visit (AST::TraitItemConst &); - void visit (AST::TraitItemType &); - void visit (AST::ExternalTypeItem &); - void visit (AST::ExternalStaticItem &); - void visit (AST::MacroMatchRepetition &); - void visit (AST::MacroMatcher &); - void visit (AST::MacroRulesDefinition &); - void visit (AST::MacroInvocation &); - void visit (AST::MetaItemPath &); - void visit (AST::MetaItemSeq &); - void visit (AST::MetaListPaths &); - void visit (AST::MetaListNameValueStr &); - void visit (AST::AltPattern &); - void visit (AST::EmptyStmt &); - void visit (AST::TraitBound &); - void visit (AST::ImplTraitType &); - void visit (AST::TraitObjectType &); - void visit (AST::ImplTraitTypeOneBound &); - void visit (AST::TraitObjectTypeOneBound &); - void visit (AST::BareFunctionType &); - void visit (AST::FunctionParam &); - void visit (AST::VariadicParam &); - void visit (AST::SelfParam &); + void visit (AST::ConstantItem &) override; + void visit (AST::StaticItem &) override; protected: DefaultResolver (NameResolutionContext &ctx) : ctx (ctx) {} 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 bcbe3bd75e33..402af27c47be 100644 --- a/gcc/rust/resolve/rust-early-name-resolver-2.0.cc +++ b/gcc/rust/resolve/rust-early-name-resolver-2.0.cc @@ -18,13 +18,16 @@ #include "rust-early-name-resolver-2.0.h" #include "rust-ast-full.h" +#include "rust-diagnostics.h" #include "rust-toplevel-name-resolver-2.0.h" #include "rust-attributes.h" +#include "rust-finalize-imports-2.0.h" namespace Rust { namespace Resolver2_0 { -Early::Early (NameResolutionContext &ctx) : DefaultResolver (ctx) {} +Early::Early (NameResolutionContext &ctx) : DefaultResolver (ctx), dirty (false) +{} void Early::insert_once (AST::MacroInvocation &invocation, NodeId resolved) @@ -51,16 +54,116 @@ Early::go (AST::Crate &crate) auto toplevel = TopLevel (ctx); toplevel.go (crate); - textual_scope.push (); + // We start with resolving the list of imports that `TopLevel` has built for + // us + for (auto &&import : toplevel.get_imports_to_resolve ()) + build_import_mapping (std::move (import)); + + // Once this is done, we finalize their resolution + FinalizeImports (std::move (import_mappings), toplevel, ctx).go (crate); - // Then we proceed to the proper "early" name resolution: Import and macro - // name resolution + dirty = toplevel.is_dirty (); + // 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); - textual_scope.pop (); } +bool +Early::resolve_glob_import (NodeId use_dec_id, TopLevel::ImportKind &&glob) +{ + auto resolved = ctx.types.resolve_path (glob.to_resolve.get_segments ()); + if (!resolved.has_value ()) + return false; + + auto result + = Analysis::Mappings::get ().lookup_ast_module (resolved->get_node_id ()); + if (!result) + return false; + + // here, we insert the module's NodeId into the import_mappings and will look + // up the module proper in `FinalizeImports` + // The namespace does not matter here since we are dealing with a glob + // TODO: Ugly + import_mappings.insert (use_dec_id, + ImportPair (std::move (glob), + ImportData::Glob (*resolved))); + + return true; +} + +bool +Early::resolve_simple_import (NodeId use_dec_id, TopLevel::ImportKind &&import) +{ + auto definitions = resolve_path_in_all_ns (import.to_resolve); + + // if we've found at least one definition, then we're good + if (definitions.empty ()) + return false; + + auto &imports = import_mappings.new_or_access (use_dec_id); + + imports.emplace_back ( + ImportPair (std::move (import), + ImportData::Simple (std::move (definitions)))); + + return true; +} + +bool +Early::resolve_rebind_import (NodeId use_dec_id, + TopLevel::ImportKind &&rebind_import) +{ + auto definitions = resolve_path_in_all_ns (rebind_import.to_resolve); + + // if we've found at least one definition, then we're good + if (definitions.empty ()) + return false; + + auto &imports = import_mappings.new_or_access (use_dec_id); + + imports.emplace_back ( + ImportPair (std::move (rebind_import), + ImportData::Rebind (std::move (definitions)))); + + return true; +} + +void +Early::build_import_mapping ( + std::pair> &&use_import) +{ + auto found = false; + auto use_dec_id = use_import.first; + + for (auto &&import : use_import.second) + { + // We create a copy of the path in case of errors, since the `import` will + // be moved into the newly created import mappings + auto path = import.to_resolve; + + switch (import.kind) + { + case TopLevel::ImportKind::Kind::Glob: + found = resolve_glob_import (use_dec_id, std::move (import)); + break; + case TopLevel::ImportKind::Kind::Simple: + found = resolve_simple_import (use_dec_id, std::move (import)); + break; + case TopLevel::ImportKind::Kind::Rebind: + found = resolve_rebind_import (use_dec_id, std::move (import)); + break; + } + + if (!found) + collect_error (Error (path.get_final_segment ().get_locus (), + ErrorCode::E0433, "unresolved import %qs", + path.as_string ().c_str ())); + } +} + void Early::TextualScope::push () { @@ -198,8 +301,9 @@ Early::visit_attributes (std::vector &attrs) if (!definition.has_value ()) { // FIXME: Change to proper error message - rust_error_at (trait.get ().get_locus (), - "could not resolve trait"); + collect_error (Error (trait.get ().get_locus (), + "could not resolve trait %qs", + trait.get ().as_string ().c_str ())); continue; } @@ -221,8 +325,9 @@ Early::visit_attributes (std::vector &attrs) if (!definition.has_value ()) { // FIXME: Change to proper error message - rust_error_at (attr.get_locus (), - "could not resolve attribute macro invocation"); + collect_error ( + Error (attr.get_locus (), + "could not resolve attribute macro invocation")); return; } auto pm_def = mappings.lookup_attribute_proc_macro_def ( 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 fc5d8af7038c..dd199cc29090 100644 --- a/gcc/rust/resolve/rust-early-name-resolver-2.0.h +++ b/gcc/rust/resolve/rust-early-name-resolver-2.0.h @@ -24,6 +24,8 @@ #include "rust-ast-visitor.h" #include "rust-name-resolution-context.h" #include "rust-default-resolver.h" +#include "rust-rib.h" +#include "rust-toplevel-name-resolver-2.0.h" namespace Rust { namespace Resolver2_0 { @@ -32,9 +34,13 @@ class Early : public DefaultResolver { using DefaultResolver::visit; + bool dirty; + public: Early (NameResolutionContext &ctx); + bool is_dirty () { return dirty; } + void go (AST::Crate &crate); const std::vector &get_macro_resolve_errors () const @@ -54,6 +60,110 @@ class Early : public DefaultResolver void visit (AST::Function &) override; void visit (AST::StructStruct &) override; + struct ImportData + { + enum class Kind + { + Simple, + Glob, + Rebind + } kind; + + static ImportData + Simple (std::vector> &&definitions) + { + return ImportData (Kind::Simple, std::move (definitions)); + } + + static ImportData + Rebind (std::vector> &&definitions) + { + return ImportData (Kind::Rebind, std::move (definitions)); + } + + static ImportData Glob (Rib::Definition module) + { + return ImportData (Kind::Glob, module); + } + + Rib::Definition module () const + { + rust_assert (kind == Kind::Glob); + return glob_module; + } + + std::vector> definitions () const + { + rust_assert (kind != Kind::Glob); + return std::move (resolved_definitions); + } + + private: + ImportData ( + Kind kind, + std::vector> &&definitions) + : kind (kind), resolved_definitions (std::move (definitions)) + {} + + ImportData (Kind kind, Rib::Definition module) + : kind (kind), glob_module (module) + {} + + // TODO: Should this be a union? + + // For Simple and Rebind + std::vector> resolved_definitions; + + // For Glob + Rib::Definition glob_module; + }; + + struct ImportPair + { + TopLevel::ImportKind import_kind; + ImportData data; + + explicit ImportPair (TopLevel::ImportKind &&kind, ImportData &&data) + : import_kind (std::move (kind)), data (std::move (data)) + {} + }; + + class ImportMappings + { + public: + std::vector &new_or_access (NodeId path_id) + { + // We insert an empty vector, unless an element was already present for + // `use_dec_id` - which is returned in the tuple's first member + auto iter = mappings.insert ({{path_id}, {}}); + + // We then get that tuple's first member, which will be an iterator to the + // existing vec> OR an iterator to our newly + // created empty vector (plus its key since this is a hashmap iterator). + // we then access the second member of the pair to get access to the + // vector directly. + return iter.first->second; + } + + void insert (NodeId path_id, std::vector &&pairs) + { + mappings.insert ({{path_id}, std::move (pairs)}); + } + + // Same as `insert`, but with just one node + void insert (NodeId path_id, ImportPair &&pair) + { + mappings.insert ({{path_id}, {pair}}); + } + + std::vector &get (NodeId use_id) { return mappings[use_id]; } + + private: + // Each path can import in multiple namespaces, hence the mapping from one + // path to a vector of import pairs + std::unordered_map> mappings; + }; + private: void visit_attributes (std::vector &attrs); @@ -91,6 +201,44 @@ class Early : public DefaultResolver std::vector> scopes; }; + // Mappings between an import and the definition it imports + ImportMappings import_mappings; + + // FIXME: Documentation + // Call this on all the paths of a UseDec - so each flattened path in a + // UseTreeList for example + // FIXME: Should that return `found`? + bool resolve_simple_import (NodeId use_dec_id, TopLevel::ImportKind &&import); + bool resolve_glob_import (NodeId use_dec_id, TopLevel::ImportKind &&import); + bool resolve_rebind_import (NodeId use_dec_id, TopLevel::ImportKind &&import); + + template + std::vector> + resolve_path_in_all_ns (const P &path) + { + const auto &segments = path.get_segments (); + std::vector> resolved; + + // Pair a definition with the namespace it was found in + auto pair_with_ns = [&] (Namespace ns) { + return [&, ns] (Rib::Definition def) { + auto pair = std::make_pair (def, ns); + return resolved.emplace_back (std::move (pair)); + }; + }; + + ctx.values.resolve_path (segments).map (pair_with_ns (Namespace::Values)); + ctx.types.resolve_path (segments).map (pair_with_ns (Namespace::Types)); + ctx.macros.resolve_path (segments).map (pair_with_ns (Namespace::Macros)); + + return resolved; + } + + // Handle an import, resolving it to its definition and adding it to the list + // of import mappings + void build_import_mapping ( + std::pair> &&use_import); + TextualScope textual_scope; std::vector macro_resolve_errors; diff --git a/gcc/rust/resolve/rust-finalize-imports-2.0.cc b/gcc/rust/resolve/rust-finalize-imports-2.0.cc new file mode 100644 index 000000000000..5ce05a9c6240 --- /dev/null +++ b/gcc/rust/resolve/rust-finalize-imports-2.0.cc @@ -0,0 +1,224 @@ +// 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-finalize-imports-2.0.h" +#include "rust-default-resolver.h" +#include "rust-hir-map.h" +#include "rust-name-resolution-context.h" +#include "rust-rib.h" +#include "rust-toplevel-name-resolver-2.0.h" + +namespace Rust { +namespace Resolver2_0 { + +void +GlobbingVisitor::go (AST::Module *module) +{ + for (auto &i : module->get_items ()) + visit (i); +} + +void +GlobbingVisitor::visit (AST::Module &module) +{ + if (module.get_visibility ().is_public ()) + ctx.insert_shadowable (module.get_name (), module.get_node_id (), + Namespace::Types); +} + +void +GlobbingVisitor::visit (AST::MacroRulesDefinition ¯o) +{ + if (macro.get_visibility ().is_public ()) + ctx.insert_shadowable (macro.get_rule_name (), macro.get_node_id (), + Namespace::Macros); +} + +void +GlobbingVisitor::visit (AST::Function &function) +{ + if (function.get_visibility ().is_public ()) + ctx.insert_shadowable (function.get_function_name (), + function.get_node_id (), Namespace::Values); +} + +void +GlobbingVisitor::visit (AST::StaticItem &static_item) +{ + if (static_item.get_visibility ().is_public ()) + ctx.insert_shadowable (static_item.get_identifier (), + static_item.get_node_id (), Namespace::Values); +} + +void +GlobbingVisitor::visit (AST::StructStruct &struct_item) +{ + if (struct_item.get_visibility ().is_public ()) + { + ctx.insert_shadowable (struct_item.get_identifier (), + struct_item.get_node_id (), Namespace::Types); + if (struct_item.is_unit_struct ()) + ctx.insert_shadowable (struct_item.get_identifier (), + struct_item.get_node_id (), Namespace::Values); + } +} + +void +GlobbingVisitor::visit (AST::TupleStruct &tuple_struct) +{ + if (tuple_struct.get_visibility ().is_public ()) + { + ctx.insert_shadowable (tuple_struct.get_identifier (), + tuple_struct.get_node_id (), Namespace::Types); + + ctx.insert_shadowable (tuple_struct.get_identifier (), + tuple_struct.get_node_id (), Namespace::Values); + } +} + +void +GlobbingVisitor::visit (AST::Enum &enum_item) +{ + if (enum_item.get_visibility ().is_public ()) + ctx.insert_shadowable (enum_item.get_identifier (), + enum_item.get_node_id (), Namespace::Types); +} + +void +GlobbingVisitor::visit (AST::Union &union_item) +{ + if (union_item.get_visibility ().is_public ()) + ctx.insert_shadowable (union_item.get_identifier (), + union_item.get_node_id (), Namespace::Values); +} + +void +GlobbingVisitor::visit (AST::ConstantItem &const_item) +{ + if (const_item.get_visibility ().is_public ()) + ctx.insert_shadowable (const_item.get_identifier (), + const_item.get_node_id (), Namespace::Values); +} + +void +GlobbingVisitor::visit (AST::ExternCrate &crate) +{} + +void +GlobbingVisitor::visit (AST::UseDeclaration &use) +{ + // Handle cycles ? +} + +void +finalize_simple_import (TopLevel &toplevel, const Early::ImportPair &mapping) +{ + // FIXME: We probably need to store namespace information + + auto locus = mapping.import_kind.to_resolve.get_locus (); + auto data = mapping.data; + auto identifier + = mapping.import_kind.to_resolve.get_final_segment ().get_segment_name (); + + for (auto &&definition : data.definitions ()) + toplevel + .insert_or_error_out ( + identifier, locus, definition.first.get_node_id (), definition.second /* TODO: This isn't clear - it would be better if it was called .ns or something */); +} + +void +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); + + GlobbingVisitor glob_visitor (ctx); + glob_visitor.go (module.value ()); +} + +void +finalize_rebind_import (TopLevel &toplevel, const Early::ImportPair &mapping) +{ + // We can fetch the value here as `resolve_rebind` will only be called on + // imports of the right kind + auto &path = mapping.import_kind.to_resolve; + auto &rebind = mapping.import_kind.rebind.value (); + auto data = mapping.data; + + location_t locus = UNKNOWN_LOCATION; + std::string declared_name; + + // FIXME: This needs to be done in `FinalizeImports` + switch (rebind.get_new_bind_type ()) + { + case AST::UseTreeRebind::NewBindType::IDENTIFIER: + declared_name = rebind.get_identifier ().as_string (); + locus = rebind.get_identifier ().get_locus (); + break; + case AST::UseTreeRebind::NewBindType::NONE: + declared_name = path.get_final_segment ().as_string (); + locus = path.get_final_segment ().get_locus (); + break; + case AST::UseTreeRebind::NewBindType::WILDCARD: + rust_unreachable (); + break; + } + + for (auto &&definition : data.definitions ()) + toplevel.insert_or_error_out ( + declared_name, locus, definition.first.get_node_id (), definition.second /* TODO: This isn't clear - it would be better if it was called .ns or something */); +} + +FinalizeImports::FinalizeImports (Early::ImportMappings &&data, + TopLevel &toplevel, + NameResolutionContext &ctx) + : DefaultResolver (ctx), data (std::move (data)), toplevel (toplevel), + ctx (ctx) +{} + +void +FinalizeImports::go (AST::Crate &crate) +{ + for (auto &item : crate.items) + item->accept_vis (*this); +} + +void +FinalizeImports::visit (AST::UseDeclaration &use) +{ + auto import_mappings = data.get (use.get_node_id ()); + + for (const auto &mapping : import_mappings) + switch (mapping.import_kind.kind) + { + case TopLevel::ImportKind::Kind::Glob: + finalize_glob_import (ctx, mapping); + break; + case TopLevel::ImportKind::Kind::Simple: + finalize_simple_import (toplevel, mapping); + break; + case TopLevel::ImportKind::Kind::Rebind: + finalize_rebind_import (toplevel, mapping); + break; + } +} + +} // namespace Resolver2_0 +} // namespace Rust diff --git a/gcc/rust/resolve/rust-finalize-imports-2.0.h b/gcc/rust/resolve/rust-finalize-imports-2.0.h new file mode 100644 index 000000000000..0fba5a517a19 --- /dev/null +++ b/gcc/rust/resolve/rust-finalize-imports-2.0.h @@ -0,0 +1,110 @@ +// 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.h" +#include "rust-expr.h" +#include "rust-name-resolution-context.h" +#include "rust-toplevel-name-resolver-2.0.h" +#include "rust-early-name-resolver-2.0.h" + +namespace Rust { +namespace Resolver2_0 { + +class GlobbingVisitor : public AST::DefaultASTVisitor +{ + using AST::DefaultASTVisitor::visit; + +public: + GlobbingVisitor (NameResolutionContext &ctx) : ctx (ctx) {} + + void go (AST::Module *module); + void visit (AST::Module &module) override; + void visit (AST::MacroRulesDefinition ¯o) override; + void visit (AST::Function &function) override; + void visit (AST::StaticItem &static_item) override; + void visit (AST::StructStruct &struct_item) override; + void visit (AST::TupleStruct &tuple_struct) override; + void visit (AST::Enum &enum_item) override; + void visit (AST::Union &union_item) override; + void visit (AST::ConstantItem &const_item) override; + void visit (AST::ExternCrate &crate) override; + void visit (AST::UseDeclaration &use) override; + +private: + NameResolutionContext &ctx; +}; + +// TODO: Fix documentation +// How do we do that? +// +// We want to resolve in the EarlyNameResolver, but we want to declare in the +// TopLevel Should the TopLevel declare stubs? How does rustc do it? How to do +// that for globbing? Should we do globbing afterwards once we've declared all +// the Uses*? +// +// Basically, for each use declare it in a separate map - in the +// EarlyNameResolver resolve and fix the ForeverStack? Emptying the maps each +// time? +// +// e.g. TopLevel builds a std::vector use_trees_to_resolve; +// Early goes through and resolves the SimplePath, then replaces the NodeId with +// the resolved one? Do we even need to do that? +// +// rustc just creates an empty definition for the use tree. +// +// What about globbing? std::vector globules; +// Early goes through and visits the module's path and calls the +// GlobbingVisitor? +// +// the file `imports.rs` goes through and *finalizes* imports. So we can +// probably add a FinalizeImport pass after the TopLevel and the Early. +// - TopLevel takes care of declaring these use trees +// - Early takes care of resolving them to definition points +// - Finalize takes care of mapping the use's definition point to the actual +// definition point +// - We need to work more on that last bit to know exactly what is being +// inserted, but probably it's going to mutate the ForeverStack - is that okay? +// - Oh actually maybe no! +// - TopLevel creates a map of UseTrees with paths to resolve. This should +// probably be an ImportKind enum or whatever +// - Early resolves them, creates a map of SimplePath with the associated +// definition: Map +// - Finalizes visits all UseTrees and inserts the Definitions found for +// each ImportKind - easy! +// - yay! + +class FinalizeImports : DefaultResolver +{ +public: + FinalizeImports (Early::ImportMappings &&data, TopLevel &toplevel, + NameResolutionContext &ctx); + + void go (AST::Crate &crate); + +private: + using AST::DefaultASTVisitor::visit; + + void visit (AST::UseDeclaration &) override; + + Early::ImportMappings data; + TopLevel &toplevel; + NameResolutionContext &ctx; +}; + +} // namespace Resolver2_0 +} // 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 f171f14429c3..9472d8c59c93 100644 --- a/gcc/rust/resolve/rust-late-name-resolver-2.0.cc +++ b/gcc/rust/resolve/rust-late-name-resolver-2.0.cc @@ -152,10 +152,10 @@ Late::visit (AST::IdentifierPattern &identifier) // 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? - auto ok - = ctx.values.insert (identifier.get_ident (), identifier.get_node_id ()); - rust_assert (ok); + // We do want to ignore duplicated data because some situations rely on it. + std::ignore + = ctx.values.insert (identifier.get_ident (), identifier.get_node_id ()); } void @@ -201,6 +201,7 @@ Late::visit (AST::PathInExpression &expr) // in a function item` error here? // do we emit it in `get`? + rust_debug ("[ARTHUR]: %s", expr.as_simple_path ().as_string ().c_str ()); auto value = ctx.values.resolve_path (expr.get_segments ()); if (!value.has_value ()) rust_unreachable (); // Should have been resolved earlier @@ -223,14 +224,23 @@ Late::visit (AST::TypePath &type) // maybe we can overload `resolve_path` to only do // typepath-like path resolution? that sounds good - auto resolved = ctx.types.get (type.get_segments ().back ()->as_string ()); - if (resolved) + auto str = type.get_segments ().back ()->get_ident_segment ().as_string (); + auto values = ctx.types.peek ().get_values (); + + if (auto resolved = ctx.types.get (str)) ctx.map_usage (Usage (type.get_node_id ()), Definition (resolved->get_node_id ())); else rust_unreachable (); } +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::StructExprStructBase &s) { 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 ee712b305d4f..b02101a1f3a8 100644 --- a/gcc/rust/resolve/rust-late-name-resolver-2.0.h +++ b/gcc/rust/resolve/rust-late-name-resolver-2.0.h @@ -48,6 +48,7 @@ class Late : public DefaultResolver void visit (AST::TypePath &) override; void visit (AST::StructExprStructBase &) override; void visit (AST::StructExprStructFields &) override; + void visit (AST::StructStruct &) override; private: /* Setup Rust's builtin types (u8, i32, !...) in the resolver */ diff --git a/gcc/rust/resolve/rust-name-resolution-context.h b/gcc/rust/resolve/rust-name-resolution-context.h index 74f110d54dee..f17cd0ae8e13 100644 --- a/gcc/rust/resolve/rust-name-resolution-context.h +++ b/gcc/rust/resolve/rust-name-resolution-context.h @@ -22,6 +22,7 @@ #include "optional.h" #include "rust-forever-stack.h" #include "rust-hir-map.h" +#include "rust-rib.h" namespace Rust { namespace Resolver2_0 { diff --git a/gcc/rust/resolve/rust-rib.cc b/gcc/rust/resolve/rust-rib.cc index a73e2bd6f757..945e1c333caf 100644 --- a/gcc/rust/resolve/rust-rib.cc +++ b/gcc/rust/resolve/rust-rib.cc @@ -92,9 +92,9 @@ Rib::insert (std::string name, Definition def) { if (std::find (current.ids.cbegin (), current.ids.cend (), id) == current.ids.cend ()) - { - current.ids.push_back (id); - } + current.ids.push_back (id); + else + return tl::make_unexpected (DuplicateNameError (name, id)); } } else if (it->second.shadowable) diff --git a/gcc/rust/resolve/rust-rib.h b/gcc/rust/resolve/rust-rib.h index 3db17b4840a3..53881a92020a 100644 --- a/gcc/rust/resolve/rust-rib.h +++ b/gcc/rust/resolve/rust-rib.h @@ -124,7 +124,7 @@ class Rib bool is_ambiguous () const; - NodeId get_node_id () + NodeId get_node_id () const { rust_assert (!is_ambiguous ()); return ids[0]; 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 6524a303061b..3dde48332545 100644 --- a/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc +++ b/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc @@ -26,107 +26,8 @@ namespace Rust { namespace Resolver2_0 { -void -GlobbingVisitor::go (AST::Module *module) -{ - for (auto &i : module->get_items ()) - visit (i); -} - -void -GlobbingVisitor::visit (AST::Module &module) -{ - if (module.get_visibility ().is_public ()) - ctx.insert_shadowable (module.get_name (), module.get_node_id (), - Namespace::Types); -} - -void -GlobbingVisitor::visit (AST::MacroRulesDefinition ¯o) -{ - if (macro.get_visibility ().is_public ()) - ctx.insert_shadowable (macro.get_rule_name (), macro.get_node_id (), - Namespace::Macros); -} - -void -GlobbingVisitor::visit (AST::Function &function) -{ - if (function.get_visibility ().is_public ()) - ctx.insert_shadowable (function.get_function_name (), - function.get_node_id (), Namespace::Values); -} - -void -GlobbingVisitor::visit (AST::StaticItem &static_item) -{ - if (static_item.get_visibility ().is_public ()) - ctx.insert_shadowable (static_item.get_identifier (), - static_item.get_node_id (), Namespace::Values); -} - -void -GlobbingVisitor::visit (AST::StructStruct &struct_item) -{ - if (struct_item.get_visibility ().is_public ()) - { - ctx.insert_shadowable (struct_item.get_identifier (), - struct_item.get_node_id (), Namespace::Types); - if (struct_item.is_unit_struct ()) - ctx.insert_shadowable (struct_item.get_identifier (), - struct_item.get_node_id (), Namespace::Values); - } -} - -void -GlobbingVisitor::visit (AST::TupleStruct &tuple_struct) -{ - if (tuple_struct.get_visibility ().is_public ()) - { - ctx.insert_shadowable (tuple_struct.get_identifier (), - tuple_struct.get_node_id (), Namespace::Types); - - ctx.insert_shadowable (tuple_struct.get_identifier (), - tuple_struct.get_node_id (), Namespace::Values); - } -} - -void -GlobbingVisitor::visit (AST::Enum &enum_item) -{ - if (enum_item.get_visibility ().is_public ()) - ctx.insert_shadowable (enum_item.get_identifier (), - enum_item.get_node_id (), Namespace::Types); -} - -void -GlobbingVisitor::visit (AST::Union &union_item) -{ - if (union_item.get_visibility ().is_public ()) - ctx.insert_shadowable (union_item.get_identifier (), - union_item.get_node_id (), Namespace::Values); -} - -void -GlobbingVisitor::visit (AST::ConstantItem &const_item) -{ - if (const_item.get_visibility ().is_public ()) - ctx.insert_shadowable (const_item.get_identifier (), - const_item.get_node_id (), Namespace::Values); -} - -void -GlobbingVisitor::visit (AST::ExternCrate &crate) -{} - -void -GlobbingVisitor::visit (AST::UseDeclaration &use) -{ - // Handle cycles ? -} - TopLevel::TopLevel (NameResolutionContext &resolver) - : DefaultResolver (resolver) + : DefaultResolver (resolver), dirty (false) {} template @@ -146,8 +47,9 @@ TopLevel::insert_or_error_out (const Identifier &identifier, node_locations.emplace (node_id, locus); auto result = ctx.insert (identifier, node_id, ns); - - if (!result && result.error ().existing != node_id) + if (result) + dirty = true; + else if (result.error ().existing != node_id) { rich_location rich_loc (line_table, locus); rich_loc.add_range (node_locations[result.error ().existing]); @@ -351,6 +253,15 @@ TopLevel::visit (AST::StaticItem &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); + insert_or_error_out (struct_item.get_struct_name (), struct_item, Namespace::Types); @@ -362,6 +273,16 @@ TopLevel::visit (AST::StructStruct &struct_item) Namespace::Values); } +void +TopLevel::visit (AST::TypeParam &type_param) +{ + // Hacky and weird, find a better solution + // We should probably not even insert self in the first place ? + if (type_param.get_type_representation ().as_string () != "Self") + insert_or_error_out (type_param.get_type_representation (), type_param, + Namespace::Types); +} + void TopLevel::visit (AST::TupleStruct &tuple_struct) { @@ -427,183 +348,6 @@ TopLevel::visit (AST::ConstantItem &const_item) DefaultResolver::visit (const_item); } -bool -TopLevel::handle_use_glob (AST::SimplePath &glob) -{ - auto resolved = ctx.types.resolve_path (glob.get_segments ()); - if (!resolved.has_value ()) - return false; - - auto result - = Analysis::Mappings::get ().lookup_ast_module (resolved->get_node_id ()); - - if (!result.has_value ()) - return false; - - GlobbingVisitor gvisitor (ctx); - gvisitor.go (result.value ()); - - return true; -} - -bool -TopLevel::handle_use_dec (AST::SimplePath &path) -{ - auto locus = path.get_final_segment ().get_locus (); - auto declared_name = path.get_final_segment ().as_string (); - - // in what namespace do we perform path resolution? All of them? see which one - // matches? Error out on ambiguities? - // so, apparently, for each one that matches, add it to the proper namespace - // :( - - auto found = false; - - auto resolve_and_insert - = [this, &found, &declared_name, locus] (Namespace ns, - const AST::SimplePath &path) { - tl::optional resolved = tl::nullopt; - - // FIXME: resolve_path needs to return an `expected` so - // that we can improve it with hints or location or w/ever. and maybe - // only emit it the first time. - switch (ns) - { - case Namespace::Values: - resolved = ctx.values.resolve_path (path.get_segments ()); - break; - case Namespace::Types: - resolved = ctx.types.resolve_path (path.get_segments ()); - break; - case Namespace::Macros: - resolved = ctx.macros.resolve_path (path.get_segments ()); - break; - case Namespace::Labels: - // TODO: Is that okay? - rust_unreachable (); - } - - // FIXME: Ugly - (void) resolved.map ([this, &found, &declared_name, locus, ns, - path] (Rib::Definition def) { - found = true; - - // what do we do with the id? - insert_or_error_out (declared_name, locus, def.get_node_id (), ns); - auto result = node_forwarding.find (def.get_node_id ()); - if (result != node_forwarding.cend () - && result->second != path.get_node_id ()) - rust_error_at (path.get_locus (), "%qs defined multiple times", - declared_name.c_str ()); - else // No previous thing has inserted this into our scope - node_forwarding.insert ({def.get_node_id (), path.get_node_id ()}); - - return def.get_node_id (); - }); - }; - - resolve_and_insert (Namespace::Values, path); - resolve_and_insert (Namespace::Types, path); - resolve_and_insert (Namespace::Macros, path); - - return found; -} - -bool -TopLevel::handle_rebind (std::pair &rebind) -{ - auto &path = rebind.first; - - location_t locus = UNKNOWN_LOCATION; - std::string declared_name; - - switch (rebind.second.get_new_bind_type ()) - { - case AST::UseTreeRebind::NewBindType::IDENTIFIER: - declared_name = rebind.second.get_identifier ().as_string (); - locus = rebind.second.get_identifier ().get_locus (); - break; - case AST::UseTreeRebind::NewBindType::NONE: - declared_name = path.get_final_segment ().as_string (); - locus = path.get_final_segment ().get_locus (); - break; - case AST::UseTreeRebind::NewBindType::WILDCARD: - rust_unreachable (); - break; - } - - // in what namespace do we perform path resolution? All - // of them? see which one matches? Error out on - // ambiguities? so, apparently, for each one that - // matches, add it to the proper namespace - // :( - auto found = false; - - auto resolve_and_insert = [this, &found, &declared_name, - locus] (Namespace ns, - const AST::SimplePath &path) { - tl::optional resolved = tl::nullopt; - tl::optional resolved_bind = tl::nullopt; - - std::vector declaration_v - = {AST::SimplePathSegment (declared_name, locus)}; - // FIXME: resolve_path needs to return an `expected` so - // that we can improve it with hints or location or w/ever. and maybe - // only emit it the first time. - switch (ns) - { - case Namespace::Values: - resolved = ctx.values.resolve_path (path.get_segments ()); - resolved_bind = ctx.values.resolve_path (declaration_v); - break; - case Namespace::Types: - resolved = ctx.types.resolve_path (path.get_segments ()); - resolved_bind = ctx.types.resolve_path (declaration_v); - break; - case Namespace::Macros: - resolved = ctx.macros.resolve_path (path.get_segments ()); - resolved_bind = ctx.macros.resolve_path (declaration_v); - break; - case Namespace::Labels: - // TODO: Is that okay? - rust_unreachable (); - } - - resolved.map ([this, &found, &declared_name, locus, ns, path, - &resolved_bind] (Rib::Definition def) { - found = true; - - insert_or_error_out (declared_name, locus, def.get_node_id (), ns); - if (resolved_bind.has_value ()) - { - auto bind_def = resolved_bind.value (); - // what do we do with the id? - auto result = node_forwarding.find (bind_def.get_node_id ()); - if (result != node_forwarding.cend () - && result->second != path.get_node_id ()) - rust_error_at (path.get_locus (), "%qs defined multiple times", - declared_name.c_str ()); - } - else - { - // No previous thing has inserted this into our scope - node_forwarding.insert ({def.get_node_id (), path.get_node_id ()}); - } - return def.get_node_id (); - }); - }; - - // do this for all namespaces (even Labels?) - - resolve_and_insert (Namespace::Values, path); - resolve_and_insert (Namespace::Types, path); - resolve_and_insert (Namespace::Macros, path); - - // TODO: No labels? No, right? - - return found; -} - static void flatten_rebind ( const AST::UseTreeRebind &glob, @@ -731,6 +475,10 @@ TopLevel::visit (AST::UseDeclaration &use) auto rebind_path = std::vector> (); + auto &values_rib = ctx.values.peek (); + auto &types_rib = ctx.types.peek (); + auto ¯os_rib = ctx.macros.peek (); + // FIXME: How do we handle `use foo::{self}` imports? Some beforehand cleanup? // How do we handle module imports in general? Should they get added to all // namespaces? @@ -738,21 +486,22 @@ TopLevel::visit (AST::UseDeclaration &use) const auto &tree = use.get_tree (); flatten (tree.get (), paths, glob_path, rebind_path, this->ctx); - for (auto &path : paths) - if (!handle_use_dec (path)) - rust_error_at (path.get_final_segment ().get_locus (), ErrorCode::E0433, - "unresolved import %qs", path.as_string ().c_str ()); - - for (auto &glob : glob_path) - if (!handle_use_glob (glob)) - rust_error_at (glob.get_final_segment ().get_locus (), ErrorCode::E0433, - "unresolved import %qs", glob.as_string ().c_str ()); - - for (auto &rebind : rebind_path) - if (!handle_rebind (rebind)) - rust_error_at (rebind.first.get_final_segment ().get_locus (), - ErrorCode::E0433, "unresolved import %qs", - rebind.first.as_string ().c_str ()); + auto imports = std::vector (); + + for (auto &&path : paths) + imports.emplace_back ( + ImportKind::Simple (std::move (path), values_rib, types_rib, macros_rib)); + + for (auto &&glob : glob_path) + imports.emplace_back ( + ImportKind::Glob (std::move (glob), values_rib, types_rib, macros_rib)); + + for (auto &&rebind : rebind_path) + imports.emplace_back ( + ImportKind::Rebind (std::move (rebind.first), std::move (rebind.second), + values_rib, types_rib, macros_rib)); + + imports_to_resolve.insert ({use.get_node_id (), std::move (imports)}); } } // namespace Resolver2_0 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 fb16866aeb12..6dc2de92f914 100644 --- a/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.h +++ b/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.h @@ -19,36 +19,16 @@ #ifndef RUST_TOPLEVEL_NAME_RESOLVER_2_0_H #define RUST_TOPLEVEL_NAME_RESOLVER_2_0_H +#include "optional.h" #include "rust-ast-visitor.h" +#include "rust-ast.h" +#include "rust-item.h" #include "rust-name-resolution-context.h" #include "rust-default-resolver.h" namespace Rust { namespace Resolver2_0 { -class GlobbingVisitor : public AST::DefaultASTVisitor -{ - using AST::DefaultASTVisitor::visit; - -public: - GlobbingVisitor (NameResolutionContext &ctx) : ctx (ctx) {} - - void go (AST::Module *module); - void visit (AST::Module &module) override; - void visit (AST::MacroRulesDefinition ¯o) override; - void visit (AST::Function &function) override; - void visit (AST::StaticItem &static_item) override; - void visit (AST::StructStruct &struct_item) override; - void visit (AST::TupleStruct &tuple_struct) override; - void visit (AST::Enum &enum_item) override; - void visit (AST::Union &union_item) override; - void visit (AST::ConstantItem &const_item) override; - void visit (AST::ExternCrate &crate) override; - void visit (AST::UseDeclaration &use) override; - -private: - NameResolutionContext &ctx; -}; /** * The `TopLevel` visitor takes care of collecting all the definitions in a * crate, and inserting them into the proper namespaces. These definitions can @@ -63,7 +43,77 @@ class TopLevel : public DefaultResolver void go (AST::Crate &crate); -private: + bool is_dirty () { return dirty; } + + // Each import will be transformed into an instance of `ImportKind`, a class + // representing some of the data we need to resolve in the + // `EarlyNameResolver`. Basically, for each `UseTree` that we see in + // `TopLevel`, create one of these. `TopLevel` should build a list of these + // `ImportKind`s, which `Early` can then resolve to their proper definitions. + // Then, a final pass will insert the definitions into the `ForeverStack` - + // `FinalizeImports`. + // + // Using this struct should be very simple - each path within a `UseTree` + // becomes one `ImportKind`. The complex case is glob imports, in which case + // one glob import will become one `ImportKind` which will later become + // multiple definitions thanks to the `GlobbingVisitor`. + struct ImportKind + { + enum class Kind + { + Glob, + Simple, + Rebind, + } kind; + + static ImportKind Glob (AST::SimplePath &&to_resolve, Rib &values_rib, + Rib &types_rib, Rib ¯os_rib) + { + return ImportKind (Kind::Glob, std::move (to_resolve), values_rib, + types_rib, macros_rib); + } + + static ImportKind Simple (AST::SimplePath &&to_resolve, Rib &values_rib, + Rib &types_rib, Rib ¯os_rib) + { + return ImportKind (Kind::Simple, std::move (to_resolve), values_rib, + types_rib, macros_rib); + } + + static ImportKind Rebind (AST::SimplePath &&to_resolve, + AST::UseTreeRebind &&rebind, Rib &values_rib, + Rib &types_rib, Rib ¯os_rib) + { + return ImportKind (Kind::Rebind, std::move (to_resolve), values_rib, + types_rib, macros_rib, std::move (rebind)); + } + + // The path for `Early` to resolve. + AST::SimplePath to_resolve; + + // The path to rebind an import to - only present if kind is Kind::Rebind + tl::optional rebind; + + Rib &values_rib; + Rib &types_rib; + Rib ¯os_rib; + + private: + ImportKind (Kind kind, AST::SimplePath &&to_resolve, Rib &values_rib, + Rib &types_rib, Rib ¯os_rib, + tl::optional &&rebind = tl::nullopt) + : kind (kind), to_resolve (std::move (to_resolve)), + rebind (std::move (rebind)), values_rib (values_rib), + types_rib (types_rib), macros_rib (macros_rib) + {} + }; + + std::unordered_map> && + get_imports_to_resolve () + { + return std::move (imports_to_resolve); + } + /** * Insert a new definition or error out if a definition with the same name was * already present in the same namespace in the same scope. @@ -80,13 +130,22 @@ class TopLevel : public DefaultResolver const location_t &locus, const NodeId &id, Namespace ns); +private: + // If a new export has been defined whilst visiting the visitor is considered + // dirty + bool dirty; + // FIXME: Do we move these to our mappings? std::unordered_map node_locations; // Store node forwarding for use declaration, the link between a - // "new" local name and its definition. + // definition and its new local name. std::unordered_map node_forwarding; + // One of the outputs of the `TopLevel` visitor - the list of imports that + // `Early` should take care of resolving + std::unordered_map> imports_to_resolve; + void visit (AST::Module &module) override; void visit (AST::Trait &trait) override; void visit (AST::MacroRulesDefinition ¯o) override; @@ -103,14 +162,7 @@ class TopLevel : public DefaultResolver void visit (AST::Union &union_item) override; void visit (AST::ConstantItem &const_item) override; void visit (AST::ExternCrate &crate) override; - - // FIXME: Documentation - // Call this on all the paths of a UseDec - so each flattened path in a - // UseTreeList for example - // FIXME: Should that return `found`? - bool handle_use_dec (AST::SimplePath &path); - bool handle_use_glob (AST::SimplePath &glob); - bool handle_rebind (std::pair &pair); + void visit (AST::TypeParam &type_param) override; void visit (AST::UseDeclaration &use) override; }; @@ -118,4 +170,17 @@ class TopLevel : public DefaultResolver } // namespace Resolver2_0 } // namespace Rust +// For storing Imports as keys in maps +namespace std { +template <> struct less +{ + bool operator() (const Rust::Resolver2_0::TopLevel::ImportKind &lhs, + const Rust::Resolver2_0::TopLevel::ImportKind &rhs) const + { + return lhs.to_resolve.as_string () < rhs.to_resolve.as_string () + && lhs.kind < rhs.kind; + } +}; +} // namespace std + #endif // !RUST_TOPLEVEL_NAME_RESOLVER_2_0_H diff --git a/gcc/rust/rust-session-manager.cc b/gcc/rust/rust-session-manager.cc index 56c8bdabd80b..1cf58e814f69 100644 --- a/gcc/rust/rust-session-manager.cc +++ b/gcc/rust/rust-session-manager.cc @@ -925,21 +925,24 @@ Session::expansion (AST::Crate &crate, Resolver2_0::NameResolutionContext &ctx) { CfgStrip ().go (crate); // Errors might happen during cfg strip pass - if (saw_errors ()) - break; + bool visitor_dirty = false; if (flag_name_resolution_2_0) { Resolver2_0::Early early (ctx); early.go (crate); macro_errors = early.get_macro_resolve_errors (); + visitor_dirty = early.is_dirty (); } else Resolver::EarlyNameResolver ().go (crate); + if (saw_errors ()) + break; + ExpandVisitor (expander).go (crate); - fixed_point_reached = !expander.has_changed (); + fixed_point_reached = !expander.has_changed () && !visitor_dirty; expander.reset_changed_state (); iterations++; diff --git a/gcc/testsuite/rust/compile/box_syntax_feature_gate.rs b/gcc/testsuite/rust/compile/box_syntax_feature_gate.rs index 8eb5503dde6c..5f62a59a04bf 100644 --- a/gcc/testsuite/rust/compile/box_syntax_feature_gate.rs +++ b/gcc/testsuite/rust/compile/box_syntax_feature_gate.rs @@ -1,4 +1,6 @@ // { dg-options "-frust-compile-until=lowering" } +#[lang = "owned_box"] +pub struct Box; fn main() { let x: Box<_> = box 1; //{ dg-error "box expression syntax is experimental." "" { target *-*-* } } diff --git a/gcc/testsuite/rust/compile/functions_without_body.rs b/gcc/testsuite/rust/compile/functions_without_body.rs index 36ddea52161e..0a0e6021e84b 100644 --- a/gcc/testsuite/rust/compile/functions_without_body.rs +++ b/gcc/testsuite/rust/compile/functions_without_body.rs @@ -1,3 +1,4 @@ +// { dg-additional-options "-frust-compile-until=nameresolution" } struct MyStruct; trait X {} diff --git a/gcc/testsuite/rust/compile/nr2/exclude b/gcc/testsuite/rust/compile/nr2/exclude index 3412617f7eb2..769a6de89314 100644 --- a/gcc/testsuite/rust/compile/nr2/exclude +++ b/gcc/testsuite/rust/compile/nr2/exclude @@ -3,7 +3,6 @@ debug-diagnostics-on.rs # main list -all-cast.rs attr-mismatch-crate-name.rs attr_deprecated.rs attr_deprecated_2.rs @@ -11,20 +10,15 @@ auto_trait_super_trait.rs auto_trait_valid.rs auto_trait_invalid.rs bad=file-name.rs -bad_type2.rs bounds1.rs -break-rust1.rs break-rust2.rs break-rust3.rs -break2.rs -break_with_value_inside_loop.rs macros/builtin/eager1.rs macros/builtin/eager2.rs macros/builtin/recurse2.rs macros/builtin/include3.rs macros/builtin/include4.rs canonical_paths1.rs -cast_generics.rs cfg1.rs cfg3.rs cfg4.rs @@ -35,14 +29,9 @@ complex_qualified_path_in_expr.rs const-issue1440.rs const1.rs const3.rs -const4.rs -const8.rs -const9.rs -const_generics_1.rs const_generics_3.rs const_generics_4.rs const_generics_5.rs -const_generics_6.rs const_generics_7.rs const_generics_8.rs derive_empty.rs @@ -51,7 +40,6 @@ derive_macro3.rs derive_macro4.rs derive_macro6.rs diagnostic_underline.rs -expand_macro_qual_path_in_type.rs expected_type_args2.rs expected_type_args3.rs feature_rust_attri0.rs @@ -59,7 +47,6 @@ feature_rust_attri1.rs for_lifetimes.rs format_args_basic_expansion.rs found_struct.rs -func1.rs generic-default1.rs generics1.rs generics10.rs @@ -73,30 +60,24 @@ generics7.rs generics8.rs generics9.rs if_let_expr.rs -implicit_returns_err4.rs infer-crate-name.rs issue-1005.rs issue-1006.rs issue-1019.rs issue-1031.rs issue-1034.rs -issue-1073.rs issue-1089.rs issue-1128.rs issue-1129-2.rs issue-1130.rs -issue-1131.rs -issue-1152.rs issue-1165.rs issue-1173.rs issue-1235.rs issue-1237.rs issue-1272.rs issue-1289.rs -issue-1383.rs issue-1447.rs issue-1483.rs -issue-1524.rs issue-1589.rs issue-1725-1.rs issue-1725-2.rs @@ -142,7 +123,6 @@ issue-2772-2.rs issue-2775.rs issue-2747.rs issue-2782.rs -issue-2788.rs issue-2812.rs issue-850.rs issue-852.rs @@ -157,14 +137,12 @@ macros/mbe/macro15.rs macros/mbe/macro20.rs macros/mbe/macro23.rs macros/mbe/macro40.rs -macros/mbe/macro42.rs macros/mbe/macro43.rs macros/mbe/macro44.rs macros/mbe/macro50.rs macros/mbe/macro54.rs macros/mbe/macro55.rs macros/mbe/macro6.rs -macros/mbe/macro9.rs macros/mbe/macro_rules_macro_rules.rs macros/mbe/macro_use1.rs match-never-ltype.rs @@ -204,10 +182,7 @@ privacy5.rs privacy6.rs privacy8.rs macros/proc/attribute_non_function.rs -macros/proc/attribute_non_root_method.rs macros/proc/derive_non_function.rs -macros/proc/non_root_method.rs -macros/proc/non_root_trait_method.rs macros/proc/non_function.rs pub_restricted_1.rs pub_restricted_2.rs @@ -243,7 +218,6 @@ type-bindings1.rs unconstrained_type_param.rs undeclared_label.rs unsafe1.rs -unsafe10.rs unsafe11.rs unsafe2.rs unsafe3.rs @@ -256,7 +230,6 @@ use_2.rs v0-mangle1.rs v0-mangle2.rs while_break_expr.rs -rust-const-blog-issue.rs negative_impls.rs auto_trait.rs exhaustiveness1.rs @@ -272,9 +245,7 @@ issue-3045-1.rs issue-3045-2.rs issue-3046.rs unknown-associated-item.rs -box_syntax_feature_gate.rs -dropck_eyepatch_feature_gate.rs inline_asm_parse_output_operand.rs issue-3030.rs issue-3035.rs -issue-3082.rs \ No newline at end of file +issue-3082.rs diff --git a/gcc/testsuite/rust/compile/name_resolution21.rs b/gcc/testsuite/rust/compile/xfail/name_resolution21.rs similarity index 62% rename from gcc/testsuite/rust/compile/name_resolution21.rs rename to gcc/testsuite/rust/compile/xfail/name_resolution21.rs index 3d0af2b37b76..df48d0015987 100644 --- a/gcc/testsuite/rust/compile/name_resolution21.rs +++ b/gcc/testsuite/rust/compile/xfail/name_resolution21.rs @@ -5,7 +5,8 @@ pub mod foo { } use foo::bar; -use foo::bar; // { dg-error ".bar. defined multiple times" } +use foo::bar; +// { dg-error ".bar. defined multiple times" "" { xfail *-*-* } .-1 } fn main() { bar!();