diff --git a/gcc/rust/resolve/rust-forever-stack.h b/gcc/rust/resolve/rust-forever-stack.h index 3ca6e286e5fc..91bc359bcc8b 100644 --- a/gcc/rust/resolve/rust-forever-stack.h +++ b/gcc/rust/resolve/rust-forever-stack.h @@ -543,6 +543,13 @@ class ForeverStackStore Node root; }; +enum class ResolutionMode +{ + Normal, + FromRoot, + FromExtern, // extern prelude +}; + template class ForeverStack { public: @@ -672,7 +679,7 @@ template class ForeverStack */ template tl::optional resolve_path ( - const std::vector &segments, bool has_opening_scope_resolution, + const std::vector &segments, ResolutionMode mode, std::function insert_segment_resolution, std::vector &collect_errors); @@ -739,6 +746,9 @@ template class ForeverStack tl::optional parent; // `None` only if the node is a root }; + // private overload which allows specifying a starting point + tl::optional get (Node &start, const Identifier &name); + /* Should we keep going upon seeing a Rib? */ enum class KeepGoing { diff --git a/gcc/rust/resolve/rust-forever-stack.hxx b/gcc/rust/resolve/rust-forever-stack.hxx index f814c896f465..24b570e958ae 100644 --- a/gcc/rust/resolve/rust-forever-stack.hxx +++ b/gcc/rust/resolve/rust-forever-stack.hxx @@ -291,12 +291,12 @@ ForeverStack::update_cursor (Node &new_cursor) template tl::optional -ForeverStack::get (const Identifier &name) +ForeverStack::get (Node &start, const Identifier &name) { tl::optional resolved_definition = tl::nullopt; // TODO: Can we improve the API? have `reverse_iter` return an optional? - reverse_iter ([&resolved_definition, &name] (Node ¤t) { + reverse_iter (start, [&resolved_definition, &name] (Node ¤t) { auto candidate = current.rib.get (name.as_string ()); return candidate.map_or ( @@ -318,6 +318,13 @@ ForeverStack::get (const Identifier &name) return resolved_definition; } +template +tl::optional +ForeverStack::get (const Identifier &name) +{ + return get (cursor (), name); +} + template tl::optional ForeverStack::get_lang_prelude (const Identifier &name) @@ -625,23 +632,25 @@ template template tl::optional ForeverStack::resolve_path ( - const std::vector &segments, bool has_opening_scope_resolution, + const std::vector &segments, ResolutionMode mode, std::function insert_segment_resolution, std::vector &collect_errors) { rust_assert (!segments.empty ()); - // handle paths with opening scopes - std::function cleanup_current = [] () {}; - if (has_opening_scope_resolution) + std::reference_wrapper starting_point = cursor (); + switch (mode) { - Node *last_current = &cursor_reference.get (); - if (get_rust_edition () == Edition::E2015) - cursor_reference = root; - else - cursor_reference = extern_prelude; - cleanup_current - = [this, last_current] () { cursor_reference = *last_current; }; + case ResolutionMode::Normal: + break; // default + case ResolutionMode::FromRoot: + starting_point = root; + break; + case ResolutionMode::FromExtern: + starting_point = extern_prelude; + break; + default: + rust_unreachable (); } // if there's only one segment, we just use `get` @@ -654,13 +663,13 @@ ForeverStack::resolve_path ( lang_item.value ()); insert_segment_resolution (seg, seg_id); - cleanup_current (); // TODO: does NonShadowable matter? return Rib::Definition::NonShadowable (seg_id); } tl::optional res - = get (unwrap_type_segment (segments.back ()).as_string ()); + = get (starting_point.get (), + unwrap_type_segment (segments.back ()).as_string ()); if (!res) res = get_lang_prelude ( @@ -668,45 +677,39 @@ ForeverStack::resolve_path ( if (res && !res->is_ambiguous ()) insert_segment_resolution (segments.back (), res->get_node_id ()); - cleanup_current (); return res; } - std::reference_wrapper starting_point = cursor (); + return find_starting_point (segments, starting_point, + insert_segment_resolution, collect_errors) + .and_then ( + [this, &segments, &starting_point, &insert_segment_resolution, + &collect_errors] (typename std::vector::const_iterator iterator) { + return resolve_segments (starting_point.get (), segments, iterator, + insert_segment_resolution, collect_errors); + }) + .and_then ([this, &segments, &insert_segment_resolution] ( + Node &final_node) -> tl::optional { + // leave resolution within impl blocks to type checker + if (final_node.rib.kind == Rib::Kind::TraitOrImpl) + return tl::nullopt; + + auto &seg = unwrap_type_segment (segments.back ()); + std::string seg_name = seg.as_string (); + + // assuming this can't be a lang item segment + tl::optional res + = resolve_final_segment (final_node, seg_name, + seg.is_lower_self_seg ()); + // Ok we didn't find it in the rib, Lets try the prelude... + if (!res) + res = get_lang_prelude (seg_name); - auto res - = find_starting_point (segments, starting_point, insert_segment_resolution, - collect_errors) - .and_then ( - [this, &segments, &starting_point, &insert_segment_resolution, - &collect_errors] (typename std::vector::const_iterator iterator) { - return resolve_segments (starting_point.get (), segments, iterator, - insert_segment_resolution, collect_errors); - }) - .and_then ([this, &segments, &insert_segment_resolution] ( - Node &final_node) -> tl::optional { - // leave resolution within impl blocks to type checker - if (final_node.rib.kind == Rib::Kind::TraitOrImpl) - return tl::nullopt; - - auto &seg = unwrap_type_segment (segments.back ()); - std::string seg_name = seg.as_string (); - - // assuming this can't be a lang item segment - tl::optional res - = resolve_final_segment (final_node, seg_name, - seg.is_lower_self_seg ()); - // Ok we didn't find it in the rib, Lets try the prelude... - if (!res) - res = get_lang_prelude (seg_name); - - if (res && !res->is_ambiguous ()) - insert_segment_resolution (segments.back (), res->get_node_id ()); - - return res; - }); - cleanup_current (); - return res; + if (res && !res->is_ambiguous ()) + insert_segment_resolution (segments.back (), res->get_node_id ()); + + return res; + }); } template 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 4ed5528c9110..54df2c4f723b 100644 --- a/gcc/rust/resolve/rust-late-name-resolver-2.0.cc +++ b/gcc/rust/resolve/rust-late-name-resolver-2.0.cc @@ -520,6 +520,62 @@ Late::visit (AST::TypePath &type) Definition (resolved->get_node_id ())); } +void +Late::visit (AST::Visibility &vis) +{ + if (!vis.has_path ()) + return; + + AST::SimplePath &path = vis.get_path (); + + rust_assert (path.get_segments ().size ()); + auto &first_seg = path.get_segments ()[0]; + + auto mode = ResolutionMode::Normal; + + if (path.has_opening_scope_resolution ()) + { + if (get_rust_edition () == Edition::E2015) + mode = ResolutionMode::FromRoot; + else + mode = ResolutionMode::FromExtern; + } + else if (!first_seg.is_crate_path_seg () && !first_seg.is_super_path_seg () + && !first_seg.is_lower_self_seg ()) + { + if (get_rust_edition () == Edition::E2015) + { + mode = ResolutionMode::FromRoot; + } + else + { + rust_error_at (path.get_locus (), + "relative paths are not supported in visibilities in " + "2018 edition or later"); + return; + } + } + + auto res = ctx.resolve_path (path.get_segments (), mode, Namespace::Types); + + if (!res.has_value ()) + { + rust_error_at (path.get_locus (), ErrorCode::E0433, + "could not resolve path %qs", path.as_string ().c_str ()); + return; + } + + // TODO: is this possible? + if (res->is_ambiguous ()) + { + rust_error_at (path.get_locus (), ErrorCode::E0659, "%qs is ambiguous", + path.as_string ().c_str ()); + return; + } + + ctx.map_usage (Usage (path.get_node_id ()), Definition (res->get_node_id ())); +} + void Late::visit (AST::Trait &trait) { 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 896b72ce4399..e41966476749 100644 --- a/gcc/rust/resolve/rust-late-name-resolver-2.0.h +++ b/gcc/rust/resolve/rust-late-name-resolver-2.0.h @@ -60,6 +60,7 @@ class Late : public DefaultResolver void visit (AST::LoopLabel &) override; void visit (AST::PathInExpression &) override; void visit (AST::TypePath &) override; + void visit (AST::Visibility &) override; void visit (AST::Trait &) override; void visit (AST::StructExprStruct &) override; void visit (AST::StructExprStructBase &) override; diff --git a/gcc/rust/resolve/rust-name-resolution-context.h b/gcc/rust/resolve/rust-name-resolution-context.h index aab04ccc18eb..48e6a7991978 100644 --- a/gcc/rust/resolve/rust-name-resolution-context.h +++ b/gcc/rust/resolve/rust-name-resolution-context.h @@ -279,8 +279,7 @@ class NameResolutionContext template tl::optional - resolve_path (const std::vector &segments, - bool has_opening_scope_resolution, + resolve_path (const std::vector &segments, ResolutionMode mode, std::vector &collect_errors, Namespace ns) { std::function insert_segment_resolution @@ -292,17 +291,17 @@ class NameResolutionContext switch (ns) { case Namespace::Values: - return values.resolve_path (segments, has_opening_scope_resolution, - insert_segment_resolution, collect_errors); + return values.resolve_path (segments, mode, insert_segment_resolution, + collect_errors); case Namespace::Types: - return types.resolve_path (segments, has_opening_scope_resolution, - insert_segment_resolution, collect_errors); + return types.resolve_path (segments, mode, insert_segment_resolution, + collect_errors); case Namespace::Macros: - return macros.resolve_path (segments, has_opening_scope_resolution, - insert_segment_resolution, collect_errors); + return macros.resolve_path (segments, mode, insert_segment_resolution, + collect_errors); case Namespace::Labels: - return labels.resolve_path (segments, has_opening_scope_resolution, - insert_segment_resolution, collect_errors); + return labels.resolve_path (segments, mode, insert_segment_resolution, + collect_errors); default: rust_unreachable (); } @@ -310,8 +309,7 @@ class NameResolutionContext template tl::optional - resolve_path (const std::vector &segments, - bool has_opening_scope_resolution, + resolve_path (const std::vector &segments, ResolutionMode mode, tl::optional &> collect_errors, Namespace ns_first, Args... ns_args) { @@ -320,8 +318,7 @@ class NameResolutionContext for (auto ns : namespaces) { std::vector collect_errors_inner; - if (auto ret = resolve_path (segments, has_opening_scope_resolution, - collect_errors_inner, ns)) + if (auto ret = resolve_path (segments, mode, collect_errors_inner, ns)) return ret; if (!collect_errors_inner.empty ()) { @@ -343,52 +340,68 @@ class NameResolutionContext return tl::nullopt; } - template + template tl::optional - resolve_path (const AST::SimplePath &path, + resolve_path (const std::vector &path_segments, + bool has_opening_scope_resolution, tl::optional &> collect_errors, Namespace ns_first, Args... ns_args) { - return resolve_path (path.get_segments (), - path.has_opening_scope_resolution (), collect_errors, - ns_first, ns_args...); + auto mode = ResolutionMode::Normal; + if (has_opening_scope_resolution) + { + if (get_rust_edition () == Edition::E2015) + mode = ResolutionMode::FromRoot; + else + mode = ResolutionMode::FromExtern; + } + return resolve_path (path_segments, mode, collect_errors, ns_first, + ns_args...); } - template + template tl::optional - resolve_path (const AST::PathInExpression &path, - tl::optional &> collect_errors, - Namespace ns_first, Args... ns_args) + resolve_path (const std::vector &path_segments, + bool has_opening_scope_resolution, Namespace ns_first, + Args... ns_args) { - return resolve_path (path.get_segments (), path.opening_scope_resolution (), - collect_errors, ns_first, ns_args...); + return resolve_path (path_segments, has_opening_scope_resolution, + tl::nullopt, ns_first, ns_args...); } - template + template tl::optional - resolve_path (const AST::TypePath &path, - tl::optional &> collect_errors, + resolve_path (const std::vector &path_segments, ResolutionMode mode, Namespace ns_first, Args... ns_args) + { + return resolve_path (path_segments, mode, tl::nullopt, ns_first, + ns_args...); + } + + template + tl::optional resolve_path (const AST::SimplePath &path, + Args &&... args) { return resolve_path (path.get_segments (), - path.has_opening_scope_resolution_op (), - collect_errors, ns_first, ns_args...); + path.has_opening_scope_resolution (), + std::forward (args)...); } - template - tl::optional resolve_path (const P &path, Namespace ns_first, - Args... ns_args) + template + tl::optional resolve_path (const AST::PathInExpression &path, + Args &&... args) { - return resolve_path (path, tl::nullopt, ns_first, ns_args...); + return resolve_path (path.get_segments (), path.opening_scope_resolution (), + std::forward (args)...); } - template - tl::optional - resolve_path (const P &path_segments, bool has_opening_scope_resolution, - Namespace ns_first, Args... ns_args) + template + tl::optional resolve_path (const AST::TypePath &path, + Args &&... args) { - return resolve_path (path_segments, has_opening_scope_resolution, - tl::nullopt, ns_first, ns_args...); + return resolve_path (path.get_segments (), + path.has_opening_scope_resolution_op (), + std::forward (args)...); } private: diff --git a/gcc/testsuite/rust/compile/nr2/exclude b/gcc/testsuite/rust/compile/nr2/exclude index d4e066a5f723..70c59f9abdd4 100644 --- a/gcc/testsuite/rust/compile/nr2/exclude +++ b/gcc/testsuite/rust/compile/nr2/exclude @@ -1,10 +1,8 @@ canonical_paths1.rs issue-3315-2.rs -privacy5.rs privacy8.rs pub_restricted_1.rs pub_restricted_2.rs -pub_restricted_3.rs issue-2905-2.rs torture/alt_patterns1.rs torture/name_resolve1.rs