Skip to content

Commit 7333c4a

Browse files
authored
Auto merge of #35143 - arielb1:rfc447-regions, r=eddyb
typeck: use a TypeVisitor in ctp Use a TypeVisitor in ctp instead of `ty::walk` This fixes a few cases where a region could be projected out of a trait while not being constrained by the type parameters, violating rust-lang/rfcs#447 and breaking soundness. As such, this is a [breaking-change]. Fixes #35139 r? @eddyb
2 parents 2b87f03 + 0a128f3 commit 7333c4a

File tree

3 files changed

+83
-71
lines changed

3 files changed

+83
-71
lines changed

Diff for: src/librustc_typeck/collect.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -2237,9 +2237,9 @@ fn enforce_impl_params_are_constrained<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
22372237
// reachable from there, to start (if this is an inherent impl,
22382238
// then just examine the self type).
22392239
let mut input_parameters: HashSet<_> =
2240-
ctp::parameters_for_type(impl_scheme.ty, false).into_iter().collect();
2240+
ctp::parameters_for(&impl_scheme.ty, false).into_iter().collect();
22412241
if let Some(ref trait_ref) = impl_trait_ref {
2242-
input_parameters.extend(ctp::parameters_for_trait_ref(trait_ref, false));
2242+
input_parameters.extend(ctp::parameters_for(trait_ref, false));
22432243
}
22442244

