Skip to content

Commit dcbe887

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 5115341 commit dcbe887

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,
@@ -213,7 +220,8 @@ impl LintPass for HardwiredLints {
213220
RAW_POINTER_DERIVE,
214221
TRANSMUTE_FROM_FN_ITEM_TYPES,
215222
OVERLAPPING_INHERENT_IMPLS,
216-
RENAMED_AND_REMOVED_LINTS
223+
RENAMED_AND_REMOVED_LINTS,
224+
HR_LIFETIME_IN_ASSOC_TYPE
217225
)
218226
}
219227
}

src/librustc_lint/lib.rs

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

193197
// 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
@@ -63,20 +63,18 @@ use require_c_abi_if_variadic;
6363
use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope,
6464
ObjectLifetimeDefaultRscope, ShiftedRscope, BindingRscope,
6565
ElisionFailureInfo, ElidedLifetime};
66-
use util::common::{ErrorReported, FN_OUTPUT_NAME};
67-
use util::nodemap::FnvHashSet;
68-
66+
use rustc::lint;
67+
use rustc_back::slice;
6968
use rustc_const_math::ConstInt;
70-
69+
use rustc_front::print::pprust;
70+
use rustc_front::hir;
7171
use syntax::{abi, ast};
7272
use syntax::codemap::{Span, Pos};
7373
use syntax::errors::DiagnosticBuilder;
7474
use syntax::feature_gate::{GateIssue, emit_feature_err};
7575
use syntax::parse::token;
76-
77-
use rustc_front::print::pprust;
78-
use rustc_front::hir;
79-
use rustc_back::slice;
76+
use util::common::{ErrorReported, FN_OUTPUT_NAME};
77+
use util::nodemap::FnvHashSet;
8078

8179
pub trait AstConv<'tcx> {
8280
fn tcx<'a>(&'a self) -> &'a TyCtxt<'tcx>;
@@ -690,6 +688,7 @@ pub fn instantiate_poly_trait_ref<'tcx>(
690688
PathParamMode::Explicit,
691689
trait_def_id,
692690
self_ty,
691+
trait_ref.ref_id,
693692
trait_ref.path.segments.last().unwrap(),
694693
poly_projections)
695694
}
@@ -737,6 +736,7 @@ fn object_path_to_poly_trait_ref<'a,'tcx>(
737736
span: Span,
738737
param_mode: PathParamMode,
739738
trait_def_id: DefId,
739+
trait_path_ref_id: ast::NodeId,
740740
trait_segment: &hir::PathSegment,
741741
mut projections: &mut Vec<ty::PolyProjectionPredicate<'tcx>>)
742742
-> ty::PolyTraitRef<'tcx>
@@ -747,6 +747,7 @@ fn object_path_to_poly_trait_ref<'a,'tcx>(
747747
param_mode,
748748
trait_def_id,
749749
None,
750+
trait_path_ref_id,
750751
trait_segment,
751752
projections)
752753
}
@@ -758,6 +759,7 @@ fn ast_path_to_poly_trait_ref<'a,'tcx>(
758759
param_mode: PathParamMode,
759760
trait_def_id: DefId,
760761
self_ty: Option<Ty<'tcx>>,
762+
path_id: ast::NodeId,
761763
trait_segment: &hir::PathSegment,
762764
poly_projections: &mut Vec<ty::PolyProjectionPredicate<'tcx>>)
763765
-> ty::PolyTraitRef<'tcx>
@@ -788,6 +790,7 @@ fn ast_path_to_poly_trait_ref<'a,'tcx>(
788790
// specify type to assert that error was already reported in Err case:
789791
let predicate: Result<_, ErrorReported> =
790792
ast_type_binding_to_poly_projection_predicate(this,
793+
path_id,
791794
poly_trait_ref.clone(),
792795
self_ty,
793796
binding);
@@ -884,6 +887,7 @@ fn create_substs_for_ast_trait_ref<'a,'tcx>(this: &AstConv<'tcx>,
884887

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

942948
// Simple case: X is defined in the current trait.
@@ -1069,6 +1075,7 @@ fn ast_ty_to_trait_ref<'tcx>(this: &AstConv<'tcx>,
10691075
path.span,
10701076
PathParamMode::Explicit,
10711077
trait_def_id,
1078+
ty.id,
10721079
path.segments.last().unwrap(),
10731080
&mut projection_bounds);
10741081
Ok((trait_ref, projection_bounds))
@@ -1479,6 +1486,7 @@ fn base_def_to_ty<'tcx>(this: &AstConv<'tcx>,
14791486
param_mode: PathParamMode,
14801487
def: &Def,
14811488
opt_self_ty: Option<Ty<'tcx>>,
1489+
base_path_ref_id: ast::NodeId,
14821490
base_segments: &[hir::PathSegment])
14831491
-> Ty<'tcx> {
14841492
let tcx = this.tcx();
@@ -1494,6 +1502,7 @@ fn base_def_to_ty<'tcx>(this: &AstConv<'tcx>,
14941502
span,
14951503
param_mode,
14961504
trait_def_id,
1505+
base_path_ref_id,
14971506
base_segments.last().unwrap(),
14981507
&mut projection_bounds);
14991508

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

