Skip to content

Commit d05a49c

Browse files
committed
warn if bindings/return-types 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.
1 parent 4bfef5c commit d05a49c

File tree

8 files changed

+225
-28
lines changed

8 files changed

+225
-28
lines changed

src/librustc/lint/builtin.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,13 @@ declare_lint! {
167167
"transmute from function item type to pointer-sized type erroneously allowed"
168168
}
169169

170+
declare_lint! {
171+
pub HR_LIFETIME_IN_ASSOC_TYPE,
172+
Warn,
173+
"binding for associated type references higher-ranked lifetime \
174+
that does not appear in the trait input types"
175+
}
176+
170177
declare_lint! {
171178
pub OVERLAPPING_INHERENT_IMPLS,
172179
Warn,
@@ -220,7 +227,8 @@ impl LintPass for HardwiredLints {
220227
TRANSMUTE_FROM_FN_ITEM_TYPES,
221228
OVERLAPPING_INHERENT_IMPLS,
222229
RENAMED_AND_REMOVED_LINTS,
223-
SUPER_OR_SELF_IN_GLOBAL_PATH
230+
SUPER_OR_SELF_IN_GLOBAL_PATH,
231+
HR_LIFETIME_IN_ASSOC_TYPE
224232
)
225233
}
226234
}

src/librustc_lint/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,10 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
190190
id: LintId::of(ILLEGAL_STRUCT_OR_ENUM_CONSTANT_PATTERN),
191191
reference: "RFC 1445 <https://github.com/rust-lang/rfcs/pull/1445>",
192192
},
193+
FutureIncompatibleInfo {
194+
id: LintId::of(HR_LIFETIME_IN_ASSOC_TYPE),
195+
reference: "issue #32330 <https://github.com/rust-lang/rust/issues/32330>",
196+
},
193197
]);
194198

195199
// We have one lint pass defined specially

src/librustc_typeck/astconv.rs

Lines changed: 73 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -64,20 +64,18 @@ use require_c_abi_if_variadic;
6464
use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope,
6565
ObjectLifetimeDefaultRscope, ShiftedRscope, BindingRscope,
6666
ElisionFailureInfo, ElidedLifetime};
67-
use util::common::{ErrorReported, FN_OUTPUT_NAME};
68-
use util::nodemap::FnvHashSet;
69-
67+
use rustc::lint;
68+
use rustc_back::slice;
7069
use rustc_const_math::ConstInt;
71-
70+
use rustc_front::print::pprust;
71+
use rustc_front::hir;
7272
use syntax::{abi, ast};
7373
use syntax::codemap::{Span, Pos};
7474
use syntax::errors::DiagnosticBuilder;
7575
use syntax::feature_gate::{GateIssue, emit_feature_err};
7676
use syntax::parse::token;
77-
78-
use rustc::hir::print as pprust;
79-
use rustc::hir;
80-
use rustc_back::slice;
77+
use util::common::{ErrorReported, FN_OUTPUT_NAME};
78+
use util::nodemap::FnvHashSet;
8179

