From: Philip Herron Date: Fri, 17 Mar 2023 22:46:37 +0000 (+0000) Subject: gccrs: support use declaration to write the type into the correct namespace X-Git-Tag: basepoints/gcc-15~2752 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7e7cffb709def41f3df115d7be4ce86b466d5011;p=thirdparty%2Fgcc.git gccrs: support use declaration to write the type into the correct namespace This builds upon the previous path resolution fixes so that it returns the resolved_node_id or UNKNOWN_NODEID on failure to resolve the use-path. It then exports the name to the current module namespace so it can be used. Fixes #850 #855 gcc/rust/ChangeLog: * ast/rust-ast.h: add const get_final_segment helper * hir/rust-ast-lower-enumitem.h: dont add an item mapping for enumitems * hir/rust-ast-lower-item.cc (ASTLoweringItem::visit): add enum to enum-items mappings * hir/rust-ast-lower-stmt.cc (ASTLoweringStmt::visit): likewise * hir/tree/rust-hir-item.h: add non const helper to get variants * resolve/rust-ast-resolve-item.cc (ResolveItem::visit): resolve the use declaration * resolve/rust-ast-resolve-path.cc (ResolvePath::resolve_path): handle self * resolve/rust-ast-resolve-toplevel.h: add enum item mappings to module mappings * typecheck/rust-hir-type-check-path.cc (TypeCheckExpr::resolve_root_path): ensure variant (TypeCheckExpr::resolve_segments): likewise * typecheck/rust-type-util.cc (query_type): lookup enum's * util/rust-hir-map.cc (Mappings::insert_hir_enumitem): enum item mappings (Mappings::lookup_hir_enumitem): likewise * util/rust-hir-map.h: likewise gcc/testsuite/ChangeLog: * rust/compile/issue-850.rs: New test. * rust/compile/issue-855.rs: New test. Signed-off-by: Philip Herron --- diff --git a/gcc/rust/ast/rust-ast.h b/gcc/rust/ast/rust-ast.h index fe520abd126f..5e5913b95f60 100644 --- a/gcc/rust/ast/rust-ast.h +++ b/gcc/rust/ast/rust-ast.h @@ -422,6 +422,11 @@ public: } std::vector &get_segments () { return segments; } + + const SimplePathSegment &get_final_segment () const + { + return segments.back (); + } }; // path-to-string inverse comparison operator diff --git a/gcc/rust/hir/rust-ast-lower-enumitem.h b/gcc/rust/hir/rust-ast-lower-enumitem.h index a1e63a195df9..d78d8b17a610 100644 --- a/gcc/rust/hir/rust-ast-lower-enumitem.h +++ b/gcc/rust/hir/rust-ast-lower-enumitem.h @@ -46,7 +46,6 @@ public: auto defid = resolver.translated->get_mappings ().get_defid (); resolver.mappings->insert_defid_mapping (defid, resolver.translated); - resolver.mappings->insert_hir_item (resolver.translated); resolver.mappings->insert_location (hirid, resolver.translated->get_locus ()); diff --git a/gcc/rust/hir/rust-ast-lower-item.cc b/gcc/rust/hir/rust-ast-lower-item.cc index b3eca5298291..07a5fc87ad06 100644 --- a/gcc/rust/hir/rust-ast-lower-item.cc +++ b/gcc/rust/hir/rust-ast-lower-item.cc @@ -274,11 +274,16 @@ ASTLoweringItem::visit (AST::Enum &enum_decl) mappings->get_next_hir_id (crate_num), mappings->get_next_localdef_id (crate_num)); - translated = new HIR::Enum (mapping, enum_decl.get_identifier (), vis, - std::move (generic_params), - std::move (where_clause), /* is_unit, */ - std::move (items), enum_decl.get_outer_attrs (), - enum_decl.get_locus ()); + HIR::Enum *hir_enum + = new HIR::Enum (mapping, enum_decl.get_identifier (), vis, + std::move (generic_params), std::move (where_clause), + std::move (items), enum_decl.get_outer_attrs (), + enum_decl.get_locus ()); + translated = hir_enum; + for (auto &variant : hir_enum->get_variants ()) + { + mappings->insert_hir_enumitem (hir_enum, variant.get ()); + } } void diff --git a/gcc/rust/hir/rust-ast-lower-stmt.cc b/gcc/rust/hir/rust-ast-lower-stmt.cc index dbff8ad715f3..5ba8db002d02 100644 --- a/gcc/rust/hir/rust-ast-lower-stmt.cc +++ b/gcc/rust/hir/rust-ast-lower-stmt.cc @@ -301,11 +301,16 @@ ASTLoweringStmt::visit (AST::Enum &enum_decl) mappings->get_next_hir_id (crate_num), mappings->get_next_localdef_id (crate_num)); - translated = new HIR::Enum (mapping, enum_decl.get_identifier (), vis, - std::move (generic_params), - std::move (where_clause), /* is_unit, */ - std::move (items), enum_decl.get_outer_attrs (), - enum_decl.get_locus ()); + HIR::Enum *hir_enum + = new HIR::Enum (mapping, enum_decl.get_identifier (), vis, + std::move (generic_params), std::move (where_clause), + std::move (items), enum_decl.get_outer_attrs (), + enum_decl.get_locus ()); + translated = hir_enum; + for (auto &variant : hir_enum->get_variants ()) + { + mappings->insert_hir_enumitem (hir_enum, variant.get ()); + } } void diff --git a/gcc/rust/hir/tree/rust-hir-item.h b/gcc/rust/hir/tree/rust-hir-item.h index fa52d7aa041a..e1a2b4eaeab7 100644 --- a/gcc/rust/hir/tree/rust-hir-item.h +++ b/gcc/rust/hir/tree/rust-hir-item.h @@ -1966,6 +1966,8 @@ public: return items; } + std::vector> &get_variants () { return items; } + protected: /* Use covariance to implement clone function as returning this object * rather than base */ diff --git a/gcc/rust/resolve/rust-ast-resolve-item.cc b/gcc/rust/resolve/rust-ast-resolve-item.cc index 4f3b924a5868..c1590ca3a2fd 100644 --- a/gcc/rust/resolve/rust-ast-resolve-item.cc +++ b/gcc/rust/resolve/rust-ast-resolve-item.cc @@ -983,7 +983,7 @@ flatten_use_dec_to_paths (const AST::UseDeclaration &use_item) void ResolveItem::visit (AST::UseDeclaration &use_item) { - auto to_resolve = flatten_use_dec_to_paths (use_item); + std::vector to_resolve = flatten_use_dec_to_paths (use_item); // FIXME: I think this does not actually resolve glob use-decls and is going // the wrong way about it. RFC #1560 specifies the following: @@ -993,8 +993,27 @@ ResolveItem::visit (AST::UseDeclaration &use_item) // importing module. // // Which is the opposite of what we're doing if I understand correctly? + + NodeId current_module = resolver->peek_current_module_scope (); for (auto &path : to_resolve) - ResolvePath::go (&path); + { + rust_debug ("resolving use-decl path: [%s]", path.as_string ().c_str ()); + NodeId resolved_node_id = ResolvePath::go (&path); + bool ok = resolved_node_id != UNKNOWN_NODEID; + if (!ok) + continue; + + const AST::SimplePathSegment &final_seg = path.get_final_segment (); + + auto decl + = CanonicalPath::new_seg (resolved_node_id, final_seg.as_string ()); + mappings->insert_module_child_item (current_module, decl); + + resolver->get_type_scope ().insert (decl, resolved_node_id, + path.get_locus (), + Rib::ItemType::Type); + rust_debug ("use-decl rexporting: [%s]", decl.get ().c_str ()); + } } ResolveImplItems::ResolveImplItems (const CanonicalPath &prefix, diff --git a/gcc/rust/resolve/rust-ast-resolve-path.cc b/gcc/rust/resolve/rust-ast-resolve-path.cc index bd0b04332632..9c3a2eeace0a 100644 --- a/gcc/rust/resolve/rust-ast-resolve-path.cc +++ b/gcc/rust/resolve/rust-ast-resolve-path.cc @@ -267,17 +267,20 @@ ResolvePath::resolve_path (AST::SimplePath *expr) NodeId crate_scope_id = resolver->peek_crate_module_scope (); NodeId module_scope_id = resolver->peek_current_module_scope (); + NodeId previous_resolved_node_id = UNKNOWN_NODEID; NodeId resolved_node_id = UNKNOWN_NODEID; for (size_t i = 0; i < expr->get_segments ().size (); i++) { - auto &segment = expr->get_segments ().at (i); + AST::SimplePathSegment &segment = expr->get_segments ().at (i); bool is_first_segment = i == 0; + bool is_final_segment = i >= (expr->get_segments ().size () - 1); resolved_node_id = UNKNOWN_NODEID; if (segment.is_crate_path_seg ()) { // what is the current crate scope node id? module_scope_id = crate_scope_id; + previous_resolved_node_id = module_scope_id; resolver->insert_resolved_name (segment.get_node_id (), module_scope_id); continue; @@ -292,6 +295,7 @@ ResolvePath::resolve_path (AST::SimplePath *expr) } module_scope_id = resolver->peek_parent_module_scope (); + previous_resolved_node_id = module_scope_id; resolver->insert_resolved_name (segment.get_node_id (), module_scope_id); continue; @@ -348,6 +352,25 @@ ResolvePath::resolve_path (AST::SimplePath *expr) } } + // if we still have not resolved and this is the final segment and the + // final segment is self its likely the case: pub use + // + // result::Result::{self, Err, Ok}; + // + // Then the resolved_node_id is just the previous one so long as it is a + // resolved node id + // rust_debug_loc (segment.get_locus (), + // "trying to resolve seg: [%s] first [%s] last [%s]", + // segment.get_segment_name ().c_str (), + // is_first_segment ? "true" : "false", + // is_final_segment ? "true" : "false"); + if (resolved_node_id == UNKNOWN_NODEID && !is_first_segment + && is_final_segment && segment.is_lower_self ()) + { + resolved_node_id = previous_resolved_node_id; + } + + // final check if (resolved_node_id == UNKNOWN_NODEID) { rust_error_at (segment.get_locus (), @@ -360,6 +383,8 @@ ResolvePath::resolve_path (AST::SimplePath *expr) { module_scope_id = resolved_node_id; } + + previous_resolved_node_id = resolved_node_id; } resolved_node = resolved_node_id; diff --git a/gcc/rust/resolve/rust-ast-resolve-toplevel.h b/gcc/rust/resolve/rust-ast-resolve-toplevel.h index 9e2fb5764815..1ab9af8e40ae 100644 --- a/gcc/rust/resolve/rust-ast-resolve-toplevel.h +++ b/gcc/rust/resolve/rust-ast-resolve-toplevel.h @@ -132,9 +132,12 @@ public: rust_error_at (r, "redefined multiple times"); }); + resolver->push_new_module_scope (enum_decl.get_node_id ()); for (auto &variant : enum_decl.get_variants ()) ResolveTopLevel::go (variant.get (), path, cpath); + resolver->pop_module_scope (); + NodeId current_module = resolver->peek_current_module_scope (); mappings->insert_module_child_item (current_module, decl); mappings->insert_canonical_path (enum_decl.get_node_id (), cpath); @@ -156,6 +159,10 @@ public: }); mappings->insert_canonical_path (item.get_node_id (), cpath); + + NodeId current_module = resolver->peek_current_module_scope (); + mappings->insert_module_child_item (current_module, decl); + mappings->insert_module_child (current_module, item.get_node_id ()); } void visit (AST::EnumItemTuple &item) override @@ -174,6 +181,10 @@ public: }); mappings->insert_canonical_path (item.get_node_id (), cpath); + + NodeId current_module = resolver->peek_current_module_scope (); + mappings->insert_module_child_item (current_module, decl); + mappings->insert_module_child (current_module, item.get_node_id ()); } void visit (AST::EnumItemStruct &item) override @@ -192,6 +203,10 @@ public: }); mappings->insert_canonical_path (item.get_node_id (), cpath); + + NodeId current_module = resolver->peek_current_module_scope (); + mappings->insert_module_child_item (current_module, decl); + mappings->insert_module_child (current_module, item.get_node_id ()); } void visit (AST::EnumItemDiscriminant &item) override @@ -210,6 +225,10 @@ public: }); mappings->insert_canonical_path (item.get_node_id (), cpath); + + NodeId current_module = resolver->peek_current_module_scope (); + mappings->insert_module_child_item (current_module, decl); + mappings->insert_module_child (current_module, item.get_node_id ()); } void visit (AST::StructStruct &struct_decl) override diff --git a/gcc/rust/typecheck/rust-hir-type-check-path.cc b/gcc/rust/typecheck/rust-hir-type-check-path.cc index c496cbf84bdb..cdd275c9ff25 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-path.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-path.cc @@ -244,6 +244,19 @@ TypeCheckExpr::resolve_root_path (HIR::PathInExpression &expr, size_t *offset, return root_tyty; } + // is it an enum item? + std::pair enum_item_lookup + = mappings->lookup_hir_enumitem (ref); + bool is_enum_item = enum_item_lookup.first != nullptr + && enum_item_lookup.second != nullptr; + if (is_enum_item) + { + HirId expr_id = expr.get_mappings ().get_hirid (); + HirId variant_id + = enum_item_lookup.second->get_mappings ().get_hirid (); + context->insert_variant_definition (expr_id, variant_id); + } + // if we have a previous segment type if (root_tyty != nullptr) { @@ -349,9 +362,13 @@ TypeCheckExpr::resolve_segments (NodeId root_resolved_node_id, const TyTy::VariantDef *variant = candidate.item.enum_field.variant; HirId variant_id = variant->get_id (); - HIR::Item *enum_item = mappings->lookup_hir_item (variant_id); - rust_assert (enum_item != nullptr); + std::pair enum_item_lookup + = mappings->lookup_hir_enumitem (variant_id); + bool enum_item_ok = enum_item_lookup.first != nullptr + && enum_item_lookup.second != nullptr; + rust_assert (enum_item_ok); + HIR::EnumItem *enum_item = enum_item_lookup.second; resolved_node_id = enum_item->get_mappings ().get_nodeid (); // insert the id of the variant we are resolved to diff --git a/gcc/rust/typecheck/rust-type-util.cc b/gcc/rust/typecheck/rust-type-util.cc index 419dfe7246d6..e0c43c713c5e 100644 --- a/gcc/rust/typecheck/rust-type-util.cc +++ b/gcc/rust/typecheck/rust-type-util.cc @@ -22,8 +22,6 @@ #include "rust-hir-type-check-implitem.h" #include "rust-hir-type-check-item.h" #include "rust-hir-type-check.h" -#include "rust-hir-visitor.h" -#include "rust-name-resolver.h" #include "rust-casts.h" #include "rust-unify.h" #include "rust-coercion.h" @@ -45,6 +43,23 @@ query_type (HirId reference, TyTy::BaseType **result) context->insert_query (reference); + std::pair enum_candidiate + = mappings->lookup_hir_enumitem (reference); + bool enum_candidiate_ok + = enum_candidiate.first != nullptr && enum_candidiate.second != nullptr; + if (enum_candidiate_ok) + { + HIR::Enum *parent = enum_candidiate.first; + HIR::EnumItem *enum_item = enum_candidiate.second; + rust_debug_loc (enum_item->get_locus (), "resolved item {%u} to", + reference); + + *result = TypeCheckItem::Resolve (*parent); + + context->query_completed (reference); + return true; + } + HIR::Item *item = mappings->lookup_hir_item (reference); if (item != nullptr) { diff --git a/gcc/rust/util/rust-hir-map.cc b/gcc/rust/util/rust-hir-map.cc index 535731b48f21..2a731fe98818 100644 --- a/gcc/rust/util/rust-hir-map.cc +++ b/gcc/rust/util/rust-hir-map.cc @@ -382,6 +382,27 @@ Mappings::lookup_hir_item (HirId id) return it->second; } +void +Mappings::insert_hir_enumitem (HIR::Enum *parent, HIR::EnumItem *item) +{ + auto id = item->get_mappings ().get_hirid (); + auto result = lookup_hir_enumitem (id); + rust_assert (result.first == nullptr); + + hirEnumItemMappings[id] = {parent, item}; + insert_node_to_hir (item->get_mappings ().get_nodeid (), id); +} + +std::pair +Mappings::lookup_hir_enumitem (HirId id) +{ + auto it = hirEnumItemMappings.find (id); + if (it == hirEnumItemMappings.end ()) + return {nullptr, nullptr}; + + return it->second; +} + void Mappings::insert_hir_trait_item (HIR::TraitItem *item) { diff --git a/gcc/rust/util/rust-hir-map.h b/gcc/rust/util/rust-hir-map.h index 6356a7505512..80d753cce363 100644 --- a/gcc/rust/util/rust-hir-map.h +++ b/gcc/rust/util/rust-hir-map.h @@ -114,6 +114,9 @@ public: void insert_hir_item (HIR::Item *item); HIR::Item *lookup_hir_item (HirId id); + void insert_hir_enumitem (HIR::Enum *parent, HIR::EnumItem *item); + std::pair lookup_hir_enumitem (HirId id); + void insert_hir_trait_item (HIR::TraitItem *item); HIR::TraitItem *lookup_hir_trait_item (HirId id); @@ -317,6 +320,7 @@ private: std::map hirModuleMappings; std::map hirItemMappings; + std::map> hirEnumItemMappings; std::map hirTypeMappings; std::map hirExprMappings; std::map hirStmtMappings; diff --git a/gcc/testsuite/rust/compile/issue-850.rs b/gcc/testsuite/rust/compile/issue-850.rs new file mode 100644 index 000000000000..531cbf4f6633 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-850.rs @@ -0,0 +1,43 @@ +extern "C" { + fn printf(s: *const i8, ...); +} + +mod option { + enum Option { + #[lang = "None"] + None, + #[lang = "Some"] + Some(T), + } +} + +pub use option::Option::{self, None, Some}; + +fn divide(numerator: f64, denominator: f64) -> Option { + if denominator == 0.0 { + None + } else { + Some(numerator / denominator) + } +} + +fn main() { + let result = divide(2.0, 3.0); + + match result { + Some(x) => unsafe { + let a = "Result: %i\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c, x); + }, + None => unsafe { + let a = "Cannot divide by 0\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c); + }, + } +} diff --git a/gcc/testsuite/rust/compile/issue-855.rs b/gcc/testsuite/rust/compile/issue-855.rs new file mode 100644 index 000000000000..f48e3a1bfe0a --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-855.rs @@ -0,0 +1,23 @@ +pub use result::Result::{self, Err, Ok}; + +extern "C" { + fn printf(s: *const i8, ...); +} + +mod result { + pub enum Result { + #[lang = "Ok"] + Ok(T), + + #[lang = "Err"] + Err(E), + } +} + +pub fn test(a: i32) -> Result { + if a > 5 { + Ok(123) + } else { + Err(false) + } +}