mirror of
https://github.com/rust-lang/rust.git
synced 2025-05-14 02:49:40 +00:00
warn for where/return-types that reference regions
This is a step towards fixing #32330. The full fix would be a breaking change, so we begin by issuing warnings for scenarios that will break.
This commit is contained in:
parent
97ca8d799c
commit
ccfb74e800
@ -167,6 +167,13 @@ declare_lint! {
|
|||||||
"transmute from function item type to pointer-sized type erroneously allowed"
|
"transmute from function item type to pointer-sized type erroneously allowed"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
declare_lint! {
|
||||||
|
pub HR_LIFETIME_IN_ASSOC_TYPE,
|
||||||
|
Warn,
|
||||||
|
"binding for associated type references higher-ranked lifetime \
|
||||||
|
that does not appear in the trait input types"
|
||||||
|
}
|
||||||
|
|
||||||
declare_lint! {
|
declare_lint! {
|
||||||
pub OVERLAPPING_INHERENT_IMPLS,
|
pub OVERLAPPING_INHERENT_IMPLS,
|
||||||
Warn,
|
Warn,
|
||||||
@ -234,7 +241,8 @@ impl LintPass for HardwiredLints {
|
|||||||
RENAMED_AND_REMOVED_LINTS,
|
RENAMED_AND_REMOVED_LINTS,
|
||||||
SUPER_OR_SELF_IN_GLOBAL_PATH,
|
SUPER_OR_SELF_IN_GLOBAL_PATH,
|
||||||
UNSIZED_IN_TUPLE,
|
UNSIZED_IN_TUPLE,
|
||||||
OBJECT_UNSAFE_FRAGMENT
|
OBJECT_UNSAFE_FRAGMENT,
|
||||||
|
HR_LIFETIME_IN_ASSOC_TYPE
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -382,6 +382,35 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns a set of all late-bound regions that are constrained
|
||||||
|
/// by `value`, meaning that if we instantiate those LBR with
|
||||||
|
/// variables and equate `value` with something else, those
|
||||||
|
/// variables will also be equated.
|
||||||
|
pub fn collect_constrained_late_bound_regions<T>(&self, value: &Binder<T>)
|
||||||
|
-> FnvHashSet<ty::BoundRegion>
|
||||||
|
where T : TypeFoldable<'tcx>
|
||||||
|
{
|
||||||
|
self.collect_late_bound_regions(value, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a set of all late-bound regions that appear in `value` anywhere.
|
||||||
|
pub fn collect_referenced_late_bound_regions<T>(&self, value: &Binder<T>)
|
||||||
|
-> FnvHashSet<ty::BoundRegion>
|
||||||
|
where T : TypeFoldable<'tcx>
|
||||||
|
{
|
||||||
|
self.collect_late_bound_regions(value, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn collect_late_bound_regions<T>(&self, value: &Binder<T>, just_constraint: bool)
|
||||||
|
-> FnvHashSet<ty::BoundRegion>
|
||||||
|
where T : TypeFoldable<'tcx>
|
||||||
|
{
|
||||||
|
let mut collector = LateBoundRegionsCollector::new(just_constraint);
|
||||||
|
let result = value.skip_binder().visit_with(&mut collector);
|
||||||
|
assert!(!result); // should never have stopped early
|
||||||
|
collector.regions
|
||||||
|
}
|
||||||
|
|
||||||
/// Replace any late-bound regions bound in `value` with `'static`. Useful in trans but also
|
/// Replace any late-bound regions bound in `value` with `'static`. Useful in trans but also
|
||||||
/// method lookup and a few other places where precise region relationships are not required.
|
/// method lookup and a few other places where precise region relationships are not required.
|
||||||
pub fn erase_late_bound_regions<T>(self, value: &Binder<T>) -> T
|
pub fn erase_late_bound_regions<T>(self, value: &Binder<T>) -> T
|
||||||
@ -625,3 +654,54 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor {
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Collects all the late-bound regions it finds into a hash set.
|
||||||
|
struct LateBoundRegionsCollector {
|
||||||
|
current_depth: u32,
|
||||||
|
regions: FnvHashSet<ty::BoundRegion>,
|
||||||
|
just_constrained: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LateBoundRegionsCollector {
|
||||||
|
fn new(just_constrained: bool) -> Self {
|
||||||
|
LateBoundRegionsCollector {
|
||||||
|
current_depth: 1,
|
||||||
|
regions: FnvHashSet(),
|
||||||
|
just_constrained: just_constrained,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx> TypeVisitor<'tcx> for LateBoundRegionsCollector {
|
||||||
|
fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &Binder<T>) -> bool {
|
||||||
|
self.current_depth += 1;
|
||||||
|
let result = t.super_visit_with(self);
|
||||||
|
self.current_depth -= 1;
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_ty(&mut self, t: Ty<'tcx>) -> bool {
|
||||||
|
// if we are only looking for "constrained" region, we have to
|
||||||
|
// ignore the inputs to a projection, as they may not appear
|
||||||
|
// in the normalized form
|
||||||
|
if self.just_constrained {
|
||||||
|
match t.sty {
|
||||||
|
ty::TyProjection(..) => { return false; }
|
||||||
|
_ => { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
t.super_visit_with(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_region(&mut self, r: ty::Region) -> bool {
|
||||||
|
match r {
|
||||||
|
ty::ReLateBound(debruijn, br) if debruijn.depth == self.current_depth => {
|
||||||
|
self.regions.insert(br);
|
||||||
|
}
|
||||||
|
_ => { }
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -197,7 +197,11 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
|
|||||||
FutureIncompatibleInfo {
|
FutureIncompatibleInfo {
|
||||||
id: LintId::of(OBJECT_UNSAFE_FRAGMENT),
|
id: LintId::of(OBJECT_UNSAFE_FRAGMENT),
|
||||||
reference: "issue #33243 <https://github.com/rust-lang/rust/issues/33243>",
|
reference: "issue #33243 <https://github.com/rust-lang/rust/issues/33243>",
|
||||||
}
|
},
|
||||||
|
FutureIncompatibleInfo {
|
||||||
|
id: LintId::of(HR_LIFETIME_IN_ASSOC_TYPE),
|
||||||
|
reference: "issue #33685 <https://github.com/rust-lang/rust/issues/33685>",
|
||||||
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// We have one lint pass defined specially
|
// We have one lint pass defined specially
|
||||||
|
@ -52,13 +52,17 @@ use middle::const_val::ConstVal;
|
|||||||
use rustc_const_eval::{eval_const_expr_partial, ConstEvalErr};
|
use rustc_const_eval::{eval_const_expr_partial, ConstEvalErr};
|
||||||
use rustc_const_eval::EvalHint::UncheckedExprHint;
|
use rustc_const_eval::EvalHint::UncheckedExprHint;
|
||||||
use rustc_const_eval::ErrKind::ErroneousReferencedConstant;
|
use rustc_const_eval::ErrKind::ErroneousReferencedConstant;
|
||||||
|
use hir::{self, SelfKind};
|
||||||
use hir::def::{self, Def};
|
use hir::def::{self, Def};
|
||||||
use hir::def_id::DefId;
|
use hir::def_id::DefId;
|
||||||
|
use hir::print as pprust;
|
||||||
use middle::resolve_lifetime as rl;
|
use middle::resolve_lifetime as rl;
|
||||||
|
use rustc::lint;
|
||||||
use rustc::ty::subst::{FnSpace, TypeSpace, SelfSpace, Subst, Substs, ParamSpace};
|
use rustc::ty::subst::{FnSpace, TypeSpace, SelfSpace, Subst, Substs, ParamSpace};
|
||||||
use rustc::traits;
|
use rustc::traits;
|
||||||
use rustc::ty::{self, Ty, TyCtxt, ToPredicate, TypeFoldable};
|
use rustc::ty::{self, Ty, TyCtxt, ToPredicate, TypeFoldable};
|
||||||
use rustc::ty::wf::object_region_bounds;
|
use rustc::ty::wf::object_region_bounds;
|
||||||
|
use rustc_back::slice;
|
||||||
use require_c_abi_if_variadic;
|
use require_c_abi_if_variadic;
|
||||||
use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope,
|
use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope,
|
||||||
ObjectLifetimeDefaultRscope, ShiftedRscope, BindingRscope,
|
ObjectLifetimeDefaultRscope, ShiftedRscope, BindingRscope,
|
||||||
@ -74,10 +78,6 @@ use syntax::errors::DiagnosticBuilder;
|
|||||||
use syntax::feature_gate::{GateIssue, emit_feature_err};
|
use syntax::feature_gate::{GateIssue, emit_feature_err};
|
||||||
use syntax::parse::token::{self, keywords};
|
use syntax::parse::token::{self, keywords};
|
||||||
|
|
||||||
use rustc::hir::print as pprust;
|
|
||||||
use rustc::hir::{self, SelfKind};
|
|
||||||
use rustc_back::slice;
|
|
||||||
|
|
||||||
pub trait AstConv<'gcx, 'tcx> {
|
pub trait AstConv<'gcx, 'tcx> {
|
||||||
fn tcx<'a>(&'a self) -> TyCtxt<'a, 'gcx, 'tcx>;
|
fn tcx<'a>(&'a self) -> TyCtxt<'a, 'gcx, 'tcx>;
|
||||||
|
|
||||||
@ -679,6 +679,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
|||||||
PathParamMode::Explicit,
|
PathParamMode::Explicit,
|
||||||
trait_def_id,
|
trait_def_id,
|
||||||
self_ty,
|
self_ty,
|
||||||
|
trait_ref.ref_id,
|
||||||
trait_ref.path.segments.last().unwrap(),
|
trait_ref.path.segments.last().unwrap(),
|
||||||
poly_projections)
|
poly_projections)
|
||||||
}
|
}
|
||||||
@ -723,6 +724,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
|||||||
span: Span,
|
span: Span,
|
||||||
param_mode: PathParamMode,
|
param_mode: PathParamMode,
|
||||||
trait_def_id: DefId,
|
trait_def_id: DefId,
|
||||||
|
trait_path_ref_id: ast::NodeId,
|
||||||
trait_segment: &hir::PathSegment,
|
trait_segment: &hir::PathSegment,
|
||||||
mut projections: &mut Vec<ty::PolyProjectionPredicate<'tcx>>)
|
mut projections: &mut Vec<ty::PolyProjectionPredicate<'tcx>>)
|
||||||
-> ty::PolyTraitRef<'tcx>
|
-> ty::PolyTraitRef<'tcx>
|
||||||
@ -732,6 +734,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
|||||||
param_mode,
|
param_mode,
|
||||||
trait_def_id,
|
trait_def_id,
|
||||||
None,
|
None,
|
||||||
|
trait_path_ref_id,
|
||||||
trait_segment,
|
trait_segment,
|
||||||
projections)
|
projections)
|
||||||
}
|
}
|
||||||
@ -742,6 +745,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
|||||||
param_mode: PathParamMode,
|
param_mode: PathParamMode,
|
||||||
trait_def_id: DefId,
|
trait_def_id: DefId,
|
||||||
self_ty: Option<Ty<'tcx>>,
|
self_ty: Option<Ty<'tcx>>,
|
||||||
|
path_id: ast::NodeId,
|
||||||
trait_segment: &hir::PathSegment,
|
trait_segment: &hir::PathSegment,
|
||||||
poly_projections: &mut Vec<ty::PolyProjectionPredicate<'tcx>>)
|
poly_projections: &mut Vec<ty::PolyProjectionPredicate<'tcx>>)
|
||||||
-> ty::PolyTraitRef<'tcx>
|
-> ty::PolyTraitRef<'tcx>
|
||||||
@ -770,7 +774,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
|||||||
.filter_map(|binding| {
|
.filter_map(|binding| {
|
||||||
// specify type to assert that error was already reported in Err case:
|
// specify type to assert that error was already reported in Err case:
|
||||||
let predicate: Result<_, ErrorReported> =
|
let predicate: Result<_, ErrorReported> =
|
||||||
self.ast_type_binding_to_poly_projection_predicate(poly_trait_ref.clone(),
|
self.ast_type_binding_to_poly_projection_predicate(path_id,
|
||||||
|
poly_trait_ref.clone(),
|
||||||
self_ty,
|
self_ty,
|
||||||
binding);
|
binding);
|
||||||
predicate.ok() // ok to ignore Err() because ErrorReported (see above)
|
predicate.ok() // ok to ignore Err() because ErrorReported (see above)
|
||||||
@ -863,7 +868,9 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
|||||||
(self.tcx().mk_substs(substs), assoc_bindings)
|
(self.tcx().mk_substs(substs), assoc_bindings)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ast_type_binding_to_poly_projection_predicate(&self,
|
fn ast_type_binding_to_poly_projection_predicate(
|
||||||
|
&self,
|
||||||
|
path_id: ast::NodeId,
|
||||||
mut trait_ref: ty::PolyTraitRef<'tcx>,
|
mut trait_ref: ty::PolyTraitRef<'tcx>,
|
||||||
self_ty: Option<Ty<'tcx>>,
|
self_ty: Option<Ty<'tcx>>,
|
||||||
binding: &ConvertedBinding<'tcx>)
|
binding: &ConvertedBinding<'tcx>)
|
||||||
@ -887,6 +894,36 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
|||||||
//
|
//
|
||||||
// We want to produce `<B as SuperTrait<int>>::T == foo`.
|
// We want to produce `<B as SuperTrait<int>>::T == foo`.
|
||||||
|
|
||||||
|
// Find any late-bound regions declared in `ty` that are not
|
||||||
|
// declared in the trait-ref. These are not wellformed.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// for<'a> <T as Iterator>::Item = &'a str // <-- 'a is bad
|
||||||
|
// for<'a> <T as FnMut<(&'a u32,)>>::Output = &'a str // <-- 'a is ok
|
||||||
|
let late_bound_in_trait_ref = tcx.collect_constrained_late_bound_regions(&trait_ref);
|
||||||
|
let late_bound_in_ty = tcx.collect_referenced_late_bound_regions(&ty::Binder(binding.ty));
|
||||||
|
debug!("late_bound_in_trait_ref = {:?}", late_bound_in_trait_ref);
|
||||||
|
debug!("late_bound_in_ty = {:?}", late_bound_in_ty);
|
||||||
|
for br in late_bound_in_ty.difference(&late_bound_in_trait_ref) {
|
||||||
|
let br_name = match *br {
|
||||||
|
ty::BrNamed(_, name) => name,
|
||||||
|
_ => {
|
||||||
|
span_bug!(
|
||||||
|
binding.span,
|
||||||
|
"anonymous bound region {:?} in binding but not trait ref",
|
||||||
|
br);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
tcx.sess.add_lint(
|
||||||
|
lint::builtin::HR_LIFETIME_IN_ASSOC_TYPE,
|
||||||
|
path_id,
|
||||||
|
binding.span,
|
||||||
|
format!("binding for associated type `{}` references lifetime `{}`, \
|
||||||
|
which does not appear in the trait input types",
|
||||||
|
binding.item_name, br_name));
|
||||||
|
}
|
||||||
|
|
||||||
// Simple case: X is defined in the current trait.
|
// Simple case: X is defined in the current trait.
|
||||||
if self.trait_defines_associated_type_named(trait_ref.def_id(), binding.item_name) {
|
if self.trait_defines_associated_type_named(trait_ref.def_id(), binding.item_name) {
|
||||||
return Ok(ty::Binder(ty::ProjectionPredicate { // <-------------------+
|
return Ok(ty::Binder(ty::ProjectionPredicate { // <-------------------+
|
||||||
@ -1012,6 +1049,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
|||||||
path.span,
|
path.span,
|
||||||
PathParamMode::Explicit,
|
PathParamMode::Explicit,
|
||||||
trait_def_id,
|
trait_def_id,
|
||||||
|
ty.id,
|
||||||
path.segments.last().unwrap(),
|
path.segments.last().unwrap(),
|
||||||
&mut projection_bounds);
|
&mut projection_bounds);
|
||||||
Ok((trait_ref, projection_bounds))
|
Ok((trait_ref, projection_bounds))
|
||||||
@ -1416,6 +1454,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
|||||||
param_mode: PathParamMode,
|
param_mode: PathParamMode,
|
||||||
def: Def,
|
def: Def,
|
||||||
opt_self_ty: Option<Ty<'tcx>>,
|
opt_self_ty: Option<Ty<'tcx>>,
|
||||||
|
base_path_ref_id: ast::NodeId,
|
||||||
base_segments: &[hir::PathSegment])
|
base_segments: &[hir::PathSegment])
|
||||||
-> Ty<'tcx> {
|
-> Ty<'tcx> {
|
||||||
let tcx = self.tcx();
|
let tcx = self.tcx();
|
||||||
@ -1434,6 +1473,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
|||||||
span,
|
span,
|
||||||
param_mode,
|
param_mode,
|
||||||
trait_def_id,
|
trait_def_id,
|
||||||
|
base_path_ref_id,
|
||||||
base_segments.last().unwrap(),
|
base_segments.last().unwrap(),
|
||||||
&mut projection_bounds);
|
&mut projection_bounds);
|
||||||
|
|
||||||
@ -1518,6 +1558,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
|||||||
param_mode: PathParamMode,
|
param_mode: PathParamMode,
|
||||||
mut def: Def,
|
mut def: Def,
|
||||||
opt_self_ty: Option<Ty<'tcx>>,
|
opt_self_ty: Option<Ty<'tcx>>,
|
||||||
|
base_path_ref_id: ast::NodeId,
|
||||||
base_segments: &[hir::PathSegment],
|
base_segments: &[hir::PathSegment],
|
||||||
assoc_segments: &[hir::PathSegment])
|
assoc_segments: &[hir::PathSegment])
|
||||||
-> (Ty<'tcx>, Def) {
|
-> (Ty<'tcx>, Def) {
|
||||||
@ -1532,6 +1573,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
|||||||
param_mode,
|
param_mode,
|
||||||
def,
|
def,
|
||||||
opt_self_ty,
|
opt_self_ty,
|
||||||
|
base_path_ref_id,
|
||||||
base_segments);
|
base_segments);
|
||||||
debug!("finish_resolving_def_to_ty: base_def_to_ty returned {:?}", ty);
|
debug!("finish_resolving_def_to_ty: base_def_to_ty returned {:?}", ty);
|
||||||
// If any associated type segments remain, attempt to resolve them.
|
// If any associated type segments remain, attempt to resolve them.
|
||||||
@ -1607,7 +1649,45 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
|||||||
}
|
}
|
||||||
hir::TyBareFn(ref bf) => {
|
hir::TyBareFn(ref bf) => {
|
||||||
require_c_abi_if_variadic(tcx, &bf.decl, bf.abi, ast_ty.span);
|
require_c_abi_if_variadic(tcx, &bf.decl, bf.abi, ast_ty.span);
|
||||||
tcx.mk_fn_ptr(self.ty_of_bare_fn(bf.unsafety, bf.abi, &bf.decl))
|
let bare_fn_ty = self.ty_of_bare_fn(bf.unsafety, bf.abi, &bf.decl);
|
||||||
|
|
||||||
|
// Find any late-bound regions declared in return type that do
|
||||||
|
// not appear in the arguments. These are not wellformed.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// for<'a> fn() -> &'a str <-- 'a is bad
|
||||||
|
// for<'a> fn(&'a String) -> &'a str <-- 'a is ok
|
||||||
|
//
|
||||||
|
// Note that we do this check **here** and not in
|
||||||
|
// `ty_of_bare_fn` because the latter is also used to make
|
||||||
|
// the types for fn items, and we do not want to issue a
|
||||||
|
// warning then. (Once we fix #32330, the regions we are
|
||||||
|
// checking for here would be considered early bound
|
||||||
|
// anyway.)
|
||||||
|
let inputs = bare_fn_ty.sig.inputs();
|
||||||
|
let late_bound_in_args = tcx.collect_constrained_late_bound_regions(&inputs);
|
||||||
|
let output = bare_fn_ty.sig.output();
|
||||||
|
let late_bound_in_ret = tcx.collect_referenced_late_bound_regions(&output);
|
||||||
|
for br in late_bound_in_ret.difference(&late_bound_in_args) {
|
||||||
|
let br_name = match *br {
|
||||||
|
ty::BrNamed(_, name) => name,
|
||||||
|
_ => {
|
||||||
|
span_bug!(
|
||||||
|
bf.decl.output.span(),
|
||||||
|
"anonymous bound region {:?} in return but not args",
|
||||||
|
br);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
tcx.sess.add_lint(
|
||||||
|
lint::builtin::HR_LIFETIME_IN_ASSOC_TYPE,
|
||||||
|
ast_ty.id,
|
||||||
|
ast_ty.span,
|
||||||
|
format!("return type references lifetime `{}`, \
|
||||||
|
which does not appear in the trait input types",
|
||||||
|
br_name));
|
||||||
|
}
|
||||||
|
tcx.mk_fn_ptr(bare_fn_ty)
|
||||||
}
|
}
|
||||||
hir::TyPolyTraitRef(ref bounds) => {
|
hir::TyPolyTraitRef(ref bounds) => {
|
||||||
self.conv_ty_poly_trait_ref(rscope, ast_ty.span, bounds)
|
self.conv_ty_poly_trait_ref(rscope, ast_ty.span, bounds)
|
||||||
@ -1635,6 +1715,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
|||||||
PathParamMode::Explicit,
|
PathParamMode::Explicit,
|
||||||
def,
|
def,
|
||||||
opt_self_ty,
|
opt_self_ty,
|
||||||
|
ast_ty.id,
|
||||||
&path.segments[..base_ty_end],
|
&path.segments[..base_ty_end],
|
||||||
&path.segments[base_ty_end..]);
|
&path.segments[base_ty_end..]);
|
||||||
|
|
||||||
|
@ -3866,6 +3866,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||||||
PathParamMode::Optional,
|
PathParamMode::Optional,
|
||||||
def,
|
def,
|
||||||
opt_self_ty,
|
opt_self_ty,
|
||||||
|
node_id,
|
||||||
&ty_segments[..base_ty_end],
|
&ty_segments[..base_ty_end],
|
||||||
&ty_segments[base_ty_end..]);
|
&ty_segments[base_ty_end..]);
|
||||||
let item_segment = path.segments.last().unwrap();
|
let item_segment = path.segments.last().unwrap();
|
||||||
|
@ -568,7 +568,8 @@ fn convert_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
|||||||
|
|
||||||
let (fty, explicit_self_category) =
|
let (fty, explicit_self_category) =
|
||||||
AstConv::ty_of_method(&ccx.icx(&(rcvr_ty_predicates, &sig.generics)),
|
AstConv::ty_of_method(&ccx.icx(&(rcvr_ty_predicates, &sig.generics)),
|
||||||
sig, untransformed_rcvr_ty);
|
sig,
|
||||||
|
untransformed_rcvr_ty);
|
||||||
|
|
||||||
let def_id = ccx.tcx.map.local_def_id(id);
|
let def_id = ccx.tcx.map.local_def_id(id);
|
||||||
let substs = mk_item_substs(ccx, &ty_generics);
|
let substs = mk_item_substs(ccx, &ty_generics);
|
||||||
|
@ -40,6 +40,17 @@ impl<'a> TheTrait<&'a isize> for UintStruct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct Tuple {
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> TheTrait<(&'a isize, &'a isize)> for Tuple {
|
||||||
|
type A = &'a isize;
|
||||||
|
|
||||||
|
fn get(&self, t: (&'a isize, &'a isize)) -> &'a isize {
|
||||||
|
t.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn foo<T>()
|
fn foo<T>()
|
||||||
where T : for<'x> TheTrait<&'x isize, A = &'x isize>
|
where T : for<'x> TheTrait<&'x isize, A = &'x isize>
|
||||||
{
|
{
|
||||||
@ -52,10 +63,28 @@ fn bar<T>()
|
|||||||
// ok for UintStruct, but not IntStruct
|
// ok for UintStruct, but not IntStruct
|
||||||
}
|
}
|
||||||
|
|
||||||
fn baz<T>()
|
fn tuple_one<T>()
|
||||||
where T : for<'x,'y> TheTrait<&'x isize, A = &'y isize>
|
where T : for<'x,'y> TheTrait<(&'x isize, &'y isize), A = &'x isize>
|
||||||
{
|
{
|
||||||
// not ok for either struct, due to the use of two lifetimes
|
// not ok for tuple, two lifetimes and we pick first
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tuple_two<T>()
|
||||||
|
where T : for<'x,'y> TheTrait<(&'x isize, &'y isize), A = &'y isize>
|
||||||
|
{
|
||||||
|
// not ok for tuple, two lifetimes and we pick second
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tuple_three<T>()
|
||||||
|
where T : for<'x> TheTrait<(&'x isize, &'x isize), A = &'x isize>
|
||||||
|
{
|
||||||
|
// ok for tuple
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tuple_four<T>()
|
||||||
|
where T : for<'x,'y> TheTrait<(&'x isize, &'y isize)>
|
||||||
|
{
|
||||||
|
// not ok for tuple, two lifetimes, and lifetime matching is invariant
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
@ -65,6 +94,16 @@ pub fn main() {
|
|||||||
bar::<IntStruct>(); //~ ERROR type mismatch
|
bar::<IntStruct>(); //~ ERROR type mismatch
|
||||||
bar::<UintStruct>();
|
bar::<UintStruct>();
|
||||||
|
|
||||||
baz::<IntStruct>(); //~ ERROR type mismatch
|
tuple_one::<Tuple>();
|
||||||
baz::<UintStruct>(); //~ ERROR type mismatch
|
//~^ ERROR E0277
|
||||||
|
//~| ERROR type mismatch
|
||||||
|
|
||||||
|
tuple_two::<Tuple>();
|
||||||
|
//~^ ERROR E0277
|
||||||
|
//~| ERROR type mismatch
|
||||||
|
|
||||||
|
tuple_three::<Tuple>();
|
||||||
|
|
||||||
|
tuple_four::<Tuple>();
|
||||||
|
//~^ ERROR E0277
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,66 @@
|
|||||||
|
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
// revisions: func object clause
|
||||||
|
|
||||||
|
#![allow(dead_code)]
|
||||||
|
#![feature(rustc_attrs)]
|
||||||
|
#![feature(unboxed_closures)]
|
||||||
|
#![deny(hr_lifetime_in_assoc_type)]
|
||||||
|
|
||||||
|
trait Foo<'a> {
|
||||||
|
type Item;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Foo<'a> for() {
|
||||||
|
type Item = ();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that appearing in a projection input in the argument is not enough:
|
||||||
|
#[cfg(func)]
|
||||||
|
fn func1(_: for<'a> fn(<() as Foo<'a>>::Item) -> &'a i32) {
|
||||||
|
//[func]~^ ERROR return type references lifetime `'a`
|
||||||
|
//[func]~| WARNING previously accepted
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that appearing in a projection input in the return still
|
||||||
|
// causes an error:
|
||||||
|
#[cfg(func)]
|
||||||
|
fn func2(_: for<'a> fn() -> <() as Foo<'a>>::Item) {
|
||||||
|
//[func]~^ ERROR return type references lifetime `'a`
|
||||||
|
//[func]~| WARNING previously accepted
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(object)]
|
||||||
|
fn object1(_: Box<for<'a> Fn(<() as Foo<'a>>::Item) -> &'a i32>) {
|
||||||
|
//[object]~^ ERROR `Output` references lifetime `'a`
|
||||||
|
//[object]~| WARNING previously accepted
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(object)]
|
||||||
|
fn object2(_: Box<for<'a> Fn() -> <() as Foo<'a>>::Item>) {
|
||||||
|
//[object]~^ ERROR `Output` references lifetime `'a`
|
||||||
|
//[object]~| WARNING previously accepted
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(clause)]
|
||||||
|
fn clause1<T>() where T: for<'a> Fn(<() as Foo<'a>>::Item) -> &'a i32 {
|
||||||
|
//[clause]~^ ERROR `Output` references lifetime `'a`
|
||||||
|
//[clause]~| WARNING previously accepted
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(clause)]
|
||||||
|
fn clause2<T>() where T: for<'a> Fn() -> <() as Foo<'a>>::Item {
|
||||||
|
//[clause]~^ ERROR `Output` references lifetime `'a`
|
||||||
|
//[clause]~| WARNING previously accepted
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rustc_error]
|
||||||
|
fn main() { } //[ok]~ ERROR compilation successful
|
@ -0,0 +1,90 @@
|
|||||||
|
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
// revisions: angle paren ok elision
|
||||||
|
|
||||||
|
#![allow(dead_code)]
|
||||||
|
#![feature(rustc_attrs)]
|
||||||
|
#![feature(unboxed_closures)]
|
||||||
|
#![deny(hr_lifetime_in_assoc_type)]
|
||||||
|
|
||||||
|
trait Foo {
|
||||||
|
type Item;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(angle)]
|
||||||
|
fn angle<T: for<'a> Foo<Item=&'a i32>>() {
|
||||||
|
//[angle]~^ ERROR binding for associated type `Item` references lifetime `'a`
|
||||||
|
//[angle]~| WARNING previously accepted
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(angle)]
|
||||||
|
fn angle1<T>() where T: for<'a> Foo<Item=&'a i32> {
|
||||||
|
//[angle]~^ ERROR binding for associated type `Item` references lifetime `'a`
|
||||||
|
//[angle]~| WARNING previously accepted
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(angle)]
|
||||||
|
fn angle2<T>() where for<'a> T: Foo<Item=&'a i32> {
|
||||||
|
//[angle]~^ ERROR binding for associated type `Item` references lifetime `'a`
|
||||||
|
//[angle]~| WARNING previously accepted
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(angle)]
|
||||||
|
fn angle3(_: &for<'a> Foo<Item=&'a i32>) {
|
||||||
|
//[angle]~^ ERROR binding for associated type `Item` references lifetime `'a`
|
||||||
|
//[angle]~| WARNING previously accepted
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(paren)]
|
||||||
|
fn paren<T: for<'a> Fn() -> &'a i32>() {
|
||||||
|
//[paren]~^ ERROR binding for associated type `Output` references lifetime `'a`
|
||||||
|
//[paren]~| WARNING previously accepted
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(paren)]
|
||||||
|
fn paren1<T>() where T: for<'a> Fn() -> &'a i32 {
|
||||||
|
//[paren]~^ ERROR binding for associated type `Output` references lifetime `'a`
|
||||||
|
//[paren]~| WARNING previously accepted
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(paren)]
|
||||||
|
fn paren2<T>() where for<'a> T: Fn() -> &'a i32 {
|
||||||
|
//[paren]~^ ERROR binding for associated type `Output` references lifetime `'a`
|
||||||
|
//[paren]~| WARNING previously accepted
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(paren)]
|
||||||
|
fn paren3(_: &for<'a> Fn() -> &'a i32) {
|
||||||
|
//[paren]~^ ERROR binding for associated type `Output` references lifetime `'a`
|
||||||
|
//[paren]~| WARNING previously accepted
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(elision)]
|
||||||
|
fn elision<T: Fn() -> &i32>() {
|
||||||
|
//[elision]~^ ERROR E0106
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Parameterized<'a> { x: &'a str }
|
||||||
|
|
||||||
|
#[cfg(ok)]
|
||||||
|
fn ok1<T: for<'a> Fn(&Parameterized<'a>) -> &'a i32>() {
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(ok)]
|
||||||
|
fn ok2<T: for<'a,'b> Fn<(&'b Parameterized<'a>,), Output=&'a i32>>() {
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(ok)]
|
||||||
|
fn ok3<T>() where for<'a> Parameterized<'a>: Foo<Item=&'a i32> {
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rustc_error]
|
||||||
|
fn main() { } //[ok]~ ERROR compilation successful
|
@ -0,0 +1,64 @@
|
|||||||
|
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
// revisions: sig local structure ok elision
|
||||||
|
|
||||||
|
#![allow(dead_code)]
|
||||||
|
#![feature(rustc_attrs)]
|
||||||
|
#![feature(unboxed_closures)]
|
||||||
|
#![deny(hr_lifetime_in_assoc_type)]
|
||||||
|
|
||||||
|
trait Foo {
|
||||||
|
type Item;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(sig)]
|
||||||
|
fn sig1(_: for<'a> fn() -> &'a i32) {
|
||||||
|
//[sig]~^ ERROR return type references lifetime `'a`
|
||||||
|
//[sig]~| WARNING previously accepted
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(sig)]
|
||||||
|
fn sig2(_: for<'a, 'b> fn(&'b i32) -> &'a i32) {
|
||||||
|
//[sig]~^ ERROR return type references lifetime `'a`
|
||||||
|
//[sig]~| WARNING previously accepted
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(local)]
|
||||||
|
fn local1() {
|
||||||
|
let _: for<'a> fn() -> &'a i32 = loop { };
|
||||||
|
//[local]~^ ERROR return type references lifetime `'a`
|
||||||
|
//[local]~| WARNING previously accepted
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(structure)]
|
||||||
|
struct Struct1 {
|
||||||
|
x: for<'a> fn() -> &'a i32
|
||||||
|
//[structure]~^ ERROR return type references lifetime `'a`
|
||||||
|
//[structure]~| WARNING previously accepted
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(elision)]
|
||||||
|
fn elision(_: fn() -> &i32) {
|
||||||
|
//[elision]~^ ERROR E0106
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Parameterized<'a> { x: &'a str }
|
||||||
|
|
||||||
|
#[cfg(ok)]
|
||||||
|
fn ok1(_: &for<'a> Fn(&Parameterized<'a>) -> &'a i32) {
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(ok)]
|
||||||
|
fn ok2(_: &for<'a,'b> Fn<(&'b Parameterized<'a>,), Output=&'a i32>) {
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rustc_error]
|
||||||
|
fn main() { } //[ok]~ ERROR compilation successful
|
Loading…
Reference in New Issue
Block a user