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