- 
                Notifications
    
You must be signed in to change notification settings  - Fork 15.1k
 
Description
| Bugzilla Link | 17917 | 
| Version | trunk | 
| OS | Linux | 
| CC | @DougGregor | 
Extended Description
Consider:
template<bool> struct enable_if { typedef void type; };
template <class T> class Foo {};
template <class X> constexpr bool check() { return true; }
template <class X, class Enable = void> struct Bar {};
#ifdef FUNCTION_ORDERING
template<class X> void func(Bar<X, typename enable_if<check<X>()>::type>) { }
template<class T> int func(Bar<Foo<T>>) {  return 0; }
int (*p)(Bar<Foo<int>>) = func;
#else
template<typename X> struct Bar<X, typename enable_if<check<X>()>::type> {};
template<typename X> struct Bar<Foo<X>> { typedef int type; };
Bar<Foo<int>>::type bar;
#endifPer 14.5.5.2/1, the class template partial specialization partial ordering and the function template partial ordering above should behave exactly the same. But they don't: for clang, gcc, and edg, the FUNCTION_ORDERING case is accepted and the other (class ordering) case is rejected.
Morally, both cases should be rejected; this is ambiguous because the first template has the constraint that enable_if<check<X>()>::type == void, and the second template has the constraint that X == Foo<T> for some T. Clearly, neither of these implies the other.
Practically, we're missing a call to something like FinishTemplateArgumentDeduction in the FunctionTemplateDecl form of isAtLeastAsSpecializedAs: we fail to check that the deduction produces template arguments that make the deduced A compatible with the original A (as required by [temp.deduct.type]p1).