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

Reply via email to