Bladeren bron

Support dependent template args in HLSL Object templates (#5140)

HLSL objects have a special hook for validating template arguments.
Previously, this didn't handle dependent arguments.
This change skips dependent arguments, which will be checked once they are concrete.
Tex Riddell 2 jaren geleden
bovenliggende
commit
5874b72e81

+ 7 - 9
tools/clang/lib/Sema/SemaHLSL.cpp

@@ -4887,10 +4887,6 @@ public:
       return false;
     }
 
-    // TemplateTypeParm here will be construction of vector return template in matrix operator[]
-    if (type->getTypeClass() == Type::TemplateTypeParm)
-      return true;
-
     QualType qt = GetStructuralForm(type);
 
     if (requireScalar) {
@@ -5113,17 +5109,19 @@ public:
                     m_vectorTemplateDecl->getCanonicalDecl();
     bool requireScalar = isMatrix || isVector;
     
-    // Check constraints on the type. Right now we only check that template
-    // types are primitive types.
+    // Check constraints on the type.
     for (unsigned int i = 0; i < TemplateArgList.size(); i++) {
       const TemplateArgumentLoc &argLoc = TemplateArgList[i];
       SourceLocation argSrcLoc = argLoc.getLocation();
       const TemplateArgument &arg = argLoc.getArgument();
       if (arg.getKind() == TemplateArgument::ArgKind::Type) {
         QualType argType = arg.getAsType();
-        if (!IsValidTemplateArgumentType(argSrcLoc, argType, requireScalar)) {
-          // NOTE: IsValidTemplateArgumentType emits its own diagnostics
-          return true;
+        // Skip dependent types.  Types will be checked later, when concrete.
+        if (!argType->isDependentType()) {
+          if (!IsValidTemplateArgumentType(argSrcLoc, argType, requireScalar)) {
+            // NOTE: IsValidTemplateArgumentType emits its own diagnostics
+            return true;
+          }
         }
       }
       else if (arg.getKind() == TemplateArgument::ArgKind::Expression) {

+ 16 - 0
tools/clang/test/HLSL/object-template-diag-deferred.hlsl

@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -fsyntax-only -ffreestanding -verify -HV 2021 %s
+
+template<typename T>
+struct Foo {
+  T foo(Texture2D<vector<T, 4> > tex) {   /* expected-error {{'MyStruct' cannot be used as a type parameter where a scalar is required}} */
+    return tex[uint2(0,0)].x;
+  }
+};
+
+struct MyStruct {
+  float f;
+};
+
+void main() {
+  Foo<MyStruct> foo;                      /* expected-note {{in instantiation of template class 'Foo<MyStruct>' requested here}} */
+}

+ 25 - 0
tools/clang/test/HLSLFileCheck/hlsl/template/DependentTypeInObjectParam.hlsl

@@ -0,0 +1,25 @@
+// RUN: %dxc -E main -T vs_6_2 -HV 2021 -enable-16bit-types -ast-dump %s | FileCheck -check-prefixes=CHECKAST %s
+// RUN: %dxc -E main -T vs_6_2 -HV 2021 -enable-16bit-types %s | FileCheck -check-prefixes=CHECK %s
+
+// CHECKAST: -CallExpr
+// CHECKAST-NEXT: -ImplicitCastExpr
+// CHECKAST-SAME: 'float (*)(Texture2D<vector<float, 4> >)' <FunctionToPointerDecay>
+
+// CHECKAST: -CallExpr
+// CHECKAST-NEXT: -ImplicitCastExpr
+// CHECKAST-SAME: 'half (*)(Texture2D<vector<half, 4> >)' <FunctionToPointerDecay>
+
+// CHECK: call %dx.types.ResRet.f32 @dx.op.textureLoad.f32
+// CHECK: call %dx.types.ResRet.f16 @dx.op.textureLoad.f16
+
+template<typename T>
+T foo(Texture2D<vector<T, 4> > tex) {
+  return tex[uint2(0,0)].x;
+}
+
+Texture2D<float4> Tex;
+Texture2D<vector<float16_t, 4> > Tex2;
+
+float main() : OUT {
+  return foo(Tex) + foo(Tex2);
+}

+ 5 - 0
tools/clang/unittests/HLSL/VerifierTest.cpp

@@ -108,6 +108,7 @@ public:
   TEST_METHOD(GloballyCoherentTemplateErrors)
   TEST_METHOD(RunBitFieldAnnotations)
   TEST_METHOD(RunUDTByteAddressBufferLoad)
+  TEST_METHOD(RunObjectTemplateDiagDeferred)
   void CheckVerifies(const wchar_t* path) {
     WEX::TestExecution::SetVerifyOutput verifySettings(WEX::TestExecution::VerifyOutputSettings::LogOnlyFailures);
     const char startMarker[] = "%clang_cc1";
@@ -473,3 +474,7 @@ TEST_F(VerifierTest, RunBitFieldAnnotations) {
 TEST_F(VerifierTest, RunUDTByteAddressBufferLoad) {
   CheckVerifiesHLSL(L"template-udt-load.hlsl");
 }
+
+TEST_F(VerifierTest, RunObjectTemplateDiagDeferred) {
+  CheckVerifiesHLSL(L"object-template-diag-deferred.hlsl");
+}

+ 2 - 0
utils/hct/VerifierHelper.py

@@ -83,6 +83,7 @@ VerifierTests = {
     'RunMintypesPromotionWarnings':              'mintypes-promotion-warnings.hlsl',
     'RunMoreOperators':                          'more-operators.hlsl',
     'RunObjectOperators':                        'object-operators.hlsl',
+    'RunObjectTemplateDiagDeferred':             'object-template-diag-deferred.hlsl',
     'RunOperatorOverloadingForNewDelete':        'overloading-new-delete-errors.hlsl',
     'RunOperatorOverloadingNotDefinedBinaryOp':  'use-undefined-overloaded-operator.hlsl',
     'RunPackReg':                                'packreg.hlsl',
@@ -129,6 +130,7 @@ fxcExcludedTests = [
     'RunIncompleteType',
     'RunIntrinsicExamples',
     'RunMatrixSyntaxExactPrecision',
+    'RunObjectTemplateDiagDeferred',
     'RunOperatorOverloadingForNewDelete',
     'RunOperatorOverloadingNotDefinedBinaryOp',
     'RunRayTracings',