aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2021-10-22 11:08:44 +0000
committerGitHub <noreply@github.com>2021-10-22 11:08:44 +0000
commit8e6c5a32b6e2c1ade6f1a835be2c2a26788db544 (patch)
treeccc8b527c45cfecc42e26a052f5fce21d0117e99 /gcc
parentdf61b8f0ee5c419c4d1b1dcdfc06812646d9f2f9 (diff)
parent92a31969774e1e9b46800c6475d1a58ccc5ca436 (diff)
downloadgcc-8e6c5a32b6e2c1ade6f1a835be2c2a26788db544.zip
gcc-8e6c5a32b6e2c1ade6f1a835be2c2a26788db544.tar.gz
gcc-8e6c5a32b6e2c1ade6f1a835be2c2a26788db544.tar.bz2
Merge #752
752: Bugfix ICE in trait resolution r=philberty a=philberty This is a series of patches which need to go in order to fix the linked bugs. - Fix type resolution of associated types in the generic context - Ensure autoderef is applied on generic receivers - Support generic substitutions on type-bounds Fixes #743 #753 #744 #741 Co-authored-by: Philip Herron <philip.herron@embecosm.com>
Diffstat (limited to 'gcc')
-rw-r--r--gcc/rust/typecheck/rust-hir-dot-operator.h6
-rw-r--r--gcc/rust/typecheck/rust-hir-inherent-impl-overlap.h2
-rw-r--r--gcc/rust/typecheck/rust-hir-path-probe.h222
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-expr.h2
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-implitem.h6
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-path.cc7
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-type.cc2
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-type.h20
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check.h2
-rw-r--r--gcc/rust/typecheck/rust-tyty-bounds.cc81
-rw-r--r--gcc/rust/typecheck/rust-tyty-cmp.h227
-rw-r--r--gcc/rust/typecheck/rust-tyty.cc165
-rw-r--r--gcc/rust/typecheck/rust-tyty.h131
-rw-r--r--gcc/testsuite/rust/execute/torture/trait6.rs41
-rw-r--r--gcc/testsuite/rust/execute/torture/trait7.rs41
-rw-r--r--gcc/testsuite/rust/execute/torture/trait8.rs41
-rw-r--r--gcc/testsuite/rust/execute/torture/trait9.rs38
17 files changed, 778 insertions, 256 deletions
diff --git a/gcc/rust/typecheck/rust-hir-dot-operator.h b/gcc/rust/typecheck/rust-hir-dot-operator.h
index 9c0cc43..98ae5ab 100644
--- a/gcc/rust/typecheck/rust-hir-dot-operator.h
+++ b/gcc/rust/typecheck/rust-hir-dot-operator.h
@@ -115,7 +115,7 @@ private:
if (fn->is_method ())
{
TyTy::BaseType *fn_self = fn->get_self_type ();
- if (receiver->can_eq (fn_self, false))
+ if (receiver->can_eq (fn_self, false, true))
{
return &c;
}
@@ -143,7 +143,7 @@ private:
if (fn->is_method ())
{
TyTy::BaseType *fn_self = fn->get_self_type ();
- if (receiver->can_eq (fn_self, false))
+ if (receiver->can_eq (fn_self, false, true))
{
return &c;
}
@@ -165,7 +165,7 @@ private:
if (fn->is_method ())
{
TyTy::BaseType *fn_self = fn->get_self_type ();
- if (receiver->can_eq (fn_self, false))
+ if (receiver->can_eq (fn_self, false, true))
{
return &c;
}
diff --git a/gcc/rust/typecheck/rust-hir-inherent-impl-overlap.h b/gcc/rust/typecheck/rust-hir-inherent-impl-overlap.h
index 9a2c7fe..eac86b0 100644
--- a/gcc/rust/typecheck/rust-hir-inherent-impl-overlap.h
+++ b/gcc/rust/typecheck/rust-hir-inherent-impl-overlap.h
@@ -122,7 +122,7 @@ public:
if (query == candidate)
continue;
- if (query->can_eq (candidate, false))
+ if (query->can_eq (candidate, false, false))
possible_collision (it->second, iy->second);
}
}
diff --git a/gcc/rust/typecheck/rust-hir-path-probe.h b/gcc/rust/typecheck/rust-hir-path-probe.h
index dd51f83..6e39fa3 100644
--- a/gcc/rust/typecheck/rust-hir-path-probe.h
+++ b/gcc/rust/typecheck/rust-hir-path-probe.h
@@ -130,24 +130,26 @@ public:
if (!probe_bounds)
return probe.candidates;
- std::vector<std::pair<TraitReference *, HIR::ImplBlock *>> probed_bounds
- = TypeBoundsProbe::Probe (receiver);
+ if (!probe.is_reciever_generic ())
+ {
+ std::vector<std::pair<TraitReference *, HIR::ImplBlock *>> probed_bounds
+ = TypeBoundsProbe::Probe (receiver);
+ for (auto &candidate : probed_bounds)
+ {
+ const TraitReference *trait_ref = candidate.first;
+ HIR::ImplBlock *impl = candidate.second;
+ probe.process_associated_trait_for_candidates (
+ trait_ref, impl, ignore_mandatory_trait_items);
+ }
+ }
- std::vector<std::pair<const TraitReference *, HIR::ImplBlock *>>
- specified_bounds;
for (const TyTy::TypeBoundPredicate &predicate :
receiver->get_specified_bounds ())
{
- const TraitReference *trait_item = predicate.get ();
-
- // FIXME lookup impl_block for this trait impl for this receiver
- specified_bounds.push_back ({trait_item, nullptr});
+ probe.process_predicate_for_candidates (predicate,
+ ignore_mandatory_trait_items);
}
- std::vector<std::pair<const TraitReference *, HIR::ImplBlock *>>
- union_type_bounds = probe.union_bounds (probed_bounds, specified_bounds);
- probe.process_traits_for_candidates (union_type_bounds,
- ignore_mandatory_trait_items);
return probe.candidates;
}
@@ -227,103 +229,137 @@ protected:
bool ok = context->lookup_type (impl_ty_id, &impl_block_ty);
rust_assert (ok);
- if (!receiver->can_eq (impl_block_ty, false))
+ if (!receiver->can_eq (impl_block_ty, false, false))
return;
// lets visit the impl_item
item->accept_vis (*this);
}
- void process_traits_for_candidates (
- const std::vector<std::pair<const TraitReference *, HIR::ImplBlock *>>
- traits,
- bool ignore_mandatory_trait_items)
+ void
+ process_associated_trait_for_candidates (const TraitReference *trait_ref,
+ HIR::ImplBlock *impl,
+ bool ignore_mandatory_trait_items)
{
- for (auto &ref : traits)
+ const TraitItemReference *trait_item_ref = nullptr;
+ if (!trait_ref->lookup_trait_item (search.as_string (), &trait_item_ref))
+ return;
+
+ bool trait_item_needs_implementation = !trait_item_ref->is_optional ();
+ if (ignore_mandatory_trait_items && trait_item_needs_implementation)
+ return;
+
+ PathProbeCandidate::CandidateType candidate_type;
+ switch (trait_item_ref->get_trait_item_type ())
{
- const TraitReference *trait_ref = ref.first;
- HIR::ImplBlock *impl = ref.second;
+ case TraitItemReference::TraitItemType::FN:
+ candidate_type = PathProbeCandidate::CandidateType::TRAIT_FUNC;
+ break;
+ case TraitItemReference::TraitItemType::CONST:
+ candidate_type = PathProbeCandidate::CandidateType::TRAIT_ITEM_CONST;
+ break;
+ case TraitItemReference::TraitItemType::TYPE:
+ candidate_type = PathProbeCandidate::CandidateType::TRAIT_TYPE_ALIAS;
+ break;
+
+ case TraitItemReference::TraitItemType::ERROR:
+ default:
+ gcc_unreachable ();
+ break;
+ }
- const TraitItemReference *trait_item_ref = nullptr;
- if (!trait_ref->lookup_trait_item (search.as_string (),
- &trait_item_ref))
- continue;
+ TyTy::BaseType *trait_item_tyty = trait_item_ref->get_tyty ();
+ if (impl != nullptr && !is_reciever_generic ())
- bool trait_item_needs_implementation = !trait_item_ref->is_optional ();
- if (ignore_mandatory_trait_items && trait_item_needs_implementation)
- continue;
+ {
+ HirId impl_block_id = impl->get_mappings ().get_hirid ();
+ AssociatedImplTrait *lookup_associated = nullptr;
+ bool found_impl_trait
+ = context->lookup_associated_trait_impl (impl_block_id,
+ &lookup_associated);
+ // see testsuite/rust/compile/torture/traits10.rs this can be false
+ if (found_impl_trait)
+ lookup_associated->setup_associated_types ();
+ }
- PathProbeCandidate::CandidateType candidate_type;
- switch (trait_item_ref->get_trait_item_type ())
+ // we can substitute the Self with the receiver here
+ if (trait_item_tyty->get_kind () == TyTy::TypeKind::FNDEF)
+ {
+ TyTy::FnType *fn = static_cast<TyTy::FnType *> (trait_item_tyty);
+ TyTy::SubstitutionParamMapping *param = nullptr;
+ for (auto &param_mapping : fn->get_substs ())
{
- case TraitItemReference::TraitItemType::FN:
- candidate_type = PathProbeCandidate::CandidateType::TRAIT_FUNC;
- break;
- case TraitItemReference::TraitItemType::CONST:
- candidate_type
- = PathProbeCandidate::CandidateType::TRAIT_ITEM_CONST;
- break;
- case TraitItemReference::TraitItemType::TYPE:
- candidate_type
- = PathProbeCandidate::CandidateType::TRAIT_TYPE_ALIAS;
- break;
-
- case TraitItemReference::TraitItemType::ERROR:
- default:
- gcc_unreachable ();
- break;
+ const HIR::TypeParam &type_param
+ = param_mapping.get_generic_param ();
+ if (type_param.get_type_representation ().compare ("Self") == 0)
+ {
+ param = &param_mapping;
+ break;
+ }
}
+ rust_assert (param != nullptr);
- TyTy::BaseType *trait_item_tyty = trait_item_ref->get_tyty ();
+ std::vector<TyTy::SubstitutionArg> mappings;
+ mappings.push_back (TyTy::SubstitutionArg (param, receiver->clone ()));
- if (impl != nullptr)
- {
- HirId impl_block_id = impl->get_mappings ().get_hirid ();
- AssociatedImplTrait *lookup_associated = nullptr;
- bool found_impl_trait
- = context->lookup_associated_trait_impl (impl_block_id,
- &lookup_associated);
- // see testsuite/rust/compile/torture/traits10.rs this can be false
- if (found_impl_trait)
- lookup_associated->setup_associated_types ();
- }
+ Location locus; // FIXME
+ TyTy::SubstitutionArgumentMappings args (std::move (mappings), locus);
+ trait_item_tyty = SubstMapperInternal::Resolve (trait_item_tyty, args);
+ }
- // we can substitute the Self with the receiver here
- if (trait_item_tyty->get_kind () == TyTy::TypeKind::FNDEF)
- {
- TyTy::FnType *fn = static_cast<TyTy::FnType *> (trait_item_tyty);
- TyTy::SubstitutionParamMapping *param = nullptr;
- for (auto &param_mapping : fn->get_substs ())
- {
- const HIR::TypeParam &type_param
- = param_mapping.get_generic_param ();
- if (type_param.get_type_representation ().compare ("Self") == 0)
- {
- param = &param_mapping;
- break;
- }
- }
- rust_assert (param != nullptr);
+ PathProbeCandidate::TraitItemCandidate trait_item_candidate{trait_ref,
+ trait_item_ref,
+ impl};
+ PathProbeCandidate candidate{candidate_type,
+ trait_item_tyty,
+ trait_ref->get_locus (),
+ {trait_item_candidate}};
+ candidates.push_back (std::move (candidate));
+ }
- std::vector<TyTy::SubstitutionArg> mappings;
- mappings.push_back (
- TyTy::SubstitutionArg (param, receiver->clone ()));
+ void
+ process_predicate_for_candidates (const TyTy::TypeBoundPredicate &predicate,
+ bool ignore_mandatory_trait_items)
+ {
+ const TraitReference *trait_ref = predicate.get ();
- Location locus; // FIXME
- TyTy::SubstitutionArgumentMappings args (std::move (mappings),
- locus);
- trait_item_tyty
- = SubstMapperInternal::Resolve (trait_item_tyty, args);
- }
+ TyTy::TypeBoundPredicateItem item
+ = predicate.lookup_associated_item (search.as_string ());
+ if (item.is_error ())
+ return;
- PathProbeCandidate::TraitItemCandidate trait_item_candidate{
- trait_ref, trait_item_ref, impl};
- PathProbeCandidate candidate{candidate_type,
- trait_item_tyty,
- trait_ref->get_locus (),
- {trait_item_candidate}};
- candidates.push_back (std::move (candidate));
+ if (ignore_mandatory_trait_items && item.needs_implementation ())
+ return;
+
+ const TraitItemReference *trait_item_ref = item.get_raw_item ();
+ PathProbeCandidate::CandidateType candidate_type;
+ switch (trait_item_ref->get_trait_item_type ())
+ {
+ case TraitItemReference::TraitItemType::FN:
+ candidate_type = PathProbeCandidate::CandidateType::TRAIT_FUNC;
+ break;
+ case TraitItemReference::TraitItemType::CONST:
+ candidate_type = PathProbeCandidate::CandidateType::TRAIT_ITEM_CONST;
+ break;
+ case TraitItemReference::TraitItemType::TYPE:
+ candidate_type = PathProbeCandidate::CandidateType::TRAIT_TYPE_ALIAS;
+ break;
+
+ case TraitItemReference::TraitItemType::ERROR:
+ default:
+ gcc_unreachable ();
+ break;
}
+
+ TyTy::BaseType *trait_item_tyty = item.get_tyty_for_receiver (receiver);
+ PathProbeCandidate::TraitItemCandidate trait_item_candidate{trait_ref,
+ trait_item_ref,
+ nullptr};
+ PathProbeCandidate candidate{candidate_type,
+ trait_item_tyty,
+ trait_item_ref->get_locus (),
+ {trait_item_candidate}};
+ candidates.push_back (std::move (candidate));
}
protected:
@@ -358,6 +394,14 @@ protected:
return union_set;
}
+ bool is_reciever_generic () const
+ {
+ const TyTy::BaseType *root = receiver->get_root ();
+ bool receiver_is_type_param = root->get_kind () == TyTy::TypeKind::PARAM;
+ bool receiver_is_dyn = root->get_kind () == TyTy::TypeKind::DYNAMIC;
+ return receiver_is_type_param || receiver_is_dyn;
+ }
+
const TyTy::BaseType *receiver;
const HIR::PathIdentSegment &search;
std::vector<PathProbeCandidate> candidates;
diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.h b/gcc/rust/typecheck/rust-hir-type-check-expr.h
index 83fafa6..8c415ebd 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-expr.h
+++ b/gcc/rust/typecheck/rust-hir-type-check-expr.h
@@ -320,7 +320,7 @@ public:
// always be at the end of the list
auto s = fn->get_self_type ()->get_root ();
- rust_assert (s->can_eq (adt, false));
+ rust_assert (s->can_eq (adt, false, false));
rust_assert (s->get_kind () == TyTy::TypeKind::ADT);
const TyTy::ADTType *self_adt
= static_cast<const TyTy::ADTType *> (s);
diff --git a/gcc/rust/typecheck/rust-hir-type-check-implitem.h b/gcc/rust/typecheck/rust-hir-type-check-implitem.h
index 1260c2e..f3a0870 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-implitem.h
+++ b/gcc/rust/typecheck/rust-hir-type-check-implitem.h
@@ -377,7 +377,7 @@ public:
return;
// check the types are compatible
- if (!resolved_trait_item.get_tyty ()->can_eq (lookup, true))
+ if (!resolved_trait_item.get_tyty ()->can_eq (lookup, true, false))
{
RichLocation r (constant.get_locus ());
r.add_range (resolved_trait_item.get_locus ());
@@ -413,7 +413,7 @@ public:
return;
// check the types are compatible
- if (!resolved_trait_item.get_tyty ()->can_eq (lookup, true))
+ if (!resolved_trait_item.get_tyty ()->can_eq (lookup, true, false))
{
RichLocation r (type.get_locus ());
r.add_range (resolved_trait_item.get_locus ());
@@ -487,7 +487,7 @@ public:
= trait_item_fntype->handle_substitions (implicit_self_substs);
// check the types are compatible
- if (!trait_item_fntype->can_eq (fntype, true))
+ if (!trait_item_fntype->can_eq (fntype, true, false))
{
RichLocation r (function.get_locus ());
r.add_range (resolved_trait_item.get_locus ());
diff --git a/gcc/rust/typecheck/rust-hir-type-check-path.cc b/gcc/rust/typecheck/rust-hir-type-check-path.cc
index 0aea8ca..c74ac85 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-path.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-path.cc
@@ -376,9 +376,12 @@ TypeCheckExpr::resolve_segments (NodeId root_resolved_node_id,
AssociatedImplTrait *lookup_associated = nullptr;
bool found_impl_trait = context->lookup_associated_trait_impl (
impl->get_mappings ().get_hirid (), &lookup_associated);
- rust_assert (found_impl_trait);
- lookup_associated->setup_associated_types ();
+ // setup associated mappings if possible we might be resolving a
+ // path within a default implementation of a trait function
+ // see: testsuite/rust/compile/torture/traits16.rs
+ if (found_impl_trait)
+ lookup_associated->setup_associated_types ();
// we need a new ty_ref_id for this trait item
tyseg = tyseg->clone ();
diff --git a/gcc/rust/typecheck/rust-hir-type-check-type.cc b/gcc/rust/typecheck/rust-hir-type-check-type.cc
index a479581..ed21d53 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-type.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-type.cc
@@ -445,7 +445,7 @@ TypeCheckType::resolve_segments (
// lookup the associated-impl-trait
HIR::ImplBlock *impl = candidate.item.trait.impl;
- if (impl != nullptr)
+ if (impl != nullptr && !reciever_is_generic)
{
AssociatedImplTrait *lookup_associated = nullptr;
bool found_impl_trait = context->lookup_associated_trait_impl (
diff --git a/gcc/rust/typecheck/rust-hir-type-check-type.h b/gcc/rust/typecheck/rust-hir-type-check-type.h
index e0c0e91..91c49e0 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-type.h
+++ b/gcc/rust/typecheck/rust-hir-type-check-type.h
@@ -234,10 +234,28 @@ public:
HIR::TraitBound *b
= static_cast<HIR::TraitBound *> (bound.get ());
- TraitReference *trait = resolve_trait_path (b->get_path ());
+ auto &type_path = b->get_path ();
+ TraitReference *trait = resolve_trait_path (type_path);
TyTy::TypeBoundPredicate predicate (
trait->get_mappings ().get_defid (), b->get_locus ());
+ auto &final_seg = type_path.get_final_segment ();
+ if (final_seg->is_generic_segment ())
+ {
+ auto final_generic_seg
+ = static_cast<HIR::TypePathSegmentGeneric *> (
+ final_seg.get ());
+ if (final_generic_seg->has_generic_args ())
+ {
+ HIR::GenericArgs &generic_args
+ = final_generic_seg->get_generic_args ();
+
+ // this is applying generic arguments to a trait
+ // reference
+ predicate.apply_generic_arguments (&generic_args);
+ }
+ }
+
specified_bounds.push_back (std::move (predicate));
}
break;
diff --git a/gcc/rust/typecheck/rust-hir-type-check.h b/gcc/rust/typecheck/rust-hir-type-check.h
index d3dc4c9..5760c4e 100644
--- a/gcc/rust/typecheck/rust-hir-type-check.h
+++ b/gcc/rust/typecheck/rust-hir-type-check.h
@@ -187,7 +187,7 @@ public:
for (auto &item : it->second)
{
- if (item.first->can_eq (self, false))
+ if (item.first->can_eq (self, false, false))
{
*mapping = item.second;
return true;
diff --git a/gcc/rust/typecheck/rust-tyty-bounds.cc b/gcc/rust/typecheck/rust-tyty-bounds.cc
index 5f69deb..88c94d2 100644
--- a/gcc/rust/typecheck/rust-tyty-bounds.cc
+++ b/gcc/rust/typecheck/rust-tyty-bounds.cc
@@ -40,7 +40,7 @@ TypeBoundsProbe::scan ()
if (!ok)
return true;
- if (!receiver->can_eq (impl_type, false))
+ if (!receiver->can_eq (impl_type, false, false))
return true;
possible_trait_paths.push_back ({impl->get_trait_ref ().get (), impl});
@@ -108,5 +108,84 @@ TypeBoundPredicate::is_object_safe (bool emit_error, Location locus) const
return trait->is_object_safe (emit_error, locus);
}
+void
+TypeBoundPredicate::apply_generic_arguments (HIR::GenericArgs *generic_args)
+{
+ args = generic_args;
+ // TODO verify these arguments are valid and not too many were added
+}
+
+bool
+TypeBoundPredicate::contains_item (const std::string &search) const
+{
+ auto trait_ref = get ();
+ const Resolver::TraitItemReference *trait_item_ref = nullptr;
+ return trait_ref->lookup_trait_item (search, &trait_item_ref);
+}
+
+TypeBoundPredicateItem
+TypeBoundPredicate::lookup_associated_item (const std::string &search) const
+{
+ auto trait_ref = get ();
+ const Resolver::TraitItemReference *trait_item_ref = nullptr;
+ if (!trait_ref->lookup_trait_item (search, &trait_item_ref))
+ return TypeBoundPredicateItem::error ();
+
+ return TypeBoundPredicateItem (this, trait_item_ref);
+}
+
+BaseType *
+TypeBoundPredicateItem::get_tyty_for_receiver (const TyTy::BaseType *receiver)
+{
+ TyTy::BaseType *trait_item_tyty = get_raw_item ()->get_tyty ();
+ if (trait_item_tyty->get_kind () == TyTy::TypeKind::FNDEF)
+ {
+ TyTy::FnType *fn = static_cast<TyTy::FnType *> (trait_item_tyty);
+ TyTy::SubstitutionParamMapping *param = nullptr;
+ for (auto &param_mapping : fn->get_substs ())
+ {
+ const HIR::TypeParam &type_param = param_mapping.get_generic_param ();
+ if (type_param.get_type_representation ().compare ("Self") == 0)
+ {
+ param = &param_mapping;
+ break;
+ }
+ }
+ rust_assert (param != nullptr);
+
+ std::vector<TyTy::SubstitutionArg> mappings;
+ mappings.push_back (TyTy::SubstitutionArg (param, receiver->clone ()));
+
+ Location locus; // FIXME
+ TyTy::SubstitutionArgumentMappings args (std::move (mappings), locus);
+ trait_item_tyty
+ = Resolver::SubstMapperInternal::Resolve (trait_item_tyty, args);
+ }
+
+ if (!parent->has_generic_args ())
+ return trait_item_tyty;
+
+ // FIXME LEAK this should really be const
+ const HIR::GenericArgs *args = parent->get_generic_args ();
+ HIR::GenericArgs *generic_args = new HIR::GenericArgs (*args);
+ TyTy::BaseType *resolved
+ = Resolver::SubstMapper::Resolve (trait_item_tyty, parent->get_locus (),
+ generic_args);
+
+ return resolved;
+}
+
+const Resolver::TraitItemReference *
+TypeBoundPredicateItem::get_raw_item () const
+{
+ return trait_item_ref;
+}
+
+bool
+TypeBoundPredicateItem::needs_implementation () const
+{
+ return !get_raw_item ()->is_optional ();
+}
+
} // namespace TyTy
} // namespace Rust
diff --git a/gcc/rust/typecheck/rust-tyty-cmp.h b/gcc/rust/typecheck/rust-tyty-cmp.h
index 519501f..9ebd564 100644
--- a/gcc/rust/typecheck/rust-tyty-cmp.h
+++ b/gcc/rust/typecheck/rust-tyty-cmp.h
@@ -371,8 +371,18 @@ public:
virtual void visit (const ParamType &type) override
{
- // it is ok for types to can eq to a ParamType
- ok = true;
+ ok = false;
+ if (emit_error_flag)
+ {
+ Location ref_locus = mappings->lookup_location (type.get_ref ());
+ Location base_locus
+ = mappings->lookup_location (get_base ()->get_ref ());
+ RichLocation r (ref_locus);
+ r.add_range (base_locus);
+ rust_error_at (r, "expected [%s] got [%s]",
+ get_base ()->as_string ().c_str (),
+ type.as_string ().c_str ());
+ }
}
virtual void visit (const DynamicObjectType &type) override
@@ -408,10 +418,10 @@ public:
}
protected:
- BaseCmp (const BaseType *base, bool emit_errors)
+ BaseCmp (const BaseType *base, bool emit_errors, bool autoderef_mode)
: mappings (Analysis::Mappings::get ()),
context (Resolver::TypeCheckContext::get ()), ok (false),
- emit_error_flag (emit_errors)
+ emit_error_flag (emit_errors), autoderef_mode_flag (autoderef_mode)
{}
Analysis::Mappings *mappings;
@@ -419,6 +429,7 @@ protected:
bool ok;
bool emit_error_flag;
+ bool autoderef_mode_flag;
private:
/* Returns a pointer to the ty that created this rule. */
@@ -430,8 +441,8 @@ class InferCmp : public BaseCmp
using Rust::TyTy::BaseCmp::visit;
public:
- InferCmp (const InferType *base, bool emit_errors)
- : BaseCmp (base, emit_errors), base (base)
+ InferCmp (const InferType *base, bool emit_errors, bool autoderef_mode)
+ : BaseCmp (base, emit_errors, autoderef_mode), base (base)
{}
void visit (const BoolType &type) override
@@ -641,18 +652,7 @@ public:
BaseCmp::visit (type);
}
- void visit (const ParamType &type) override
- {
- bool is_valid
- = (base->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL);
- if (is_valid)
- {
- ok = true;
- return;
- }
-
- BaseCmp::visit (type);
- }
+ void visit (const ParamType &) override { ok = true; }
void visit (const DynamicObjectType &type) override
{
@@ -690,8 +690,8 @@ class FnCmp : public BaseCmp
using Rust::TyTy::BaseCmp::visit;
public:
- FnCmp (const FnType *base, bool emit_errors)
- : BaseCmp (base, emit_errors), base (base)
+ FnCmp (const FnType *base, bool emit_errors, bool autoderef_mode)
+ : BaseCmp (base, emit_errors, autoderef_mode), base (base)
{}
void visit (const InferType &type) override
@@ -712,7 +712,7 @@ public:
auto a = base->param_at (i).second;
auto b = type.param_at (i).second;
- if (!a->can_eq (b, emit_error_flag))
+ if (!a->can_eq (b, emit_error_flag, autoderef_mode_flag))
{
emit_error_flag = false;
BaseCmp::visit (type);
@@ -721,7 +721,8 @@ public:
}
if (!base->get_return_type ()->can_eq (type.get_return_type (),
- emit_error_flag))
+ emit_error_flag,
+ autoderef_mode_flag))
{
emit_error_flag = false;
BaseCmp::visit (type);
@@ -741,8 +742,8 @@ class FnptrCmp : public BaseCmp
using Rust::TyTy::BaseCmp::visit;
public:
- FnptrCmp (const FnPtr *base, bool emit_errors)
- : BaseCmp (base, emit_errors), base (base)
+ FnptrCmp (const FnPtr *base, bool emit_errors, bool autoderef_mode)
+ : BaseCmp (base, emit_errors, autoderef_mode), base (base)
{}
void visit (const InferType &type) override
@@ -766,7 +767,8 @@ public:
auto this_ret_type = base->get_return_type ();
auto other_ret_type = type.get_return_type ();
- if (!this_ret_type->can_eq (other_ret_type, emit_error_flag))
+ if (!this_ret_type->can_eq (other_ret_type, emit_error_flag,
+ autoderef_mode_flag))
{
BaseCmp::visit (type);
return;
@@ -776,7 +778,8 @@ public:
{
auto this_param = base->param_at (i);
auto other_param = type.param_at (i);
- if (!this_param->can_eq (other_param, emit_error_flag))
+ if (!this_param->can_eq (other_param, emit_error_flag,
+ autoderef_mode_flag))
{
BaseCmp::visit (type);
return;
@@ -796,7 +799,8 @@ public:
auto this_ret_type = base->get_return_type ();
auto other_ret_type = type.get_return_type ();
- if (!this_ret_type->can_eq (other_ret_type, emit_error_flag))
+ if (!this_ret_type->can_eq (other_ret_type, emit_error_flag,
+ autoderef_mode_flag))
{
BaseCmp::visit (type);
return;
@@ -806,7 +810,8 @@ public:
{
auto this_param = base->param_at (i);
auto other_param = type.param_at (i).second;
- if (!this_param->can_eq (other_param, emit_error_flag))
+ if (!this_param->can_eq (other_param, emit_error_flag,
+ autoderef_mode_flag))
{
BaseCmp::visit (type);
return;
@@ -826,8 +831,8 @@ class ClosureCmp : public BaseCmp
using Rust::TyTy::BaseCmp::visit;
public:
- ClosureCmp (const ClosureType *base, bool emit_errors)
- : BaseCmp (base, emit_errors), base (base)
+ ClosureCmp (const ClosureType *base, bool emit_errors, bool autoderef_mode)
+ : BaseCmp (base, emit_errors, autoderef_mode), base (base)
{}
private:
@@ -840,8 +845,8 @@ class ArrayCmp : public BaseCmp
using Rust::TyTy::BaseCmp::visit;
public:
- ArrayCmp (const ArrayType *base, bool emit_errors)
- : BaseCmp (base, emit_errors), base (base)
+ ArrayCmp (const ArrayType *base, bool emit_errors, bool autoderef_mode)
+ : BaseCmp (base, emit_errors, autoderef_mode), base (base)
{}
void visit (const ArrayType &type) override
@@ -856,7 +861,8 @@ public:
// check base type
const BaseType *base_element = base->get_element_type ();
const BaseType *other_element = type.get_element_type ();
- if (!base_element->can_eq (other_element, emit_error_flag))
+ if (!base_element->can_eq (other_element, emit_error_flag,
+ autoderef_mode_flag))
{
BaseCmp::visit (type);
return;
@@ -865,6 +871,8 @@ public:
ok = true;
}
+ void visit (const ParamType &type) override { ok = true; }
+
private:
const BaseType *get_base () const override { return base; }
const ArrayType *base;
@@ -875,8 +883,8 @@ class BoolCmp : public BaseCmp
using Rust::TyTy::BaseCmp::visit;
public:
- BoolCmp (const BoolType *base, bool emit_errors)
- : BaseCmp (base, emit_errors), base (base)
+ BoolCmp (const BoolType *base, bool emit_errors, bool autoderef_mode)
+ : BaseCmp (base, emit_errors, autoderef_mode), base (base)
{}
void visit (const BoolType &type) override { ok = true; }
@@ -886,6 +894,8 @@ public:
ok = type.get_infer_kind () == InferType::InferTypeKind::GENERAL;
}
+ void visit (const ParamType &type) override { ok = true; }
+
private:
const BaseType *get_base () const override { return base; }
const BoolType *base;
@@ -896,8 +906,8 @@ class IntCmp : public BaseCmp
using Rust::TyTy::BaseCmp::visit;
public:
- IntCmp (const IntType *base, bool emit_errors)
- : BaseCmp (base, emit_errors), base (base)
+ IntCmp (const IntType *base, bool emit_errors, bool autoderef_mode)
+ : BaseCmp (base, emit_errors, autoderef_mode), base (base)
{}
void visit (const InferType &type) override
@@ -910,6 +920,8 @@ public:
ok = type.get_int_kind () == base->get_int_kind ();
}
+ void visit (const ParamType &type) override { ok = true; }
+
private:
const BaseType *get_base () const override { return base; }
const IntType *base;
@@ -920,8 +932,8 @@ class UintCmp : public BaseCmp
using Rust::TyTy::BaseCmp::visit;
public:
- UintCmp (const UintType *base, bool emit_errors)
- : BaseCmp (base, emit_errors), base (base)
+ UintCmp (const UintType *base, bool emit_errors, bool autoderef_mode)
+ : BaseCmp (base, emit_errors, autoderef_mode), base (base)
{}
void visit (const InferType &type) override
@@ -934,6 +946,8 @@ public:
ok = type.get_uint_kind () == base->get_uint_kind ();
}
+ void visit (const ParamType &type) override { ok = true; }
+
private:
const BaseType *get_base () const override { return base; }
const UintType *base;
@@ -944,8 +958,8 @@ class FloatCmp : public BaseCmp
using Rust::TyTy::BaseCmp::visit;
public:
- FloatCmp (const FloatType *base, bool emit_errors)
- : BaseCmp (base, emit_errors), base (base)
+ FloatCmp (const FloatType *base, bool emit_errors, bool autoderef_mode)
+ : BaseCmp (base, emit_errors, autoderef_mode), base (base)
{}
void visit (const InferType &type) override
@@ -958,6 +972,8 @@ public:
ok = type.get_float_kind () == base->get_float_kind ();
}
+ void visit (const ParamType &type) override { ok = true; }
+
private:
const BaseType *get_base () const override { return base; }
const FloatType *base;
@@ -968,8 +984,8 @@ class ADTCmp : public BaseCmp
using Rust::TyTy::BaseCmp::visit;
public:
- ADTCmp (const ADTType *base, bool emit_errors)
- : BaseCmp (base, emit_errors), base (base)
+ ADTCmp (const ADTType *base, bool emit_errors, bool autoderef_mode)
+ : BaseCmp (base, emit_errors, autoderef_mode), base (base)
{}
void visit (const ADTType &type) override
@@ -994,7 +1010,8 @@ public:
TyTy::BaseType *this_field_ty = base_field->get_field_type ();
TyTy::BaseType *other_field_ty = other_field->get_field_type ();
- if (!this_field_ty->can_eq (other_field_ty, emit_error_flag))
+ if (!this_field_ty->can_eq (other_field_ty, emit_error_flag,
+ autoderef_mode_flag))
{
BaseCmp::visit (type);
return;
@@ -1004,6 +1021,8 @@ public:
ok = true;
}
+ void visit (const ParamType &type) override { ok = true; }
+
private:
const BaseType *get_base () const override { return base; }
const ADTType *base;
@@ -1014,8 +1033,8 @@ class TupleCmp : public BaseCmp
using Rust::TyTy::BaseCmp::visit;
public:
- TupleCmp (const TupleType *base, bool emit_errors)
- : BaseCmp (base, emit_errors), base (base)
+ TupleCmp (const TupleType *base, bool emit_errors, bool autoderef_mode)
+ : BaseCmp (base, emit_errors, autoderef_mode), base (base)
{}
void visit (const TupleType &type) override
@@ -1031,7 +1050,7 @@ public:
BaseType *bo = base->get_field (i);
BaseType *fo = type.get_field (i);
- if (!bo->can_eq (fo, emit_error_flag))
+ if (!bo->can_eq (fo, emit_error_flag, autoderef_mode_flag))
{
BaseCmp::visit (type);
return;
@@ -1041,6 +1060,8 @@ public:
ok = true;
}
+ void visit (const ParamType &type) override { ok = true; }
+
private:
const BaseType *get_base () const override { return base; }
const TupleType *base;
@@ -1051,8 +1072,8 @@ class USizeCmp : public BaseCmp
using Rust::TyTy::BaseCmp::visit;
public:
- USizeCmp (const USizeType *base, bool emit_errors)
- : BaseCmp (base, emit_errors), base (base)
+ USizeCmp (const USizeType *base, bool emit_errors, bool autoderef_mode)
+ : BaseCmp (base, emit_errors, autoderef_mode), base (base)
{}
void visit (const InferType &type) override
@@ -1062,6 +1083,8 @@ public:
void visit (const USizeType &type) override { ok = true; }
+ void visit (const ParamType &type) override { ok = true; }
+
private:
const BaseType *get_base () const override { return base; }
const USizeType *base;
@@ -1072,8 +1095,8 @@ class ISizeCmp : public BaseCmp
using Rust::TyTy::BaseCmp::visit;
public:
- ISizeCmp (const ISizeType *base, bool emit_errors)
- : BaseCmp (base, emit_errors), base (base)
+ ISizeCmp (const ISizeType *base, bool emit_errors, bool autoderef_mode)
+ : BaseCmp (base, emit_errors, autoderef_mode), base (base)
{}
void visit (const InferType &type) override
@@ -1083,6 +1106,8 @@ public:
void visit (const ISizeType &type) override { ok = true; }
+ void visit (const ParamType &type) override { ok = true; }
+
private:
const BaseType *get_base () const override { return base; }
const ISizeType *base;
@@ -1093,8 +1118,8 @@ class CharCmp : public BaseCmp
using Rust::TyTy::BaseCmp::visit;
public:
- CharCmp (const CharType *base, bool emit_errors)
- : BaseCmp (base, emit_errors), base (base)
+ CharCmp (const CharType *base, bool emit_errors, bool autoderef_mode)
+ : BaseCmp (base, emit_errors, autoderef_mode), base (base)
{}
void visit (const InferType &type) override
@@ -1104,6 +1129,8 @@ public:
void visit (const CharType &type) override { ok = true; }
+ void visit (const ParamType &type) override { ok = true; }
+
private:
const BaseType *get_base () const override { return base; }
const CharType *base;
@@ -1114,8 +1141,9 @@ class ReferenceCmp : public BaseCmp
using Rust::TyTy::BaseCmp::visit;
public:
- ReferenceCmp (const ReferenceType *base, bool emit_errors)
- : BaseCmp (base, emit_errors), base (base)
+ ReferenceCmp (const ReferenceType *base, bool emit_errors,
+ bool autoderef_mode)
+ : BaseCmp (base, emit_errors, autoderef_mode), base (base)
{}
void visit (const ReferenceType &type) override
@@ -1123,7 +1151,8 @@ public:
auto base_type = base->get_base ();
auto other_base_type = type.get_base ();
- ok = base_type->can_eq (other_base_type, emit_error_flag)
+ ok = base_type->can_eq (other_base_type, emit_error_flag,
+ autoderef_mode_flag)
&& (base->is_mutable () == type.is_mutable ());
}
@@ -1137,8 +1166,8 @@ class PointerCmp : public BaseCmp
using Rust::TyTy::BaseCmp::visit;
public:
- PointerCmp (const PointerType *base, bool emit_errors)
- : BaseCmp (base, emit_errors), base (base)
+ PointerCmp (const PointerType *base, bool emit_errors, bool autoderef_mode)
+ : BaseCmp (base, emit_errors, autoderef_mode), base (base)
{}
void visit (const ReferenceType &type) override
@@ -1146,7 +1175,8 @@ public:
auto base_type = base->get_base ();
auto other_base_type = type.get_base ();
- ok = base_type->can_eq (other_base_type, emit_error_flag)
+ ok = base_type->can_eq (other_base_type, emit_error_flag,
+ autoderef_mode_flag)
&& (base->is_mutable () == type.is_mutable ());
}
@@ -1160,8 +1190,8 @@ class ParamCmp : public BaseCmp
using Rust::TyTy::BaseCmp::visit;
public:
- ParamCmp (const ParamType *base, bool emit_errors)
- : BaseCmp (base, emit_errors), base (base)
+ ParamCmp (const ParamType *base, bool emit_errors, bool autoderef_mode)
+ : BaseCmp (base, emit_errors, autoderef_mode), base (base)
{}
// param types are a placeholder we shouldn't have cases where we unify
@@ -1183,13 +1213,7 @@ public:
bool ok = context->lookup_type (base->get_ty_ref (), &lookup);
rust_assert (ok);
- if (lookup->get_kind () == TypeKind::PARAM)
- {
- InferType infer (UNKNOWN_HIRID, InferType::InferTypeKind::GENERAL);
- return infer.can_eq (other, emit_error_flag);
- }
-
- return lookup->can_eq (other, emit_error_flag);
+ return lookup->can_eq (other, emit_error_flag, autoderef_mode_flag);
}
// imagine the case where we have:
@@ -1198,7 +1222,46 @@ public:
// impl <X>Foo<X> { ... }
// both of these types are compatible so we mostly care about the number of
// generic arguments
- void visit (const ParamType &type) override { ok = true; }
+ void visit (const ParamType &) override { ok = true; }
+
+ void visit (const TupleType &) override { ok = true; }
+
+ void visit (const ADTType &) override { ok = true; }
+
+ void visit (const InferType &) override { ok = true; }
+
+ void visit (const FnType &) override { ok = true; }
+
+ void visit (const FnPtr &) override { ok = true; }
+
+ void visit (const ArrayType &) override { ok = true; }
+
+ void visit (const BoolType &) override { ok = true; }
+
+ void visit (const IntType &) override { ok = true; }
+
+ void visit (const UintType &) override { ok = true; }
+
+ void visit (const USizeType &) override { ok = true; }
+
+ void visit (const ISizeType &) override { ok = true; }
+
+ void visit (const FloatType &) override { ok = true; }
+
+ void visit (const CharType &) override { ok = true; }
+
+ void visit (const ReferenceType &) override { ok = !autoderef_mode_flag; }
+
+ void visit (const PointerType &) override { ok = !autoderef_mode_flag; }
+
+ void visit (const StrType &) override { ok = true; }
+
+ void visit (const NeverType &) override { ok = true; }
+
+ void visit (const PlaceholderType &type) override
+ {
+ ok = base->get_symbol ().compare (type.get_symbol ()) == 0;
+ }
private:
const BaseType *get_base () const override { return base; }
@@ -1211,12 +1274,14 @@ class StrCmp : public BaseCmp
using Rust::TyTy::BaseCmp::visit;
public:
- StrCmp (const StrType *base, bool emit_errors)
- : BaseCmp (base, emit_errors), base (base)
+ StrCmp (const StrType *base, bool emit_errors, bool autoderef_mode)
+ : BaseCmp (base, emit_errors, autoderef_mode), base (base)
{}
void visit (const StrType &type) override { ok = true; }
+ void visit (const ParamType &type) override { ok = true; }
+
private:
const BaseType *get_base () const override { return base; }
const StrType *base;
@@ -1227,12 +1292,14 @@ class NeverCmp : public BaseCmp
using Rust::TyTy::BaseCmp::visit;
public:
- NeverCmp (const NeverType *base, bool emit_errors)
- : BaseCmp (base, emit_errors), base (base)
+ NeverCmp (const NeverType *base, bool emit_errors, bool autoderef_mode)
+ : BaseCmp (base, emit_errors, autoderef_mode), base (base)
{}
void visit (const NeverType &type) override { ok = true; }
+ void visit (const ParamType &type) override { ok = true; }
+
private:
const BaseType *get_base () const override { return base; }
const NeverType *base;
@@ -1243,8 +1310,9 @@ class PlaceholderCmp : public BaseCmp
using Rust::TyTy::BaseCmp::visit;
public:
- PlaceholderCmp (const PlaceholderType *base, bool emit_errors)
- : BaseCmp (base, emit_errors), base (base)
+ PlaceholderCmp (const PlaceholderType *base, bool emit_errors,
+ bool autoderef_mode)
+ : BaseCmp (base, emit_errors, autoderef_mode), base (base)
{}
bool can_eq (const BaseType *other) override
@@ -1253,7 +1321,7 @@ public:
return BaseCmp::can_eq (other);
BaseType *lookup = base->resolve ();
- return lookup->can_eq (other, emit_error_flag);
+ return lookup->can_eq (other, emit_error_flag, autoderef_mode_flag);
}
void visit (const TupleType &) override { ok = true; }
@@ -1308,8 +1376,9 @@ class DynamicCmp : public BaseCmp
using Rust::TyTy::BaseCmp::visit;
public:
- DynamicCmp (const DynamicObjectType *base, bool emit_errors)
- : BaseCmp (base, emit_errors), base (base)
+ DynamicCmp (const DynamicObjectType *base, bool emit_errors,
+ bool autoderef_mode)
+ : BaseCmp (base, emit_errors, autoderef_mode), base (base)
{}
void visit (const DynamicObjectType &type) override
@@ -1324,6 +1393,8 @@ public:
ok = base->bounds_compatible (type, ref_locus, false);
}
+ void visit (const ParamType &type) override { ok = true; }
+
private:
const BaseType *get_base () const override { return base; }
diff --git a/gcc/rust/typecheck/rust-tyty.cc b/gcc/rust/typecheck/rust-tyty.cc
index f2216f9..37f93b4 100644
--- a/gcc/rust/typecheck/rust-tyty.cc
+++ b/gcc/rust/typecheck/rust-tyty.cc
@@ -201,9 +201,10 @@ InferType::unify (BaseType *other)
}
bool
-InferType::can_eq (const BaseType *other, bool emit_errors) const
+InferType::can_eq (const BaseType *other, bool emit_errors,
+ bool autoderef_mode) const
{
- InferCmp r (this, emit_errors);
+ InferCmp r (this, emit_errors, autoderef_mode);
return r.can_eq (other);
}
@@ -278,7 +279,8 @@ ErrorType::unify (BaseType *other)
}
bool
-ErrorType::can_eq (const BaseType *other, bool emit_errors) const
+ErrorType::can_eq (const BaseType *other, bool emit_errors,
+ bool autoderef_mode) const
{
return get_kind () == other->get_kind ();
}
@@ -331,9 +333,11 @@ StructFieldType::clone () const
get_field_type ()->clone ());
}
-void
+bool
SubstitutionParamMapping::fill_param_ty (BaseType &type, Location locus)
{
+ auto context = Resolver::TypeCheckContext::get ();
+
if (type.get_kind () == TyTy::TypeKind::INFER)
{
type.inherit_bounds (*param);
@@ -341,7 +345,7 @@ SubstitutionParamMapping::fill_param_ty (BaseType &type, Location locus)
else
{
if (!param->bounds_compatible (type, locus, true))
- return;
+ return false;
}
if (type.get_kind () == TypeKind::PARAM)
@@ -351,8 +355,52 @@ SubstitutionParamMapping::fill_param_ty (BaseType &type, Location locus)
}
else
{
+ // check the substitution is compatible with bounds
+ if (!param->bounds_compatible (type, locus, true))
+ return false;
+
+ // setup any associated type mappings for the specified bonds and this
+ // type
+ auto candidates = Resolver::TypeBoundsProbe::Probe (&type);
+ for (auto &specified_bound : param->get_specified_bounds ())
+ {
+ const Resolver::TraitReference *specified_bound_ref
+ = specified_bound.get ();
+
+ // since the bounds_compatible check has occurred we should be able to
+ // assert on finding the trait references
+ HirId associated_impl_block_id = UNKNOWN_HIRID;
+ bool found = false;
+ for (auto &bound : candidates)
+ {
+ const Resolver::TraitReference *bound_trait_ref = bound.first;
+ const HIR::ImplBlock *associated_impl = bound.second;
+
+ found = specified_bound_ref->is_equal (*bound_trait_ref);
+ if (found)
+ {
+ rust_assert (associated_impl != nullptr);
+ associated_impl_block_id
+ = associated_impl->get_mappings ().get_hirid ();
+ break;
+ }
+ }
+
+ if (found && associated_impl_block_id != UNKNOWN_HIRID)
+ {
+ Resolver::AssociatedImplTrait *lookup_associated = nullptr;
+ bool found_impl_trait = context->lookup_associated_trait_impl (
+ associated_impl_block_id, &lookup_associated);
+
+ if (found_impl_trait)
+ lookup_associated->setup_associated_types ();
+ }
+ }
+
param->set_ty_ref (type.get_ref ());
}
+
+ return true;
}
void
@@ -595,9 +643,10 @@ ADTType::cast (BaseType *other)
}
bool
-ADTType::can_eq (const BaseType *other, bool emit_errors) const
+ADTType::can_eq (const BaseType *other, bool emit_errors,
+ bool autoderef_mode) const
{
- ADTCmp r (this, emit_errors);
+ ADTCmp r (this, emit_errors, autoderef_mode);
return r.can_eq (other);
}
@@ -776,9 +825,10 @@ TupleType::cast (BaseType *other)
}
bool
-TupleType::can_eq (const BaseType *other, bool emit_errors) const
+TupleType::can_eq (const BaseType *other, bool emit_errors,
+ bool autoderef_mode) const
{
- TupleCmp r (this, emit_errors);
+ TupleCmp r (this, emit_errors, autoderef_mode);
return r.can_eq (other);
}
@@ -880,9 +930,10 @@ FnType::cast (BaseType *other)
}
bool
-FnType::can_eq (const BaseType *other, bool emit_errors) const
+FnType::can_eq (const BaseType *other, bool emit_errors,
+ bool autoderef_mode) const
{
- FnCmp r (this, emit_errors);
+ FnCmp r (this, emit_errors, autoderef_mode);
return r.can_eq (other);
}
@@ -1097,9 +1148,10 @@ FnPtr::cast (BaseType *other)
}
bool
-FnPtr::can_eq (const BaseType *other, bool emit_errors) const
+FnPtr::can_eq (const BaseType *other, bool emit_errors,
+ bool autoderef_mode) const
{
- FnptrCmp r (this, emit_errors);
+ FnptrCmp r (this, emit_errors, autoderef_mode);
return r.can_eq (other);
}
@@ -1163,9 +1215,10 @@ ClosureType::unify (BaseType *other)
}
bool
-ClosureType::can_eq (const BaseType *other, bool emit_errors) const
+ClosureType::can_eq (const BaseType *other, bool emit_errors,
+ bool autoderef_mode) const
{
- ClosureCmp r (this, emit_errors);
+ ClosureCmp r (this, emit_errors, autoderef_mode);
return r.can_eq (other);
}
@@ -1251,9 +1304,10 @@ ArrayType::cast (BaseType *other)
}
bool
-ArrayType::can_eq (const BaseType *other, bool emit_errors) const
+ArrayType::can_eq (const BaseType *other, bool emit_errors,
+ bool autoderef_mode) const
{
- ArrayCmp r (this, emit_errors);
+ ArrayCmp r (this, emit_errors, autoderef_mode);
return r.can_eq (other);
}
@@ -1326,9 +1380,10 @@ BoolType::cast (BaseType *other)
}
bool
-BoolType::can_eq (const BaseType *other, bool emit_errors) const
+BoolType::can_eq (const BaseType *other, bool emit_errors,
+ bool autoderef_mode) const
{
- BoolCmp r (this, emit_errors);
+ BoolCmp r (this, emit_errors, autoderef_mode);
return r.can_eq (other);
}
@@ -1392,9 +1447,10 @@ IntType::cast (BaseType *other)
}
bool
-IntType::can_eq (const BaseType *other, bool emit_errors) const
+IntType::can_eq (const BaseType *other, bool emit_errors,
+ bool autoderef_mode) const
{
- IntCmp r (this, emit_errors);
+ IntCmp r (this, emit_errors, autoderef_mode);
return r.can_eq (other);
}
@@ -1469,9 +1525,10 @@ UintType::cast (BaseType *other)
}
bool
-UintType::can_eq (const BaseType *other, bool emit_errors) const
+UintType::can_eq (const BaseType *other, bool emit_errors,
+ bool autoderef_mode) const
{
- UintCmp r (this, emit_errors);
+ UintCmp r (this, emit_errors, autoderef_mode);
return r.can_eq (other);
}
@@ -1540,9 +1597,10 @@ FloatType::cast (BaseType *other)
}
bool
-FloatType::can_eq (const BaseType *other, bool emit_errors) const
+FloatType::can_eq (const BaseType *other, bool emit_errors,
+ bool autoderef_mode) const
{
- FloatCmp r (this, emit_errors);
+ FloatCmp r (this, emit_errors, autoderef_mode);
return r.can_eq (other);
}
@@ -1603,9 +1661,10 @@ USizeType::cast (BaseType *other)
}
bool
-USizeType::can_eq (const BaseType *other, bool emit_errors) const
+USizeType::can_eq (const BaseType *other, bool emit_errors,
+ bool autoderef_mode) const
{
- USizeCmp r (this, emit_errors);
+ USizeCmp r (this, emit_errors, autoderef_mode);
return r.can_eq (other);
}
@@ -1655,9 +1714,10 @@ ISizeType::cast (BaseType *other)
}
bool
-ISizeType::can_eq (const BaseType *other, bool emit_errors) const
+ISizeType::can_eq (const BaseType *other, bool emit_errors,
+ bool autoderef_mode) const
{
- ISizeCmp r (this, emit_errors);
+ ISizeCmp r (this, emit_errors, autoderef_mode);
return r.can_eq (other);
}
@@ -1707,9 +1767,10 @@ CharType::cast (BaseType *other)
}
bool
-CharType::can_eq (const BaseType *other, bool emit_errors) const
+CharType::can_eq (const BaseType *other, bool emit_errors,
+ bool autoderef_mode) const
{
- CharCmp r (this, emit_errors);
+ CharCmp r (this, emit_errors, autoderef_mode);
return r.can_eq (other);
}
@@ -1760,9 +1821,10 @@ ReferenceType::cast (BaseType *other)
}
bool
-ReferenceType::can_eq (const BaseType *other, bool emit_errors) const
+ReferenceType::can_eq (const BaseType *other, bool emit_errors,
+ bool autoderef_mode) const
{
- ReferenceCmp r (this, emit_errors);
+ ReferenceCmp r (this, emit_errors, autoderef_mode);
return r.can_eq (other);
}
@@ -1846,9 +1908,10 @@ PointerType::cast (BaseType *other)
}
bool
-PointerType::can_eq (const BaseType *other, bool emit_errors) const
+PointerType::can_eq (const BaseType *other, bool emit_errors,
+ bool autoderef_mode) const
{
- PointerCmp r (this, emit_errors);
+ PointerCmp r (this, emit_errors, autoderef_mode);
return r.can_eq (other);
}
@@ -1941,9 +2004,10 @@ ParamType::cast (BaseType *other)
}
bool
-ParamType::can_eq (const BaseType *other, bool emit_errors) const
+ParamType::can_eq (const BaseType *other, bool emit_errors,
+ bool autoderef_mode) const
{
- ParamCmp r (this, emit_errors);
+ ParamCmp r (this, emit_errors, autoderef_mode);
return r.can_eq (other);
}
@@ -1998,7 +2062,7 @@ ParamType::is_equal (const BaseType &other) const
return false;
if (can_resolve ())
- return resolve ()->can_eq (other2.resolve (), false);
+ return resolve ()->can_eq (other2.resolve (), false, false);
return get_symbol ().compare (other2.get_symbol ()) == 0;
}
@@ -2062,9 +2126,10 @@ StrType::cast (BaseType *other)
}
bool
-StrType::can_eq (const BaseType *other, bool emit_errors) const
+StrType::can_eq (const BaseType *other, bool emit_errors,
+ bool autoderef_mode) const
{
- StrCmp r (this, emit_errors);
+ StrCmp r (this, emit_errors, autoderef_mode);
return r.can_eq (other);
}
@@ -2114,9 +2179,10 @@ NeverType::cast (BaseType *other)
}
bool
-NeverType::can_eq (const BaseType *other, bool emit_errors) const
+NeverType::can_eq (const BaseType *other, bool emit_errors,
+ bool autoderef_mode) const
{
- NeverCmp r (this, emit_errors);
+ NeverCmp r (this, emit_errors, autoderef_mode);
return r.can_eq (other);
}
@@ -2169,9 +2235,10 @@ PlaceholderType::cast (BaseType *other)
}
bool
-PlaceholderType::can_eq (const BaseType *other, bool emit_errors) const
+PlaceholderType::can_eq (const BaseType *other, bool emit_errors,
+ bool autoderef_mode) const
{
- PlaceholderCmp r (this, emit_errors);
+ PlaceholderCmp r (this, emit_errors, autoderef_mode);
return r.can_eq (other);
}
@@ -2269,9 +2336,10 @@ ProjectionType::cast (BaseType *other)
}
bool
-ProjectionType::can_eq (const BaseType *other, bool emit_errors) const
+ProjectionType::can_eq (const BaseType *other, bool emit_errors,
+ bool autoderef_mode) const
{
- return base->can_eq (other, emit_errors);
+ return base->can_eq (other, emit_errors, autoderef_mode);
}
BaseType *
@@ -2375,9 +2443,10 @@ DynamicObjectType::unify (BaseType *other)
}
bool
-DynamicObjectType::can_eq (const BaseType *other, bool emit_errors) const
+DynamicObjectType::can_eq (const BaseType *other, bool emit_errors,
+ bool autoderef_mode) const
{
- DynamicCmp r (this, emit_errors);
+ DynamicCmp r (this, emit_errors, autoderef_mode);
return r.can_eq (other);
}
diff --git a/gcc/rust/typecheck/rust-tyty.h b/gcc/rust/typecheck/rust-tyty.h
index 054e327..20bad10 100644
--- a/gcc/rust/typecheck/rust-tyty.h
+++ b/gcc/rust/typecheck/rust-tyty.h
@@ -146,11 +146,42 @@ public:
}
};
+class BaseType;
+class TypeBoundPredicate;
+class TypeBoundPredicateItem
+{
+public:
+ TypeBoundPredicateItem (const TypeBoundPredicate *parent,
+ const Resolver::TraitItemReference *trait_item_ref)
+ : parent (parent), trait_item_ref (trait_item_ref)
+ {}
+
+ static TypeBoundPredicateItem error ()
+ {
+ return TypeBoundPredicateItem (nullptr, nullptr);
+ }
+
+ bool is_error () const
+ {
+ return parent == nullptr || trait_item_ref == nullptr;
+ }
+
+ BaseType *get_tyty_for_receiver (const TyTy::BaseType *receiver);
+
+ const Resolver::TraitItemReference *get_raw_item () const;
+
+ bool needs_implementation () const;
+
+private:
+ const TypeBoundPredicate *parent;
+ const Resolver::TraitItemReference *trait_item_ref;
+};
+
class TypeBoundPredicate
{
public:
TypeBoundPredicate (DefId reference, Location locus)
- : reference (reference), locus (locus)
+ : reference (reference), locus (locus), args (nullptr)
{}
std::string as_string () const;
@@ -165,9 +196,29 @@ public:
// https://doc.rust-lang.org/reference/items/traits.html#object-safety
bool is_object_safe (bool emit_error, Location locus) const;
+ void apply_generic_arguments (HIR::GenericArgs *generic_args);
+
+ bool contains_item (const std::string &search) const;
+
+ TypeBoundPredicateItem
+ lookup_associated_item (const std::string &search) const;
+
+ HIR::GenericArgs *get_generic_args () { return args; }
+
+ const HIR::GenericArgs *get_generic_args () const { return args; }
+
+ bool has_generic_args () const
+ {
+ if (args == nullptr)
+ return false;
+
+ return args->has_generic_args ();
+ }
+
private:
DefId reference;
Location locus;
+ HIR::GenericArgs *args;
};
class TypeBoundsMappings
@@ -259,7 +310,8 @@ public:
//
// It can also be used to optional emit errors for trait item compatibility
// checks
- virtual bool can_eq (const BaseType *other, bool emit_errors) const = 0;
+ virtual bool can_eq (const BaseType *other, bool emit_errors,
+ bool autoderef_mode) const = 0;
// this is the base coercion interface for types
virtual BaseType *coerce (BaseType *other) = 0;
@@ -404,7 +456,8 @@ public:
BaseType *unify (BaseType *other) override;
- bool can_eq (const BaseType *other, bool emit_errors) const override final;
+ bool can_eq (const BaseType *other, bool emit_errors,
+ bool autoderef_mode) const override final;
BaseType *coerce (BaseType *other) override;
BaseType *cast (BaseType *other) override;
@@ -442,7 +495,8 @@ public:
std::string as_string () const override;
BaseType *unify (BaseType *other) override;
- bool can_eq (const BaseType *other, bool emit_errors) const override final;
+ bool can_eq (const BaseType *other, bool emit_errors,
+ bool autoderef_mode) const override final;
BaseType *coerce (BaseType *other) override;
BaseType *cast (BaseType *other) override;
@@ -476,7 +530,8 @@ public:
std::string as_string () const override;
BaseType *unify (BaseType *other) override;
- bool can_eq (const BaseType *other, bool emit_errors) const override final;
+ bool can_eq (const BaseType *other, bool emit_errors,
+ bool autoderef_mode) const override final;
BaseType *coerce (BaseType *other) override;
BaseType *cast (BaseType *other) override;
@@ -564,7 +619,8 @@ public:
std::string as_string () const override;
BaseType *unify (BaseType *other) override;
- bool can_eq (const BaseType *other, bool emit_errors) const override final;
+ bool can_eq (const BaseType *other, bool emit_errors,
+ bool autoderef_mode) const override final;
BaseType *coerce (BaseType *other) override;
BaseType *cast (BaseType *other) override;
@@ -626,7 +682,7 @@ public:
std::string as_string () const { return param->as_string (); }
- void fill_param_ty (BaseType &type, Location locus);
+ bool fill_param_ty (BaseType &type, Location locus);
SubstitutionParamMapping clone () const
{
@@ -998,7 +1054,8 @@ public:
std::string as_string () const override;
BaseType *unify (BaseType *other) override;
- bool can_eq (const BaseType *other, bool emit_errors) const override final;
+ bool can_eq (const BaseType *other, bool emit_errors,
+ bool autoderef_mode) const override final;
BaseType *coerce (BaseType *other) override;
BaseType *cast (BaseType *other) override;
@@ -1126,7 +1183,8 @@ public:
std::string get_identifier () const { return identifier; }
BaseType *unify (BaseType *other) override;
- bool can_eq (const BaseType *other, bool emit_errors) const override final;
+ bool can_eq (const BaseType *other, bool emit_errors,
+ bool autoderef_mode) const override final;
BaseType *coerce (BaseType *other) override;
BaseType *cast (BaseType *other) override;
@@ -1234,7 +1292,8 @@ public:
std::string as_string () const override;
BaseType *unify (BaseType *other) override;
- bool can_eq (const BaseType *other, bool emit_errors) const override final;
+ bool can_eq (const BaseType *other, bool emit_errors,
+ bool autoderef_mode) const override final;
BaseType *coerce (BaseType *other) override;
BaseType *cast (BaseType *other) override;
@@ -1294,7 +1353,8 @@ public:
std::string get_name () const override final { return as_string (); }
BaseType *unify (BaseType *other) override;
- bool can_eq (const BaseType *other, bool emit_errors) const override final;
+ bool can_eq (const BaseType *other, bool emit_errors,
+ bool autoderef_mode) const override final;
BaseType *coerce (BaseType *other) override;
BaseType *cast (BaseType *other) override;
@@ -1346,7 +1406,8 @@ public:
std::string get_name () const override final { return as_string (); }
BaseType *unify (BaseType *other) override;
- bool can_eq (const BaseType *other, bool emit_errors) const override final;
+ bool can_eq (const BaseType *other, bool emit_errors,
+ bool autoderef_mode) const override final;
BaseType *coerce (BaseType *other) override;
BaseType *cast (BaseType *other) override;
@@ -1388,7 +1449,8 @@ public:
std::string get_name () const override final { return as_string (); }
BaseType *unify (BaseType *other) override;
- bool can_eq (const BaseType *other, bool emit_errors) const override final;
+ bool can_eq (const BaseType *other, bool emit_errors,
+ bool autoderef_mode) const override final;
BaseType *coerce (BaseType *other) override;
BaseType *cast (BaseType *other) override;
@@ -1424,7 +1486,8 @@ public:
std::string get_name () const override final { return as_string (); }
BaseType *unify (BaseType *other) override;
- bool can_eq (const BaseType *other, bool emit_errors) const override final;
+ bool can_eq (const BaseType *other, bool emit_errors,
+ bool autoderef_mode) const override final;
BaseType *coerce (BaseType *other) override;
BaseType *cast (BaseType *other) override;
@@ -1467,7 +1530,8 @@ public:
std::string get_name () const override final { return as_string (); }
BaseType *unify (BaseType *other) override;
- bool can_eq (const BaseType *other, bool emit_errors) const override final;
+ bool can_eq (const BaseType *other, bool emit_errors,
+ bool autoderef_mode) const override final;
BaseType *coerce (BaseType *other) override;
BaseType *cast (BaseType *other) override;
@@ -1508,7 +1572,8 @@ public:
std::string get_name () const override final { return as_string (); }
BaseType *unify (BaseType *other) override;
- bool can_eq (const BaseType *other, bool emit_errors) const override final;
+ bool can_eq (const BaseType *other, bool emit_errors,
+ bool autoderef_mode) const override final;
BaseType *coerce (BaseType *other) override;
BaseType *cast (BaseType *other) override;
@@ -1541,7 +1606,8 @@ public:
std::string get_name () const override final { return as_string (); }
BaseType *unify (BaseType *other) override;
- bool can_eq (const BaseType *other, bool emit_errors) const override final;
+ bool can_eq (const BaseType *other, bool emit_errors,
+ bool autoderef_mode) const override final;
BaseType *coerce (BaseType *other) override;
BaseType *cast (BaseType *other) override;
@@ -1567,7 +1633,8 @@ public:
std::string get_name () const override final { return as_string (); }
BaseType *unify (BaseType *other) override;
- bool can_eq (const BaseType *other, bool emit_errors) const override final;
+ bool can_eq (const BaseType *other, bool emit_errors,
+ bool autoderef_mode) const override final;
BaseType *coerce (BaseType *other) override;
BaseType *cast (BaseType *other) override;
@@ -1593,7 +1660,8 @@ public:
std::string get_name () const override final { return as_string (); }
BaseType *unify (BaseType *other) override;
- bool can_eq (const BaseType *other, bool emit_errors) const override final;
+ bool can_eq (const BaseType *other, bool emit_errors,
+ bool autoderef_mode) const override final;
BaseType *coerce (BaseType *other) override;
BaseType *cast (BaseType *other) override;
@@ -1623,7 +1691,8 @@ public:
std::string get_name () const override final { return as_string (); }
BaseType *unify (BaseType *other) override;
- bool can_eq (const BaseType *other, bool emit_errors) const override final;
+ bool can_eq (const BaseType *other, bool emit_errors,
+ bool autoderef_mode) const override final;
BaseType *coerce (BaseType *other) override;
BaseType *cast (BaseType *other) override;
@@ -1670,7 +1739,8 @@ public:
std::string get_name () const override final { return as_string (); }
BaseType *unify (BaseType *other) override;
- bool can_eq (const BaseType *other, bool emit_errors) const override final;
+ bool can_eq (const BaseType *other, bool emit_errors,
+ bool autoderef_mode) const override final;
BaseType *coerce (BaseType *other) override;
BaseType *cast (BaseType *other) override;
@@ -1715,7 +1785,8 @@ public:
std::string as_string () const override;
BaseType *unify (BaseType *other) override;
- bool can_eq (const BaseType *other, bool emit_errors) const override final;
+ bool can_eq (const BaseType *other, bool emit_errors,
+ bool autoderef_mode) const override final;
BaseType *coerce (BaseType *other) override;
BaseType *cast (BaseType *other) override;
@@ -1751,7 +1822,8 @@ public:
std::string as_string () const override;
BaseType *unify (BaseType *other) override;
- bool can_eq (const BaseType *other, bool emit_errors) const override final;
+ bool can_eq (const BaseType *other, bool emit_errors,
+ bool autoderef_mode) const override final;
BaseType *coerce (BaseType *other) override;
BaseType *cast (BaseType *other) override;
@@ -1784,7 +1856,8 @@ public:
std::string as_string () const override;
BaseType *unify (BaseType *other) override;
- bool can_eq (const BaseType *other, bool emit_errors) const override final;
+ bool can_eq (const BaseType *other, bool emit_errors,
+ bool autoderef_mode) const override final;
BaseType *coerce (BaseType *other) override;
BaseType *cast (BaseType *other) override;
@@ -1812,7 +1885,9 @@ public:
bool contains_type_parameters () const override
{
- rust_assert (can_resolve ());
+ if (!can_resolve ())
+ return false;
+
return resolve ()->contains_type_parameters ();
}
@@ -1850,7 +1925,8 @@ public:
std::string as_string () const override;
BaseType *unify (BaseType *other) override;
- bool can_eq (const BaseType *other, bool emit_errors) const override final;
+ bool can_eq (const BaseType *other, bool emit_errors,
+ bool autoderef_mode) const override final;
BaseType *coerce (BaseType *other) override;
BaseType *cast (BaseType *other) override;
@@ -1910,7 +1986,8 @@ public:
std::string as_string () const override;
BaseType *unify (BaseType *other) override;
- bool can_eq (const BaseType *other, bool emit_errors) const override final;
+ bool can_eq (const BaseType *other, bool emit_errors,
+ bool autoderef_mode) const override final;
BaseType *coerce (BaseType *other) override;
BaseType *cast (BaseType *other) override;
bool is_equal (const BaseType &other) const override;
diff --git a/gcc/testsuite/rust/execute/torture/trait6.rs b/gcc/testsuite/rust/execute/torture/trait6.rs
new file mode 100644
index 0000000..54023d2
--- /dev/null
+++ b/gcc/testsuite/rust/execute/torture/trait6.rs
@@ -0,0 +1,41 @@
+/* { dg-output "123\n" } */
+extern "C" {
+ fn printf(s: *const i8, ...);
+}
+
+pub trait Foo {
+ type A;
+
+ fn bar(self) -> Self::A;
+ // { dg-warning "unused name" "" { target *-*-* } .-1 }
+}
+
+struct S(i32);
+impl Foo for S {
+ type A = i32;
+
+ fn bar(self) -> Self::A {
+ // { dg-warning "unused name" "" { target *-*-* } .-1 }
+ self.0
+ }
+}
+
+fn test_bar<T: Foo>(x: T) -> T::A {
+ x.bar()
+}
+
+fn main() -> i32 {
+ let a;
+ a = S(123);
+
+ let bar: i32 = test_bar::<S>(a);
+ unsafe {
+ let a = "%i\n\0";
+ let b = a as *const str;
+ let c = b as *const i8;
+
+ printf(c, bar);
+ }
+
+ 0
+}
diff --git a/gcc/testsuite/rust/execute/torture/trait7.rs b/gcc/testsuite/rust/execute/torture/trait7.rs
new file mode 100644
index 0000000..059ba15
--- /dev/null
+++ b/gcc/testsuite/rust/execute/torture/trait7.rs
@@ -0,0 +1,41 @@
+/* { dg-output "123\n" } */
+extern "C" {
+ fn printf(s: *const i8, ...);
+}
+
+pub trait Foo {
+ type A;
+
+ fn bar(self) -> Self::A;
+ // { dg-warning "unused name" "" { target *-*-* } .-1 }
+}
+
+struct S(i32);
+impl Foo for S {
+ type A = i32;
+
+ fn bar(self) -> Self::A {
+ // { dg-warning "unused name" "" { target *-*-* } .-1 }
+ self.0
+ }
+}
+
+fn test_bar<T: Foo>(x: T) -> T::A {
+ x.bar()
+}
+
+fn main() -> i32 {
+ let a;
+ a = S(123);
+
+ let bar: i32 = test_bar(a);
+ unsafe {
+ let a = "%i\n\0";
+ let b = a as *const str;
+ let c = b as *const i8;
+
+ printf(c, bar);
+ }
+
+ 0
+}
diff --git a/gcc/testsuite/rust/execute/torture/trait8.rs b/gcc/testsuite/rust/execute/torture/trait8.rs
new file mode 100644
index 0000000..da8a560
--- /dev/null
+++ b/gcc/testsuite/rust/execute/torture/trait8.rs
@@ -0,0 +1,41 @@
+/* { dg-output "123\n" } */
+extern "C" {
+ fn printf(s: *const i8, ...);
+}
+
+pub trait Foo {
+ type A;
+
+ fn bar(&self) -> Self::A;
+ // { dg-warning "unused name" "" { target *-*-* } .-1 }
+}
+
+struct S(i32);
+impl Foo for S {
+ type A = i32;
+
+ fn bar(&self) -> Self::A {
+ // { dg-warning "unused name" "" { target *-*-* } .-1 }
+ self.0
+ }
+}
+
+fn test_bar<T: Foo>(x: T) -> T::A {
+ x.bar()
+}
+
+fn main() -> i32 {
+ let a;
+ a = S(123);
+
+ let bar: i32 = test_bar(a);
+ unsafe {
+ let a = "%i\n\0";
+ let b = a as *const str;
+ let c = b as *const i8;
+
+ printf(c, bar);
+ }
+
+ 0
+}
diff --git a/gcc/testsuite/rust/execute/torture/trait9.rs b/gcc/testsuite/rust/execute/torture/trait9.rs
new file mode 100644
index 0000000..1fe77e3
--- /dev/null
+++ b/gcc/testsuite/rust/execute/torture/trait9.rs
@@ -0,0 +1,38 @@
+/* { dg-output "3\n" } */
+extern "C" {
+ fn printf(s: *const i8, ...);
+}
+
+trait FnLike<A, R> {
+ fn call(&self, arg: A) -> R;
+ // { dg-warning "unused name .self." "" { target *-*-* } .-1 }
+ // { dg-warning "unused name .arg." "" { target *-*-* } .-2 }
+}
+
+struct S;
+impl<T> FnLike<&T, &T> for S {
+ fn call(&self, arg: &T) -> &T {
+ // { dg-warning "unused name .self." "" { target *-*-* } .-1 }
+ // { dg-warning "unused name .<S as FnLike>::call." "" { target *-*-* } .-2 }
+ arg
+ }
+}
+
+fn indirect<F: FnLike<&isize, &isize>>(f: F) {
+ let x = 3;
+ let y = f.call(&x);
+
+ unsafe {
+ let a = "%i\n\0";
+ let b = a as *const str;
+ let c = b as *const i8;
+
+ printf(c, *y);
+ }
+}
+
+fn main() -> i32 {
+ indirect(S);
+
+ 0
+}