File: ps4-dllstorage-vtable-rtti.cpp

package info (click to toggle)
llvm-toolchain-15 1%3A15.0.6-4
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 1,554,644 kB
  • sloc: cpp: 5,922,452; ansic: 1,012,136; asm: 674,362; python: 191,568; objc: 73,855; f90: 42,327; lisp: 31,913; pascal: 11,973; javascript: 10,144; sh: 9,421; perl: 7,447; ml: 5,527; awk: 3,523; makefile: 2,520; xml: 885; cs: 573; fortran: 567
file content (211 lines) | stat: -rw-r--r-- 8,661 bytes parent folder | download
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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
// For a class that has a vtable (and hence, also has a typeinfo symbol for
// RTTI), if a user marks either:
//
//  (a) the entire class as dllexport (dllimport), or
//  (b) all non-inline virtual methods of the class as dllexport (dllimport)
//
// then Clang must export the vtable and typeinfo symbol from the TU where they
// are defined (the TU containing the definition of the Itanium C++ ABI "key
// function"), and must import them in other modules where they are referenced.
//
// Conversely to point (b), if some (but not all) of the non-inline virtual
// methods of a class are marked as dllexport (dllimport), then the vtable and
// typeinfo symbols must not be exported (imported).  This will result in a
// link-time failure when linking the importing module.  This link-time failure
// is the desired behavior, because the Microsoft toolchain also gets a
// link-time failure in these cases (and since __declspec(dllexport)
// (__declspec(dllimport)) is a Microsoft extension, our intention is to mimic
// that Microsoft behavior).
//
// Side note: It is within the bodies of constructors (and in some cases,
// destructors) that the vtable is explicitly referenced.  In case (a) above,
// where the entire class is exported (imported), then all constructors (among
// other things) are exported (imported).  So for that situation, an importing
// module for a well-formed program will not actually reference the vtable,
// since constructor calls will all be to functions external to that module
// (and imported into it, from the exporting module).  I.e., all vtable
// references will be in that module where the constructor and destructor
// bodies are, therefore, there will not be a need to import the vtable in
// that case.
//
// This test contains 6 test classes:
//   2 for point (a),
//   2 for point (b),
//   and 2 negative tests for the converse of point (b).
//
// The two tests for each of these points are one for importing, and one for
// exporting.

// RUN: %clang_cc1 -no-opaque-pointers -I%S -fdeclspec -triple x86_64-unknown-windows-itanium -emit-llvm -o - %s -fhalf-no-semantic-interposition | FileCheck %s -check-prefix=WI
// RUN: %clang_cc1 -no-opaque-pointers -I%S -fdeclspec -triple x86_64-scei-windows-itanium -emit-llvm -o - %s -fhalf-no-semantic-interposition | FileCheck %s --check-prefixes=PS4,SCEI_WI
// RUN: %clang_cc1 -no-opaque-pointers -I%S -fdeclspec -triple x86_64-scei-ps4 -emit-llvm -o - %s -fhalf-no-semantic-interposition | FileCheck %s --check-prefixes=PS4,SCEI_PS4
// RUN: %clang_cc1 -no-opaque-pointers -I%S -fdeclspec -triple x86_64-sie-ps5  -emit-llvm -o - %s -fhalf-no-semantic-interposition | FileCheck %s --check-prefixes=PS4,SCEI_PS4

#include <typeinfo>

// Case (a) -- Import Aspect
// The entire class is imported.  The typeinfo symbol must also be imported,
// but the vtable will not be referenced, and so does not need to be imported
// (as described in the "Side note", above).
//
// PS4-DAG: @_ZTI10FullImport = {{.*}}dllimport
// WI-DAG: @_ZTI10FullImport = external dllimport constant i8*
struct __declspec(dllimport) FullImport
{
  virtual void getId() {}
  virtual void Bump();
  virtual void Decrement();
};

// 'FullImport::Bump()' is the key function, so the vtable and typeinfo symbol
// of 'FullImport' will be defined in the TU that contains the definition of
// 'Bump()' (and they must be exported from there).
void FullImportTest()
{
  typeid(FullImport).name();
}

///////////////////////////////////////////////////////////////////

// Case (a) -- Export Aspect
// The entire class is exported.  The vtable and typeinfo symbols must also be
// exported,
//
// PS4-DAG: @_ZTV10FullExport ={{.*}}dllexport
// WI-DAG: @_ZTV10FullExport ={{.*}}dllexport
// PS4-DAG: @_ZTI10FullExport ={{.*}}dllexport
// WI-DAG: @_ZTI10FullExport = dso_local dllexport constant {
struct __declspec(dllexport) FullExport // Easy case: Entire class is exported.
{
  virtual void getId() {}
  virtual void Bump();
  virtual void Decrement();
};

