1 // For a class that has a vtable (and hence, also has a typeinfo symbol for 2 // RTTI), if a user marks either: 3 // 4 // (a) the entire class as dllexport (dllimport), or 5 // (b) all non-inline virtual methods of the class as dllexport (dllimport) 6 // 7 // then Clang must export the vtable and typeinfo symbol from the TU where they 8 // are defined (the TU containing the definition of the Itanium C++ ABI "key 9 // function"), and must import them in other modules where they are referenced. 10 // 11 // Conversely to point (b), if some (but not all) of the non-inline virtual 12 // methods of a class are marked as dllexport (dllimport), then the vtable and 13 // typeinfo symbols must not be exported (imported). This will result in a 14 // link-time failure when linking the importing module. This link-time failure 15 // is the desired behavior, because the Microsoft toolchain also gets a 16 // link-time failure in these cases (and since __declspec(dllexport) 17 // (__declspec(dllimport)) is a Microsoft extension, our intention is to mimic 18 // that Microsoft behavior). 19 // 20 // Side note: It is within the bodies of constructors (and in some cases, 21 // destructors) that the vtable is explicitly referenced. In case (a) above, 22 // where the entire class is exported (imported), then all constructors (among 23 // other things) are exported (imported). So for that situation, an importing 24 // module for a well-formed program will not actually reference the vtable, 25 // since constructor calls will all be to functions external to that module 26 // (and imported into it, from the exporting module). I.e., all vtable 27 // references will be in that module where the constructor and destructor 28 // bodies are, therefore, there will not be a need to import the vtable in 29 // that case. 30 // 31 // This test contains 6 test classes: 32 // 2 for point (a), 33 // 2 for point (b), 34 // and 2 negative tests for the converse of point (b). 35 // 36 // The two tests for each of these points are one for importing, and one for 37 // exporting. 38 39 // RUN: %clang_cc1 -I%S -fdeclspec -triple x86_64-unknown-windows-itanium -emit-llvm -o - %s -fhalf-no-semantic-interposition | FileCheck %s -check-prefix=WI 40 // RUN: %clang_cc1 -I%S -fdeclspec -triple x86_64-scei-windows-itanium -emit-llvm -o - %s -fhalf-no-semantic-interposition | FileCheck %s --check-prefixes=PS4,SCEI_WI 41 // RUN: %clang_cc1 -I%S -fdeclspec -triple x86_64-scei-ps4 -emit-llvm -o - %s -fhalf-no-semantic-interposition | FileCheck %s --check-prefixes=PS4,SCEI_PS4 42 43 #include <typeinfo> 44 45 // Case (a) -- Import Aspect 46 // The entire class is imported. The typeinfo symbol must also be imported, 47 // but the vtable will not be referenced, and so does not need to be imported 48 // (as described in the "Side note", above). 49 // 50 // PS4-DAG: @_ZTI10FullImport = {{.*}}dllimport 51 // WI-DAG: @_ZTI10FullImport = external dllimport constant i8* 52 struct __declspec(dllimport) FullImport 53 { 54 virtual void getId() {} 55 virtual void Bump(); 56 virtual void Decrement(); 57 }; 58 59 // 'FullImport::Bump()' is the key function, so the vtable and typeinfo symbol 60 // of 'FullImport' will be defined in the TU that contains the definition of 61 // 'Bump()' (and they must be exported from there). 62 void FullImportTest() 63 { 64 typeid(FullImport).name(); 65 } 66 67 /////////////////////////////////////////////////////////////////// 68 69 // Case (a) -- Export Aspect 70 // The entire class is exported. The vtable and typeinfo symbols must also be 71 // exported, 72 // 73 // PS4-DAG: @_ZTV10FullExport ={{.*}}dllexport 74 // WI-DAG: @_ZTV10FullExport ={{.*}}dllexport 75 // PS4-DAG: @_ZTI10FullExport ={{.*}}dllexport 76 // WI-DAG: @_ZTI10FullExport = dso_local dllexport constant { 77 struct __declspec(dllexport) FullExport // Easy case: Entire class is exported. 78 { 79 virtual void getId() {} 80 virtual void Bump(); 81 virtual void Decrement(); 82 }; 83 84 // This is the key function of the class 'FullExport', so the vtable and 85 // typeinfo symbols of 'FullExport' will be defined in this TU, and so they 86 // must be exported from this TU. 87 void FullExport::Bump() 88 { 89 typeid(FullExport).name(); 90 } 91 92 /////////////////////////////////////////////////////////////////// 93 94 // Case (b) -- Import Aspect 95 // The class as a whole is not imported, but all non-inline virtual methods of 96 // the class are, so the vtable and typeinfo symbol must be imported. 97 // 98 // PS4-DAG: @_ZTV9FooImport ={{.*}}dllimport 99 // WI-DAG: @_ZTV9FooImport = linkonce_odr dso_local unnamed_addr constant { 100 // PS4-DAG: @_ZTI9FooImport ={{.*}}dllimport 101 // WI-DAG: @_ZTI9FooImport = linkonce_odr dso_local constant { 102 103 104 struct FooImport 105 { 106 virtual void getId() const {} 107 __declspec(dllimport) virtual void Bump(); 108 __declspec(dllimport) virtual void Decrement(); 109 }; 110 111 // 'FooImport::Bump()' is the key function, so the vtable and typeinfo symbol 112 // of 'FooImport' will be defined in the TU that contains the definition of 113 // 'Bump()' (and they must be exported from there). Here, we will reference 114 // the vtable and typeinfo symbol, so we must also import them. 115 void importTest() 116 { 117 typeid(FooImport).name(); 118 } 119 120 /////////////////////////////////////////////////////////////////// 121 122 // Case (b) -- Export Aspect 123 // The class as a whole is not exported, but all non-inline virtual methods of 124 // the class are, so the vtable and typeinfo symbol must be exported. 125 // 126 // PS4-DAG: @_ZTV9FooExport ={{.*}}dllexport 127 // WI-DAG: @_ZTV9FooExport = dso_local unnamed_addr constant { 128 // PS4-DAG: @_ZTI9FooExport ={{.*}}dllexport 129 // WI-DAG: @_ZTI9FooExport = dso_local constant { 130 struct FooExport 131 { 132 virtual void getId() const {} 133 __declspec(dllexport) virtual void Bump(); 134 __declspec(dllexport) virtual void Decrement(); 135 }; 136 137 // This is the key function of the class 'FooExport', so the vtable and 138 // typeinfo symbol of 'FooExport' will be defined in this TU, and so they must 139 // be exported from this TU. 140 void FooExport::Bump() 141 { 142 FooImport f; 143 typeid(FooExport).name(); 144 } 145 146 /////////////////////////////////////////////////////////////////// 147 148 // The tests below verify that the associated vtable and typeinfo symbols are 149 // not imported/exported. These are the converse of case (b). 150 // 151 // Note that ultimately, if the module doing the importing calls a constructor 152 // of the class with the vtable, or makes a reference to the typeinfo symbol of 153 // the class, then this will result in an unresolved reference (to the vtable 154 // or typeinfo symbol) when linking the importing module, and thus a link-time 155 // failure. 156 // 157 // Note that with the Microsoft toolchain there will also be a link-time 158 // failure when linking the module doing the importing. With the Microsoft 159 // toolchain, it will be an unresolved reference to the method 'Decrement()' 160 // of the approriate class, rather than to the vtable or typeinfo symbol of 161 // the class, because Microsoft defines the vtable and typeinfo symbol (weakly) 162 // everywhere they are used. 163 164 // Converse of case (b) -- Import Aspect 165 // The class as a whole is not imported, and not all non-inline virtual methods 166 // are imported, so the vtable and typeinfo symbol are not to be imported. 167 // 168 // CHECK-PS4: @_ZTV11FooNoImport = external dso_local unnamed_addr constant { 169 // CHECK-WI: @_ZTV11FooNoImport = linkonce_odr dso_local unnamed_addr constant { 170 // CHECK-PS4: @_ZTI11FooNoImport = external dso_local constant i8*{{$}} 171 // CHECK-WI: @_ZTI11FooNoImport = linkonce_odr dso_local constant { 172 struct FooNoImport 173 { 174 virtual void getId() const {} 175 __declspec(dllimport) virtual void Bump(); 176 virtual void Decrement(); // Not imported. 177 int mCounter; 178 }; 179 180 void importNegativeTest() 181 { 182 FooNoImport f; 183 typeid(FooNoImport).name(); 184 } 185 186 /////////////////////////////////////////////////////////////////// 187 188 // Converse of case (b) -- Export Aspect 189 // The class as a whole is not exported, and not all non-inline virtual methods 190 // are exported, so the vtable and typeinfo symbol are not to be exported. 191 // 192 // SCEI_PS4-DAG: @_ZTV11FooNoImport = external unnamed_addr constant { 193 // SCEI_WI-DAG: @_ZTV11FooNoExport = dso_local unnamed_addr constant { 194 195 // WI-DAG: @_ZTV11FooNoExport = dso_local unnamed_addr constant { 196 // SCEI_PS4-DAG: @_ZTI11FooNoExport = constant { 197 // SCEI_WI-DAG: @_ZTI11FooNoExport = dso_local constant { 198 // WI-DAG: @_ZTI11FooNoExport = dso_local constant { 199 struct FooNoExport 200 { 201 virtual void getId() const {} 202 __declspec(dllexport) virtual void Bump(); 203 virtual void Decrement(); // Not exported. 204 int mCounter; 205 }; 206 207 void FooNoExport::Bump() 208 { 209 typeid(FooNoExport).name(); 210 } 211