22452245
ctp::setup_constraining_predicates(impl_predicates.predicates.get_mut_slice(TypeSpace),
@@ -2267,9 +2267,9 @@ fn enforce_impl_lifetimes_are_constrained<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
22672267
let impl_trait_ref = ccx.tcx.impl_trait_ref(impl_def_id);
22682268

22692269
let mut input_parameters: HashSet<_> =
2270-
ctp::parameters_for_type(impl_scheme.ty, false).into_iter().collect();
2270+
ctp::parameters_for(&impl_scheme.ty, false).into_iter().collect();
22712271
if let Some(ref trait_ref) = impl_trait_ref {
2272-
input_parameters.extend(ctp::parameters_for_trait_ref(trait_ref, false));
2272+
input_parameters.extend(ctp::parameters_for(trait_ref, false));
22732273
}
22742274
ctp::identify_constrained_type_params(
22752275
&impl_predicates.predicates.as_slice(), impl_trait_ref, &mut input_parameters);
@@ -2280,7 +2280,7 @@ fn enforce_impl_lifetimes_are_constrained<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
22802280
ty::TypeTraitItem(ref assoc_ty) => assoc_ty.ty,
22812281
ty::ConstTraitItem(..) | ty::MethodTraitItem(..) => None
22822282
})
2283-
.flat_map(|ty| ctp::parameters_for_type(ty, true))
2283+
.flat_map(|ty| ctp::parameters_for(&ty, true))
22842284
.filter_map(|p| match p {
22852285
ctp::Parameter::Type(_) => None,
22862286
ctp::Parameter::Region(r) => Some(r),

Diff for: src/librustc_typeck/constrained_type_params.rs

+42-66
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
use rustc::ty::{self, subst, Ty};
12-
11+
use rustc::ty::{self, Ty};
12+
use rustc::ty::fold::{TypeFoldable, TypeVisitor};
1313
use std::collections::HashSet;
1414

1515
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
@@ -19,77 +19,53 @@ pub enum Parameter {
1919
}
2020

2121
/// If `include_projections` is false, returns the list of parameters that are
22-
/// constrained by the type `ty` - i.e. the value of each parameter in the list is
23-
/// uniquely determined by `ty` (see RFC 447). If it is true, return the list
22+
/// constrained by `t` - i.e. the value of each parameter in the list is
23+
/// uniquely determined by `t` (see RFC 447). If it is true, return the list
2424
/// of parameters whose values are needed in order to constrain `ty` - these
2525
/// differ, with the latter being a superset, in the presence of projections.
26-
pub fn parameters_for_type<'tcx>(ty: Ty<'tcx>,
27-
include_projections: bool) -> Vec<Parameter> {
28-
let mut result = vec![];
29-
ty.maybe_walk(|t| match t.sty {
30-
ty::TyProjection(..) if !include_projections => {
26+
pub fn parameters_for<'tcx, T>(t: &T,
27+
include_nonconstraining: bool)
28+
-> Vec<Parameter>
29+
where T: TypeFoldable<'tcx>
30+
{
3131

32-
false // projections are not injective.
33-
}
34-
_ => {
35-
result.append(&mut parameters_for_type_shallow(t));
36-
// non-projection type constructors are injective.
37-
true
38-
}
39-
});
40-
result
32+
let mut collector = ParameterCollector {
33+
parameters: vec![],
34+
include_nonconstraining: include_nonconstraining
35+
};
36+
t.visit_with(&mut collector);
37+
collector.parameters
4138
}
4239

43-
pub fn parameters_for_trait_ref<'tcx>(trait_ref: &ty::TraitRef<'tcx>,
44-
include_projections: bool) -> Vec<Parameter> {
45-
let mut region_parameters =
46-
parameters_for_regions_in_substs(&trait_ref.substs);
47-
48-
let type_parameters =
49-
trait_ref.substs
50-
.types
51-
.iter()
52-
.flat_map(|ty| parameters_for_type(ty, include_projections));
53-
54-
region_parameters.extend(type_parameters);
55-
56-
region_parameters
40+
struct ParameterCollector {
41+
parameters: Vec<Parameter>,
42+
include_nonconstraining: bool
5743
}
5844

59-
fn parameters_for_type_shallow<'tcx>(ty: Ty<'tcx>) -> Vec<Parameter> {
60-
match ty.sty {
61-
ty::TyParam(ref d) =>
62-
vec![Parameter::Type(d.clone())],
63-
ty::TyRef(region, _) =>
64-
parameters_for_region(region).into_iter().collect(),
65-
ty::TyStruct(_, substs) |
66-
ty::TyEnum(_, substs) =>
67-
parameters_for_regions_in_substs(substs),
68-
ty::TyTrait(ref data) =>
69-
parameters_for_regions_in_substs(&data.principal.skip_binder().substs),
70-
ty::TyProjection(ref pi) =>
71-
parameters_for_regions_in_substs(&pi.trait_ref.substs),
72-
ty::TyBool | ty::TyChar | ty::TyInt(..) | ty::TyUint(..) |
73-
ty::TyFloat(..) | ty::TyBox(..) | ty::TyStr |
74-
ty::TyArray(..) | ty::TySlice(..) |
75-
ty::TyFnDef(..) | ty::TyFnPtr(_) |
76-
ty::TyTuple(..) | ty::TyRawPtr(..) |
77-
ty::TyInfer(..) | ty::TyClosure(..) | ty::TyError =>
78-
vec![]
79-
}
80-
}
45+
impl<'tcx> TypeVisitor<'tcx> for ParameterCollector {
46+
fn visit_ty(&mut self, t: Ty<'tcx>) -> bool {
47+
match t.sty {
48+
ty::TyProjection(..) if !self.include_nonconstraining => {
49+
// projections are not injective
50+
return false;
51+
}
52+
ty::TyParam(ref d) => {
53+
self.parameters.push(Parameter::Type(d.clone()));
54+
}
55+
_ => {}
56+
}
8157

82-
fn parameters_for_regions_in_substs(substs: &subst::Substs) -> Vec<Parameter> {
83-
substs.regions
84-
.iter()
85-
.filter_map(|r| parameters_for_region(r))
86-
.collect()
87-
}
58+
t.super_visit_with(self)
59+
}
8860

89-
fn parameters_for_region(region: &ty::Region) -> Option<Parameter> {
90-
match *region {
91-
ty::ReEarlyBound(data) => Some(Parameter::Region(data)),
92-
_ => None,
61+
fn visit_region(&mut self, r: ty::Region) -> bool {
62+
match r {
63+
ty::ReEarlyBound(data) => {
64+
self.parameters.push(Parameter::Region(data));
65+
}
66+
_ => {}
67+
}
68+
false
9369
}
9470
}
9571

@@ -191,12 +167,12 @@ pub fn setup_constraining_predicates<'tcx>(predicates: &mut [ty::Predicate<'tcx>
191167
// Then the projection only applies if `T` is known, but it still
192168
// does not determine `U`.
193169

194-
let inputs = parameters_for_trait_ref(&projection.projection_ty.trait_ref, true);
170+
let inputs = parameters_for(&projection.projection_ty.trait_ref, true);
195171
let relies_only_on_inputs = inputs.iter().all(|p| input_parameters.contains(&p));
196172
if !relies_only_on_inputs {
197173
continue;
198174
}
199-
input_parameters.extend(parameters_for_type(projection.ty, false));
175+
input_parameters.extend(parameters_for(&projection.ty, false));
200176
} else {
201177
continue;
202178
}

Diff for: src/test/compile-fail/issue-35139.rs

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
use std::fmt;
12+
13+
pub trait MethodType {
14+
type GetProp: ?Sized;
15+
}
16+
17+
pub struct MTFn;
18+
19+
impl<'a> MethodType for MTFn { //~ ERROR E0207
20+
type GetProp = fmt::Debug + 'a;
21+
}
22+
23+
fn bad(a: Box<<MTFn as MethodType>::GetProp>) -> Box<fmt::Debug+'static> {
24+
a
25+
}
26+
27+
fn dangling(a: &str) -> Box<fmt::Debug> {
28+
bad(Box::new(a))
29+
}
30+
31+
fn main() {
32+
let mut s = "hello".to_string();
33+
let x = dangling(&s);
34+
s = String::new();
35+
println!("{:?}", x);
36+
}

0 commit comments

Comments
 (0)