Issue |
140258
|
Summary |
[ClangCL] Incompatible behavior of explicit template instantiation combined with dllexport
|
Labels |
new issue
|
Assignees |
|
Reporter |
kikairoya
|
MSVC does not apply dllexport on explicit template instantiation definition to its inner class but able to override by attaching dllexport explicitly to inner class itself using explicit template instantiation.
Clang-cl emulates former behavior but not latter.
To reproduce:
```c++
template <typename T>
struct outer_template {
static void fn_outer();
struct inner_class {
static void fn_inner();
};
};
template <typename T>
void outer_template<T>::fn_outer() { }
template <typename T>
void outer_template<T>::inner_class::fn_inner() { }
template struct __declspec(dllexport) outer_template<int>;
```
Compile above with `> cl /FA /Fatest.asm /c test.cc` produces:
```asm
; Listing generated by Microsoft (R) Optimizing Compiler Version 19.44.35207.1
include listing.inc
INCLUDELIB LIBCMT
INCLUDELIB OLDNAMES
PUBLIC ?fn_outer@?$outer_template@H@@SAXXZ ; outer_template<int>::fn_outer
PUBLIC ??4?$outer_template@H@@QEAAAEAU0@AEBU0@@Z ; outer_template<int>::operator=
PUBLIC ??4?$outer_template@H@@QEAAAEAU0@$$QEAU0@@Z ; outer_template<int>::operator=
PUBLIC ?fn_inner@inner_class@?$outer_template@H@@SAXXZ ; outer_template<int>::inner_class::fn_inner
; Function compile flags: /Odtp
; COMDAT ?fn_inner@inner_class@?$outer_template@H@@SAXXZ
_TEXT SEGMENT
?fn_inner@inner_class@?$outer_template@H@@SAXXZ PROC ; outer_template<int>::inner_class::fn_inner, COMDAT
; File D:\tmp\test.cc
; Line 11
ret 0
?fn_inner@inner_class@?$outer_template@H@@SAXXZ ENDP ; outer_template<int>::inner_class::fn_inner
_TEXT ENDS
(snip)
; Function compile flags: /Odtp
; COMDAT ?fn_outer@?$outer_template@H@@SAXXZ
_TEXT SEGMENT
?fn_outer@?$outer_template@H@@SAXXZ PROC ; outer_template<int>::fn_outer, COMDAT
; File D:\tmp\test.cc
; Line 9
ret 0
?fn_outer@?$outer_template@H@@SAXXZ ENDP ; outer_template<int>::fn_outer
_TEXT ENDS
END
```
Asm shows outer_template<int>::inner_class::fn_inner was instantiated but `> cl test.cc /LD && objdump -p test.dll` shows
```
(snip)
[Ordinal/Name Pointer] Table -- Ordinal Base 1
Ordinal Hint Name
[ 0] +base[ 1] 0000 ??4?$outer_template@H@@QEAAAEAU0@$$QEAU0@@Z
[ 1] +base[ 2] 0001 ??4?$outer_template@H@@QEAAAEAU0@AEBU0@@Z
[ 2] +base[ 3] 0002 ?fn_outer@?$outer_template@H@@SAXXZ
The Function Table (interpreted .pdata section contents)
(snip)
```
means outer_template<int>::inner_class::fn_inner was instantiated but NOT exported. (this is the former described behavior).
In case of clang-cl, `> clang-cl /FA /Fa6.asm /c test.cc` shows
```asm
(snip)
.def "?fn_outer@?$outer_template@H@@SAXXZ";
.scl 2;
.type 32;
.endef
.section .text,"xr",discard,"?fn_outer@?$outer_template@H@@SAXXZ"
.globl "?fn_outer@?$outer_template@H@@SAXXZ" # -- Begin function ?fn_outer@?$outer_template@H@@SAXXZ
.p2align 4
"?fn_outer@?$outer_template@H@@SAXXZ": # @"?fn_outer@?$outer_template@H@@SAXXZ"
# %bb.0:
ret
# -- End function
.def "?fn_inner@inner_class@?$outer_template@H@@SAXXZ";
.scl 2;
.type 32;
.endef
.section .text,"xr",discard,"?fn_inner@inner_class@?$outer_template@H@@SAXXZ"
.globl "?fn_inner@inner_class@?$outer_template@H@@SAXXZ" # -- Begin function ?fn_inner@inner_class@?$outer_template@H@@SAXXZ
.p2align 4
"?fn_inner@inner_class@?$outer_template@H@@SAXXZ": # @"?fn_inner@inner_class@?$outer_template@H@@SAXXZ"
# %bb.0:
ret
# -- End function
.section .drectve,"yni"
.ascii " /DEFAULTLIB:libcmt.lib"
.ascii " /DEFAULTLIB:oldnames.lib"
.ascii " /EXPORT:\"??4?$outer_template@H@@QEAAAEAU0@AEBU0@@Z\""
.ascii " /EXPORT:\"??4?$outer_template@H@@QEAAAEAU0@$$QEAU0@@Z\""
.ascii " /EXPORT:\"?fn_outer@?$outer_template@H@@SAXXZ\""
.addrsig
```
says outer_template::inner_class::fn_inner was instantiated but not exported correctly.
In contrast, modifying to
```
(snip)
template struct __declspec(dllexport) outer_template<int>::inner_class;
template struct __declspec(dllexport) outer_template<int>;
```
results by MSVC
```
(snip)
[Ordinal/Name Pointer] Table -- Ordinal Base 1
Ordinal Hint Name
[ 0] +base[ 1] 0000 ??4?$outer_template@H@@QEAAAEAU0@$$QEAU0@@Z
[ 1] +base[ 2] 0001 ??4?$outer_template@H@@QEAAAEAU0@AEBU0@@Z
[ 2] +base[ 3] 0002 ??4inner_class@?$outer_template@H@@QEAAAEAU01@$$QEAU01@@Z
[ 3] +base[ 4] 0003 ??4inner_class@?$outer_template@H@@QEAAAEAU01@AEBU01@@Z
[ 4] +base[ 5] 0004 ?fn_inner@inner_class@?$outer_template@H@@SAXXZ
[ 5] +base[ 6] 0005 ?fn_outer@?$outer_template@H@@SAXXZ
The Function Table (interpreted .pdata section contents)
(snip)
```
says outer_template::inner_class::fn_inner was exported (latter described behavior) but compiling with clang-cl shows error
```
test.cc(13,17): error: an attribute list cannot appear here
13 | template struct __declspec(dllexport) outer_template<int>::inner_class;
| ^~~~~~~~~~~~~~~~~~~~~
test.cc(14,17): warning: duplicate explicit instantiation of 'inner_class' ignored as a Microsoft extension [-Wmicrosoft-template]
14 | template struct outer_template<int>;
| ^
test.cc(13,60): note: previous explicit instantiation is here
13 | template struct __declspec(dllexport) outer_template<int>::inner_class;
| ^
1 warning and 1 error generated.
```
Clang-cl should allow attaching and adding __declspec(dllexport) to inner class by using explicit template instantiation definition.
_______________________________________________
llvm-bugs mailing list
llvm-bugs@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs