summaryrefslogtreecommitdiffstats
path: root/tests/codegen/virtual-function-elimination.rs
blob: 4cf7e12fee215f079f6b208da91a914a5f84798c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
// compile-flags: -Zvirtual-function-elimination -Clto -O -Csymbol-mangling-version=v0
// ignore-32bit

// CHECK: @vtable.0 = {{.*}}, !type ![[TYPE0:[0-9]+]], !vcall_visibility ![[VCALL_VIS0:[0-9]+]]
// CHECK: @vtable.1 = {{.*}}, !type ![[TYPE1:[0-9]+]], !vcall_visibility ![[VCALL_VIS0:[0-9]+]]
// CHECK: @vtable.2 = {{.*}}, !type ![[TYPE2:[0-9]+]], !vcall_visibility ![[VCALL_VIS2:[0-9]+]]

#![crate_type = "lib"]
#![allow(incomplete_features)]
#![feature(unsized_locals)]

use std::rc::Rc;

trait T {
    // CHECK-LABEL: ; <virtual_function_elimination::S as virtual_function_elimination::T>::used
    fn used(&self) -> i32 {
        1
    }
    // CHECK-LABEL: ; <virtual_function_elimination::S as virtual_function_elimination::T>::used_through_sub_trait
    fn used_through_sub_trait(&self) -> i32 {
        3
    }
    // CHECK-LABEL: ; <virtual_function_elimination::S as virtual_function_elimination::T>::by_rc
    fn by_rc(self: Rc<Self>) -> i32 {
        self.used() + self.used()
    }
    // CHECK-LABEL-NOT: {{.*}}::unused
    fn unused(&self) -> i32 {
        2
    }
    // CHECK-LABEL-NOT: {{.*}}::by_rc_unused
    fn by_rc_unused(self: Rc<Self>) -> i32 {
        self.by_rc()
    }
}

trait U: T {
    // CHECK-LABEL: ; <virtual_function_elimination::S as virtual_function_elimination::U>::subtrait_used
    fn subtrait_used(&self) -> i32 {
        4
    }
    // CHECK-LABEL-NOT: {{.*}}::subtrait_unused
    fn subtrait_unused(&self) -> i32 {
        5
    }
}

pub trait V {
    // CHECK-LABEL: ; <virtual_function_elimination::S as virtual_function_elimination::V>::public_function
    fn public_function(&self) -> i32;
}

#[derive(Copy, Clone)]
struct S;

impl T for S {}

impl U for S {}

impl V for S {
    fn public_function(&self) -> i32 {
        6
    }
}

fn taking_t(t: &dyn T) -> i32 {
    // CHECK: @llvm.type.checked.load({{.*}}, i32 24, metadata !"[[MANGLED_TYPE0:[0-9a-zA-Z_]+]]")
    t.used()
}

fn taking_rc_t(t: Rc<dyn T>) -> i32 {
    // CHECK: @llvm.type.checked.load({{.*}}, i32 40, metadata !"[[MANGLED_TYPE0:[0-9a-zA-Z_]+]]")
    t.by_rc()
}

fn taking_u(u: &dyn U) -> i32 {
    // CHECK: @llvm.type.checked.load({{.*}}, i32 64, metadata !"[[MANGLED_TYPE1:[0-9a-zA-Z_]+]]")
    // CHECK: @llvm.type.checked.load({{.*}}, i32 24, metadata !"[[MANGLED_TYPE1:[0-9a-zA-Z_]+]]")
    // CHECK: @llvm.type.checked.load({{.*}}, i32 32, metadata !"[[MANGLED_TYPE1:[0-9a-zA-Z_]+]]")
    u.subtrait_used() + u.used() + u.used_through_sub_trait()
}

pub fn taking_v(v: &dyn V) -> i32 {
    // CHECK: @llvm.type.checked.load({{.*}}, i32 24, metadata !"NtCsfRpWlKdQPZn_28virtual_function_elimination1V")
    v.public_function()
}

pub fn main() {
    let s = S;
    taking_t(&s);
    taking_rc_t(Rc::new(s));
    taking_u(&s);
    taking_v(&s);
}

// CHECK: ![[TYPE0]] = !{i64 0, !"[[MANGLED_TYPE0]]"}
// CHECK: ![[VCALL_VIS0]] = !{i64 2}
// CHECK: ![[TYPE1]] = !{i64 0, !"[[MANGLED_TYPE1]]"}
// CHECK: ![[TYPE2]] = !{i64 0, !"NtCsfRpWlKdQPZn_28virtual_function_elimination1V"}
// CHECK: ![[VCALL_VIS2]] = !{i64 1}