// This is the key function of the class 'FullExport', so the vtable and
// typeinfo symbols of 'FullExport' will be defined in this TU, and so they
// must be exported from this TU.
void FullExport::Bump()
{
  typeid(FullExport).name();
}

///////////////////////////////////////////////////////////////////

// Case (b) -- Import Aspect
// The class as a whole is not imported, but all non-inline virtual methods of
// the class are, so the vtable and typeinfo symbol must be imported.
//
// PS4-DAG: @_ZTV9FooImport ={{.*}}dllimport
// WI-DAG:  @_ZTV9FooImport = linkonce_odr dso_local unnamed_addr constant {
// PS4-DAG: @_ZTI9FooImport ={{.*}}dllimport
// WI-DAG:  @_ZTI9FooImport = linkonce_odr dso_local constant {


struct FooImport
{
  virtual void getId() const {}
  __declspec(dllimport) virtual void Bump();
  __declspec(dllimport) virtual void Decrement();
};

// 'FooImport::Bump()' is the key function, so the vtable and typeinfo symbol
// of 'FooImport' will be defined in the TU that contains the definition of
// 'Bump()' (and they must be exported from there).  Here, we will reference
// the vtable and typeinfo symbol, so we must also import them.
void importTest()
{
  typeid(FooImport).name();
}

///////////////////////////////////////////////////////////////////

// Case (b) -- Export Aspect
// The class as a whole is not exported, but all non-inline virtual methods of
// the class are, so the vtable and typeinfo symbol must be exported.
//
// PS4-DAG: @_ZTV9FooExport ={{.*}}dllexport
// WI-DAG:  @_ZTV9FooExport = dso_local unnamed_addr constant {
// PS4-DAG: @_ZTI9FooExport ={{.*}}dllexport
// WI-DAG:  @_ZTI9FooExport = dso_local constant {
struct FooExport
{
  virtual void getId() const {}
  __declspec(dllexport) virtual void Bump();
  __declspec(dllexport) virtual void Decrement();
};

// This is the key function of the class 'FooExport', so the vtable and
// typeinfo symbol of 'FooExport' will be defined in this TU, and so they must
// be exported from this TU.
void FooExport::Bump()
{
  FooImport f;
  typeid(FooExport).name();
}

///////////////////////////////////////////////////////////////////

// The tests below verify that the associated vtable and typeinfo symbols are
// not imported/exported.  These are the converse of case (b).
//
// Note that ultimately, if the module doing the importing calls a constructor
// of the class with the vtable, or makes a reference to the typeinfo symbol of
// the class, then this will result in an unresolved reference (to the vtable
// or typeinfo symbol) when linking the importing module, and thus a link-time
// failure.
//
// Note that with the Microsoft toolchain there will also be a link-time
// failure when linking the module doing the importing.  With the Microsoft
// toolchain, it will be an unresolved reference to the method 'Decrement()'
// of the approriate class, rather than to the vtable or typeinfo symbol of
// the class, because Microsoft defines the vtable and typeinfo symbol (weakly)
// everywhere they are used.

// Converse of case (b) -- Import Aspect
// The class as a whole is not imported, and not all non-inline virtual methods
// are imported, so the vtable and typeinfo symbol are not to be imported.
//
// CHECK-PS4: @_ZTV11FooNoImport = external dso_local unnamed_addr constant {
// CHECK-WI:  @_ZTV11FooNoImport = linkonce_odr dso_local unnamed_addr constant {
// CHECK-PS4: @_ZTI11FooNoImport = external dso_local constant i8*{{$}}
// CHECK-WI:  @_ZTI11FooNoImport = linkonce_odr dso_local constant {
struct FooNoImport
{
  virtual void getId() const {}
  __declspec(dllimport) virtual void Bump();
  virtual void Decrement();     // Not imported.
  int mCounter;
};

void importNegativeTest()
{
  FooNoImport f;
  typeid(FooNoImport).name();
}

///////////////////////////////////////////////////////////////////

// Converse of case (b) -- Export Aspect
// The class as a whole is not exported, and not all non-inline virtual methods
// are exported, so the vtable and typeinfo symbol are not to be exported.
//
// SCEI_PS4-DAG: @_ZTV11FooNoImport = external unnamed_addr constant {
// SCEI_WI-DAG:  @_ZTV11FooNoExport = dso_local unnamed_addr constant {

// WI-DAG:       @_ZTV11FooNoExport = dso_local unnamed_addr constant {
// SCEI_PS4-DAG: @_ZTI11FooNoExport = constant {
// SCEI_WI-DAG:  @_ZTI11FooNoExport = dso_local constant {
// WI-DAG:       @_ZTI11FooNoExport = dso_local constant {
struct FooNoExport
{
  virtual void getId() const {}
  __declspec(dllexport) virtual void Bump();
  virtual void Decrement(); // Not exported.
  int mCounter;
};

void FooNoExport::Bump()
{
  typeid(FooNoExport).name();
}