Init template support.
diff --git a/tools/clang/lib/Parse/ParseDecl.cpp b/tools/clang/lib/Parse/ParseDecl.cpp
index ff02da0..df1de25 100644
--- a/tools/clang/lib/Parse/ParseDecl.cpp
+++ b/tools/clang/lib/Parse/ParseDecl.cpp
@@ -1925,13 +1925,6 @@
   Decl *OwnedType = nullptr;
   switch (Tok.getKind()) {
   case tok::kw_template:
-    // HLSL Change Starts
-    if (getLangOpts().HLSL) {
-      Diag(Tok, diag::err_hlsl_reserved_keyword) << Tok.getName();
-      SkipMalformedDecl();
-      return DeclGroupPtrTy();
-    }
-    // HLSL Change Ends
     ProhibitAttributes(attrs);
     SingleDecl = ParseDeclarationStartingWithTemplate(Context, DeclEnd);
     break;
@@ -4048,7 +4041,7 @@
     case tok::kw_union: {
       // HLSL Change Starts
       if (getLangOpts().HLSL) {
-        if (Tok.is(tok::kw_union) || Tok.is(tok::kw___interface)) {
+        if (Tok.is(tok::kw___interface)) {
           goto HLSLReservedKeyword;
         }
       }
diff --git a/tools/clang/lib/Parse/ParseDeclCXX.cpp b/tools/clang/lib/Parse/ParseDeclCXX.cpp
index 1dd1e38..8a26f50 100644
--- a/tools/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/tools/clang/lib/Parse/ParseDeclCXX.cpp
@@ -2347,13 +2347,6 @@
   if (Tok.is(tok::kw_template)) {
     assert(!TemplateInfo.TemplateParams &&
            "Nested template improperly parsed?");
-    // HLSL Change Start - disallow template members
-    if (getLangOpts().HLSL) {
-      Diag(Tok, diag::err_hlsl_reserved_keyword) << Tok.getName();
-      SkipUntil(tok::r_brace, StopAtSemi);
-      return;
-    }
-    // HLSL Change End
     SourceLocation DeclEnd;
     ParseDeclarationStartingWithTemplate(Declarator::MemberContext, DeclEnd,
                                          AS, AccessAttrs);
diff --git a/tools/clang/lib/Parse/ParseTemplate.cpp b/tools/clang/lib/Parse/ParseTemplate.cpp
index ea9c804..546b802 100644
--- a/tools/clang/lib/Parse/ParseTemplate.cpp
+++ b/tools/clang/lib/Parse/ParseTemplate.cpp
@@ -29,7 +29,6 @@
                                              SourceLocation &DeclEnd,
                                              AccessSpecifier AS,
                                              AttributeList *AccessAttrs) {
-  assert(!getLangOpts().HLSL && "no template parsing is supported in HLSL"); // HLSL Change
   ObjCDeclContextSwitch ObjCDC(*this);
   
   if (Tok.is(tok::kw_template) && NextToken().isNot(tok::less)) {
@@ -63,7 +62,6 @@
                                                  SourceLocation &DeclEnd,
                                                  AccessSpecifier AS,
                                                  AttributeList *AccessAttrs) {
-  assert(!getLangOpts().HLSL && "no template parsing is supported in HLSL"); // HLSL Change
   assert(Tok.isOneOf(tok::kw_export, tok::kw_template) &&
          "Token does not start a template declaration.");
 
@@ -177,7 +175,6 @@
                                        SourceLocation &DeclEnd,
                                        AccessSpecifier AS,
                                        AttributeList *AccessAttrs) {
-  assert(!getLangOpts().HLSL && "no template parsing is supported in HLSL"); // HLSL Change
   assert(TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate &&
          "Template information required");
 
@@ -340,7 +337,6 @@
                                SmallVectorImpl<Decl*> &TemplateParams,
                                      SourceLocation &LAngleLoc,
                                      SourceLocation &RAngleLoc) {
-  assert(!getLangOpts().HLSL && "no template parsing is supported in HLSL"); // HLSL Change
   // Get the template parameter list.
   if (!TryConsumeToken(tok::less, LAngleLoc)) {
     Diag(Tok.getLocation(), diag::err_expected_less_after) << "template";
@@ -379,7 +375,6 @@
 bool
 Parser::ParseTemplateParameterList(unsigned Depth,
                              SmallVectorImpl<Decl*> &TemplateParams) {
-  assert(!getLangOpts().HLSL && "no template parsing is supported in HLSL"); // HLSL Change
   while (1) {
     if (Decl *TmpParam
           = ParseTemplateParameter(Depth, TemplateParams.size())) {
@@ -413,7 +408,6 @@
 /// \brief Determine whether the parser is at the start of a template
 /// type parameter.
 bool Parser::isStartOfTemplateTypeParameter() {
-  assert(!getLangOpts().HLSL && "no template parsing is supported in HLSL"); // HLSL Change
   if (Tok.is(tok::kw_class)) {
     // "class" may be the start of an elaborated-type-specifier or a
     // type-parameter. Per C++ [temp.param]p3, we prefer the type-parameter.
@@ -490,7 +484,6 @@
 ///         'template' '<' template-parameter-list '>' 'class' identifier[opt]
 ///               = id-expression
 Decl *Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) {
-  assert(!getLangOpts().HLSL && "no template parsing is supported in HLSL"); // HLSL Change
   if (isStartOfTemplateTypeParameter())
     return ParseTypeParameter(Depth, Position);
 
@@ -513,7 +506,6 @@
 ///         'typename' ...[opt][C++0x] identifier[opt]
 ///         'typename' identifier[opt] '=' type-id
 Decl *Parser::ParseTypeParameter(unsigned Depth, unsigned Position) {
-  assert(!getLangOpts().HLSL && "no template parsing is supported in HLSL"); // HLSL Change
   assert(Tok.isOneOf(tok::kw_class, tok::kw_typename) &&
          "A type-parameter starts with 'class' or 'typename'");
 
@@ -577,7 +569,6 @@
 ///         'typename'       [C++1z]
 Decl *
 Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) {
-  assert(!getLangOpts().HLSL && "no template parsing is supported in HLSL"); // HLSL Change
   assert(Tok.is(tok::kw_template) && "Expected 'template' keyword");
 
   // Handle the template <...> part.
@@ -684,7 +675,6 @@
 ///         parameter-declaration
 Decl *
 Parser::ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position) {
-  assert(!getLangOpts().HLSL && "no template parsing is supported in HLSL"); // HLSL Change
   // Parse the declaration-specifiers (i.e., the type).
   // FIXME: The type should probably be restricted in some way... Not all
   // declarators (parts of declarators?) are accepted for parameters.
@@ -1359,7 +1349,6 @@
 
 /// \brief Late parse a C++ function template in Microsoft mode.
 void Parser::ParseLateTemplatedFuncDef(LateParsedTemplate &LPT) {
-  assert(!getLangOpts().HLSL && "no template parsing is supported in HLSL"); // HLSL Change
   if (!LPT.D)
      return;
 
@@ -1450,7 +1439,6 @@
 
 /// \brief Lex a delayed template function for late parsing.
 void Parser::LexTemplateFunctionForLateParsing(CachedTokens &Toks) {
-  assert(!getLangOpts().HLSL && "no template parsing is supported in HLSL"); // HLSL Change
   tok::TokenKind kind = Tok.getKind();
   if (!ConsumeAndStoreFunctionPrologue(Toks)) {
     // Consume everything up to (and including) the matching right brace.
diff --git a/tools/clang/lib/Sema/SemaHLSL.cpp b/tools/clang/lib/Sema/SemaHLSL.cpp
index a1cb1fa..be8568f 100644
--- a/tools/clang/lib/Sema/SemaHLSL.cpp
+++ b/tools/clang/lib/Sema/SemaHLSL.cpp
@@ -74,7 +74,7 @@
   AR_BASIC_NONE,
   AR_BASIC_UNKNOWN,
   AR_BASIC_NOCAST,
-
+  AR_BASIC_DEPENDENT,
   //
   // The following pseudo-entries represent higher-level
   // object types that are treated as units.
@@ -371,6 +371,7 @@
   0,            // AR_BASIC_NONE
   BPROP_OTHER,  // AR_BASIC_UNKNOWN
   BPROP_OTHER,  // AR_BASIC_NOCAST
+  0,            // AR_BASIC_DEPENDENT
 
   //
   // The following pseudo-entries represent higher-level
@@ -581,6 +582,7 @@
   AR_TOBJ_INNER_OBJ, // Represents a built-in inner object, such as an 
                      // indexer object used to implement .mips[1].
   AR_TOBJ_STRING,    // Represents a string
+  AR_TOBJ_DEPENDENT, // Dependent type for template.
 };
 
 enum TYPE_CONVERSION_FLAGS
@@ -1529,6 +1531,7 @@
   "<none>",
   "<unknown>",
   "<nocast>",
+  "<dependent>",
   "<pointer>",
   "enum class",
 
@@ -3714,7 +3717,8 @@
         return AR_TOBJ_MATRIX;
       else if (decl == m_vectorTemplateDecl)
         return AR_TOBJ_VECTOR;
-      DXASSERT(decl->isImplicit(), "otherwise object template decl is not set to implicit");
+      else if (!decl->isImplicit())
+        return AR_TOBJ_COMPOUND;
       return AR_TOBJ_OBJECT;
     }
 
@@ -3782,6 +3786,9 @@
     if (type->isPointerType()) {
       return hlsl::IsPointerStringType(type) ? AR_TOBJ_STRING : AR_TOBJ_POINTER;
     }
+    if (type->isDependentType()) {
+      return AR_TOBJ_DEPENDENT;
+    }
     if (type->isStructureOrClassType()) {
       const RecordType* recordType = type->getAs<RecordType>();
       return ClassifyRecordType(recordType);
@@ -3913,6 +3920,7 @@
       case BuiltinType::Min10Float: return AR_BASIC_MIN10FLOAT;
       case BuiltinType::LitFloat: return AR_BASIC_LITERAL_FLOAT;
       case BuiltinType::LitInt: return AR_BASIC_LITERAL_INT;
+      case BuiltinType::Dependent: return AR_BASIC_DEPENDENT;
       default:
         // Only builtin types that have basickind equivalents.
         break;
@@ -8542,6 +8550,9 @@
   bool requiresIntegrals,
   bool requiresNumerics)
 {
+  if (elementKind == AR_BASIC_DEPENDENT)
+    return true;
+
   if (requiresIntegrals || requiresNumerics)
   {
     if (!IsObjectKindPrimitiveAggregate(objectKind))
@@ -9196,8 +9207,10 @@
 
   // Get information about the function we have.
   CXXMethodDecl* functionMethod = dyn_cast<CXXMethodDecl>(FunctionTemplate->getTemplatedDecl());
-  DXASSERT(functionMethod != nullptr,
-    "otherwise this is standalone function rather than a method, which isn't supported in the HLSL object model");
+  if (!functionMethod) {
+    // standalone function.
+    return Sema::TemplateDeductionResult::TDK_Invalid;
+  }
   CXXRecordDecl* functionParentRecord = functionMethod->getParent();
   DXASSERT(functionParentRecord != nullptr, "otherwise function is orphaned");
   QualType objectElement = GetFirstElementTypeFromDecl(functionParentRecord);
@@ -9255,6 +9268,11 @@
   size_t intrinsicCount = 0;
   const char* objectName = nullptr;
   FindIntrinsicTable(FunctionTemplate->getDeclContext(), &objectName, &intrinsics, &intrinsicCount);
+  // user-defined template object.
+  if (objectName == nullptr && intrinsics == nullptr) {
+    return Sema::TemplateDeductionResult::TDK_Invalid;
+  }
+
   DXASSERT(objectName != nullptr &&
     (intrinsics != nullptr || m_intrinsicTables.size() > 0),
     "otherwise FindIntrinsicTable failed to lookup a valid object, "
diff --git a/tools/clang/test/HLSL/cpp-errors-hv2015.hlsl b/tools/clang/test/HLSL/cpp-errors-hv2015.hlsl
index b5655b8..0488a10 100644
--- a/tools/clang/test/HLSL/cpp-errors-hv2015.hlsl
+++ b/tools/clang/test/HLSL/cpp-errors-hv2015.hlsl
@@ -230,7 +230,7 @@
 
 typedef void VOID_TYPE;
 
-template <typename T> // expected-error {{'template' is a reserved keyword in HLSL}}
+template <typename T>
 int fn_template(T t)
 {
   return (int)t;
@@ -332,7 +332,7 @@
 }
 
 struct s_with_template_member {
-  template<typename T> T fn(); // expected-error {{'template' is a reserved keyword in HLSL}}
+  template<typename T> T fn();
 };
 
 struct s_with_using {
@@ -578,7 +578,7 @@
 
   Texture2D<::c_outer_fn> local_texture; // expected-error {{'::c_outer_fn' cannot be used as a type parameter}}
   ::new local_new; // expected-error {{new' is a reserved keyword in HLSL}}
-  ::template foo local_template; // expected-error {{'template' is a reserved keyword in HLSL}} expected-error {{unknown type name 'foo'}}
+  ::template foo local_template; // expected-error {{'template' is a reserved keyword in HLSL}}  expected-error {{unknown type name 'foo'}}
 
   class CInlineWithTry {
     void fn()
diff --git a/tools/clang/test/HLSL/cpp-errors.hlsl b/tools/clang/test/HLSL/cpp-errors.hlsl
index 601933c..1c6b579 100644
--- a/tools/clang/test/HLSL/cpp-errors.hlsl
+++ b/tools/clang/test/HLSL/cpp-errors.hlsl
@@ -230,7 +230,7 @@
 
 typedef void VOID_TYPE;
 
-template <typename T> // expected-error {{'template' is a reserved keyword in HLSL}}
+template <typename T>
 int fn_template(T t)
 {
   return (int)t;
@@ -332,7 +332,7 @@
 }
 
 struct s_with_template_member {
-  template<typename T> T fn(); // expected-error {{'template' is a reserved keyword in HLSL}}
+  template<typename T> T fn();
 };
 
 struct s_with_using {
diff --git a/tools/clang/test/HLSLFileCheck/hlsl/template/templateFunc.hlsl b/tools/clang/test/HLSLFileCheck/hlsl/template/templateFunc.hlsl
new file mode 100644
index 0000000..fc70129
--- /dev/null
+++ b/tools/clang/test/HLSLFileCheck/hlsl/template/templateFunc.hlsl
@@ -0,0 +1,12 @@
+// RUN: %dxc -E main -T ps_6_0 %s | FileCheck %s
+
+// CHECK:define void @main
+
+template<typename T>
+T foo(T t0, T t1) {
+  return sin(t0) * cos(t1);
+}
+
+float2 main(float4 a:A) : SV_Target {
+  return foo(a.x, a.y) + foo(a.xy, a.zw);
+}
\ No newline at end of file
diff --git a/tools/clang/test/HLSLFileCheck/hlsl/template/templateMethod.hlsl b/tools/clang/test/HLSLFileCheck/hlsl/template/templateMethod.hlsl
new file mode 100644
index 0000000..67042d0
--- /dev/null
+++ b/tools/clang/test/HLSLFileCheck/hlsl/template/templateMethod.hlsl
@@ -0,0 +1,18 @@
+// RUN: %dxc -E main -T ps_6_0 %s | FileCheck %s
+
+// CHECK:define void @main
+
+struct Test {
+
+template<typename T>
+T foo(T t) {
+  return sin(t);
+}
+
+};
+
+float2 main(float4 a:A) : SV_Target {
+  Test t0;
+  Test t1;
+  return t0.foo<float>(a.y) + t1.foo<float2>(a.zw);
+}
\ No newline at end of file
diff --git a/tools/clang/test/HLSLFileCheck/hlsl/template/templateStruct.hlsl b/tools/clang/test/HLSLFileCheck/hlsl/template/templateStruct.hlsl
new file mode 100644
index 0000000..8094d6b
--- /dev/null
+++ b/tools/clang/test/HLSLFileCheck/hlsl/template/templateStruct.hlsl
@@ -0,0 +1,14 @@
+// RUN: %dxc -E main -T ps_6_0 %s | FileCheck %s
+
+// CHECK:define void @main
+
+template<typename T>
+struct TS {
+  T t;
+};
+
+struct TS<float4> ts;
+
+float4 main() : SV_Target {
+  return ts.t;
+}
\ No newline at end of file
diff --git a/tools/clang/test/HLSLFileCheck/hlsl/template/templateStructFunc.hlsl b/tools/clang/test/HLSLFileCheck/hlsl/template/templateStructFunc.hlsl
new file mode 100644
index 0000000..7fd5fc9
--- /dev/null
+++ b/tools/clang/test/HLSLFileCheck/hlsl/template/templateStructFunc.hlsl
@@ -0,0 +1,21 @@
+// RUN: %dxc -E main -T ps_6_0 %s | FileCheck %s
+
+// CHECK:define void @main
+
+template<typename T>
+struct Test {
+
+T t;
+T foo(T t1) {
+  return sin(t) * cos(t1);
+}
+
+};
+
+float2 main(float4 a:A) : SV_Target {
+  Test<float> t0;
+  t0.t = a.x;
+  Test<float2> t1;
+  t1.t = a.xy;
+  return t0.foo(a.y) + t1.foo(a.zw);
+}
\ No newline at end of file
diff --git a/tools/clang/test/HLSLFileCheck/hlsl/template/templateStructFunc2.hlsl b/tools/clang/test/HLSLFileCheck/hlsl/template/templateStructFunc2.hlsl
new file mode 100644
index 0000000..a1b224d
--- /dev/null
+++ b/tools/clang/test/HLSLFileCheck/hlsl/template/templateStructFunc2.hlsl
@@ -0,0 +1,13 @@
+// RUN: %dxc -E main -T ps_6_0 %s | FileCheck %s
+
+// CHECK:define void @main
+
+
+template<typename T>
+T foo(T t0, T t1) {
+  return sin(t0) * cos(t1);
+}
+
+float2 main(float4 a:A) : SV_Target {
+  return foo(a.x, a.y) + foo(a.xy, a.zw);
+}
\ No newline at end of file