8280
pub trait AstConv<'tcx> {
8381
fn tcx<'a>(&'a self) -> &'a TyCtxt<'tcx>;
@@ -691,6 +689,7 @@ pub fn instantiate_poly_trait_ref<'tcx>(
691689
PathParamMode::Explicit,
692690
trait_def_id,
693691
self_ty,
692+
trait_ref.ref_id,
694693
trait_ref.path.segments.last().unwrap(),
695694
poly_projections)
696695
}
@@ -738,6 +737,7 @@ fn object_path_to_poly_trait_ref<'a,'tcx>(
738737
span: Span,
739738
param_mode: PathParamMode,
740739
trait_def_id: DefId,
740+
trait_path_ref_id: ast::NodeId,
741741
trait_segment: &hir::PathSegment,
742742
mut projections: &mut Vec<ty::PolyProjectionPredicate<'tcx>>)
743743
-> ty::PolyTraitRef<'tcx>
@@ -748,6 +748,7 @@ fn object_path_to_poly_trait_ref<'a,'tcx>(
748748
param_mode,
749749
trait_def_id,
750750
None,
751+
trait_path_ref_id,
751752
trait_segment,
752753
projections)
753754
}
@@ -759,6 +760,7 @@ fn ast_path_to_poly_trait_ref<'a,'tcx>(
759760
param_mode: PathParamMode,
760761
trait_def_id: DefId,
761762
self_ty: Option<Ty<'tcx>>,
763+
path_id: ast::NodeId,
762764
trait_segment: &hir::PathSegment,
763765
poly_projections: &mut Vec<ty::PolyProjectionPredicate<'tcx>>)
764766
-> ty::PolyTraitRef<'tcx>
@@ -789,6 +791,7 @@ fn ast_path_to_poly_trait_ref<'a,'tcx>(
789791
// specify type to assert that error was already reported in Err case:
790792
let predicate: Result<_, ErrorReported> =
791793
ast_type_binding_to_poly_projection_predicate(this,
794+
path_id,
792795
poly_trait_ref.clone(),
793796
self_ty,
794797
binding);
@@ -885,6 +888,7 @@ fn create_substs_for_ast_trait_ref<'a,'tcx>(this: &AstConv<'tcx>,
885888

886889
fn ast_type_binding_to_poly_projection_predicate<'tcx>(
887890
this: &AstConv<'tcx>,
891+
path_id: ast::NodeId,
888892
mut trait_ref: ty::PolyTraitRef<'tcx>,
889893
self_ty: Option<Ty<'tcx>>,
890894
binding: &ConvertedBinding<'tcx>)
@@ -933,11 +937,13 @@ fn ast_type_binding_to_poly_projection_predicate<'tcx>(
933937
br));
934938
}
935939
};
936-
this.tcx().sess.span_err(
940+
this.tcx().sess.add_lint(
941+
lint::builtin::HR_LIFETIME_IN_ASSOC_TYPE,
942+
path_id,
937943
binding.span,
938-
&format!("binding for associated type `{}` references lifetime `{}`, \
939-
which does not appear in the trait input types",
940-
binding.item_name, br_name));
944+
format!("binding for associated type `{}` references lifetime `{}`, \
945+
which does not appear in the trait input types",
946+
binding.item_name, br_name));
941947
}
942948

943949
// Simple case: X is defined in the current trait.
@@ -1070,6 +1076,7 @@ fn ast_ty_to_trait_ref<'tcx>(this: &AstConv<'tcx>,
10701076
path.span,
10711077
PathParamMode::Explicit,
10721078
trait_def_id,
1079+
ty.id,
10731080
path.segments.last().unwrap(),
10741081
&mut projection_bounds);
10751082
Ok((trait_ref, projection_bounds))
@@ -1480,6 +1487,7 @@ fn base_def_to_ty<'tcx>(this: &AstConv<'tcx>,
14801487
param_mode: PathParamMode,
14811488
def: &Def,
14821489
opt_self_ty: Option<Ty<'tcx>>,
1490+
base_path_ref_id: ast::NodeId,
14831491
base_segments: &[hir::PathSegment])
14841492
-> Ty<'tcx> {
14851493
let tcx = this.tcx();
@@ -1495,6 +1503,7 @@ fn base_def_to_ty<'tcx>(this: &AstConv<'tcx>,
14951503
span,
14961504
param_mode,
14971505
trait_def_id,
1506+
base_path_ref_id,
14981507
base_segments.last().unwrap(),
14991508
&mut projection_bounds);
15001509

