diff --git a/tools/clang/include/clang/Basic/Attr.td b/tools/clang/include/clang/Basic/Attr.td index 89c9a1b022..21b57c8934 100644 --- a/tools/clang/include/clang/Basic/Attr.td +++ b/tools/clang/include/clang/Basic/Attr.td @@ -1188,6 +1188,15 @@ def HLSLSubObject : InheritableAttr { let Args = [UnsignedArgument<"SubObjKindUint">, UnsignedArgument<"HitGroupType">]; } +// Marks builtin record types that have no deducible value form, so 'auto' must +// not infer them: the inner indexer objects behind .mips / .sample, and the +// subobject types used to configure DXR state objects. +def HLSLNonAutoDeducible : InheritableAttr { + let Spellings = []; // No spellings! + let Subjects = SubjectList<[CXXRecord]>; + let Documentation = [Undocumented]; +} + // HLSL HitObject Attribute def HLSLHitObject : InheritableAttr { diff --git a/tools/clang/include/clang/Basic/DiagnosticSemaKinds.td b/tools/clang/include/clang/Basic/DiagnosticSemaKinds.td index a9f9f7d5fa..e3e472e48e 100644 --- a/tools/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/tools/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -8070,6 +8070,9 @@ def err_hlsl_auto_descriptor_heap : Error< "'auto' cannot deduce the type of '%select{ResourceDescriptorHeap|SamplerDescriptorHeap}0'; " "use a specific resource or sampler type instead">; +def err_hlsl_auto_undeducible_type : Error< + "'auto' cannot deduce type %0">; + // HLSL Change Ends // SPIRV Change Starts diff --git a/tools/clang/include/clang/Sema/SemaHLSL.h b/tools/clang/include/clang/Sema/SemaHLSL.h index 1917a9277a..be17274521 100644 --- a/tools/clang/include/clang/Sema/SemaHLSL.h +++ b/tools/clang/include/clang/Sema/SemaHLSL.h @@ -93,6 +93,10 @@ bool DiagnoseTypeElements(clang::Sema &S, clang::SourceLocation Loc, TypeDiagContext LongVecDiagContext, const clang::FieldDecl *FD = nullptr); +// Returns true if 'auto' is allowed to deduce the given type. Container types +// are deducible only when the type they wrap is deducible. +bool IsTypeDeducibleWithAuto(clang::Sema &S, clang::QualType Ty); + void DiagnoseControlFlowConditionForHLSL(clang::Sema *self, clang::Expr *condExpr, llvm::StringRef StmtName); diff --git a/tools/clang/lib/Sema/SemaDecl.cpp b/tools/clang/lib/Sema/SemaDecl.cpp index bde23e0d59..52c870d994 100644 --- a/tools/clang/lib/Sema/SemaDecl.cpp +++ b/tools/clang/lib/Sema/SemaDecl.cpp @@ -9051,6 +9051,16 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, VDecl->setInvalidDecl(); return; } + + // A dependent deduced type cannot be classified yet; defer the check to + // instantiation, when 'auto' is re-deduced to a concrete type. + if (!DeducedType->isDependentType() && + !hlsl::IsTypeDeducibleWithAuto(*this, DeducedType)) { + Diag(VDecl->getLocation(), diag::err_hlsl_auto_undeducible_type) + << DeducedType; + VDecl->setInvalidDecl(); + return; + } } VDecl->setType(DeducedType); diff --git a/tools/clang/lib/Sema/SemaHLSL.cpp b/tools/clang/lib/Sema/SemaHLSL.cpp index 2067ebaf26..d1ff0ec7b6 100644 --- a/tools/clang/lib/Sema/SemaHLSL.cpp +++ b/tools/clang/lib/Sema/SemaHLSL.cpp @@ -3007,6 +3007,7 @@ StartSubobjectDecl(ASTContext &context, const char *name, NoLoc, &id, nullptr, DelayTypeCreationTrue); decl->addAttr(HLSLSubObjectAttr::CreateImplicit( context, static_cast(Kind), static_cast(HGT))); + decl->addAttr(HLSLNonAutoDeducibleAttr::CreateImplicit(context)); decl->addAttr(FinalAttr::CreateImplicit(context, FinalAttr::Keyword_final)); decl->startDefinition(); return decl; @@ -3528,6 +3529,8 @@ class HLSLExternalSource : public ExternalSemaSource { &m_context->Idents.get(StringRef(type1Name))); sampleSliceTypeDecl->setAccess(AS_public); sampleSliceTypeDecl->setImplicit(); + sampleSliceTypeDecl->addAttr( + HLSLNonAutoDeducibleAttr::CreateImplicit(*m_context)); recordDecl->addDecl(sampleSliceTypeDecl); sampleSliceTypeDecl->startDefinition(); const bool MutableFalse = false; @@ -3556,6 +3559,8 @@ class HLSLExternalSource : public ExternalSemaSource { recordDecl->addDecl(sampleTypeDecl); sampleTypeDecl->startDefinition(); sampleTypeDecl->setImplicit(); + sampleTypeDecl->addAttr( + HLSLNonAutoDeducibleAttr::CreateImplicit(*m_context)); FieldDecl *sampleHandleDecl = FieldDecl::Create( *m_context, sampleTypeDecl, NoLoc, NoLoc, @@ -4773,6 +4778,26 @@ class HLSLExternalSource : public ExternalSemaSource { return type; } + bool IsTypeDeducibleWithAuto(QualType type) { + if (type.isNull()) + return false; + + if (hlsl::IsStringType(type) || hlsl::IsStringLiteralType(type)) + return false; + + if (const CXXRecordDecl *recordDecl = + GetStructuralForm(type)->getAsCXXRecordDecl()) { + if (!recordDecl->hasAttr()) + if (const CXXRecordDecl *pattern = + recordDecl->getTemplateInstantiationPattern()) + recordDecl = pattern; + if (recordDecl->hasAttr()) + return false; + } + + return true; + } + /// Given a Clang type, return the ArBasicKind classification for its /// contents. ArBasicKind GetTypeElementKind(QualType type) { @@ -12787,6 +12812,10 @@ bool hlsl::DiagnoseTypeElements(Sema &S, SourceLocation Loc, QualType Ty, LongVecDiagContext, CheckedDecls, FD); } +bool hlsl::IsTypeDeducibleWithAuto(Sema &S, QualType Ty) { + return HLSLExternalSource::FromSema(&S)->IsTypeDeducibleWithAuto(Ty); +} + bool hlsl::DiagnoseNodeStructArgument(Sema *self, TemplateArgumentLoc ArgLoc, QualType ArgTy, bool &Empty, const FieldDecl *FD) { diff --git a/tools/clang/test/HLSLFileCheckLit/hlsl/auto/auto-deducible-types.hlsl b/tools/clang/test/HLSLFileCheckLit/hlsl/auto/auto-deducible-types.hlsl new file mode 100644 index 0000000000..26a19f2b52 --- /dev/null +++ b/tools/clang/test/HLSLFileCheckLit/hlsl/auto/auto-deducible-types.hlsl @@ -0,0 +1,40 @@ +// RUN: %dxc -T cs_6_0 -HV 202x -verify %s +// expected-no-diagnostics + +struct MyStruct { + float a; + int b; +}; + +Texture2D tex : register(t0); +SamplerState samp : register(s0); +RWBuffer output : register(u0); + +[numthreads(1,1,1)] +void main() { + // Scalars. + auto i = 5; + auto f = 1.5f; + auto b = true; + + // Vectors. + auto v = float4(1, 2, 3, 4); + + + // Matrices. + float2x2 matInit = { 1, 2, 3, 4 }; + auto m = matInit; + auto row = m[0]; + auto elem = m[0][0]; + + // User-defined structs. + MyStruct s = { 1.0f, 2 }; + auto sCopy = s; + + // Resource objects (their handles are copyable, so binding one is allowed). + auto t = tex; + + // Use every value to prevent dead-code elimination. + output[0] = (float)i + f + (float)b + v.x + m._11 + row.x + elem + sCopy.a + + (float)sCopy.b + t.SampleLevel(samp, float2(0, 0), 0).x; +} diff --git a/tools/clang/test/HLSLFileCheckLit/hlsl/auto/auto-no-subobject.hlsl b/tools/clang/test/HLSLFileCheckLit/hlsl/auto/auto-no-subobject.hlsl new file mode 100644 index 0000000000..7df36bd6c3 --- /dev/null +++ b/tools/clang/test/HLSLFileCheckLit/hlsl/auto/auto-no-subobject.hlsl @@ -0,0 +1,32 @@ +// RUN: %dxc -T lib_6_3 -HV 202x -verify %s + +GlobalRootSignature grs = {"CBV(b0)"}; +LocalRootSignature lrs = {"UAV(u0)"}; +StateObjectConfig soc = { STATE_OBJECT_FLAGS_ALLOW_LOCAL_DEPENDENCIES_ON_EXTERNAL_DEFINITONS }; +SubobjectToExportsAssociation sea = { "grs", "a;b" }; +RaytracingShaderConfig rsc = { 128, 64 }; +RaytracingPipelineConfig rpc = { 512 }; +RaytracingPipelineConfig1 rpc1 = { 32, RAYTRACING_PIPELINE_FLAG_ALLOW_OPACITY_MICROMAPS }; +TriangleHitGroup trHitGt = { "a", "b" }; +ProceduralPrimitiveHitGroup ppHitGt = { "a", "b", "c" }; + +void useSubobjects() { + // expected-error@+1 {{'auto' cannot deduce type 'GlobalRootSignature'}} + auto a = grs; + // expected-error@+1 {{'auto' cannot deduce type 'LocalRootSignature'}} + auto b = lrs; + // expected-error@+1 {{'auto' cannot deduce type 'StateObjectConfig'}} + auto c = soc; + // expected-error@+1 {{'auto' cannot deduce type 'SubobjectToExportsAssociation'}} + auto d = sea; + // expected-error@+1 {{'auto' cannot deduce type 'RaytracingShaderConfig'}} + auto e = rsc; + // expected-error@+1 {{'auto' cannot deduce type 'RaytracingPipelineConfig'}} + auto f = rpc; + // expected-error@+1 {{'auto' cannot deduce type 'RaytracingPipelineConfig1'}} + auto g = rpc1; + // expected-error@+1 {{'auto' cannot deduce type 'TriangleHitGroup'}} + auto h = trHitGt; + // expected-error@+1 {{'auto' cannot deduce type 'ProceduralPrimitiveHitGroup'}} + auto i = ppHitGt; +} diff --git a/tools/clang/test/HLSLFileCheckLit/hlsl/auto/auto-undeducible-types.hlsl b/tools/clang/test/HLSLFileCheckLit/hlsl/auto/auto-undeducible-types.hlsl new file mode 100644 index 0000000000..cbd5d71859 --- /dev/null +++ b/tools/clang/test/HLSLFileCheckLit/hlsl/auto/auto-undeducible-types.hlsl @@ -0,0 +1,35 @@ +// RUN: %dxc -T cs_6_0 -HV 202x -verify %s + + +void voidFunc() {} + +Texture2D tex : register(t0); +Texture2DMS texMS : register(t1); + +[numthreads(1,1,1)] +void main() { + int y = 1; + + // expected-error@+1 {{'auto' cannot deduce type}} + auto str = "abc"; + + // expected-error@+1 {{variable has incomplete type 'void'}} + auto x = voidFunc(); + + // expected-error@+1 {{variable has incomplete type 'void'}} + auto v = (void)y; + + // expected-error@+1 {{'auto' cannot deduce type}} + auto m = tex.mips; + // expected-error@+1 {{'auto' cannot deduce type}} + auto m2 = tex.mips[0]; + // legal: load float4 from mip 0 + auto m3 = tex.mips[0][int2(1,2)]; + + // expected-error@+1 {{'auto' cannot deduce type}} + auto s = texMS.sample; + // expected-error@+1 {{'auto' cannot deduce type}} + auto s2 = texMS.sample[0]; + // legal: load float4 from sample 0 + auto s3 = texMS.sample[0][int2(1,2)]; +} diff --git a/tools/clang/test/SemaHLSL/inner-object-ast-dump.hlsl b/tools/clang/test/SemaHLSL/inner-object-ast-dump.hlsl new file mode 100644 index 0000000000..0981457701 --- /dev/null +++ b/tools/clang/test/SemaHLSL/inner-object-ast-dump.hlsl @@ -0,0 +1,27 @@ +// RUN: %dxc -T ps_6_0 -ast-dump-implicit %s | FileCheck %s + +// This test verifies that the inner indexer object types backing .mips and +// .sample (mips_type / mips_slice_type, sample_type / sample_slice_type) carry +// the implicit HLSLNonAutoDeducibleAttr, so that 'auto' cannot deduce them. +// See also subobjects-ast-dump.hlsl, which checks the same attribute on +// subobject types. + +Texture2D srv; +Texture2DMS srvMS; + +float4 main() : SV_Target { + return 0; +} + +// The slice type is created before the indexer type, so it is dumped first; +// each carries the attribute as its first child. Texture2D (.mips) is referenced +// before Texture2DMS (.sample), so the mips records are dumped first. + +// CHECK: CXXRecordDecl {{0x[0-9a-fA-F]+}} <> implicit {{.*}}mips_slice_type definition +// CHECK-NEXT: HLSLNonAutoDeducibleAttr {{0x[0-9a-fA-F]+}} <> Implicit +// CHECK: CXXRecordDecl {{0x[0-9a-fA-F]+}} <> implicit {{.*}}mips_type definition +// CHECK-NEXT: HLSLNonAutoDeducibleAttr {{0x[0-9a-fA-F]+}} <> Implicit +// CHECK: CXXRecordDecl {{0x[0-9a-fA-F]+}} <> implicit {{.*}}sample_slice_type definition +// CHECK-NEXT: HLSLNonAutoDeducibleAttr {{0x[0-9a-fA-F]+}} <> Implicit +// CHECK: CXXRecordDecl {{0x[0-9a-fA-F]+}} <> implicit {{.*}}sample_type definition +// CHECK-NEXT: HLSLNonAutoDeducibleAttr {{0x[0-9a-fA-F]+}} <> Implicit diff --git a/tools/clang/test/SemaHLSL/subobjects-ast-dump.hlsl b/tools/clang/test/SemaHLSL/subobjects-ast-dump.hlsl index 6133847fb8..ecd155ed41 100644 --- a/tools/clang/test/SemaHLSL/subobjects-ast-dump.hlsl +++ b/tools/clang/test/SemaHLSL/subobjects-ast-dump.hlsl @@ -8,43 +8,52 @@ // ASTIMPL: CXXRecordDecl 0x{{.+}} <> implicit referenced struct StateObjectConfig definition // ASTIMPL-NEXT: HLSLSubObjectAttr 0x{{.+}} <> Implicit 0 2 +// ASTIMPL-NEXT: HLSLNonAutoDeducibleAttr 0x{{.+}} <> Implicit // ASTIMPL-NEXT: FinalAttr 0x{{.+}} <> Implicit final // ASTIMPL-NEXT: FieldDecl 0x{{.+}} <> implicit Flags 'unsigned int' // ASTIMPL-NEXT: CXXRecordDecl 0x{{.+}} <> implicit referenced struct GlobalRootSignature definition // ASTIMPL-NEXT: HLSLSubObjectAttr 0x{{.+}} <> Implicit 1 2 +// ASTIMPL-NEXT: HLSLNonAutoDeducibleAttr 0x{{.+}} <> Implicit // ASTIMPL-NEXT: FinalAttr 0x{{.+}} <> Implicit final // ASTIMPL-NEXT: FieldDecl 0x{{.+}} <> implicit Data 'string' // ASTIMPL-NEXT: CXXRecordDecl 0x{{.+}} <> implicit referenced struct LocalRootSignature definition // ASTIMPL-NEXT: HLSLSubObjectAttr 0x{{.+}} <> Implicit 2 2 +// ASTIMPL-NEXT: HLSLNonAutoDeducibleAttr 0x{{.+}} <> Implicit // ASTIMPL-NEXT: FinalAttr 0x{{.+}} <> Implicit final // ASTIMPL-NEXT: FieldDecl 0x{{.+}} <> implicit Data 'string' // ASTIMPL-NEXT: CXXRecordDecl 0x{{.+}} <> implicit referenced struct SubobjectToExportsAssociation definition // ASTIMPL-NEXT: HLSLSubObjectAttr 0x{{.+}} <> Implicit 8 2 +// ASTIMPL-NEXT: HLSLNonAutoDeducibleAttr 0x{{.+}} <> Implicit // ASTIMPL-NEXT: FinalAttr 0x{{.+}} <> Implicit final // ASTIMPL-NEXT: FieldDecl 0x{{.+}} <> implicit Subobject 'string' // ASTIMPL-NEXT: FieldDecl 0x{{.+}} <> implicit Exports 'string' // ASTIMPL-NEXT: CXXRecordDecl 0x{{.+}} <> implicit referenced struct RaytracingShaderConfig definition // ASTIMPL-NEXT: HLSLSubObjectAttr 0x{{.+}} <> Implicit 9 2 +// ASTIMPL-NEXT: HLSLNonAutoDeducibleAttr 0x{{.+}} <> Implicit // ASTIMPL-NEXT: FinalAttr 0x{{.+}} <> Implicit final // ASTIMPL-NEXT: FieldDecl 0x{{.+}} <> implicit MaxPayloadSizeInBytes 'unsigned int' // ASTIMPL-NEXT: FieldDecl 0x{{.+}} <> implicit MaxAttributeSizeInBytes 'unsigned int' // ASTIMPL-NEXT: CXXRecordDecl 0x{{.+}} <> implicit struct RaytracingPipelineConfig definition // ASTIMPL-NEXT: HLSLSubObjectAttr 0x{{.+}} <> Implicit 10 2 +// ASTIMPL-NEXT: HLSLNonAutoDeducibleAttr 0x{{.+}} <> Implicit // ASTIMPL-NEXT: FinalAttr 0x{{.+}} <> Implicit final // ASTIMPL-NEXT: FieldDecl 0x{{.+}} <> implicit MaxTraceRecursionDepth 'unsigned int' // ASTIMPL-NEXT: CXXRecordDecl 0x{{.+}} <> implicit referenced struct TriangleHitGroup definition // ASTIMPL-NEXT: HLSLSubObjectAttr 0x{{.+}} <> Implicit 11 0 +// ASTIMPL-NEXT: HLSLNonAutoDeducibleAttr 0x{{.+}} <> Implicit // ASTIMPL-NEXT: FinalAttr 0x{{.+}} <> Implicit final // ASTIMPL-NEXT: FieldDecl 0x{{.+}} <> implicit AnyHit 'string' // ASTIMPL-NEXT: FieldDecl 0x{{.+}} <> implicit ClosestHit 'string' // ASTIMPL-NEXT: CXXRecordDecl 0x{{.+}} <> implicit referenced struct ProceduralPrimitiveHitGroup definition // ASTIMPL-NEXT: HLSLSubObjectAttr 0x{{.+}} <> Implicit 11 1 +// ASTIMPL-NEXT: HLSLNonAutoDeducibleAttr 0x{{.+}} <> Implicit // ASTIMPL-NEXT: FinalAttr 0x{{.+}} <> Implicit final // ASTIMPL-NEXT: FieldDecl 0x{{.+}} <> implicit AnyHit 'string' // ASTIMPL-NEXT: FieldDecl 0x{{.+}} <> implicit ClosestHit 'string' // ASTIMPL-NEXT: FieldDecl 0x{{.+}} <> implicit Intersection 'string' // ASTIMPL-NEXT: CXXRecordDecl 0x{{.+}} <> implicit referenced struct RaytracingPipelineConfig1 definition // ASTIMPL-NEXT: HLSLSubObjectAttr 0x{{.+}} <> Implicit 12 2 +// ASTIMPL-NEXT: HLSLNonAutoDeducibleAttr 0x{{.+}} <> Implicit // ASTIMPL-NEXT: FinalAttr 0x{{.+}} <> Implicit final // ASTIMPL-NEXT: FieldDecl 0x{{.+}} <> implicit MaxTraceRecursionDepth 'unsigned int' // ASTIMPL-NEXT: FieldDecl 0x{{.+}} <> implicit Flags 'unsigned int'