From f4a5629fb7f6274433005c255bc9baf113856a5d Mon Sep 17 00:00:00 2001 From: Philip Herron Date: Wed, 29 Jun 2022 16:14:33 +0100 Subject: Fix name resolution using self paths and nested functions When we resolve paths the code was looking at the crate hierarchy first in the algorithm this leads to a bug where in rust you can have a function named foo at the item level then declare a nested function with the same name. So when we wanted to call the nested function the code was defaulting to the toplevel first resulting in bad name resolution. This patch updates the code to look at the scope first, then look at the module scope hierarchy. It finally adds the error handling in a nice single path at the end. We can only error out if its not the first segment since paths such as associated types like Self::foo we cannot resolve foo as this requires the type-resolution system to determine the projection. Fixes #1231 --- gcc/rust/resolve/rust-ast-resolve-path.cc | 86 +++++++++++++----------- gcc/rust/resolve/rust-ast-resolve-type.cc | 84 +++++++++++------------ gcc/testsuite/rust/execute/torture/issue-1231.rs | 36 ++++++++++ 3 files changed, 124 insertions(+), 82 deletions(-) create mode 100644 gcc/testsuite/rust/execute/torture/issue-1231.rs (limited to 'gcc') diff --git a/gcc/rust/resolve/rust-ast-resolve-path.cc b/gcc/rust/resolve/rust-ast-resolve-path.cc index c3631fd..9bd836a 100644 --- a/gcc/rust/resolve/rust-ast-resolve-path.cc +++ b/gcc/rust/resolve/rust-ast-resolve-path.cc @@ -130,7 +130,43 @@ ResolvePath::resolve_path (AST::PathInExpression *expr) // // can only use old resolution when previous segment is unkown - if (previous_resolved_node_id == module_scope_id) + if (is_first_segment) + { + // name scope first + NodeId resolved_node = UNKNOWN_NODEID; + const CanonicalPath path + = CanonicalPath::new_seg (segment.get_node_id (), + ident_seg.as_string ()); + if (resolver->get_name_scope ().lookup (path, &resolved_node)) + { + resolver->insert_resolved_name (segment.get_node_id (), + resolved_node); + resolved_node_id = resolved_node; + } + // check the type scope + else if (resolver->get_type_scope ().lookup (path, &resolved_node)) + { + resolver->insert_resolved_type (segment.get_node_id (), + resolved_node); + resolved_node_id = resolved_node; + } + else if (segment.is_lower_self_seg ()) + { + 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; + } + else + { + // no error handling here since we might be able to resolve via + // the module hierarchy and handle errors at the end + } + } + + if (resolved_node_id == UNKNOWN_NODEID + && previous_resolved_node_id == module_scope_id) { Optional resolved_child = mappings->lookup_module_child (module_scope_id, @@ -162,45 +198,8 @@ ResolvePath::resolve_path (AST::PathInExpression *expr) } } - if (resolved_node_id == UNKNOWN_NODEID && is_first_segment) - { - // name scope first - NodeId resolved_node = UNKNOWN_NODEID; - const CanonicalPath path - = CanonicalPath::new_seg (segment.get_node_id (), - ident_seg.as_string ()); - if (resolver->get_name_scope ().lookup (path, &resolved_node)) - { - resolver->insert_resolved_name (segment.get_node_id (), - resolved_node); - } - // check the type scope - else if (resolver->get_type_scope ().lookup (path, &resolved_node)) - { - resolver->insert_resolved_type (segment.get_node_id (), - resolved_node); - } - else - { - if (segment.is_lower_self_seg ()) - { - 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; - } - - rust_error_at (segment.get_locus (), - "Cannot find path %<%s%> in this scope", - segment.as_string ().c_str ()); - return; - } - - resolved_node_id = resolved_node; - } - - if (resolved_node_id != UNKNOWN_NODEID) + bool did_resolve_segment = resolved_node_id != UNKNOWN_NODEID; + if (did_resolve_segment) { if (mappings->node_is_module (resolved_node_id)) { @@ -208,6 +207,13 @@ ResolvePath::resolve_path (AST::PathInExpression *expr) } previous_resolved_node_id = resolved_node_id; } + else if (is_first_segment) + { + rust_error_at (segment.get_locus (), + "Cannot find path %<%s%> in this scope", + segment.as_string ().c_str ()); + return; + } } resolved_node = resolved_node_id; diff --git a/gcc/rust/resolve/rust-ast-resolve-type.cc b/gcc/rust/resolve/rust-ast-resolve-type.cc index 7d7eac1..d444e37 100644 --- a/gcc/rust/resolve/rust-ast-resolve-type.cc +++ b/gcc/rust/resolve/rust-ast-resolve-type.cc @@ -155,8 +155,39 @@ ResolveRelativeTypePath::go (AST::TypePath &path, NodeId &resolved_node_id) break; } - if (previous_resolved_node_id == module_scope_id - && path.get_segments ().size () > 1) + if (is_first_segment) + { + // name scope first + NodeId resolved_node = UNKNOWN_NODEID; + const CanonicalPath path + = CanonicalPath::new_seg (segment->get_node_id (), + ident_seg.as_string ()); + if (resolver->get_type_scope ().lookup (path, &resolved_node)) + { + resolver->insert_resolved_type (segment->get_node_id (), + resolved_node); + resolved_node_id = resolved_node; + } + else if (resolver->get_name_scope ().lookup (path, &resolved_node)) + { + resolver->insert_resolved_name (segment->get_node_id (), + resolved_node); + resolved_node_id = resolved_node; + } + else if (segment->is_lower_self_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; + } + } + + if (resolved_node_id == UNKNOWN_NODEID + && previous_resolved_node_id == module_scope_id) { Optional resolved_child = mappings->lookup_module_child (module_scope_id, @@ -188,46 +219,8 @@ ResolveRelativeTypePath::go (AST::TypePath &path, NodeId &resolved_node_id) } } - if (resolved_node_id == UNKNOWN_NODEID && is_first_segment) - { - // name scope first - NodeId resolved_node = UNKNOWN_NODEID; - const CanonicalPath path - = CanonicalPath::new_seg (segment->get_node_id (), - ident_seg.as_string ()); - if (resolver->get_type_scope ().lookup (path, &resolved_node)) - { - resolver->insert_resolved_type (segment->get_node_id (), - resolved_node); - } - else if (resolver->get_name_scope ().lookup (path, &resolved_node)) - { - resolver->insert_resolved_name (segment->get_node_id (), - resolved_node); - } - else - { - if (segment->is_lower_self_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; - } - - rust_error_at (segment->get_locus (), - "failed to resolve TypePath: %s in this scope", - segment->as_string ().c_str ()); - return false; - } - - resolved_node_id = resolved_node; - } - - if (resolved_node_id != UNKNOWN_NODEID) + bool did_resolve_segment = resolved_node_id != UNKNOWN_NODEID; + if (did_resolve_segment) { if (mappings->node_is_module (resolved_node_id)) { @@ -235,6 +228,13 @@ ResolveRelativeTypePath::go (AST::TypePath &path, NodeId &resolved_node_id) } previous_resolved_node_id = resolved_node_id; } + else if (is_first_segment) + { + rust_error_at (segment->get_locus (), + "failed to resolve TypePath: %s in this scope", + segment->as_string ().c_str ()); + return false; + } } if (resolved_node_id != UNKNOWN_NODEID) diff --git a/gcc/testsuite/rust/execute/torture/issue-1231.rs b/gcc/testsuite/rust/execute/torture/issue-1231.rs new file mode 100644 index 0000000..970e86f --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/issue-1231.rs @@ -0,0 +1,36 @@ +// { dg-additional-options "-w" } +// { dg-output "outer\ninner\n" } +extern "C" { + fn printf(s: *const i8, ...); +} + +fn machin() { + unsafe { + let a = "outer\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c, 123); + } +} + +fn bidule() { + fn machin() { + unsafe { + let a = "inner\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c, 123); + } + } + + self::machin(); + machin(); +} + +fn main() -> i32 { + bidule(); + + 0 +} -- cgit v1.1