Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
int
Rust
提交
fc3c90cf
R
Rust
项目概览
int
/
Rust
大约 1 年 前同步成功
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
R
Rust
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
fc3c90cf
编写于
3月 15, 2018
作者:
N
Niko Matsakis
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
report an error if we see an unexpected lifetime in impl Trait
But leave closure substs alone.
上级
a9cbfaa2
变更
5
显示空白变更内容
内联
并排
Showing
5 changed file
with
291 addition
and
34 deletion
+291
-34
src/librustc/diagnostics.rs
src/librustc/diagnostics.rs
+48
-0
src/librustc/infer/anon_types/mod.rs
src/librustc/infer/anon_types/mod.rs
+154
-34
src/test/ui/impl-trait/region-escape-via-bound-contravariant.rs
...st/ui/impl-trait/region-escape-via-bound-contravariant.rs
+35
-0
src/test/ui/impl-trait/region-escape-via-bound.rs
src/test/ui/impl-trait/region-escape-via-bound.rs
+34
-0
src/test/ui/impl-trait/region-escape-via-bound.stderr
src/test/ui/impl-trait/region-escape-via-bound.stderr
+20
-0
未找到文件。
src/librustc/diagnostics.rs
浏览文件 @
fc3c90cf
...
@@ -2074,6 +2074,54 @@ struct Foo {
...
@@ -2074,6 +2074,54 @@ struct Foo {
transparent wrapper around a float. This can make a difference for the ABI.
transparent wrapper around a float. This can make a difference for the ABI.
"##
,
"##
,
E0909
:
r##"
The `impl Trait` return type captures lifetime parameters that do not
appear within the `impl Trait` itself.
Erroneous code example:
```compile-fail,E0909
use std::cell::Cell;
trait Trait<'a> { }
impl Trait<'b> for Cell<&'a u32> { }
fn foo<'x, 'y>(x: Cell<&'x u32>) -> impl Trait<'y>
where 'x: 'y
{
x
}
```
Here, the function `foo` returns a value of type `Cell<&'x u32>`,
which references the lifetime `'x`. However, the return type is
declared as `impl Trait<'y>` -- this indicates that `foo` returns
"some type that implements `Trait<'y>`", but it also indicates that
the return type **only captures data referencing the lifetime `'y`**.
In this case, though, we are referencing data with lifetime `'x`, so
this function is in error.
To fix this, you must reference the lifetime `'x` from the return
type. For example, changing the return type to `impl Trait<'y> + 'x`
would work:
```
use std::cell::Cell;
trait Trait<'a> { }
impl Trait<'b> for Cell<&'a u32> { }
fn foo<'x, 'y>(x: Cell<&'x u32>) -> impl Trait<'y> + 'x
where 'x: 'y
{
x
}
```
"##
,
}
}
...
...
src/librustc/infer/anon_types/mod.rs
浏览文件 @
fc3c90cf
...
@@ -17,7 +17,7 @@
...
@@ -17,7 +17,7 @@
use
ty
::{
self
,
Ty
,
TyCtxt
};
use
ty
::{
self
,
Ty
,
TyCtxt
};
use
ty
::
fold
::{
BottomUpFolder
,
TypeFoldable
,
TypeFolder
};
use
ty
::
fold
::{
BottomUpFolder
,
TypeFoldable
,
TypeFolder
};
use
ty
::
outlives
::
Component
;
use
ty
::
outlives
::
Component
;
use
ty
::
subst
::{
Kind
,
UnpackedKind
,
Substs
};
use
ty
::
subst
::{
Kind
,
Substs
,
UnpackedKind
};
use
util
::
nodemap
::
DefIdMap
;
use
util
::
nodemap
::
DefIdMap
;
pub
type
AnonTypeMap
<
'tcx
>
=
DefIdMap
<
AnonTypeDecl
<
'tcx
>>
;
pub
type
AnonTypeMap
<
'tcx
>
=
DefIdMap
<
AnonTypeDecl
<
'tcx
>>
;
...
@@ -113,10 +113,7 @@ pub fn instantiate_anon_types<T: TypeFoldable<'tcx>>(
...
@@ -113,10 +113,7 @@ pub fn instantiate_anon_types<T: TypeFoldable<'tcx>>(
)
->
InferOk
<
'tcx
,
(
T
,
AnonTypeMap
<
'tcx
>
)
>
{
)
->
InferOk
<
'tcx
,
(
T
,
AnonTypeMap
<
'tcx
>
)
>
{
debug!
(
debug!
(
"instantiate_anon_types(value={:?}, parent_def_id={:?}, body_id={:?}, param_env={:?})"
,
"instantiate_anon_types(value={:?}, parent_def_id={:?}, body_id={:?}, param_env={:?})"
,
value
,
value
,
parent_def_id
,
body_id
,
param_env
,
parent_def_id
,
body_id
,
param_env
,
);
);
let
mut
instantiator
=
Instantiator
{
let
mut
instantiator
=
Instantiator
{
infcx
:
self
,
infcx
:
self
,
...
@@ -458,7 +455,14 @@ pub fn infer_anon_definition_from_instantiation(
...
@@ -458,7 +455,14 @@ pub fn infer_anon_definition_from_instantiation(
// Convert the type from the function into a type valid outside
// Convert the type from the function into a type valid outside
// the function, by replacing invalid regions with 'static,
// the function, by replacing invalid regions with 'static,
// after producing an error for each of them.
// after producing an error for each of them.
let
definition_ty
=
instantiated_ty
.fold_with
(
&
mut
ReverseMapper
{
tcx
:
self
.tcx
,
map
});
let
definition_ty
=
instantiated_ty
.fold_with
(
&
mut
ReverseMapper
::
new
(
self
.tcx
,
self
.is_tainted_by_errors
(),
def_id
,
map
,
instantiated_ty
,
));
debug!
(
debug!
(
"infer_anon_definition_from_instantiation: definition_ty={:?}"
,
"infer_anon_definition_from_instantiation: definition_ty={:?}"
,
definition_ty
definition_ty
...
@@ -475,7 +479,49 @@ pub fn infer_anon_definition_from_instantiation(
...
@@ -475,7 +479,49 @@ pub fn infer_anon_definition_from_instantiation(
struct
ReverseMapper
<
'cx
,
'gcx
:
'tcx
,
'tcx
:
'cx
>
{
struct
ReverseMapper
<
'cx
,
'gcx
:
'tcx
,
'tcx
:
'cx
>
{
tcx
:
TyCtxt
<
'cx
,
'gcx
,
'tcx
>
,
tcx
:
TyCtxt
<
'cx
,
'gcx
,
'tcx
>
,
map
:
FxHashMap
<
Kind
<
'tcx
>
,
Kind
<
'gcx
>>
/// If errors have already been reported in this fn, we suppress
/// our own errors because they are sometimes derivative.
tainted_by_errors
:
bool
,
anon_type_def_id
:
DefId
,
map
:
FxHashMap
<
Kind
<
'tcx
>
,
Kind
<
'gcx
>>
,
map_missing_regions_to_empty
:
bool
,
/// initially `Some`, set to `None` once error has been reported
hidden_ty
:
Option
<
Ty
<
'tcx
>>
,
}
impl
<
'cx
,
'gcx
,
'tcx
>
ReverseMapper
<
'cx
,
'gcx
,
'tcx
>
{
fn
new
(
tcx
:
TyCtxt
<
'cx
,
'gcx
,
'tcx
>
,
tainted_by_errors
:
bool
,
anon_type_def_id
:
DefId
,
map
:
FxHashMap
<
Kind
<
'tcx
>
,
Kind
<
'gcx
>>
,
hidden_ty
:
Ty
<
'tcx
>
,
)
->
Self
{
Self
{
tcx
,
tainted_by_errors
,
anon_type_def_id
,
map
,
map_missing_regions_to_empty
:
false
,
hidden_ty
:
Some
(
hidden_ty
),
}
}
fn
fold_kind_mapping_missing_regions_to_empty
(
&
mut
self
,
kind
:
Kind
<
'tcx
>
)
->
Kind
<
'tcx
>
{
assert
!
(
!
self
.map_missing_regions_to_empty
);
self
.map_missing_regions_to_empty
=
true
;
let
kind
=
kind
.fold_with
(
self
);
self
.map_missing_regions_to_empty
=
false
;
kind
}
fn
fold_kind_normally
(
&
mut
self
,
kind
:
Kind
<
'tcx
>
)
->
Kind
<
'tcx
>
{
assert
!
(
!
self
.map_missing_regions_to_empty
);
kind
.fold_with
(
self
)
}
}
}
impl
<
'cx
,
'gcx
,
'tcx
>
TypeFolder
<
'gcx
,
'tcx
>
for
ReverseMapper
<
'cx
,
'gcx
,
'tcx
>
{
impl
<
'cx
,
'gcx
,
'tcx
>
TypeFolder
<
'gcx
,
'tcx
>
for
ReverseMapper
<
'cx
,
'gcx
,
'tcx
>
{
...
@@ -484,33 +530,105 @@ fn tcx(&self) -> TyCtxt<'_, 'gcx, 'tcx> {
...
@@ -484,33 +530,105 @@ fn tcx(&self) -> TyCtxt<'_, 'gcx, 'tcx> {
}
}
fn
fold_region
(
&
mut
self
,
r
:
ty
::
Region
<
'tcx
>
)
->
ty
::
Region
<
'tcx
>
{
fn
fold_region
(
&
mut
self
,
r
:
ty
::
Region
<
'tcx
>
)
->
ty
::
Region
<
'tcx
>
{
match
r
{
// ignore bound regions that appear in the type (e.g., this
// ignore bound regions that appear in the type (e.g., this
// would ignore `'r` in a type like `for<'r> fn(&'r u32)`.
// would ignore `'r` in a type like `for<'r> fn(&'r u32)`.
if
let
ty
::
ReLateBound
(
..
)
=
*
r
{
ty
::
ReLateBound
(
..
)
=>
return
r
,
return
r
;
// ignore `'static`, as that can appear anywhere
ty
::
ReStatic
=>
return
r
,
_
=>
{
}
}
}
match
self
.map
.get
(
&
r
.into
())
.map
(|
k
|
k
.unpack
())
{
match
self
.map
.get
(
&
r
.into
())
.map
(|
k
|
k
.unpack
())
{
Some
(
UnpackedKind
::
Lifetime
(
r1
))
=>
r1
,
Some
(
UnpackedKind
::
Lifetime
(
r1
))
=>
r1
,
Some
(
u
)
=>
panic!
(
"region mapped to unexpected kind: {:?}"
,
u
),
Some
(
u
)
=>
panic!
(
"region mapped to unexpected kind: {:?}"
,
u
),
None
=>
{
None
=>
{
// No mapping was found. This means that it is either a
if
!
self
.map_missing_regions_to_empty
&&
!
self
.tainted_by_errors
{
// disallowed lifetime, which will be caught by regionck,
if
let
Some
(
hidden_ty
)
=
self
.hidden_ty
.take
()
{
// or it is a region in a non-upvar closure generic, which
let
span
=
self
.tcx
.def_span
(
self
.anon_type_def_id
);
// is explicitly allowed. If that surprises you, read on.
let
mut
err
=
struct_span_err!
(
self
.tcx.sess
,
span
,
E0909
,
"hidden type for `impl Trait` captures lifetime that
\
does not appear in bounds"
,
);
// Assuming regionck succeeded, then we must
// be capturing *some* region from the fn
// header, and hence it must be free, so it's
// ok to invoke this fn (which doesn't accept
// all regions, and would ICE if an
// inappropriate region is given). We check
// `is_tainted_by_errors` by errors above, so
// we don't get in here unless regionck
// succeeded. (Note also that if regionck
// failed, then the regions we are attempting
// to map here may well be giving errors
// *because* the constraints were not
// satisfiable.)
self
.tcx
.note_and_explain_free_region
(
&
mut
err
,
&
format!
(
"hidden type `{}` captures "
,
hidden_ty
),
r
,
""
);
err
.emit
();
}
}
self
.tcx.types.re_empty
},
}
}
fn
fold_ty
(
&
mut
self
,
ty
:
Ty
<
'tcx
>
)
->
Ty
<
'tcx
>
{
match
ty
.sty
{
ty
::
TyClosure
(
def_id
,
substs
)
=>
{
// I am a horrible monster and I pray for death. When
// we encounter a closure here, it is always a closure
// from within the function that we are currently
// type-checking -- one that is now being encapsulated
// in an existential abstract type. Ideally, we would
// go through the types/lifetimes that it references
// and treat them just like we would any other type,
// which means we would error out if we find any
// reference to a type/region that is not in the
// "reverse map".
//
//
// The case of closure is a somewhat subtle (read: hacky)
// **However,** in the case of closures, there is a
// consideration. The problem is that our closure types
// somewhat subtle (read: hacky) consideration. The
// currently include all the lifetime parameters declared
// problem is that our closure types currently include
// on the enclosing function, even if they are unused by
// all the lifetime parameters declared on the
// the closure itself. We can't readily filter them out,
// enclosing function, even if they are unused by the
// closure itself. We can't readily filter them out,
// so here we replace those values with `'empty`. This
// so here we replace those values with `'empty`. This
// can't really make a difference to the rest of the
// can't really make a difference to the rest of the
// compiler; those regions are ignored for the outlives
// compiler; those regions are ignored for the
// relation, and hence don't affect trait selection or
// outlives relation, and hence don't affect trait
// auto traits, and they are erased during trans.
// selection or auto traits, and they are erased
self
.tcx.types.re_empty
// during trans.
let
generics
=
self
.tcx
.generics_of
(
def_id
);
let
parent_len
=
generics
.parent_count
();
let
substs
=
self
.tcx
.mk_substs
(
substs
.substs
.iter
()
.enumerate
()
.map
(
|(
index
,
&
kind
)|
{
if
index
<
parent_len
{
// Accommodate missing regions in the parent kinds...
self
.fold_kind_mapping_missing_regions_to_empty
(
kind
)
}
else
{
// ...but not elsewhere.
self
.fold_kind_normally
(
kind
)
}
}
},
));
self
.tcx
.mk_closure
(
def_id
,
ty
::
ClosureSubsts
{
substs
})
}
_
=>
ty
.super_fold_with
(
self
),
}
}
}
}
}
}
...
@@ -573,12 +691,13 @@ fn instantiate_anon_types_in_map<T: TypeFoldable<'tcx>>(&mut self, value: &T) ->
...
@@ -573,12 +691,13 @@ fn instantiate_anon_types_in_map<T: TypeFoldable<'tcx>>(&mut self, value: &T) ->
return
self
.fold_anon_ty
(
ty
,
def_id
,
substs
);
return
self
.fold_anon_ty
(
ty
,
def_id
,
substs
);
}
}
debug!
(
"instantiate_anon_types_in_map:
\
debug!
(
"instantiate_anon_types_in_map:
\
encountered anon with wrong parent
\
encountered anon with wrong parent
\
def_id={:?}
\
def_id={:?}
\
anon_parent_def_id={:?}"
,
anon_parent_def_id={:?}"
,
def_id
,
def_id
,
anon_parent_def_id
anon_parent_def_id
);
);
}
}
}
}
...
@@ -598,8 +717,7 @@ fn fold_anon_ty(
...
@@ -598,8 +717,7 @@ fn fold_anon_ty(
debug!
(
debug!
(
"instantiate_anon_types: TyAnon(def_id={:?}, substs={:?})"
,
"instantiate_anon_types: TyAnon(def_id={:?}, substs={:?})"
,
def_id
,
def_id
,
substs
substs
);
);
// Use the same type variable if the exact same TyAnon appears more
// Use the same type variable if the exact same TyAnon appears more
...
@@ -608,8 +726,10 @@ fn fold_anon_ty(
...
@@ -608,8 +726,10 @@ fn fold_anon_ty(
return
anon_defn
.concrete_ty
;
return
anon_defn
.concrete_ty
;
}
}
let
span
=
tcx
.def_span
(
def_id
);
let
span
=
tcx
.def_span
(
def_id
);
let
ty_var
=
infcx
.next_ty_var
(
ty
::
UniverseIndex
::
ROOT
,
let
ty_var
=
infcx
.next_ty_var
(
TypeVariableOrigin
::
TypeInference
(
span
));
ty
::
UniverseIndex
::
ROOT
,
TypeVariableOrigin
::
TypeInference
(
span
),
);
let
predicates_of
=
tcx
.predicates_of
(
def_id
);
let
predicates_of
=
tcx
.predicates_of
(
def_id
);
let
bounds
=
predicates_of
.instantiate
(
tcx
,
substs
);
let
bounds
=
predicates_of
.instantiate
(
tcx
,
substs
);
...
...
src/test/ui/impl-trait/region-escape-via-bound-contravariant.rs
0 → 100644
浏览文件 @
fc3c90cf
// Copyright 2016 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.
// In contrast to `region-escape-via-bound-invariant`, in this case we
// *can* return a value of type `&'x u32`, even though `'x` does not
// appear in the bounds. This is because `&` is contravariant, and so
// we are *actually* returning a `&'y u32`.
//
// See https://github.com/rust-lang/rust/issues/46541 for more details.
// run-pass
#![allow(dead_code)]
#![feature(conservative_impl_trait)]
#![feature(in_band_lifetimes)]
#![feature(nll)]
trait
Trait
<
'a
>
{
}
impl
Trait
<
'b
>
for
&
'a
u32
{
}
fn
foo
(
x
:
&
'x
u32
)
->
impl
Trait
<
'y
>
where
'x
:
'y
{
x
}
fn
main
()
{
}
src/test/ui/impl-trait/region-escape-via-bound.rs
0 → 100644
浏览文件 @
fc3c90cf
// Copyright 2016 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.
// Test that we do not allow the region `'x` to escape in the impl
// trait **even though** `'y` escapes, which outlives `'x`.
//
// See https://github.com/rust-lang/rust/issues/46541 for more details.
#![allow(dead_code)]
#![feature(conservative_impl_trait)]
#![feature(in_band_lifetimes)]
#![feature(nll)]
use
std
::
cell
::
Cell
;
trait
Trait
<
'a
>
{
}
impl
Trait
<
'b
>
for
Cell
<&
'a
u32
>
{
}
fn
foo
(
x
:
Cell
<&
'x
u32
>
)
->
impl
Trait
<
'y
>
//~^ ERROR hidden type for `impl Trait` captures lifetime that does not appear in bounds [E0909]
where
'x
:
'y
{
x
}
fn
main
()
{
}
src/test/ui/impl-trait/region-escape-via-bound.stderr
0 → 100644
浏览文件 @
fc3c90cf
error[E0909]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
--> $DIR/region-escape-via-bound.rs:27:29
|
LL | fn foo(x: Cell<&'x u32>) -> impl Trait<'y>
| ^^^^^^^^^^^^^^
|
note: hidden type `std::cell::Cell<&'x u32>` captures the lifetime 'x as defined on the function body at 27:1
--> $DIR/region-escape-via-bound.rs:27:1
|
LL | / fn foo(x: Cell<&'x u32>) -> impl Trait<'y>
LL | | //~^ ERROR hidden type for `impl Trait` captures lifetime that does not appear in bounds [E0909]
LL | | where 'x: 'y
LL | | {
LL | | x
LL | | }
| |_^
error: aborting due to previous error
For more information about this error, try `rustc --explain E0909`.
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录