Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
int
Rust
提交
63ed6253
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,发现更多精彩内容 >>
提交
63ed6253
编写于
7月 31, 2021
作者:
crlf0710
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Implement pointer casting.
上级
7069a8c2
变更
11
隐藏空白更改
内联
并排
Showing
11 changed file
with
256 addition
and
88 deletion
+256
-88
compiler/rustc_codegen_cranelift/src/unsize.rs
compiler/rustc_codegen_cranelift/src/unsize.rs
+48
-15
compiler/rustc_codegen_cranelift/src/vtable.rs
compiler/rustc_codegen_cranelift/src/vtable.rs
+1
-1
compiler/rustc_codegen_ssa/src/base.rs
compiler/rustc_codegen_ssa/src/base.rs
+66
-41
compiler/rustc_codegen_ssa/src/mir/rvalue.rs
compiler/rustc_codegen_ssa/src/mir/rvalue.rs
+8
-19
compiler/rustc_middle/src/query/mod.rs
compiler/rustc_middle/src/query/mod.rs
+5
-0
compiler/rustc_mir/src/interpret/cast.rs
compiler/rustc_mir/src/interpret/cast.rs
+27
-5
compiler/rustc_mir/src/interpret/operand.rs
compiler/rustc_mir/src/interpret/operand.rs
+10
-0
compiler/rustc_mir/src/interpret/traits.rs
compiler/rustc_mir/src/interpret/traits.rs
+23
-0
compiler/rustc_query_impl/src/keys.rs
compiler/rustc_query_impl/src/keys.rs
+10
-0
compiler/rustc_trait_selection/src/traits/mod.rs
compiler/rustc_trait_selection/src/traits/mod.rs
+9
-7
src/test/ui/traits/trait-upcasting/replace-vptr.rs
src/test/ui/traits/trait-upcasting/replace-vptr.rs
+49
-0
未找到文件。
compiler/rustc_codegen_cranelift/src/unsize.rs
浏览文件 @
63ed6253
...
...
@@ -25,39 +25,73 @@ pub(crate) fn unsized_info<'tcx>(
.bcx
.ins
()
.iconst
(
fx
.pointer_type
,
len
.eval_usize
(
fx
.tcx
,
ParamEnv
::
reveal_all
())
as
i64
),
(
&
ty
::
Dynamic
(
..
),
&
ty
::
Dynamic
(
..
))
=>
{
// For now, upcasts are limited to changes in marker
// traits, and hence never actually require an actual
// change to the vtable.
old_info
.expect
(
"unsized_info: missing old info for trait upcast"
)
(
&
ty
::
Dynamic
(
ref
data_a
,
..
),
&
ty
::
Dynamic
(
ref
data_b
,
..
))
=>
{
let
old_info
=
old_info
.expect
(
"unsized_info: missing old info for trait upcasting coercion"
);
if
data_a
.principal_def_id
()
==
data_b
.principal_def_id
()
{
return
old_info
;
}
// trait upcasting coercion
// if both of the two `principal`s are `None`, this function would have returned early above.
// and if one of the two `principal`s is `None`, typechecking would have rejected this case.
let
principal_a
=
data_a
.principal
()
.expect
(
"unsized_info: missing principal trait for trait upcasting coercion"
);
let
principal_b
=
data_b
.principal
()
.expect
(
"unsized_info: missing principal trait for trait upcasting coercion"
);
let
vptr_entry_idx
=
fx
.tcx
.vtable_trait_upcasting_coercion_new_vptr_slot
((
principal_a
.with_self_ty
(
fx
.tcx
,
source
),
principal_b
.with_self_ty
(
fx
.tcx
,
source
),
));
if
let
Some
(
entry_idx
)
=
vptr_entry_idx
{
let
entry_idx
=
u32
::
try_from
(
entry_idx
)
.unwrap
();
let
entry_offset
=
entry_idx
*
fx
.pointer_type
.bytes
();
let
vptr_ptr
=
Pointer
::
new
(
old_info
)
.offset_i64
(
fx
,
entry_offset
.into
())
.load
(
fx
,
fx
.pointer_type
,
crate
::
vtable
::
vtable_memflags
(),
);
vptr_ptr
}
else
{
old_info
}
}
(
_
,
&
ty
::
Dynamic
(
ref
data
,
..
))
=>
crate
::
vtable
::
get_vtable
(
fx
,
source
,
data
.principal
()),
_
=>
bug!
(
"unsized_info: invalid unsizing {:?} -> {:?}"
,
source
,
target
),
}
}
/// Coerce `src` to `dst_ty`.
`src_ty` must be a thin pointer.
fn
unsize_
thin_
ptr
<
'tcx
>
(
/// Coerce `src` to `dst_ty`.
fn
unsize_ptr
<
'tcx
>
(
fx
:
&
mut
FunctionCx
<
'_
,
'_
,
'tcx
>
,
src
:
Value
,
src_layout
:
TyAndLayout
<
'tcx
>
,
dst_layout
:
TyAndLayout
<
'tcx
>
,
old_info
:
Option
<
Value
>
,
)
->
(
Value
,
Value
)
{
match
(
&
src_layout
.ty
.kind
(),
&
dst_layout
.ty
.kind
())
{
(
&
ty
::
Ref
(
_
,
a
,
_
),
&
ty
::
Ref
(
_
,
b
,
_
))
|
(
&
ty
::
Ref
(
_
,
a
,
_
),
&
ty
::
RawPtr
(
ty
::
TypeAndMut
{
ty
:
b
,
..
}))
|
(
&
ty
::
RawPtr
(
ty
::
TypeAndMut
{
ty
:
a
,
..
}),
&
ty
::
RawPtr
(
ty
::
TypeAndMut
{
ty
:
b
,
..
}))
=>
{
assert
!
(
!
fx
.layout_of
(
a
)
.is_unsized
());
(
src
,
unsized_info
(
fx
,
a
,
b
,
None
))
(
src
,
unsized_info
(
fx
,
a
,
b
,
old_info
))
}
(
&
ty
::
Adt
(
def_a
,
_
),
&
ty
::
Adt
(
def_b
,
_
))
if
def_a
.is_box
()
&&
def_b
.is_box
()
=>
{
let
(
a
,
b
)
=
(
src_layout
.ty
.boxed_ty
(),
dst_layout
.ty
.boxed_ty
());
assert
!
(
!
fx
.layout_of
(
a
)
.is_unsized
());
(
src
,
unsized_info
(
fx
,
a
,
b
,
None
))
(
src
,
unsized_info
(
fx
,
a
,
b
,
old_info
))
}
(
&
ty
::
Adt
(
def_a
,
_
),
&
ty
::
Adt
(
def_b
,
_
))
=>
{
assert_eq!
(
def_a
,
def_b
);
if
src_layout
==
dst_layout
{
return
(
src
,
old_info
.unwrap
());
}
let
mut
result
=
None
;
for
i
in
0
..
src_layout
.fields
.count
()
{
let
src_f
=
src_layout
.field
(
fx
,
i
);
...
...
@@ -71,11 +105,11 @@ fn unsize_thin_ptr<'tcx>(
let
dst_f
=
dst_layout
.field
(
fx
,
i
);
assert_ne!
(
src_f
.ty
,
dst_f
.ty
);
assert_eq!
(
result
,
None
);
result
=
Some
(
unsize_
thin_ptr
(
fx
,
src
,
src_f
,
dst_f
));
result
=
Some
(
unsize_
ptr
(
fx
,
src
,
src_f
,
dst_f
,
old_info
));
}
result
.unwrap
()
}
_
=>
bug!
(
"unsize_
thin_
ptr: called on bad types"
),
_
=>
bug!
(
"unsize_ptr: called on bad types"
),
}
}
...
...
@@ -91,12 +125,11 @@ pub(crate) fn coerce_unsized_into<'tcx>(
let
mut
coerce_ptr
=
||
{
let
(
base
,
info
)
=
if
fx
.layout_of
(
src
.layout
()
.ty
.builtin_deref
(
true
)
.unwrap
()
.ty
)
.is_unsized
()
{
// fat-ptr to fat-ptr unsize preserves the vtable
// i.e., &'a fmt::Debug+Send => &'a fmt::Debug
src
.load_scalar_pair
(
fx
)
let
(
old_base
,
old_info
)
=
src
.load_scalar_pair
(
fx
);
unsize_ptr
(
fx
,
old_base
,
src
.layout
(),
dst
.layout
(),
Some
(
old_info
))
}
else
{
let
base
=
src
.load_scalar
(
fx
);
unsize_
thin_ptr
(
fx
,
base
,
src
.layout
(),
dst
.layout
()
)
unsize_
ptr
(
fx
,
base
,
src
.layout
(),
dst
.layout
(),
None
)
};
dst
.write_cvalue
(
fx
,
CValue
::
by_val_pair
(
base
,
info
,
dst
.layout
()));
};
...
...
compiler/rustc_codegen_cranelift/src/vtable.rs
浏览文件 @
63ed6253
...
...
@@ -5,7 +5,7 @@
use
crate
::
constant
::
data_id_for_alloc_id
;
use
crate
::
prelude
::
*
;
fn
vtable_memflags
()
->
MemFlags
{
pub
(
crate
)
fn
vtable_memflags
()
->
MemFlags
{
let
mut
flags
=
MemFlags
::
trusted
();
// A vtable access is always aligned and will never trap.
flags
.set_readonly
();
// A vtable is always read-only.
flags
...
...
compiler/rustc_codegen_ssa/src/base.rs
浏览文件 @
63ed6253
...
...
@@ -23,7 +23,6 @@
use
rustc_middle
::
middle
::
lang_items
;
use
rustc_middle
::
mir
::
mono
::{
CodegenUnit
,
CodegenUnitNameBuilder
,
MonoItem
};
use
rustc_middle
::
ty
::
layout
::{
HasTyCtxt
,
TyAndLayout
};
use
rustc_middle
::
ty
::
layout
::{
FAT_PTR_ADDR
,
FAT_PTR_EXTRA
};
use
rustc_middle
::
ty
::
query
::
Providers
;
use
rustc_middle
::
ty
::{
self
,
Instance
,
Ty
,
TyCtxt
};
use
rustc_session
::
cgu_reuse_tracker
::
CguReuse
;
...
...
@@ -32,6 +31,7 @@
use
rustc_span
::
symbol
::
sym
;
use
rustc_target
::
abi
::{
Align
,
LayoutOf
,
VariantIdx
};
use
std
::
convert
::
TryFrom
;
use
std
::
ops
::{
Deref
,
DerefMut
};
use
std
::
time
::{
Duration
,
Instant
};
...
...
@@ -128,55 +128,92 @@ pub fn compare_simd_types<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
///
/// The `old_info` argument is a bit odd. It is intended for use in an upcast,
/// where the new vtable for an object will be derived from the old one.
pub
fn
unsized_info
<
'
tcx
,
Cx
:
CodegenMethods
<
'tcx
>>
(
cx
:
&
C
x
,
pub
fn
unsized_info
<
'
a
,
'tcx
,
Bx
:
BuilderMethods
<
'a
,
'tcx
>>
(
bx
:
&
mut
B
x
,
source
:
Ty
<
'tcx
>
,
target
:
Ty
<
'tcx
>
,
old_info
:
Option
<
Cx
::
Value
>
,
)
->
Cx
::
Value
{
old_info
:
Option
<
Bx
::
Value
>
,
)
->
Bx
::
Value
{
let
cx
=
bx
.cx
();
let
(
source
,
target
)
=
cx
.tcx
()
.struct_lockstep_tails_erasing_lifetimes
(
source
,
target
,
c
x
.param_env
());
cx
.tcx
()
.struct_lockstep_tails_erasing_lifetimes
(
source
,
target
,
b
x
.param_env
());
match
(
source
.kind
(),
target
.kind
())
{
(
&
ty
::
Array
(
_
,
len
),
&
ty
::
Slice
(
_
))
=>
{
cx
.const_usize
(
len
.eval_usize
(
cx
.tcx
(),
ty
::
ParamEnv
::
reveal_all
()))
}
(
&
ty
::
Dynamic
(
..
),
&
ty
::
Dynamic
(
..
))
=>
{
// For now, upcasts are limited to changes in marker
// traits, and hence never actually require an actual
// change to the vtable.
old_info
.expect
(
"unsized_info: missing old info for trait upcast"
)
(
&
ty
::
Dynamic
(
ref
data_a
,
..
),
&
ty
::
Dynamic
(
ref
data_b
,
..
))
=>
{
let
old_info
=
old_info
.expect
(
"unsized_info: missing old info for trait upcasting coercion"
);
if
data_a
.principal_def_id
()
==
data_b
.principal_def_id
()
{
return
old_info
;
}
// trait upcasting coercion
// if both of the two `principal`s are `None`, this function would have returned early above.
// and if one of the two `principal`s is `None`, typechecking would have rejected this case.
let
principal_a
=
data_a
.principal
()
.expect
(
"unsized_info: missing principal trait for trait upcasting coercion"
);
let
principal_b
=
data_b
.principal
()
.expect
(
"unsized_info: missing principal trait for trait upcasting coercion"
);
let
vptr_entry_idx
=
cx
.tcx
()
.vtable_trait_upcasting_coercion_new_vptr_slot
((
principal_a
.with_self_ty
(
cx
.tcx
(),
source
),
principal_b
.with_self_ty
(
cx
.tcx
(),
source
),
));
if
let
Some
(
entry_idx
)
=
vptr_entry_idx
{
let
ptr_ty
=
cx
.type_i8p
();
let
ptr_align
=
cx
.tcx
()
.data_layout.pointer_align.abi
;
let
llvtable
=
bx
.pointercast
(
old_info
,
bx
.type_ptr_to
(
ptr_ty
));
let
gep
=
bx
.inbounds_gep
(
llvtable
,
&
[
bx
.const_usize
(
u64
::
try_from
(
entry_idx
)
.unwrap
())]);
let
new_vptr
=
bx
.load
(
ptr_ty
,
gep
,
ptr_align
);
bx
.nonnull_metadata
(
new_vptr
);
// Vtable loads are invariant.
bx
.set_invariant_load
(
new_vptr
);
new_vptr
}
else
{
old_info
}
}
(
_
,
&
ty
::
Dynamic
(
ref
data
,
..
))
=>
{
let
vtable_ptr
=
cx
.layout_of
(
cx
.tcx
()
.mk_mut_ptr
(
target
))
.field
(
cx
,
FAT_PTR_EXTRA
);
cx
.const_ptrcast
(
meth
::
get_vtable
(
cx
,
source
,
data
.principal
()),
cx
.backend_type
(
vtable_ptr
),
)
let
vtable_ptr_ty
=
cx
.scalar_pair_element_backend_type
(
cx
.layout_of
(
cx
.tcx
()
.mk_mut_ptr
(
target
)),
1
,
true
,
);
cx
.const_ptrcast
(
meth
::
get_vtable
(
cx
,
source
,
data
.principal
()),
vtable_ptr_ty
)
}
_
=>
bug!
(
"unsized_info: invalid unsizing {:?} -> {:?}"
,
source
,
target
),
}
}
/// Coerces `src` to `dst_ty`. `src_ty` must be a
thin
pointer.
pub
fn
unsize_
thin_
ptr
<
'a
,
'tcx
,
Bx
:
BuilderMethods
<
'a
,
'tcx
>>
(
/// Coerces `src` to `dst_ty`. `src_ty` must be a pointer.
pub
fn
unsize_ptr
<
'a
,
'tcx
,
Bx
:
BuilderMethods
<
'a
,
'tcx
>>
(
bx
:
&
mut
Bx
,
src
:
Bx
::
Value
,
src_ty
:
Ty
<
'tcx
>
,
dst_ty
:
Ty
<
'tcx
>
,
old_info
:
Option
<
Bx
::
Value
>
,
)
->
(
Bx
::
Value
,
Bx
::
Value
)
{
debug!
(
"unsize_
thin_
ptr: {:?} => {:?}"
,
src_ty
,
dst_ty
);
debug!
(
"unsize_ptr: {:?} => {:?}"
,
src_ty
,
dst_ty
);
match
(
src_ty
.kind
(),
dst_ty
.kind
())
{
(
&
ty
::
Ref
(
_
,
a
,
_
),
&
ty
::
Ref
(
_
,
b
,
_
)
|
&
ty
::
RawPtr
(
ty
::
TypeAndMut
{
ty
:
b
,
..
}))
|
(
&
ty
::
RawPtr
(
ty
::
TypeAndMut
{
ty
:
a
,
..
}),
&
ty
::
RawPtr
(
ty
::
TypeAndMut
{
ty
:
b
,
..
}))
=>
{
assert
!
(
bx
.cx
()
.type_is_sized
(
a
));
assert
_eq!
(
bx
.cx
()
.type_is_sized
(
a
),
old_info
.is_none
(
));
let
ptr_ty
=
bx
.cx
()
.type_ptr_to
(
bx
.cx
()
.backend_type
(
bx
.cx
()
.layout_of
(
b
)));
(
bx
.pointercast
(
src
,
ptr_ty
),
unsized_info
(
bx
.cx
(),
a
,
b
,
None
))
(
bx
.pointercast
(
src
,
ptr_ty
),
unsized_info
(
bx
,
a
,
b
,
old_info
))
}
(
&
ty
::
Adt
(
def_a
,
_
),
&
ty
::
Adt
(
def_b
,
_
))
=>
{
assert_eq!
(
def_a
,
def_b
);
let
src_layout
=
bx
.cx
()
.layout_of
(
src_ty
);
let
dst_layout
=
bx
.cx
()
.layout_of
(
dst_ty
);
if
src_ty
==
dst_ty
{
return
(
src
,
old_info
.unwrap
());
}
let
mut
result
=
None
;
for
i
in
0
..
src_layout
.fields
.count
()
{
let
src_f
=
src_layout
.field
(
bx
.cx
(),
i
);
...
...
@@ -190,18 +227,15 @@ pub fn unsize_thin_ptr<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
let
dst_f
=
dst_layout
.field
(
bx
.cx
(),
i
);
assert_ne!
(
src_f
.ty
,
dst_f
.ty
);
assert_eq!
(
result
,
None
);
result
=
Some
(
unsize_
thin_ptr
(
bx
,
src
,
src_f
.ty
,
dst_f
.ty
));
result
=
Some
(
unsize_
ptr
(
bx
,
src
,
src_f
.ty
,
dst_f
.ty
,
old_info
));
}
let
(
lldata
,
llextra
)
=
result
.unwrap
();
let
lldata_ty
=
bx
.cx
()
.scalar_pair_element_backend_type
(
dst_layout
,
0
,
true
);
let
llextra_ty
=
bx
.cx
()
.scalar_pair_element_backend_type
(
dst_layout
,
1
,
true
);
// HACK(eddyb) have to bitcast pointers until LLVM removes pointee types.
// FIXME(eddyb) move these out of this `match` arm, so they're always
// applied, uniformly, no matter the source/destination types.
(
bx
.bitcast
(
lldata
,
bx
.cx
()
.scalar_pair_element_backend_type
(
dst_layout
,
0
,
true
)),
bx
.bitcast
(
llextra
,
bx
.cx
()
.scalar_pair_element_backend_type
(
dst_layout
,
1
,
true
)),
)
(
bx
.bitcast
(
lldata
,
lldata_ty
),
bx
.bitcast
(
llextra
,
llextra_ty
))
}
_
=>
bug!
(
"unsize_
thin_
ptr: called on bad types"
),
_
=>
bug!
(
"unsize_ptr: called on bad types"
),
}
}
...
...
@@ -217,17 +251,8 @@ pub fn coerce_unsized_into<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
match
(
src_ty
.kind
(),
dst_ty
.kind
())
{
(
&
ty
::
Ref
(
..
),
&
ty
::
Ref
(
..
)
|
&
ty
::
RawPtr
(
..
))
|
(
&
ty
::
RawPtr
(
..
),
&
ty
::
RawPtr
(
..
))
=>
{
let
(
base
,
info
)
=
match
bx
.load_operand
(
src
)
.val
{
OperandValue
::
Pair
(
base
,
info
)
=>
{
// fat-ptr to fat-ptr unsize preserves the vtable
// i.e., &'a fmt::Debug+Send => &'a fmt::Debug
// So we need to pointercast the base to ensure
// the types match up.
// FIXME(eddyb) use `scalar_pair_element_backend_type` here,
// like `unsize_thin_ptr` does.
let
thin_ptr
=
dst
.layout
.field
(
bx
.cx
(),
FAT_PTR_ADDR
);
(
bx
.pointercast
(
base
,
bx
.cx
()
.backend_type
(
thin_ptr
)),
info
)
}
OperandValue
::
Immediate
(
base
)
=>
unsize_thin_ptr
(
bx
,
base
,
src_ty
,
dst_ty
),
OperandValue
::
Pair
(
base
,
info
)
=>
unsize_ptr
(
bx
,
base
,
src_ty
,
dst_ty
,
Some
(
info
)),
OperandValue
::
Immediate
(
base
)
=>
unsize_ptr
(
bx
,
base
,
src_ty
,
dst_ty
,
None
),
OperandValue
::
Ref
(
..
)
=>
bug!
(),
};
OperandValue
::
Pair
(
base
,
info
)
.store
(
bx
,
dst
);
...
...
compiler/rustc_codegen_ssa/src/mir/rvalue.rs
浏览文件 @
63ed6253
...
...
@@ -220,34 +220,23 @@ pub fn codegen_rvalue_operand(
}
mir
::
CastKind
::
Pointer
(
PointerCast
::
Unsize
)
=>
{
assert
!
(
bx
.cx
()
.is_backend_scalar_pair
(
cast
));
match
operand
.val
{
let
(
lldata
,
llextra
)
=
match
operand
.val
{
OperandValue
::
Pair
(
lldata
,
llextra
)
=>
{
// unsize from a fat pointer -- this is a
// "trait-object-to-supertrait" coercion, for
// example, `&'a fmt::Debug + Send => &'a fmt::Debug`.
// HACK(eddyb) have to bitcast pointers
// until LLVM removes pointee types.
let
lldata
=
bx
.pointercast
(
lldata
,
bx
.cx
()
.scalar_pair_element_backend_type
(
cast
,
0
,
true
),
);
OperandValue
::
Pair
(
lldata
,
llextra
)
// "trait-object-to-supertrait" coercion.
(
lldata
,
Some
(
llextra
))
}
OperandValue
::
Immediate
(
lldata
)
=>
{
// "standard" unsize
let
(
lldata
,
llextra
)
=
base
::
unsize_thin_ptr
(
&
mut
bx
,
lldata
,
operand
.layout.ty
,
cast
.ty
,
);
OperandValue
::
Pair
(
lldata
,
llextra
)
(
lldata
,
None
)
}
OperandValue
::
Ref
(
..
)
=>
{
bug!
(
"by-ref operand {:?} in `codegen_rvalue_operand`"
,
operand
);
}
}
};
let
(
lldata
,
llextra
)
=
base
::
unsize_ptr
(
&
mut
bx
,
lldata
,
operand
.layout.ty
,
cast
.ty
,
llextra
);
OperandValue
::
Pair
(
lldata
,
llextra
)
}
mir
::
CastKind
::
Pointer
(
PointerCast
::
MutToConstPointer
)
|
mir
::
CastKind
::
Misc
...
...
compiler/rustc_middle/src/query/mod.rs
浏览文件 @
63ed6253
...
...
@@ -977,6 +977,11 @@
desc
{
|
tcx
|
"finding all vtable entries for trait {}"
,
tcx
.def_path_str
(
key
.def_id
())
}
}
query
vtable_trait_upcasting_coercion_new_vptr_slot
(
key
:
(
ty
::
PolyTraitRef
<
'tcx
>
,
ty
::
PolyTraitRef
<
'tcx
>
))
->
Option
<
usize
>
{
desc
{
|
tcx
|
"finding the slot within vtable for trait {} vtable ptr during trait upcasting coercion from {} vtable"
,
tcx
.def_path_str
(
key
.1
.def_id
()),
tcx
.def_path_str
(
key
.0
.def_id
())
}
}
query
codegen_fulfill_obligation
(
key
:
(
ty
::
ParamEnv
<
'tcx
>
,
ty
::
PolyTraitRef
<
'tcx
>
)
)
->
Result
<
ImplSource
<
'tcx
,
()
>
,
ErrorReported
>
{
...
...
compiler/rustc_mir/src/interpret/cast.rs
浏览文件 @
63ed6253
...
...
@@ -269,12 +269,34 @@ fn unsize_into_ptr(
Immediate
::
new_slice
(
ptr
,
length
.eval_usize
(
*
self
.tcx
,
self
.param_env
),
self
);
self
.write_immediate
(
val
,
dest
)
}
(
&
ty
::
Dynamic
(
..
),
&
ty
::
Dynamic
(
..
))
=>
{
// For now, upcasts are limited to changes in marker
// traits, and hence never actually require an actual
// change to the vtable.
(
&
ty
::
Dynamic
(
ref
data_a
,
..
),
&
ty
::
Dynamic
(
ref
data_b
,
..
))
=>
{
let
val
=
self
.read_immediate
(
src
)
?
;
self
.write_immediate
(
*
val
,
dest
)
if
data_a
.principal_def_id
()
==
data_b
.principal_def_id
()
{
return
self
.write_immediate
(
*
val
,
dest
);
}
// trait upcasting coercion
let
principal_a
=
data_a
.principal
()
.expect
(
"unsize_into_ptr: missing principal trait for trait upcasting coercion"
,
);
let
principal_b
=
data_b
.principal
()
.expect
(
"unsize_into_ptr: missing principal trait for trait upcasting coercion"
,
);
let
vptr_entry_idx
=
self
.tcx
.vtable_trait_upcasting_coercion_new_vptr_slot
((
principal_a
.with_self_ty
(
*
self
.tcx
,
src_pointee_ty
),
principal_b
.with_self_ty
(
*
self
.tcx
,
src_pointee_ty
),
));
if
let
Some
(
entry_idx
)
=
vptr_entry_idx
{
let
entry_idx
=
u64
::
try_from
(
entry_idx
)
.unwrap
();
let
(
old_data
,
old_vptr
)
=
val
.to_scalar_pair
()
?
;
let
old_vptr
=
self
.scalar_to_ptr
(
old_vptr
);
let
new_vptr
=
self
.read_new_vtable_after_trait_upcasting_from_vtable
(
old_vptr
,
entry_idx
)
?
;
self
.write_immediate
(
Immediate
::
new_dyn_trait
(
old_data
,
new_vptr
,
self
),
dest
)
}
else
{
self
.write_immediate
(
*
val
,
dest
)
}
}
(
_
,
&
ty
::
Dynamic
(
ref
data
,
_
))
=>
{
// Initial cast from sized to dyn trait
...
...
compiler/rustc_mir/src/interpret/operand.rs
浏览文件 @
63ed6253
...
...
@@ -79,6 +79,16 @@ pub fn to_scalar_or_uninit(self) -> ScalarMaybeUninit<Tag> {
pub
fn
to_scalar
(
self
)
->
InterpResult
<
'tcx
,
Scalar
<
Tag
>>
{
self
.to_scalar_or_uninit
()
.check_init
()
}
#[inline]
pub
fn
to_scalar_pair
(
self
)
->
InterpResult
<
'tcx
,
(
Scalar
<
Tag
>
,
Scalar
<
Tag
>
)
>
{
match
self
{
Immediate
::
ScalarPair
(
val1
,
val2
)
=>
Ok
((
val1
.check_init
()
?
,
val2
.check_init
()
?
)),
Immediate
::
Scalar
(
..
)
=>
{
bug!
(
"Got a scalar where a wide pointer was expected"
)
}
}
}
}
// ScalarPair needs a type to interpret, so we often have an immediate and a type together
...
...
compiler/rustc_mir/src/interpret/traits.rs
浏览文件 @
63ed6253
...
...
@@ -121,4 +121,27 @@ pub fn read_size_and_align_from_vtable(
}
Ok
((
Size
::
from_bytes
(
size
),
align
))
}
pub
fn
read_new_vtable_after_trait_upcasting_from_vtable
(
&
self
,
vtable
:
Pointer
<
Option
<
M
::
PointerTag
>>
,
idx
:
u64
,
)
->
InterpResult
<
'tcx
,
Pointer
<
M
::
PointerTag
>>
{
let
pointer_size
=
self
.pointer_size
();
let
vtable
=
self
.memory
.get
(
vtable
,
pointer_size
*
idx
.checked_add
(
1
)
.unwrap
(),
self
.tcx.data_layout.pointer_align.abi
,
)
?
.expect
(
"cannot be a ZST"
);
let
new_vtable
=
self
.scalar_to_ptr
(
vtable
.read_ptr_sized
(
pointer_size
*
idx
)
?
.check_init
()
?
)
.into_pointer_or_addr
()
.expect
(
"should be a pointer"
);
Ok
(
new_vtable
)
}
}
compiler/rustc_query_impl/src/keys.rs
浏览文件 @
63ed6253
...
...
@@ -282,6 +282,16 @@ fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
}
}
impl
<
'tcx
>
Key
for
(
ty
::
PolyTraitRef
<
'tcx
>
,
ty
::
PolyTraitRef
<
'tcx
>
)
{
#[inline(always)]
fn
query_crate_is_local
(
&
self
)
->
bool
{
self
.0
.def_id
()
.krate
==
LOCAL_CRATE
}
fn
default_span
(
&
self
,
tcx
:
TyCtxt
<
'_
>
)
->
Span
{
tcx
.def_span
(
self
.0
.def_id
())
}
}
impl
<
'tcx
>
Key
for
GenericArg
<
'tcx
>
{
#[inline(always)]
fn
query_crate_is_local
(
&
self
)
->
bool
{
...
...
compiler/rustc_trait_selection/src/traits/mod.rs
浏览文件 @
63ed6253
...
...
@@ -756,16 +756,17 @@ fn vtable_trait_first_method_offset<'tcx>(
}
/// Find slot offset for trait vptr within vtable entries of another trait
/// FIXME: This function is not yet used. Remove `#[allow(dead_code)]` when it's used in upcoming pr.
#[allow(dead_code)]
fn
vtable_trait_vptr_slot_offset
<
'tcx
>
(
pub
fn
vtable_trait_upcasting_coercion_new_vptr_slot
(
tcx
:
TyCtxt
<
'tcx
>
,
key
:
(
ty
::
PolyTraitRef
<
'tcx
>
,
// trait
_to_be_found
ty
::
PolyTraitRef
<
'tcx
>
,
//
trait_owning_vtable
ty
::
PolyTraitRef
<
'tcx
>
,
// trait
owning vtable
ty
::
PolyTraitRef
<
'tcx
>
,
//
super trait ref
),
)
->
Option
<
usize
>
{
let
(
trait_to_be_found
,
trait_owning_vtable
)
=
key
;
let
(
trait_owning_vtable
,
super_trait_ref
)
=
key
;
let
super_trait_did
=
super_trait_ref
.def_id
();
// FIXME: take substsref part into account here after upcasting coercion allows the same def_id occur
// multiple times.
let
vtable_segment_callback
=
{
let
mut
vptr_offset
=
0
;
...
...
@@ -776,7 +777,7 @@ fn vtable_trait_vptr_slot_offset<'tcx>(
}
VtblSegment
::
TraitOwnEntries
{
trait_ref
,
emit_vptr
}
=>
{
vptr_offset
+=
util
::
count_own_vtable_entries
(
tcx
,
trait_ref
);
if
trait_ref
==
trait_to_be_foun
d
{
if
trait_ref
.def_id
()
==
super_trait_di
d
{
if
emit_vptr
{
return
ControlFlow
::
Break
(
Some
(
vptr_offset
));
}
else
{
...
...
@@ -810,6 +811,7 @@ pub fn provide(providers: &mut ty::query::Providers) {
specializes
:
specialize
::
specializes
,
codegen_fulfill_obligation
:
codegen
::
codegen_fulfill_obligation
,
vtable_entries
,
vtable_trait_upcasting_coercion_new_vptr_slot
,
subst_and_check_impossible_predicates
,
mir_abstract_const
:
|
tcx
,
def_id
|
{
let
def_id
=
def_id
.expect_local
();
...
...
src/test/ui/traits/trait-upcasting/replace-vptr.rs
0 → 100644
浏览文件 @
63ed6253
// run-pass
#![feature(trait_upcasting)]
#![allow(incomplete_features)]
trait
A
{
fn
foo_a
(
&
self
);
}
trait
B
{
fn
foo_b
(
&
self
);
}
trait
C
:
A
+
B
{
fn
foo_c
(
&
self
);
}
struct
S
(
i32
);
impl
A
for
S
{
fn
foo_a
(
&
self
)
{
unreachable!
();
}
}
impl
B
for
S
{
fn
foo_b
(
&
self
)
{
assert_eq!
(
42
,
self
.0
);
}
}
impl
C
for
S
{
fn
foo_c
(
&
self
)
{
unreachable!
();
}
}
fn
invoke_inner
(
b
:
&
dyn
B
)
{
b
.foo_b
();
}
fn
invoke_outer
(
c
:
&
dyn
C
)
{
invoke_inner
(
c
);
}
fn
main
()
{
let
s
=
S
(
42
);
invoke_outer
(
&
s
);
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录