@@ -1791,8 +1846,11 @@ pub fn ty_of_method<'tcx>(this: &AstConv<'tcx>,
17911846
(bare_fn_ty, optional_explicit_self_category.unwrap())
17921847
}
17931848

1794-
pub fn ty_of_bare_fn<'tcx>(this: &AstConv<'tcx>, unsafety: hir::Unsafety, abi: abi::Abi,
1795-
decl: &hir::FnDecl) -> ty::BareFnTy<'tcx> {
1849+
pub fn ty_of_bare_fn<'tcx>(this: &AstConv<'tcx>,
1850+
unsafety: hir::Unsafety,
1851+
abi: abi::Abi,
1852+
decl: &hir::FnDecl)
1853+
-> ty::BareFnTy<'tcx> {
17961854
let (bare_fn_ty, _) = ty_of_method_or_bare_fn(this, unsafety, abi, None, decl);
17971855
bare_fn_ty
17981856
}

src/librustc_typeck/check/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3749,6 +3749,7 @@ pub fn resolve_ty_and_def_ufcs<'a, 'b, 'tcx>(fcx: &FnCtxt<'b, 'tcx>,
37493749
PathParamMode::Optional,
37503750
&mut def,
37513751
opt_self_ty,
3752+
node_id,
37523753
&ty_segments[..base_ty_end],
37533754
&ty_segments[base_ty_end..]);
37543755
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
@@ -545,7 +545,8 @@ fn convert_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
545545

546546
let (fty, explicit_self_category) =
547547
astconv::ty_of_method(&ccx.icx(&(rcvr_ty_predicates, &sig.generics)),
548-
sig, untransformed_rcvr_ty);
548+
sig,
549+
untransformed_rcvr_ty);
549550

550551
let def_id = ccx.tcx.map.local_def_id(id);
551552
let substs = ccx.tcx.mk_substs(mk_item_substs(ccx, &ty_generics));
@@ -1457,7 +1458,10 @@ fn compute_type_scheme_of_item<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
14571458
}
14581459
hir::ItemFn(ref decl, unsafety, _, abi, ref generics, _) => {
14591460
let ty_generics = ty_generics_for_fn(ccx, generics, &ty::Generics::empty());
1460-
let tofd = astconv::ty_of_bare_fn(&ccx.icx(generics), unsafety, abi, &decl);
1461+
let tofd = astconv::ty_of_bare_fn(&ccx.icx(generics),
1462+
unsafety,
1463+
abi,
1464+
&decl);
14611465
let def_id = ccx.tcx.map.local_def_id(it.id);
14621466
let substs = tcx.mk_substs(mk_item_substs(ccx, &ty_generics));
14631467
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)