aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2022-07-06 09:15:56 +0000
committerGitHub <noreply@github.com>2022-07-06 09:15:56 +0000
commite0844def89deb7953b6eee563833b0e8e8e2668d (patch)
tree7b5e1dc63abdd67e9e9a1ccf8e76ddeb5e10ab64
parent408b7f87b99c1b9d074787ac279c86319ab00667 (diff)
parentf4a5629fb7f6274433005c255bc9baf113856a5d (diff)
downloadgcc-e0844def89deb7953b6eee563833b0e8e8e2668d.zip
gcc-e0844def89deb7953b6eee563833b0e8e8e2668d.tar.gz
gcc-e0844def89deb7953b6eee563833b0e8e8e2668d.tar.bz2
Merge #1346
1346: Support self paths r=philberty a=philberty This adds support for the self path which is used in two different contexts. One where it refers to the self parameter within methods the other is where it can refer to the crate module scope. Handling self has some limitations where it must be the first the segment in the path or be a single segment path for example see: ``` struct foo; fn test() { crate::self::foo; } ``` Errors with (rustc 1.61): ``` Error[E0433]: failed to resolve: `self` in paths can only be used in start position ``` crate and super keywords can be chained as expected but self seems to be a special case. The patch here reorders the algorithm to look at the name/type scope first if its the first segment and handle the lower case self as a special case. If this fails to result in a resolved node we then try to look at the module_scope_id hierarchy to handle the case that the previous segments were crate or super and finally error out at the end if we failed to resolve the segment. We can only error for the first segment as associated paths such as Foo::Bar with Bar being an associated impl block item requiring type-resolution. Fixes #1231 #1227 Co-authored-by: Philip Herron <philip.herron@embecosm.com>
-rw-r--r--gcc/rust/ast/rust-path.h6
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-path.cc89
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-type.cc90
-rw-r--r--gcc/testsuite/rust/compile/self-path1.rs12
-rw-r--r--gcc/testsuite/rust/compile/self-path2.rs21
-rw-r--r--gcc/testsuite/rust/execute/torture/issue-1231.rs36
6 files changed, 188 insertions, 66 deletions
diff --git a/gcc/rust/ast/rust-path.h b/gcc/rust/ast/rust-path.h
index 36f1c04..c6485c0 100644
--- a/gcc/rust/ast/rust-path.h
+++ b/gcc/rust/ast/rust-path.h
@@ -50,6 +50,8 @@ public:
std::string as_string () const { return segment_name; }
+ Location get_locus () const { return locus; }
+
bool is_super_segment () const { return as_string ().compare ("super") == 0; }
bool is_crate_segment () const { return as_string ().compare ("crate") == 0; }
bool is_lower_self () const { return as_string ().compare ("self") == 0; }
@@ -691,6 +693,10 @@ public:
return get_ident_segment ().is_super_segment ();
}
bool is_big_self_seg () const { return get_ident_segment ().is_big_self (); }
+ bool is_lower_self_seg () const
+ {
+ return get_ident_segment ().is_lower_self ();
+ }
};
// Segment used in type path with generic args
diff --git a/gcc/rust/resolve/rust-ast-resolve-path.cc b/gcc/rust/resolve/rust-ast-resolve-path.cc
index 3c69b65..9bd836a 100644
--- a/gcc/rust/resolve/rust-ast-resolve-path.cc
+++ b/gcc/rust/resolve/rust-ast-resolve-path.cc
@@ -59,6 +59,18 @@ ResolvePath::resolve_path (AST::PathInExpression *expr)
bool is_first_segment = i == 0;
resolved_node_id = UNKNOWN_NODEID;
+ bool in_middle_of_path = i > 0;
+ if (in_middle_of_path && segment.is_lower_self_seg ())
+ {
+ // error[E0433]: failed to resolve: `self` in paths can only be used
+ // in start position
+ rust_error_at (segment.get_locus (),
+ "failed to resolve: %<%s%> in paths can only be used "
+ "in start position",
+ segment.as_string ().c_str ());
+ return;
+ }
+
NodeId crate_scope_id = resolver->peek_crate_module_scope ();
if (segment.is_crate_path_seg ())
{
@@ -118,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<CanonicalPath &> resolved_child
= mappings->lookup_module_child (module_scope_id,
@@ -150,36 +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
- {
- 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))
{
@@ -187,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 a823543..d444e37 100644
--- a/gcc/rust/resolve/rust-ast-resolve-type.cc
+++ b/gcc/rust/resolve/rust-ast-resolve-type.cc
@@ -95,6 +95,18 @@ ResolveRelativeTypePath::go (AST::TypePath &path, NodeId &resolved_node_id)
bool is_first_segment = i == 0;
resolved_node_id = UNKNOWN_NODEID;
+ bool in_middle_of_path = i > 0;
+ if (in_middle_of_path && segment->is_lower_self_seg ())
+ {
+ // error[E0433]: failed to resolve: `self` in paths can only be used
+ // in start position
+ rust_error_at (segment->get_locus (),
+ "failed to resolve: %<%s%> in paths can only be used "
+ "in start position",
+ segment->as_string ().c_str ());
+ return false;
+ }
+
NodeId crate_scope_id = resolver->peek_crate_module_scope ();
if (segment->is_crate_path_seg ())
{
@@ -129,10 +141,7 @@ ResolveRelativeTypePath::go (AST::TypePath &path, NodeId &resolved_node_id)
= static_cast<AST::TypePathSegmentGeneric *> (segment.get ());
if (s->has_generic_args ())
{
- for (auto &gt : s->get_generic_args ().get_type_args ())
- {
- ResolveType::go (gt.get ());
- }
+ ResolveType::type_resolve_generic_args (s->get_generic_args ());
}
}
break;
@@ -146,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<CanonicalPath &> resolved_child
= mappings->lookup_module_child (module_scope_id,
@@ -179,35 +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
- {
- 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))
{
@@ -215,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/compile/self-path1.rs b/gcc/testsuite/rust/compile/self-path1.rs
new file mode 100644
index 0000000..425ba84
--- /dev/null
+++ b/gcc/testsuite/rust/compile/self-path1.rs
@@ -0,0 +1,12 @@
+// { dg-additional-options "-w" }
+struct foo;
+
+fn bar() -> self::foo {
+ crate::foo
+}
+
+fn baz() {
+ let a: foo = self::bar();
+
+ crate::bar();
+}
diff --git a/gcc/testsuite/rust/compile/self-path2.rs b/gcc/testsuite/rust/compile/self-path2.rs
new file mode 100644
index 0000000..b9b82ca
--- /dev/null
+++ b/gcc/testsuite/rust/compile/self-path2.rs
@@ -0,0 +1,21 @@
+// { dg-additional-options "-w" }
+struct foo;
+
+fn bar() -> self::foo {
+ crate::foo
+}
+
+fn baz() {
+ let a: foo = self::bar();
+
+ crate::bar();
+
+ crate::self::foo();
+ // { dg-error "failed to resolve: .self. in paths can only be used in start position" "" { target *-*-* } .-1 }
+}
+
+type a = foo;
+type b = crate::foo;
+type c = self::foo;
+type d = crate::self::foo;
+// { dg-error "failed to resolve: .self. in paths can only be used in start position" "" { target *-*-* } .-1 }
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
+}