@@ -1584,6 +1593,7 @@ pub fn finish_resolving_def_to_ty<'tcx>(this: &AstConv<'tcx>,
15841593
param_mode: PathParamMode,
15851594
def: &Def,
15861595
opt_self_ty: Option<Ty<'tcx>>,
1596+
base_path_ref_id: ast::NodeId,
15871597
base_segments: &[hir::PathSegment],
15881598
assoc_segments: &[hir::PathSegment])
15891599
-> Ty<'tcx> {
@@ -1593,6 +1603,7 @@ pub fn finish_resolving_def_to_ty<'tcx>(this: &AstConv<'tcx>,
15931603
param_mode,
15941604
def,
15951605
opt_self_ty,
1606+
base_path_ref_id,
15961607
base_segments);
15971608
let mut def = *def;
15981609
// If any associated type segments remain, attempt to resolve them.
@@ -1672,7 +1683,50 @@ pub fn ast_ty_to_ty<'tcx>(this: &AstConv<'tcx>,
16721683
}
16731684
hir::TyBareFn(ref bf) => {
16741685
require_c_abi_if_variadic(tcx, &bf.decl, bf.abi, ast_ty.span);
1675-
tcx.mk_fn_ptr(ty_of_bare_fn(this, bf.unsafety, bf.abi, &bf.decl))
1686+
let bare_fn_ty = ty_of_bare_fn(this,
1687+
bf.unsafety,
1688+
bf.abi,
1689+
&bf.decl);
1690+
1691+
// Find any late-bound regions declared in return type that do
1692+
// not appear in the arguments. These are not wellformed.
1693+
//
1694+
// Example:
1695+
//
1696+
// for<'a> fn() -> &'a str <-- 'a is bad
1697+
// for<'a> fn(&'a String) -> &'a str <-- 'a is ok
1698+
//
1699+
// Note that we do this check **here** and not in
1700+
// `ty_of_bare_fn` because the latter is also used to make
1701+
// the types for fn items, and we do not want to issue a
1702+
// warning then. (Once we fix #32330, the regions we are
1703+
// checking for here would be considered early bound
1704+
// anyway.)
1705+
let inputs = bare_fn_ty.sig.inputs();
1706+
let late_bound_in_args = this.tcx().collect_late_bound_regions(&inputs);
1707+
let output = bare_fn_ty.sig.output();
1708+
let late_bound_in_ret = this.tcx().collect_late_bound_regions(&output);
1709+
for br in late_bound_in_ret.difference(&late_bound_in_args) {
1710+
let br_name = match *br {
1711+
ty::BrNamed(_, name) => name,
1712+
_ => {
1713+
this.tcx().sess.span_bug(
1714+
bf.decl.output.span(),
1715+
&format!("anonymous bound region {:?} in \
1716+
return but not args",
1717+
br));
1718+
}
1719+
};
1720+
this.tcx().sess.add_lint(
1721+
lint::builtin::HR_LIFETIME_IN_ASSOC_TYPE,
1722+
ast_ty.id,
1723+
bf.decl.output.span(),
1724+
format!("return type references lifetime `{}`, \
1725+
which does not appear in the argument types",
1726+
br_name));
1727+
}
1728+
1729+
tcx.mk_fn_ptr(bare_fn_ty)
16761730
}
16771731
hir::TyPolyTraitRef(ref bounds) => {
16781732
conv_ty_poly_trait_ref(this, rscope, ast_ty.span, bounds)
@@ -1700,6 +1754,7 @@ pub fn ast_ty_to_ty<'tcx>(this: &AstConv<'tcx>,
17001754
PathParamMode::Explicit,
17011755
&def,
17021756
opt_self_ty,
1757+
ast_ty.id,
17031758
&path.segments[..base_ty_end],
17041759
&path.segments[base_ty_end..]);
17051760

@@ -1795,8 +1850,11 @@ pub fn ty_of_method<'tcx>(this: &AstConv<'tcx>,
17951850
(bare_fn_ty, optional_explicit_self_category.unwrap())
17961851
}
17971852

1798-
pub fn ty_of_bare_fn<'tcx>(this: &AstConv<'tcx>, unsafety: hir::Unsafety, abi: abi::Abi,
1799-
decl: &hir::FnDecl) -> ty::BareFnTy<'tcx> {
1853+
pub fn ty_of_bare_fn<'tcx>(this: &AstConv<'tcx>,
1854+
unsafety: hir::Unsafety,
1855+
abi: abi::Abi,
1856+
decl: &hir::FnDecl)
1857+
-> ty::BareFnTy<'tcx> {
18001858
let (bare_fn_ty, _) = ty_of_method_or_bare_fn(this, unsafety, abi, None, decl);
18011859
bare_fn_ty
18021860
}

src/librustc_typeck/check/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3769,6 +3769,7 @@ pub fn resolve_ty_and_def_ufcs<'a, 'b, 'tcx>(fcx: &FnCtxt<'b, 'tcx>,
37693769
PathParamMode::Optional,
37703770
&mut def,
37713771
opt_self_ty,
3772+
node_id,
37723773
&ty_segments[..base_ty_end],
37733774
&ty_segments[base_ty_end..]);
37743775
let item_segment = path.segments.last().unwrap();

