PR12647: An alias template instantiation which occurs in a SFINAE context is
itself a SFINAE context.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@155621 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 128dc2f..793ee0e 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -638,8 +638,13 @@
        ++Active) 
   {
     switch(Active->Kind) {
-    case ActiveTemplateInstantiation::DefaultFunctionArgumentInstantiation:
     case ActiveTemplateInstantiation::TemplateInstantiation:
+      // An instantiation of an alias template may or may not be a SFINAE
+      // context, depending on what else is on the stack.
+      if (isa<TypeAliasTemplateDecl>(reinterpret_cast<Decl *>(Active->Entity)))
+        break;
+      // Fall through.
+    case ActiveTemplateInstantiation::DefaultFunctionArgumentInstantiation:
     case ActiveTemplateInstantiation::ExceptionSpecInstantiation:
       // This is a template instantiation, so there is no SFINAE.
       return llvm::Optional<TemplateDeductionInfo *>();
diff --git a/test/SemaCXX/alias-template.cpp b/test/SemaCXX/alias-template.cpp
index 484dd33..4bf79f8 100644
--- a/test/SemaCXX/alias-template.cpp
+++ b/test/SemaCXX/alias-template.cpp
@@ -145,3 +145,30 @@
   template<typename T, typename U> struct S;
   template<typename T> template<typename U> using SS = S<T, U>; // expected-error {{extraneous template parameter list in alias template declaration}}
 }
+
+// PR12647
+namespace SFINAE {
+  template<bool> struct enable_if; // expected-note 2{{here}}
+  template<> struct enable_if<true> { using type = void; };
+
+  template<typename T> struct is_enum { static constexpr bool value = __is_enum(T); };
+
+  template<typename T> using EnableIf = typename enable_if<T::value>::type; // expected-error {{undefined template}}
+  template<typename T> using DisableIf = typename enable_if<!T::value>::type; // expected-error {{undefined template}}
+
+  template<typename T> EnableIf<is_enum<T>> f();
+  template<typename T> DisableIf<is_enum<T>> f();
+
+  enum E { e };
+
+  int main() {
+    f<int>();
+    f<E>();
+  }
+
+  template<typename T, typename U = EnableIf<is_enum<T>>> struct fail1 {}; // expected-note {{here}}
+  template<typename T> struct fail2 : DisableIf<is_enum<T>> {}; // expected-note {{here}}
+
+  fail1<int> f1; // expected-note {{here}}
+  fail2<E> f2; // expected-note {{here}}
+}