The following code (which is a simplified repro from a much larger function introspection library) used to work with GCC 9.x, but does not with the update to 10.1. Is this a compiler/toolchain bug or is there something incorrect about the code that I'm missing (obviously it's non-standard and relying on the behavior of vendor extensions)? >>>>>>>>>>>>>>> #if defined(_MSC_VER) #define CC_FASTCALL __fastcall #define CC_STDCALL __stdcall #else #define CC_FASTCALL __attribute__((fastcall)) #define CC_STDCALL __attribute__((stdcall)) #endif template <typename FuncT> struct FuncResult; template <typename R, typename... Args> struct FuncResult<R(*)(Args...)> { using type = R; }; template <typename R, typename... Args> struct FuncResult<R(CC_FASTCALL*)(Args...)> { using type = R; }; template <typename R, typename... Args> struct FuncResult<R(CC_STDCALL*)(Args...)> { using type = R; }; template <typename FuncT> auto wrap(FuncT f) -> typename FuncResult<FuncT>::type { return f(1, 2, 3); } int CC_FASTCALL func1(int x, int y, int z) { return x + y + z; } int CC_STDCALL func2(int x, int y, int z) { return x + y + z; } int main() { return wrap(&func1) + wrap(&func2); } >>>>>>>>>>>>>>> With the calling convention specific specialization: >>>>>>>>>>>>>>> main.cpp:19:8: error: redefinition of 'struct FuncResult<R (*)(Args ...)>' 19 | struct FuncResult<R(CC_FASTCALL*)(Args...)> | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ main.cpp:13:8: note: previous definition of 'struct FuncResult<R (*)(Args ...)>' 13 | struct FuncResult<R(*)(Args...)> | ^~~~~~~~~~~~~~~~~~~~~~~~~ >>>>>>>>>>>>>>> Without the calling convention specific specialization: >>>>>>>>>>>>>>> main.cpp:50:23: error: no matching function for call to 'wrap(int (__attribute__((fastcall)) *)(int, int, int))' 50 | return wrap(&func1) + wrap(&func2); | ^ main.cpp:33:6: note: candidate: 'template<class FuncT> typename FuncResult<FuncT>::type wrap(FuncT)' 33 | auto wrap(FuncT f) -> typename FuncResult<FuncT>::type | ^~~~ main.cpp:33:6: note: template argument deduction/substitution failed: main.cpp: In substitution of 'template<class FuncT> typename FuncResult<FuncT>::type wrap(FuncT) [with FuncT = int (__attribute__((fastcall)) *)(int, int, int)]': main.cpp:50:23: required from here main.cpp:33:6: error: invalid use of incomplete type 'struct FuncResult<int (__attribute__((fastcall)) *)(int, int, int)>' main.cpp:10:8: note: declaration of 'struct FuncResult<int (__attribute__((fastcall)) *)(int, int, int)>' 10 | struct FuncResult; | ^~~~~~~~~~ >>>>>>>>>>>>>>> Damned if you do, damned if you don't. Is anyone aware of a workaround for this? It's blocking my build and I can't figure out an easy workaround. Thanks.
$ g++ -v Using built-in specs. COLLECT_GCC=C:\Redacted\msys2-x86_64-rolling\mingw32\bin\g++.exe COLLECT_LTO_WRAPPER=C:/Redacted/msys2-x86_64-rolling/mingw32/bin/../lib/gcc/i686-w64-mingw32/10.1.0/lto-wrapper.exe Target: i686-w64-mingw32 Configured with: ../gcc-10.1.0/configure --prefix=/mingw32 --with-local-prefix=/mingw32/local --build=i686-w64-mingw32 --host=i686-w64-mingw32 --target=i686-w64-mingw32 --with-native-system-header-dir=/mingw32/i686-w64-mingw32/include --libexecdir=/mingw32/lib --enable-bootstrap --with-arch=i686 --with-tune=generic --enable-languages=c,lto,c++,fortran,ada,objc,obj-c++ --enable-shared --enable-static --enable-libatomic --enable-threads=posix --enable-graphite --enable-fully-dynamic-string --enable-libstdcxx-filesystem-ts=yes --enable-libstdcxx-time=yes --disable-libstdcxx-pch --disable-libstdcxx-debug --disable-isl-version-check --enable-lto --enable-libgomp --disable-multilib --enable-checking=release --disable-rpath --disable-win32-registry --disable-nls --disable-werror --disable-symvers --disable-plugin --with-libiconv --with-system-zlib --with-gmp=/mingw32 --with-mpfr=/mingw32 --with-mpc=/mingw32 --with-isl=/mingw32 --with-pkgversion='Rev2, Built by MSYS2 project' --with-bugurl=https://sourceforge.net/projects/msys2 --with-gnu-as --with-gnu-ld --disable-sjlj-exceptions --with-dwarf2 Thread model: posix Supported LTO compression algorithms: zlib zstd gcc version 10.1.0 (Rev2, Built by MSYS2 project)
Rejected since r10-7998-g5f1cd1da1a805c3d00332da45c3ab78a3931af63 , on Linux needs -m32.
The master branch has been updated by Jason Merrill <jason@gcc.gnu.org>: https://gcc.gnu.org/g:7e7d9fcff56385812764cba63e1ebf6f4c6c0320 commit r11-662-g7e7d9fcff56385812764cba63e1ebf6f4c6c0320 Author: Jason Merrill <jason@redhat.com> Date: Mon May 25 19:04:05 2020 -0400 c++: Fix stdcall attribute in template. [PR95222] Another case that breaks with my fix for PR90750: we shouldn't move type attributes in TYPENAME context either, as there's no decl for them to move to. gcc/cp/ChangeLog: PR c++/95222 * decl.c (grokdeclarator): Don't shift attributes in TYPENAME context. gcc/testsuite/ChangeLog: PR c++/95222 * g++.dg/ext/tmplattr10.C: New test.
The releases/gcc-10 branch has been updated by Jason Merrill <jason@gcc.gnu.org>: https://gcc.gnu.org/g:0c473d8f32510fcc96d584ee5099b856cfd3d8d6 commit r10-8189-g0c473d8f32510fcc96d584ee5099b856cfd3d8d6 Author: Jason Merrill <jason@redhat.com> Date: Mon May 25 19:04:05 2020 -0400 c++: Fix stdcall attribute in template. [PR95222] Another case that breaks with my fix for PR90750: we shouldn't move type attributes in TYPENAME context either, as there's no decl for them to move to. gcc/cp/ChangeLog: PR c++/95222 * decl.c (grokdeclarator): Don't shift attributes in TYPENAME context. gcc/testsuite/ChangeLog: PR c++/95222 * g++.dg/ext/tmplattr10.C: New test. (cherry picked from commit 7e7d9fcff56385812764cba63e1ebf6f4c6c0320)
Fixed for 10.2/11.
The new testcase FAILs on 32-bit Solaris/x86: +FAIL: g++.dg/ext/tmplattr10.C -std=c++98 (test for excess errors) Excess errors: /vol/gcc/src/hg/master/local/gcc/testsuite/g++.dg/ext/tmplattr10.C:15:31: error: variadic templates only available with '-std=c++11' or '-std=gnu++11' /vol/gcc/src/hg/master/local/gcc/testsuite/g++.dg/ext/tmplattr10.C:16:28: error: variadic templates only available with '-std=c++11' or '-std=gnu++11' /vol/gcc/src/hg/master/local/gcc/testsuite/g++.dg/ext/tmplattr10.C:18:11: error: expected nested-name-specifier before 'type' /vol/gcc/src/hg/master/local/gcc/testsuite/g++.dg/ext/tmplattr10.C:21:31: error: variadic templates only available with '-std=c++11' or '-std=gnu++11' /vol/gcc/src/hg/master/local/gcc/testsuite/g++.dg/ext/tmplattr10.C:22:39: error: variadic templates only available with '-std=c++11' or '-std=gnu++11' /vol/gcc/src/hg/master/local/gcc/testsuite/g++.dg/ext/tmplattr10.C:24:11: error: expected nested-name-specifier before 'type' /vol/gcc/src/hg/master/local/gcc/testsuite/g++.dg/ext/tmplattr10.C:27:31: error: variadic templates only available with '-std=c++11' or '-std=gnu++11' /vol/gcc/src/hg/master/local/gcc/testsuite/g++.dg/ext/tmplattr10.C:28:38: error: variadic templates only available with '-std=c++11' or '-std=gnu++11' /vol/gcc/src/hg/master/local/gcc/testsuite/g++.dg/ext/tmplattr10.C:30:11: error: expected nested-name-specifier before 'type' /vol/gcc/src/hg/master/local/gcc/testsuite/g++.dg/ext/tmplattr10.C:34:6: error: ISO C++ forbids declaration of 'wrap' with no type [-fpermissive] /vol/gcc/src/hg/master/local/gcc/testsuite/g++.dg/ext/tmplattr10.C:34:1: error: top-level declaration of 'wrap' specifies 'auto' /vol/gcc/src/hg/master/local/gcc/testsuite/g++.dg/ext/tmplattr10.C:34:51: error: trailing return type only available with '-std=c++11' or '-std=gnu++11' /vol/gcc/src/hg/master/local/gcc/testsuite/g++.dg/ext/tmplattr10.C:51:12: error: 'wrap' was not declared in this scope
Testcase fixed.
This bug can also manifest as wrong-code, e.g. >>>>>>>>>>>>>>> template<bool bIsStdcall, typename T> struct func_ptr_t; template<typename T> struct func_ptr_t<false,T> { using type = void(*)(T); }; template<typename T> struct func_ptr_t<true,T> { #if 1 using type = void(__attribute__((__stdcall__))*)(T); #else using type = void(__attribute__((__stdcall__))*)(int); // this works, using T is important somehow #endif }; #if 1 using foo_stdcall_ptr = func_ptr_t<true,int>::type; using foo_cdecl_ptr = func_ptr_t<false,int>::type; #else using foo_stdcall_ptr = void(__attribute__((__stdcall__))*)(int,int); using foo_cdecl_ptr = void(*)(int,int); #endif foo_stdcall_ptr foo_stdcall; foo_cdecl_ptr foo_cdecl; void bar_stdcall() { foo_stdcall(1); } void bar_cdecl() { foo_cdecl(1); } >>>>>>>>>>>>>>> Should compile so that the bar_stdcall versions pops fewer bytes off the stack (as foo_stdcall already cleaned up its own arguments). >>>>>>>>>>>>>>> --- bar_cdecl.S 2021-03-09 00:54:58.404022904 +0000 +++ bar_stdcall.S 2021-03-09 00:52:07.900015002 +0000 @@ -1,15 +1,15 @@ -<bar_cdecl()>: +<bar_stdcall()>: 0: f3 0f 1e fb endbr32 4: 55 push %ebp 5: 89 e5 mov %esp,%ebp 7: 83 ec 08 sub $0x8,%esp - a: e8 fc ff ff ff call 32 <bar_cdecl()+0xb> + a: e8 fc ff ff ff call b <bar_stdcall()+0xb> f: 05 01 00 00 00 add $0x1,%eax 14: 8b 80 00 00 00 00 mov 0x0(%eax),%eax 1a: 83 ec 0c sub $0xc,%esp 1d: 6a 01 push $0x1 1f: ff d0 call *%eax - 21: 83 c4 10 add $0x10,%esp + 21: 83 c4 0c add $0xc,%esp 24: 90 nop 25: c9 leave 26: c3 ret >>>>>>>>>>>>>>> But doesn't in 9.4, 10.0, and 10.1 (seems to be fixed again in 10.2+, presumably per this fix). I mention this only because I finally found this relevant PR, and perhaps knowing it might affect decisions about which branches should get fixed - e.g. 9.x is in stage 4 but this is a 9.3.0->9.4.0 regression (presumably PR090750), and also wrong-code. But we were able to work around it, and so I'm not directly arguing for (or against) a backport to Ubuntu 20.04 compiler **is** affected despite claiming to be 9.3.0 - Ubuntu has seemingly backported the gcc 9 branch through 4ad02cfb768 (git-updates.patch in gcc-9_9.3.0-17ubuntu1~20.04.debian.tar.xz). But I'll raise that separately in their bug tracker.
I accidentally dropped a word, meant to say: I'm not directly arguing for (or against) a backport to (a hypothetical 9.5.0) Just noting that this issue could also manifest as wrong-code, for consideration in case there's going to be one.