Bug 516338 - Detect substitution failure during instantiation of dependent alias template arguments

Change-Id: Ia97e0632e17b4047a0fe35c05be72dab75e43d5c
diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2TemplateTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2TemplateTests.java
index 47f4a66..8ea14a8 100644
--- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2TemplateTests.java
+++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2TemplateTests.java
@@ -10131,6 +10131,22 @@
 		parseAndCheckBindings();
 	}
 	
+	//	template <typename> 
+	//	using void_t = void;
+	//
+	//	template <typename T, typename = void>
+	//	struct Waldo {
+	//	    using type = T;
+	//	};
+	//
+	//	template <typename T>
+	//	struct Waldo<T, void_t<typename T::type>> {};
+	//
+	//	Waldo<int>::type foo();
+	public void testSFINAEInAliasTemplateArgs_516338() throws Exception {
+		parseAndCheckBindings();
+	}
+	
 	//	template <typename, typename>
 	//	struct is_same {
 	//	    static constexpr bool value = false;
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPTemplates.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPTemplates.java
index c21ff48..ee3cce1 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPTemplates.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPTemplates.java
@@ -1536,7 +1536,7 @@
 					return type;
 				}
 			}
-
+			
 			if (type instanceof TypeOfUnknownMember) {
 				IBinding binding = resolveUnknown(((TypeOfUnknownMember) type).getUnknownMember(), context);
 				if (binding instanceof IType) {
@@ -1592,6 +1592,27 @@
 				}
 			}
 
+			// An alias template instance may have dependent arguments that don't contribute 
+			// to the target type but can SFINAE out during instantiation, so it's not
+			// sufficient to handle it in the ITypeContainer case.
+			if (type instanceof ICPPAliasTemplateInstance) {
+				ICPPAliasTemplateInstance instance = (ICPPAliasTemplateInstance) type;
+				ICPPAliasTemplate template = instance.getTemplateDefinition();
+				ICPPTemplateArgument[] args = instance.getTemplateArguments();
+				ICPPTemplateArgument[] newArgs = instantiateArguments(args, context, true);
+				if (newArgs == null) {
+					return (IType) createProblem(template, 
+							IProblemBinding.SEMANTIC_INVALID_TEMPLATE_ARGUMENTS, context.getPoint());
+				}
+				if (args != newArgs) {
+					IType target = instantiateType(instance.getType(), context);
+					CPPTemplateParameterMap map = 
+							instantiateArgumentMap(instance.getTemplateParameterMap(), context);
+					return new CPPAliasTemplateInstance(template, target, instance.getOwner(), map, newArgs);
+				}
+				return type;
+			}
+
 			if (type instanceof ITypeContainer) {
 				final ITypeContainer typeContainer = (ITypeContainer) type;
 				IType nestedType = typeContainer.getType();