src/librustc_typeck/collect.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -547,7 +547,8 @@ fn convert_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
547547

548548
let (fty, explicit_self_category) =
549549
astconv::ty_of_method(&ccx.icx(&(rcvr_ty_predicates, &sig.generics)),
550-
sig, untransformed_rcvr_ty);
550+
sig,
551+
untransformed_rcvr_ty);
551552

552553
let def_id = ccx.tcx.map.local_def_id(id);
553554
let substs = ccx.tcx.mk_substs(mk_item_substs(ccx, &ty_generics));
@@ -1453,7 +1454,10 @@ fn compute_type_scheme_of_item<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
14531454
}
14541455
hir::ItemFn(ref decl, unsafety, _, abi, ref generics, _) => {
14551456
let ty_generics = ty_generics_for_fn(ccx, generics, &ty::Generics::empty());
1456-
let tofd = astconv::ty_of_bare_fn(&ccx.icx(generics), unsafety, abi, &decl);
1457+
let tofd = astconv::ty_of_bare_fn(&ccx.icx(generics),
1458+
unsafety,
1459+
abi,
1460+
&decl);
14571461
let def_id = ccx.tcx.map.local_def_id(it.id);
14581462
let substs = tcx.mk_substs(mk_item_substs(ccx, &ty_generics));
14591463
let ty = tcx.mk_fn_def(def_id, substs, tofd);

src/test/compile-fail/associated-types-eq-hr.rs

Lines changed: 44 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,17 @@ impl<'a> TheTrait<&'a isize> for UintStruct {
4040
}
4141
}
4242

43+
struct Tuple {
44+
}
45+
46+
impl<'a> TheTrait<(&'a isize, &'a isize)> for Tuple {
47+
type A = &'a isize;
48+
49+
fn get(&self, t: (&'a isize, &'a isize)) -> &'a isize {
50+
t.0
51+
}
52+
}
53+
4354
fn foo<T>()
4455
where T : for<'x> TheTrait<&'x isize, A = &'x isize>
4556
{
@@ -52,10 +63,28 @@ fn bar<T>()
5263
// ok for UintStruct, but not IntStruct
5364
}
5465

55-
fn baz<T>()
56-
where T : for<'x,'y> TheTrait<&'x isize, A = &'y isize>
66+
fn tuple_one<T>()
67+
where T : for<'x,'y> TheTrait<(&'x isize, &'y isize), A = &'x isize>
68+
{
69+
// not ok for tuple, two lifetimes and we pick first
70+
}
71+
72+
fn tuple_two<T>()
73+
where T : for<'x,'y> TheTrait<(&'x isize, &'y isize), A = &'y isize>
5774
{
58-
// not ok for either struct, due to the use of two lifetimes
75+
// not ok for tuple, two lifetimes and we pick second
76+
}
77+
78+
fn tuple_three<T>()
79+
where T : for<'x> TheTrait<(&'x isize, &'x isize), A = &'x isize>
80+
{
81+
// ok for tuple
82+
}
83+
84+
fn tuple_four<T>()
85+
where T : for<'x,'y> TheTrait<(&'x isize, &'y isize)>
86+
{
87+
// not ok for tuple, two lifetimes, and lifetime matching is invariant
5988
}
6089

6190
pub fn main() {
@@ -65,6 +94,16 @@ pub fn main() {
6594
bar::<IntStruct>(); //~ ERROR type mismatch
6695
bar::<UintStruct>();
6796

68-
baz::<IntStruct>(); //~ ERROR type mismatch
69-
baz::<UintStruct>(); //~ ERROR type mismatch
97+
tuple_one::<Tuple>();
98+
//~^ ERROR E0277
99+
//~| ERROR type mismatch
100+
101+
tuple_two::<Tuple>();
102+
//~^ ERROR E0277
103+
//~| ERROR type mismatch
104+
105+
tuple_three::<Tuple>();
106+
107+
tuple_four::<Tuple>();
108+
//~^ ERROR E0277
70109
}

0 commit comments

Comments
 (0)