Clang rejects and gcc accepts the following code: template <typename Method> struct nsRunnableMethodTraits { }; //template <class C> struct nsRunnableMethodTraits<void __attribute__ ((regparm (0))) (C::*)()> { template <class C> struct nsRunnableMethodTraits<void (C::*)()> { typedef int base_type; }; template<typename Method> typename nsRunnableMethodTraits<Method>::base_type* NS_NewRunnableMethod(Method method) ; struct C1 { virtual void __attribute__ ((regparm (0))) FinishStream(void) { NS_NewRunnableMethod( &C1::FinishStream); } }; Changing which line make clang accept the code.
Changing which line is commented...
The analogous case is that clang accepts template <typename Method> struct nsRunnableMethodTraits; template <class C> struct nsRunnableMethodTraits<void (C::*)()> { typedef int base_type; }; template <class C> struct nsRunnableMethodTraits<void __attribute__ ((regparm (0))) (C::*)()> { typedef int base_type; }; and g++ rejects it: nsUrlClassifierProxies.ii:7:27: error: redefinition of ‘struct nsRunnableMethodTraits<void (C::*)()>’ nsUrlClassifierProxies.ii:3:27: error: previous definition of ‘struct nsRunnableMethodTraits<void (C::*)()>’
Clang is behaving correctly here. A regparm-attributed member function pointer type is distinct from a non-regparm-attributed member function pointer type, so they'll have different template specializations. GCC's behavior appears to be inconsistent here, because the types are considered equivalent for the purposes of matching template arguments, so the regparm attribute associated with the first instantiation is the one that "sticks", even if subsequent instantiations don't have the regparm attribute.