aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/rust/ast/rust-ast.h2
-rw-r--r--gcc/rust/ast/rust-item.h57
-rw-r--r--gcc/rust/backend/rust-compile-base.cc8
-rw-r--r--gcc/rust/backend/rust-compile-base.h2
-rw-r--r--gcc/rust/expand/rust-attribute-visitor.cc175
-rw-r--r--gcc/rust/expand/rust-attribute-visitor.h2
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-item.cc297
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-item.h11
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-type.cc47
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-type.h55
-rw-r--r--gcc/rust/rust-lang.cc2
-rw-r--r--gcc/rust/rust-session-manager.cc36
-rw-r--r--gcc/testsuite/rust/compile/torture/cfg_attr.rs2
-rw-r--r--gcc/testsuite/rust/compile/use_1.rs16
14 files changed, 518 insertions, 194 deletions
diff --git a/gcc/rust/ast/rust-ast.h b/gcc/rust/ast/rust-ast.h
index fb8982a..69ad6eb 100644
--- a/gcc/rust/ast/rust-ast.h
+++ b/gcc/rust/ast/rust-ast.h
@@ -410,6 +410,8 @@ public:
{
return segments;
}
+
+ std::vector<SimplePathSegment> &get_segments () { return segments; }
};
// path-to-string inverse comparison operator
diff --git a/gcc/rust/ast/rust-item.h b/gcc/rust/ast/rust-item.h
index 9dc61a8..4bed5af 100644
--- a/gcc/rust/ast/rust-item.h
+++ b/gcc/rust/ast/rust-item.h
@@ -1179,8 +1179,29 @@ class UseTree
Location locus;
public:
+ enum Kind
+ {
+ Glob,
+ Rebind,
+ List,
+ };
+
virtual ~UseTree () {}
+ // Overload assignment operator to clone
+ UseTree &operator= (UseTree const &other)
+ {
+ locus = other.locus;
+
+ return *this;
+ }
+
+ UseTree (const UseTree &other) = default;
+
+ // move constructors
+ UseTree (UseTree &&other) = default;
+ UseTree &operator= (UseTree &&other) = default;
+
// Unique pointer custom clone function
std::unique_ptr<UseTree> clone_use_tree () const
{
@@ -1188,6 +1209,7 @@ public:
}
virtual std::string as_string () const = 0;
+ virtual Kind get_kind () const = 0;
Location get_locus () const { return locus; }
@@ -1237,6 +1259,14 @@ public:
void accept_vis (ASTVisitor &vis) override;
+ Kind get_kind () const override { return Glob; }
+
+ SimplePath get_path () const
+ {
+ rust_assert (has_path ());
+ return path;
+ }
+
/* TODO: find way to ensure only PATH_PREFIXED glob_type has path - factory
* methods? */
protected:
@@ -1318,6 +1348,18 @@ public:
void accept_vis (ASTVisitor &vis) override;
+ Kind get_kind () const override { return List; }
+ SimplePath get_path () const
+ {
+ rust_assert (has_path ());
+ return path;
+ }
+
+ const std::vector<std::unique_ptr<UseTree>> &get_trees () const
+ {
+ return trees;
+ }
+
// TODO: find way to ensure only PATH_PREFIXED path_type has path - factory
// methods?
protected:
@@ -1363,6 +1405,20 @@ public:
void accept_vis (ASTVisitor &vis) override;
+ Kind get_kind () const override { return Rebind; }
+
+ SimplePath get_path () const
+ {
+ rust_assert (has_path ());
+ return path;
+ }
+
+ const Identifier &get_identifier () const
+ {
+ rust_assert (has_identifier ());
+ return identifier;
+ }
+
// TODO: find way to ensure only PATH_PREFIXED path_type has path - factory
// methods?
protected:
@@ -1420,6 +1476,7 @@ public:
UseDeclaration &operator= (UseDeclaration &&other) = default;
Location get_locus () const override final { return locus; }
+ const std::unique_ptr<UseTree> &get_tree () const { return use_tree; }
void accept_vis (ASTVisitor &vis) override;
diff --git a/gcc/rust/backend/rust-compile-base.cc b/gcc/rust/backend/rust-compile-base.cc
index b969b7a..49f31fc 100644
--- a/gcc/rust/backend/rust-compile-base.cc
+++ b/gcc/rust/backend/rust-compile-base.cc
@@ -38,14 +38,14 @@ bool inline should_mangle_item (const tree fndecl)
void
HIRCompileBase::setup_fndecl (tree fndecl, bool is_main_entry_point,
- HIR::Visibility &visibility,
+ bool is_generic_fn, HIR::Visibility &visibility,
const HIR::FunctionQualifiers &qualifiers,
const AST::AttrVec &attrs)
{
// if its the main fn or pub visibility mark its as DECL_PUBLIC
// please see https://github.com/Rust-GCC/gccrs/pull/137
bool is_pub = visibility.get_vis_type () == HIR::Visibility::VisType::PUBLIC;
- if (is_main_entry_point || is_pub)
+ if (is_main_entry_point || (is_pub && !is_generic_fn))
{
TREE_PUBLIC (fndecl) = 1;
}
@@ -427,7 +427,9 @@ HIRCompileBase::compile_function (
unsigned int flags = 0;
tree fndecl = ctx->get_backend ()->function (compiled_fn_type, ir_symbol_name,
"" /* asm_name */, flags, locus);
- setup_fndecl (fndecl, is_main_fn, visibility, qualifiers, outer_attrs);
+
+ setup_fndecl (fndecl, is_main_fn, fntype->has_subsititions_defined (),
+ visibility, qualifiers, outer_attrs);
setup_abi_options (fndecl, fntype->get_abi ());
// conditionally mangle the function name
diff --git a/gcc/rust/backend/rust-compile-base.h b/gcc/rust/backend/rust-compile-base.h
index c09c562..f12913c 100644
--- a/gcc/rust/backend/rust-compile-base.h
+++ b/gcc/rust/backend/rust-compile-base.h
@@ -76,7 +76,7 @@ protected:
tree expression, Location locus);
static void setup_fndecl (tree fndecl, bool is_main_entry_point,
- HIR::Visibility &visibility,
+ bool is_generic_fn, HIR::Visibility &visibility,
const HIR::FunctionQualifiers &qualifiers,
const AST::AttrVec &attrs);
diff --git a/gcc/rust/expand/rust-attribute-visitor.cc b/gcc/rust/expand/rust-attribute-visitor.cc
index 842fbdf..771f034 100644
--- a/gcc/rust/expand/rust-attribute-visitor.cc
+++ b/gcc/rust/expand/rust-attribute-visitor.cc
@@ -41,9 +41,7 @@ AttrVisitor::expand_struct_fields (std::vector<AST::StructField> &fields)
auto &type = field.get_field_type ();
type->accept_vis (*this);
- auto t_fragment = expander.take_expanded_fragment (*this);
- if (t_fragment.should_expand ())
- type = t_fragment.take_type_fragment ();
+ maybe_expand_type (type);
if (type->is_marked_for_strip ())
rust_error_at (type->get_locus (),
@@ -110,9 +108,7 @@ AttrVisitor::expand_function_params (std::vector<AST::FunctionParam> &params)
auto &type = param.get_type ();
type->accept_vis (*this);
- auto t_fragment = expander.take_expanded_fragment (*this);
- if (t_fragment.should_expand ())
- type = t_fragment.take_type_fragment ();
+ maybe_expand_type (type);
if (type->is_marked_for_strip ())
rust_error_at (type->get_locus (),
@@ -137,9 +133,7 @@ AttrVisitor::expand_generic_args (AST::GenericArgs &args)
for (auto &type : args.get_type_args ())
{
type->accept_vis (*this);
- auto t_fragment = expander.take_expanded_fragment (*this);
- if (t_fragment.should_expand ())
- type = t_fragment.take_type_fragment ();
+ maybe_expand_type (type);
if (type->is_marked_for_strip ())
rust_error_at (type->get_locus (),
@@ -169,9 +163,7 @@ AttrVisitor::expand_qualified_path_type (AST::QualifiedPathType &path_type)
auto &type = path_type.get_type ();
type->accept_vis (*this);
- auto t_fragment = expander.take_expanded_fragment (*this);
- if (t_fragment.should_expand ())
- type = t_fragment.take_type_fragment ();
+ maybe_expand_type (type);
expander.pop_context ();
@@ -216,9 +208,7 @@ AttrVisitor::AttrVisitor::expand_closure_params (
auto &type = param.get_type ();
type->accept_vis (*this);
- auto t_fragment = expander.take_expanded_fragment (*this);
- if (t_fragment.should_expand ())
- type = t_fragment.take_type_fragment ();
+ maybe_expand_type (type);
if (type->is_marked_for_strip ())
rust_error_at (type->get_locus (),
@@ -241,9 +231,7 @@ AttrVisitor::expand_self_param (AST::SelfParam &self_param)
auto &type = self_param.get_type ();
type->accept_vis (*this);
- auto t_fragment = expander.take_expanded_fragment (*this);
- if (t_fragment.should_expand ())
- type = t_fragment.take_type_fragment ();
+ maybe_expand_type (type);
if (type->is_marked_for_strip ())
rust_error_at (type->get_locus (),
@@ -281,9 +269,7 @@ AttrVisitor::expand_trait_function_decl (AST::TraitFunctionDecl &decl)
auto &return_type = decl.get_return_type ();
return_type->accept_vis (*this);
- auto r_fragment = expander.take_expanded_fragment (*this);
- if (r_fragment.should_expand ())
- return_type = r_fragment.take_type_fragment ();
+ maybe_expand_type (return_type);
if (return_type->is_marked_for_strip ())
rust_error_at (return_type->get_locus (),
@@ -319,9 +305,7 @@ AttrVisitor::expand_trait_method_decl (AST::TraitMethodDecl &decl)
auto &return_type = decl.get_return_type ();
return_type->accept_vis (*this);
- auto r_fragment = expander.take_expanded_fragment (*this);
- if (r_fragment.should_expand ())
- return_type = r_fragment.take_type_fragment ();
+ maybe_expand_type (return_type);
if (return_type->is_marked_for_strip ())
rust_error_at (return_type->get_locus (),
@@ -445,9 +429,7 @@ AttrVisitor::visit (AST::TypePathSegmentFunction &segment)
auto &return_type = type_path_function.get_return_type ();
return_type->accept_vis (*this);
- auto r_fragment = expander.take_expanded_fragment (*this);
- if (r_fragment.should_expand ())
- return_type = r_fragment.take_type_fragment ();
+ maybe_expand_type (return_type);
if (return_type->is_marked_for_strip ())
rust_error_at (return_type->get_locus (),
@@ -612,17 +594,13 @@ AttrVisitor::visit (AST::ArithmeticOrLogicalExpr &expr)
* with outer expr */
auto &l_expr = expr.get_left_expr ();
l_expr->accept_vis (*this);
- auto l_fragment = expander.take_expanded_fragment (*this);
- if (l_fragment.should_expand ())
- l_expr = l_fragment.take_expression_fragment ();
+ maybe_expand_expr (l_expr);
/* should syntactically not have outer attributes, though this may
* not have worked in practice */
auto &r_expr = expr.get_right_expr ();
r_expr->accept_vis (*this);
- auto r_fragment = expander.take_expanded_fragment (*this);
- if (r_fragment.should_expand ())
- r_expr = r_fragment.take_expression_fragment ();
+ maybe_expand_expr (r_expr);
// ensure that they are not marked for strip
if (expr.get_left_expr ()->is_marked_for_strip ())
@@ -645,17 +623,13 @@ AttrVisitor::visit (AST::ComparisonExpr &expr)
* with outer expr */
auto &l_expr = expr.get_left_expr ();
l_expr->accept_vis (*this);
- auto l_fragment = expander.take_expanded_fragment (*this);
- if (l_fragment.should_expand ())
- l_expr = l_fragment.take_expression_fragment ();
+ maybe_expand_expr (l_expr);
/* should syntactically not have outer attributes, though this may
* not have worked in practice */
auto &r_expr = expr.get_right_expr ();
r_expr->accept_vis (*this);
- auto r_fragment = expander.take_expanded_fragment (*this);
- if (r_fragment.should_expand ())
- r_expr = r_fragment.take_expression_fragment ();
+ maybe_expand_expr (r_expr);
// ensure that they are not marked for strip
if (expr.get_left_expr ()->is_marked_for_strip ())
@@ -678,17 +652,13 @@ AttrVisitor::visit (AST::LazyBooleanExpr &expr)
* with outer expr */
auto &l_expr = expr.get_left_expr ();
l_expr->accept_vis (*this);
- auto l_fragment = expander.take_expanded_fragment (*this);
- if (l_fragment.should_expand ())
- l_expr = l_fragment.take_expression_fragment ();
+ maybe_expand_expr (l_expr);
/* should syntactically not have outer attributes, though this may
* not have worked in practice */
auto &r_expr = expr.get_right_expr ();
r_expr->accept_vis (*this);
- auto r_fragment = expander.take_expanded_fragment (*this);
- if (r_fragment.should_expand ())
- r_expr = r_fragment.take_expression_fragment ();
+ maybe_expand_expr (r_expr);
// ensure that they are not marked for strip
if (expr.get_left_expr ()->is_marked_for_strip ())
@@ -738,17 +708,13 @@ AttrVisitor::visit (AST::AssignmentExpr &expr)
* with outer expr */
auto &l_expr = expr.get_left_expr ();
l_expr->accept_vis (*this);
- auto l_fragment = expander.take_expanded_fragment (*this);
- if (l_fragment.should_expand ())
- l_expr = l_fragment.take_expression_fragment ();
+ maybe_expand_expr (l_expr);
/* should syntactically not have outer attributes, though this may
* not have worked in practice */
auto &r_expr = expr.get_right_expr ();
r_expr->accept_vis (*this);
- auto r_fragment = expander.take_expanded_fragment (*this);
- if (r_fragment.should_expand ())
- r_expr = r_fragment.take_expression_fragment ();
+ maybe_expand_expr (r_expr);
// ensure that they are not marked for strip
if (expr.get_left_expr ()->is_marked_for_strip ())
@@ -771,17 +737,13 @@ AttrVisitor::visit (AST::CompoundAssignmentExpr &expr)
* with outer expr */
auto &l_expr = expr.get_left_expr ();
l_expr->accept_vis (*this);
- auto l_frag = expander.take_expanded_fragment (*this);
- if (l_frag.should_expand ())
- l_expr = l_frag.take_expression_fragment ();
+ maybe_expand_expr (l_expr);
/* should syntactically not have outer attributes, though this may
* not have worked in practice */
auto &r_expr = expr.get_right_expr ();
r_expr->accept_vis (*this);
- auto r_frag = expander.take_expanded_fragment (*this);
- if (r_frag.should_expand ())
- r_expr = r_frag.take_expression_fragment ();
+ maybe_expand_expr (r_expr);
// ensure that they are not marked for strip
if (expr.get_left_expr ()->is_marked_for_strip ())
@@ -1259,9 +1221,7 @@ AttrVisitor::visit (AST::BlockExpr &expr)
auto &tail_expr = expr.get_tail_expr ();
tail_expr->accept_vis (*this);
- auto fragment = expander.take_expanded_fragment (*this);
- if (fragment.should_expand ())
- tail_expr = fragment.take_expression_fragment ();
+ maybe_expand_expr (tail_expr);
if (tail_expr->is_marked_for_strip ())
expr.strip_tail_expr ();
@@ -1290,9 +1250,7 @@ AttrVisitor::visit (AST::ClosureExprInnerTyped &expr)
auto &type = expr.get_return_type ();
type->accept_vis (*this);
- auto t_fragment = expander.take_expanded_fragment (*this);
- if (t_fragment.should_expand ())
- type = t_fragment.take_type_fragment ();
+ maybe_expand_type (type);
if (type->is_marked_for_strip ())
rust_error_at (type->get_locus (), "cannot strip type in this position");
@@ -1630,9 +1588,7 @@ AttrVisitor::visit (AST::IfExpr &expr)
// can't strip condition expr itself, but can strip sub-expressions
auto &condition_expr = expr.get_condition_expr ();
condition_expr->accept_vis (*this);
- auto cond_fragment = expander.take_expanded_fragment (*this);
- if (cond_fragment.should_expand ())
- condition_expr = cond_fragment.take_expression_fragment ();
+ maybe_expand_expr (condition_expr);
if (condition_expr->is_marked_for_strip ())
rust_error_at (condition_expr->get_locus (),
"cannot strip expression in this position - outer "
@@ -1660,9 +1616,7 @@ AttrVisitor::visit (AST::IfExprConseqElse &expr)
// can't strip condition expr itself, but can strip sub-expressions
auto &condition_expr = expr.get_condition_expr ();
condition_expr->accept_vis (*this);
- auto cond_fragment = expander.take_expanded_fragment (*this);
- if (cond_fragment.should_expand ())
- condition_expr = cond_fragment.take_expression_fragment ();
+ maybe_expand_expr (condition_expr);
if (condition_expr->is_marked_for_strip ())
rust_error_at (condition_expr->get_locus (),
"cannot strip expression in this position - outer "
@@ -1698,9 +1652,7 @@ AttrVisitor::visit (AST::IfExprConseqIf &expr)
// can't strip condition expr itself, but can strip sub-expressions
auto &condition_expr = expr.get_condition_expr ();
condition_expr->accept_vis (*this);
- auto cond_fragment = expander.take_expanded_fragment (*this);
- if (cond_fragment.should_expand ())
- condition_expr = cond_fragment.take_expression_fragment ();
+ maybe_expand_expr (condition_expr);
if (condition_expr->is_marked_for_strip ())
rust_error_at (condition_expr->get_locus (),
"cannot strip expression in this position - outer "
@@ -1736,9 +1688,7 @@ AttrVisitor::visit (AST::IfExprConseqIfLet &expr)
// can't strip condition expr itself, but can strip sub-expressions
auto &condition_expr = expr.get_condition_expr ();
condition_expr->accept_vis (*this);
- auto cond_fragment = expander.take_expanded_fragment (*this);
- if (cond_fragment.should_expand ())
- condition_expr = cond_fragment.take_expression_fragment ();
+ maybe_expand_expr (condition_expr);
if (condition_expr->is_marked_for_strip ())
rust_error_at (condition_expr->get_locus (),
"cannot strip expression in this position - outer "
@@ -2061,9 +2011,7 @@ AttrVisitor::visit (AST::TypeParam &param)
auto &type = param.get_type ();
type->accept_vis (*this);
- auto t_fragment = expander.take_expanded_fragment (*this);
- if (t_fragment.should_expand ())
- type = t_fragment.take_type_fragment ();
+ maybe_expand_type (type);
if (type->is_marked_for_strip ())
rust_error_at (type->get_locus (),
@@ -2087,9 +2035,7 @@ AttrVisitor::visit (AST::TypeBoundWhereClauseItem &item)
auto &type = item.get_type ();
type->accept_vis (*this);
- auto t_fragment = expander.take_expanded_fragment (*this);
- if (t_fragment.should_expand ())
- type = t_fragment.take_type_fragment ();
+ maybe_expand_type (type);
if (type->is_marked_for_strip ())
rust_error_at (type->get_locus (), "cannot strip type in this position");
@@ -2131,9 +2077,7 @@ AttrVisitor::visit (AST::Method &method)
auto &return_type = method.get_return_type ();
return_type->accept_vis (*this);
- auto r_fragment = expander.take_expanded_fragment (*this);
- if (r_fragment.should_expand ())
- return_type = r_fragment.take_type_fragment ();
+ maybe_expand_type (return_type);
if (return_type->is_marked_for_strip ())
rust_error_at (return_type->get_locus (),
@@ -2253,9 +2197,7 @@ AttrVisitor::visit (AST::Function &function)
auto &return_type = function.get_return_type ();
return_type->accept_vis (*this);
- auto t_fragment = expander.take_expanded_fragment (*this);
- if (t_fragment.should_expand ())
- return_type = t_fragment.take_type_fragment ();
+ maybe_expand_type (return_type);
if (return_type->is_marked_for_strip ())
rust_error_at (return_type->get_locus (),
@@ -2467,9 +2409,7 @@ AttrVisitor::visit (AST::ConstantItem &const_item)
auto &type = const_item.get_type ();
type->accept_vis (*this);
- auto t_fragment = expander.take_expanded_fragment (*this);
- if (t_fragment.should_expand ())
- type = t_fragment.take_type_fragment ();
+ maybe_expand_type (type);
if (type->is_marked_for_strip ())
rust_error_at (type->get_locus (), "cannot strip type in this position");
@@ -2503,9 +2443,7 @@ AttrVisitor::visit (AST::StaticItem &static_item)
auto &type = static_item.get_type ();
type->accept_vis (*this);
- auto t_fragment = expander.take_expanded_fragment (*this);
- if (t_fragment.should_expand ())
- type = t_fragment.take_type_fragment ();
+ maybe_expand_type (type);
if (type->is_marked_for_strip ())
rust_error_at (type->get_locus (), "cannot strip type in this position");
@@ -2591,9 +2529,7 @@ AttrVisitor::visit (AST::TraitItemConst &item)
auto &type = item.get_type ();
type->accept_vis (*this);
- auto t_fragment = expander.take_expanded_fragment (*this);
- if (t_fragment.should_expand ())
- type = t_fragment.take_type_fragment ();
+ maybe_expand_type (type);
if (type->is_marked_for_strip ())
rust_error_at (type->get_locus (), "cannot strip type in this position");
@@ -2698,9 +2634,7 @@ AttrVisitor::visit (AST::InherentImpl &impl)
auto &type = impl.get_type ();
type->accept_vis (*this);
- auto t_fragment = expander.take_expanded_fragment (*this);
- if (t_fragment.should_expand ())
- type = t_fragment.take_type_fragment ();
+ maybe_expand_type (type);
if (type->is_marked_for_strip ())
rust_error_at (type->get_locus (), "cannot strip type in this position");
@@ -2744,9 +2678,7 @@ AttrVisitor::visit (AST::TraitImpl &impl)
auto &type = impl.get_type ();
type->accept_vis (*this);
- auto t_fragment = expander.take_expanded_fragment (*this);
- if (t_fragment.should_expand ())
- type = t_fragment.take_type_fragment ();
+ maybe_expand_type (type);
if (type->is_marked_for_strip ())
rust_error_at (type->get_locus (), "cannot strip type in this position");
@@ -2785,9 +2717,7 @@ AttrVisitor::visit (AST::ExternalStaticItem &item)
auto &type = item.get_type ();
type->accept_vis (*this);
- auto t_fragment = expander.take_expanded_fragment (*this);
- if (t_fragment.should_expand ())
- type = t_fragment.take_type_fragment ();
+ maybe_expand_type (type);
if (type->is_marked_for_strip ())
rust_error_at (type->get_locus (), "cannot strip type in this position");
@@ -2829,9 +2759,7 @@ AttrVisitor::visit (AST::ExternalFunctionItem &item)
auto &type = param.get_type ();
type->accept_vis (*this);
- auto t_fragment = expander.take_expanded_fragment (*this);
- if (t_fragment.should_expand ())
- type = t_fragment.take_type_fragment ();
+ maybe_expand_type (type);
if (type->is_marked_for_strip ())
rust_error_at (type->get_locus (),
@@ -2856,9 +2784,7 @@ AttrVisitor::visit (AST::ExternalFunctionItem &item)
auto &return_type = item.get_return_type ();
return_type->accept_vis (*this);
- auto r_fragment = expander.take_expanded_fragment (*this);
- if (r_fragment.should_expand ())
- return_type = r_fragment.take_type_fragment ();
+ maybe_expand_type (return_type);
if (return_type->is_marked_for_strip ())
rust_error_at (return_type->get_locus (),
@@ -3233,9 +3159,7 @@ AttrVisitor::visit (AST::LetStmt &stmt)
auto &type = stmt.get_type ();
type->accept_vis (*this);
- auto t_fragment = expander.take_expanded_fragment (*this);
- if (t_fragment.should_expand ())
- type = t_fragment.take_type_fragment ();
+ maybe_expand_type (type);
if (type->is_marked_for_strip ())
rust_error_at (type->get_locus (),
@@ -3257,9 +3181,7 @@ AttrVisitor::visit (AST::LetStmt &stmt)
"cannot strip expression in this position - outer "
"attributes not allowed");
- auto fragment = expander.take_expanded_fragment (*this);
- if (fragment.should_expand ())
- init_expr = fragment.take_expression_fragment ();
+ maybe_expand_expr (init_expr);
}
}
void
@@ -3441,9 +3363,7 @@ AttrVisitor::visit (AST::BareFunctionType &type)
auto &type = param.get_type ();
type->accept_vis (*this);
- auto t_fragment = expander.take_expanded_fragment (*this);
- if (t_fragment.should_expand ())
- type = t_fragment.take_type_fragment ();
+ maybe_expand_type (type);
if (type->is_marked_for_strip ())
rust_error_at (type->get_locus (),
@@ -3472,4 +3392,19 @@ AttrVisitor::visit (AST::BareFunctionType &type)
// no where clause, apparently
}
+void
+AttrVisitor::maybe_expand_expr (std::unique_ptr<AST::Expr> &expr)
+{
+ auto fragment = expander.take_expanded_fragment (*this);
+ if (fragment.should_expand ())
+ expr = fragment.take_expression_fragment ();
+}
+
+void
+AttrVisitor::maybe_expand_type (std::unique_ptr<AST::Type> &type)
+{
+ auto fragment = expander.take_expanded_fragment (*this);
+ if (fragment.should_expand ())
+ type = fragment.take_type_fragment ();
+}
} // namespace Rust
diff --git a/gcc/rust/expand/rust-attribute-visitor.h b/gcc/rust/expand/rust-attribute-visitor.h
index 1c6410d..4b42d78 100644
--- a/gcc/rust/expand/rust-attribute-visitor.h
+++ b/gcc/rust/expand/rust-attribute-visitor.h
@@ -25,6 +25,8 @@ class AttrVisitor : public AST::ASTVisitor
{
private:
MacroExpander &expander;
+ void maybe_expand_expr (std::unique_ptr<AST::Expr> &expr);
+ void maybe_expand_type (std::unique_ptr<AST::Type> &expr);
public:
AttrVisitor (MacroExpander &expander) : expander (expander) {}
diff --git a/gcc/rust/resolve/rust-ast-resolve-item.cc b/gcc/rust/resolve/rust-ast-resolve-item.cc
index 2c383c9..93eca1b 100644
--- a/gcc/rust/resolve/rust-ast-resolve-item.cc
+++ b/gcc/rust/resolve/rust-ast-resolve-item.cc
@@ -17,6 +17,8 @@
// <http://www.gnu.org/licenses/>.
#include "rust-ast-resolve-item.h"
+#include "rust-ast-resolve-path.h"
+#include "selftest.h"
namespace Rust {
namespace Resolver {
@@ -133,7 +135,7 @@ ResolveTraitItems::visit (AST::TraitItemMethod &func)
self_param.get_is_mut (),
std::unique_ptr<AST::Pattern> (nullptr));
- std::vector<std::unique_ptr<AST::TypePathSegment> > segments;
+ std::vector<std::unique_ptr<AST::TypePathSegment>> segments;
segments.push_back (std::unique_ptr<AST::TypePathSegment> (
new AST::TypePathSegment ("Self", false, self_param.get_locus ())));
@@ -694,7 +696,7 @@ ResolveItem::visit (AST::Method &method)
self_param.get_is_mut (),
std::unique_ptr<AST::Pattern> (nullptr));
- std::vector<std::unique_ptr<AST::TypePathSegment> > segments;
+ std::vector<std::unique_ptr<AST::TypePathSegment>> segments;
segments.push_back (std::unique_ptr<AST::TypePathSegment> (
new AST::TypePathSegment ("Self", false, self_param.get_locus ())));
@@ -902,6 +904,133 @@ ResolveItem::visit (AST::ExternBlock &extern_block)
}
}
+static void
+flatten_glob (const AST::UseTreeGlob &glob,
+ std::vector<AST::SimplePath> &paths);
+static void
+flatten_rebind (const AST::UseTreeRebind &glob,
+ std::vector<AST::SimplePath> &paths);
+static void
+flatten_list (const AST::UseTreeList &glob,
+ std::vector<AST::SimplePath> &paths);
+
+static void
+flatten (const AST::UseTree *tree, std::vector<AST::SimplePath> &paths)
+{
+ switch (tree->get_kind ())
+ {
+ case AST::UseTree::Glob: {
+ auto glob = static_cast<const AST::UseTreeGlob *> (tree);
+ flatten_glob (*glob, paths);
+ break;
+ }
+ case AST::UseTree::Rebind: {
+ auto rebind = static_cast<const AST::UseTreeRebind *> (tree);
+ flatten_rebind (*rebind, paths);
+ break;
+ }
+ case AST::UseTree::List: {
+ auto list = static_cast<const AST::UseTreeList *> (tree);
+ flatten_list (*list, paths);
+ break;
+ }
+ break;
+ }
+}
+
+static void
+flatten_glob (const AST::UseTreeGlob &glob, std::vector<AST::SimplePath> &paths)
+{
+ if (glob.has_path ())
+ paths.emplace_back (glob.get_path ());
+}
+
+static void
+flatten_rebind (const AST::UseTreeRebind &rebind,
+ std::vector<AST::SimplePath> &paths)
+{
+ auto path = rebind.get_path ();
+ if (rebind.has_path ())
+ paths.emplace_back (path);
+
+ // FIXME: Do we want to emplace the rebind here as well?
+ if (rebind.has_identifier ())
+ {
+ auto rebind_path = path;
+ auto new_seg = rebind.get_identifier ();
+
+ // Add the identifier as a new path
+ rebind_path.get_segments ().back ()
+ = AST::SimplePathSegment (new_seg, Location ());
+
+ paths.emplace_back (rebind_path);
+ }
+}
+
+static void
+flatten_list (const AST::UseTreeList &list, std::vector<AST::SimplePath> &paths)
+{
+ auto prefix = AST::SimplePath::create_empty ();
+ if (list.has_path ())
+ prefix = list.get_path ();
+
+ for (const auto &tree : list.get_trees ())
+ {
+ auto sub_paths = std::vector<AST::SimplePath> ();
+ flatten (tree.get (), sub_paths);
+
+ for (auto &sub_path : sub_paths)
+ {
+ auto new_path = prefix;
+ std::copy (sub_path.get_segments ().begin (),
+ sub_path.get_segments ().end (),
+ std::back_inserter (new_path.get_segments ()));
+
+ paths.emplace_back (new_path);
+ }
+ }
+}
+
+/**
+ * Flatten a UseDeclaration's UseTree into multiple simple paths to resolve.
+ *
+ * Given the following use declarations:
+ * ```
+ * use some::path::to_resolve; #1
+ * use some::path::to_glob::*; #2
+ * use some::path::{one, two}; #2
+ * ```
+ *
+ * In the first case, we simply want to return a vector with a single
+ * SimplePath:
+ * [some::path::to_resolve]
+ *
+ * In the second case, we want to resolve the glob's "origin path":
+ * [some::path::to_glob]
+ *
+ * Finally in the third case, we want to create two SimplePaths to resolve:
+ * [some::path::one, some::path::two]
+ */
+static std::vector<AST::SimplePath>
+flatten_use_dec_to_paths (const AST::UseDeclaration &use_item)
+{
+ auto paths = std::vector<AST::SimplePath> ();
+
+ const auto &tree = use_item.get_tree ();
+ flatten (tree.get (), paths);
+
+ return paths;
+}
+
+void
+ResolveItem::visit (AST::UseDeclaration &use_item)
+{
+ auto to_resolve = flatten_use_dec_to_paths (use_item);
+
+ for (auto &path : to_resolve)
+ ResolvePath::go (&path, parent);
+}
+
void
ResolveImplItems::go (AST::InherentImplItem *item, const CanonicalPath &prefix,
const CanonicalPath &canonical_prefix)
@@ -991,3 +1120,167 @@ ResolveExternItem::visit (AST::ExternalStaticItem &item)
} // namespace Resolver
} // namespace Rust
+
+#if CHECKING_P
+
+namespace selftest {
+
+static void
+rust_flatten_nested_glob (void)
+{
+ auto foo = Rust::AST::SimplePathSegment ("foo", Location ());
+ auto bar = Rust::AST::SimplePathSegment ("bar", Location ());
+ auto foobar = Rust::AST::SimplePath ({foo, bar});
+
+ auto glob
+ = Rust::AST::UseTreeGlob (Rust::AST::UseTreeGlob::PathType::PATH_PREFIXED,
+ foobar, Location ());
+
+ auto paths = std::vector<Rust::AST::SimplePath> ();
+ Rust::Resolver::flatten_glob (glob, paths);
+
+ ASSERT_TRUE (!paths.empty ());
+ ASSERT_EQ (paths.size (), 1);
+ ASSERT_EQ (paths[0].get_segments ()[0].as_string (), "foo");
+ ASSERT_EQ (paths[0].get_segments ()[1].as_string (), "bar");
+}
+
+static void
+rust_flatten_glob (void)
+{
+ auto frob = Rust::AST::SimplePath::from_str ("frobulator", Location ());
+
+ auto glob
+ = Rust::AST::UseTreeGlob (Rust::AST::UseTreeGlob::PathType::PATH_PREFIXED,
+ frob, Location ());
+
+ auto paths = std::vector<Rust::AST::SimplePath> ();
+ Rust::Resolver::flatten_glob (glob, paths);
+
+ ASSERT_TRUE (!paths.empty ());
+ ASSERT_EQ (paths.size (), 1);
+ ASSERT_EQ (paths[0], "frobulator");
+}
+
+static void
+rust_flatten_rebind_none (void)
+{
+ auto foo = Rust::AST::SimplePathSegment ("foo", Location ());
+ auto bar = Rust::AST::SimplePathSegment ("bar", Location ());
+ auto foobar = Rust::AST::SimplePath ({foo, bar});
+
+ auto rebind = Rust::AST::UseTreeRebind (Rust::AST::UseTreeRebind::NONE,
+ foobar, Location ());
+
+ auto paths = std::vector<Rust::AST::SimplePath> ();
+ Rust::Resolver::flatten_rebind (rebind, paths);
+
+ ASSERT_TRUE (!paths.empty ());
+ ASSERT_EQ (paths.size (), 1);
+ ASSERT_EQ (paths[0].get_segments ()[0].as_string (), "foo");
+ ASSERT_EQ (paths[0].get_segments ()[1].as_string (), "bar");
+}
+
+static void
+rust_flatten_rebind (void)
+{
+ auto frob = Rust::AST::SimplePath::from_str ("frobulator", Location ());
+
+ auto rebind = Rust::AST::UseTreeRebind (Rust::AST::UseTreeRebind::IDENTIFIER,
+ frob, Location (), "saindoux");
+
+ auto paths = std::vector<Rust::AST::SimplePath> ();
+ Rust::Resolver::flatten_rebind (rebind, paths);
+
+ ASSERT_TRUE (!paths.empty ());
+ ASSERT_EQ (paths.size (), 2);
+ ASSERT_EQ (paths[0], "frobulator");
+ ASSERT_EQ (paths[1], "saindoux");
+}
+
+static void
+rust_flatten_rebind_nested (void)
+{
+ auto foo = Rust::AST::SimplePathSegment ("foo", Location ());
+ auto bar = Rust::AST::SimplePathSegment ("bar", Location ());
+ auto baz = Rust::AST::SimplePathSegment ("baz", Location ());
+
+ auto foo_bar_baz = Rust::AST::SimplePath ({foo, bar, baz});
+
+ auto rebind = Rust::AST::UseTreeRebind (Rust::AST::UseTreeRebind::IDENTIFIER,
+ foo_bar_baz, Location (), "saindoux");
+
+ auto paths = std::vector<Rust::AST::SimplePath> ();
+ Rust::Resolver::flatten_rebind (rebind, paths);
+
+ ASSERT_TRUE (!paths.empty ());
+ ASSERT_EQ (paths.size (), 2);
+ ASSERT_EQ (paths[0].get_segments ()[0].as_string (), "foo");
+ ASSERT_EQ (paths[0].get_segments ()[1].as_string (), "bar");
+ ASSERT_EQ (paths[0].get_segments ()[2].as_string (), "baz");
+ ASSERT_EQ (paths[1].get_segments ()[0].as_string (), "foo");
+ ASSERT_EQ (paths[1].get_segments ()[1].as_string (), "bar");
+ ASSERT_EQ (paths[1].get_segments ()[2].as_string (), "saindoux");
+}
+
+static void
+rust_flatten_list (void)
+{
+ auto foo = Rust::AST::SimplePathSegment ("foo", Location ());
+ auto bar = Rust::AST::SimplePathSegment ("bar", Location ());
+ auto foo_bar = Rust::AST::SimplePath ({foo, bar});
+
+ auto baz = Rust::AST::SimplePath::from_str ("baz", Location ());
+ auto bul = Rust::AST::SimplePath::from_str ("bul", Location ());
+
+ // use foo::bar::{baz, bul};
+
+ auto use0 = std::unique_ptr<Rust::AST::UseTree> (
+ new Rust::AST::UseTreeRebind (Rust::AST::UseTreeRebind::NONE, baz,
+ Location ()));
+ auto use1 = std::unique_ptr<Rust::AST::UseTree> (
+ new Rust::AST::UseTreeRebind (Rust::AST::UseTreeRebind::NONE, bul,
+ Location ()));
+
+ auto uses = std::vector<std::unique_ptr<Rust::AST::UseTree>> ();
+ uses.emplace_back (std::move (use0));
+ uses.emplace_back (std::move (use1));
+
+ auto list = Rust::AST::UseTreeList (Rust::AST::UseTreeList::PATH_PREFIXED,
+ foo_bar, std::move (uses), Location ());
+
+ auto paths = std::vector<Rust::AST::SimplePath> ();
+ Rust::Resolver::flatten_list (list, paths);
+
+ for (auto &path : paths)
+ fprintf (stderr, "%s\n", path.as_string ().c_str ());
+
+ ASSERT_TRUE (!paths.empty ());
+ ASSERT_EQ (paths.size (), 2);
+ ASSERT_EQ (paths[0].get_segments ()[0].as_string (), "foo");
+ ASSERT_EQ (paths[0].get_segments ()[1].as_string (), "bar");
+ ASSERT_EQ (paths[0].get_segments ()[2].as_string (), "baz");
+ ASSERT_EQ (paths[1].get_segments ()[0].as_string (), "foo");
+ ASSERT_EQ (paths[1].get_segments ()[1].as_string (), "bar");
+ ASSERT_EQ (paths[1].get_segments ()[2].as_string (), "bul");
+}
+
+static void
+rust_use_dec_flattening (void)
+{
+ rust_flatten_glob ();
+ rust_flatten_nested_glob ();
+ rust_flatten_rebind_none ();
+ rust_flatten_rebind ();
+ rust_flatten_rebind_nested ();
+ rust_flatten_list ();
+}
+
+void
+rust_simple_path_resolve_test (void)
+{
+ rust_use_dec_flattening ();
+}
+} // namespace selftest
+
+#endif // CHECKING_P
diff --git a/gcc/rust/resolve/rust-ast-resolve-item.h b/gcc/rust/resolve/rust-ast-resolve-item.h
index da5d4e8..e6b11f5 100644
--- a/gcc/rust/resolve/rust-ast-resolve-item.h
+++ b/gcc/rust/resolve/rust-ast-resolve-item.h
@@ -26,6 +26,7 @@
#include "rust-ast-resolve-type.h"
#include "rust-ast-resolve-pattern.h"
#include "rust-ast-resolve-stmt.h"
+#include "config.h"
namespace Rust {
namespace Resolver {
@@ -81,6 +82,7 @@ public:
void visit (AST::TraitImpl &impl_block) override;
void visit (AST::Trait &trait) override;
void visit (AST::ExternBlock &extern_block) override;
+ void visit (AST::UseDeclaration &) override;
protected:
void resolve_impl_item (AST::TraitImplItem *item, const CanonicalPath &prefix,
@@ -136,4 +138,13 @@ private:
} // namespace Resolver
} // namespace Rust
+#if CHECKING_P
+
+namespace selftest {
+extern void
+rust_simple_path_resolve_test (void);
+} // namespace selftest
+
+#endif // CHECKING_P
+
#endif // RUST_AST_RESOLVE_ITEM_H
diff --git a/gcc/rust/resolve/rust-ast-resolve-type.cc b/gcc/rust/resolve/rust-ast-resolve-type.cc
index 29b5edf..14178801 100644
--- a/gcc/rust/resolve/rust-ast-resolve-type.cc
+++ b/gcc/rust/resolve/rust-ast-resolve-type.cc
@@ -248,5 +248,52 @@ ResolveType::visit (AST::SliceType &type)
type.get_elem_type ()->accept_vis (*this);
}
+ResolveRelativeTypePath::ResolveRelativeTypePath (CanonicalPath qualified_path)
+ : ResolveTypeToCanonicalPath (true, true)
+{
+ result = qualified_path;
+}
+
+bool
+ResolveRelativeTypePath::go (AST::QualifiedPathInType &path)
+{
+ // resolve the type and trait path
+ auto &qualified_path = path.get_qualified_path_type ();
+ CanonicalPath result = CanonicalPath::create_empty ();
+ if (!resolve_qual_seg (qualified_path, result))
+ return false;
+
+ // resolve the associated impl if available but it can also be from a trait
+ // and this is allowed to fail
+ auto resolver = Resolver::get ();
+ NodeId projection_resolved_id = UNKNOWN_NODEID;
+ if (resolver->get_name_scope ().lookup (result, &projection_resolved_id))
+ {
+ // mark the resolution for this
+ resolver->insert_resolved_name (qualified_path.get_node_id (),
+ projection_resolved_id);
+ }
+
+ // qualified types are similar to other paths in that we cannot guarantee
+ // that we can resolve the path at name resolution. We must look up
+ // associated types and type information to figure this out properly
+
+ ResolveRelativeTypePath o (result);
+ std::unique_ptr<AST::TypePathSegment> &associated
+ = path.get_associated_segment ();
+
+ associated->accept_vis (o);
+ if (o.failure_flag)
+ return false;
+
+ for (auto &seg : path.get_segments ())
+ {
+ seg->accept_vis (o);
+ if (o.failure_flag)
+ return false;
+ }
+
+ return true;
+}
} // namespace Resolver
} // namespace Rust
diff --git a/gcc/rust/resolve/rust-ast-resolve-type.h b/gcc/rust/resolve/rust-ast-resolve-type.h
index 7284633..9334135 100644
--- a/gcc/rust/resolve/rust-ast-resolve-type.h
+++ b/gcc/rust/resolve/rust-ast-resolve-type.h
@@ -190,54 +190,10 @@ class ResolveRelativeTypePath : public ResolveTypeToCanonicalPath
using ResolveTypeToCanonicalPath::visit;
public:
- static bool go (AST::QualifiedPathInType &path, NodeId parent,
- bool canonicalize_type_with_generics)
- {
- // resolve the type and trait path
- auto &qualified_path = path.get_qualified_path_type ();
- CanonicalPath result = CanonicalPath::create_empty ();
- if (!resolve_qual_seg (qualified_path, result))
- return false;
-
- // resolve the associated impl if available but it can also be from a trait
- // and this is allowed to fail
- auto resolver = Resolver::get ();
- NodeId projection_resolved_id = UNKNOWN_NODEID;
- if (resolver->get_name_scope ().lookup (result, &projection_resolved_id))
- {
- // mark the resolution for this
- resolver->insert_resolved_name (qualified_path.get_node_id (),
- projection_resolved_id);
- }
-
- // qualified types are similar to other paths in that we cannot guarantee
- // that we can resolve the path at name resolution. We must look up
- // associated types and type information to figure this out properly
-
- ResolveRelativeTypePath o (result);
- std::unique_ptr<AST::TypePathSegment> &associated
- = path.get_associated_segment ();
-
- associated->accept_vis (o);
- if (o.failure_flag)
- return false;
-
- for (auto &seg : path.get_segments ())
- {
- seg->accept_vis (o);
- if (o.failure_flag)
- return false;
- }
-
- return true;
- }
+ static bool go (AST::QualifiedPathInType &path);
private:
- ResolveRelativeTypePath (CanonicalPath qualified_path)
- : ResolveTypeToCanonicalPath (true, true)
- {
- result = qualified_path;
- }
+ ResolveRelativeTypePath (CanonicalPath qualified_path);
static bool resolve_qual_seg (AST::QualifiedPathType &seg,
CanonicalPath &result);
@@ -375,8 +331,7 @@ public:
void visit (AST::QualifiedPathInType &path) override
{
- ok = ResolveRelativeTypePath::go (path, parent,
- canonicalize_type_with_generics);
+ ok = ResolveRelativeTypePath::go (path);
}
void visit (AST::ArrayType &type) override;
@@ -431,7 +386,7 @@ public:
ok = resolved_node != UNKNOWN_NODEID;
}
- void visit (AST::Lifetime &bound) override { ok = true; }
+ void visit (AST::Lifetime &) override { ok = true; }
private:
ResolveTypeBound (NodeId parent, bool canonicalize_type_with_generics)
@@ -459,7 +414,7 @@ public:
return resolver.resolved_node;
};
- void visit (AST::LifetimeParam &param) override
+ void visit (AST::LifetimeParam &) override
{
// For now do not do anything and accept everything.
ok = true;
diff --git a/gcc/rust/rust-lang.cc b/gcc/rust/rust-lang.cc
index 4584c93..73f9839 100644
--- a/gcc/rust/rust-lang.cc
+++ b/gcc/rust/rust-lang.cc
@@ -36,6 +36,7 @@
#include "selftest.h"
#include "rust-cfg-parser.h"
#include "rust-privacy-ctx.h"
+#include "rust-ast-resolve-item.h"
#include <mpfr.h>
// note: header files must be in this order or else forward declarations don't
@@ -459,6 +460,7 @@ run_rust_tests ()
rust_cfg_parser_test ();
rust_privacy_ctx_test ();
rust_crate_name_validation_test ();
+ rust_simple_path_resolve_test ();
}
} // namespace selftest
diff --git a/gcc/rust/rust-session-manager.cc b/gcc/rust/rust-session-manager.cc
index 845a66a..0b0e5af 100644
--- a/gcc/rust/rust-session-manager.cc
+++ b/gcc/rust/rust-session-manager.cc
@@ -932,23 +932,25 @@ Session::injection (AST::Crate &crate)
// create use tree path
// prelude is injected_crate_name
- std::vector<AST::SimplePathSegment> segments
- = {AST::SimplePathSegment (injected_crate_name, Location ()),
- AST::SimplePathSegment ("prelude", Location ()),
- AST::SimplePathSegment ("v1", Location ())};
- // create use tree and decl
- std::unique_ptr<AST::UseTreeGlob> use_tree (
- new AST::UseTreeGlob (AST::UseTreeGlob::PATH_PREFIXED,
- AST::SimplePath (std::move (segments)), Location ()));
- AST::Attribute prelude_attr (AST::SimplePath::from_str ("prelude_import",
- Location ()),
- nullptr);
- std::unique_ptr<AST::UseDeclaration> use_decl (
- new AST::UseDeclaration (std::move (use_tree),
- AST::Visibility::create_error (),
- {std::move (prelude_attr)}, Location ()));
-
- crate.items.insert (crate.items.begin (), std::move (use_decl));
+ // FIXME: Once we do want to include the standard library, add the prelude
+ // use item
+ // std::vector<AST::SimplePathSegment> segments
+ // = {AST::SimplePathSegment (injected_crate_name, Location ()),
+ // AST::SimplePathSegment ("prelude", Location ()),
+ // AST::SimplePathSegment ("v1", Location ())};
+ // // create use tree and decl
+ // std::unique_ptr<AST::UseTreeGlob> use_tree (
+ // new AST::UseTreeGlob (AST::UseTreeGlob::PATH_PREFIXED,
+ // AST::SimplePath (std::move (segments)), Location ()));
+ // AST::Attribute prelude_attr (AST::SimplePath::from_str ("prelude_import",
+ // Location ()),
+ // nullptr);
+ // std::unique_ptr<AST::UseDeclaration> use_decl (
+ // new AST::UseDeclaration (std::move (use_tree),
+ // AST::Visibility::create_error (),
+ // {std::move (prelude_attr)}, Location ()));
+
+ // crate.items.insert (crate.items.begin (), std::move (use_decl));
/* TODO: potentially add checking attribute crate type? I can't figure out
* what this does currently comment says "Unconditionally collect crate
diff --git a/gcc/testsuite/rust/compile/torture/cfg_attr.rs b/gcc/testsuite/rust/compile/torture/cfg_attr.rs
index 962d875..d65faf2 100644
--- a/gcc/testsuite/rust/compile/torture/cfg_attr.rs
+++ b/gcc/testsuite/rust/compile/torture/cfg_attr.rs
@@ -1,4 +1,4 @@
-use std::env; // Add one line so gccrs doesn't believe we're parsing a shebang
+mod fake {} // Add one line so gccrs doesn't believe we're parsing a shebang
#[cfg_attr(feature = "somefeature", attribute = "someattr")]
struct Feature;
diff --git a/gcc/testsuite/rust/compile/use_1.rs b/gcc/testsuite/rust/compile/use_1.rs
new file mode 100644
index 0000000..94b9632
--- /dev/null
+++ b/gcc/testsuite/rust/compile/use_1.rs
@@ -0,0 +1,16 @@
+mod frob {}
+
+use foo::bar::baz; // { dg-error "cannot find simple path segment .foo." }
+use frob::ulator; // { dg-error "cannot find simple path segment .ulator." }
+
+mod sain {
+ mod doux {}
+
+ mod dron {}
+}
+
+use not_sain::*; // { dg-error "cannot find simple path segment .not_sain." }
+
+use sain::*;
+use sain::{doux, dron};
+use sain::{doux, dron, graal}; // { dg-error "cannot find simple path segment .graal." }