Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions tools/clang/include/clang/Basic/Attr.td
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
3 changes: 3 additions & 0 deletions tools/clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 4 additions & 0 deletions tools/clang/include/clang/Sema/SemaHLSL.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
10 changes: 10 additions & 0 deletions tools/clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
24 changes: 24 additions & 0 deletions tools/clang/lib/Sema/SemaHLSL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3007,6 +3007,7 @@ StartSubobjectDecl(ASTContext &context, const char *name,
NoLoc, &id, nullptr, DelayTypeCreationTrue);
decl->addAttr(HLSLSubObjectAttr::CreateImplicit(
context, static_cast<unsigned>(Kind), static_cast<unsigned>(HGT)));
decl->addAttr(HLSLNonAutoDeducibleAttr::CreateImplicit(context));
decl->addAttr(FinalAttr::CreateImplicit(context, FinalAttr::Keyword_final));
decl->startDefinition();
return decl;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -4773,6 +4778,21 @@ 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<HLSLNonAutoDeducibleAttr>())
return false;

return true;
}

/// <summary>Given a Clang type, return the ArBasicKind classification for its
/// contents.</summary>
ArBasicKind GetTypeElementKind(QualType type) {
Expand Down Expand Up @@ -12787,6 +12807,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) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// RUN: %dxc -T cs_6_0 -HV 202x -verify %s
// expected-no-diagnostics

struct MyStruct {
float a;
int b;
};

Texture2D<float4> tex : register(t0);
SamplerState samp : register(s0);
RWBuffer<float> 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;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about something like?

    auto row = m[0];

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;
}
32 changes: 32 additions & 0 deletions tools/clang/test/HLSLFileCheckLit/hlsl/auto/auto-no-subobject.hlsl
Original file line number Diff line number Diff line change
@@ -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;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// RUN: %dxc -T cs_6_0 -HV 202x -verify %s


void voidFunc() {}

Texture2D<float4> tex : register(t0);
Texture2DMS<float4> 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 s = texMS.sample;
}
27 changes: 27 additions & 0 deletions tools/clang/test/SemaHLSL/inner-object-ast-dump.hlsl
Original file line number Diff line number Diff line change
@@ -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<float4> srv;
Texture2DMS<float4> 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]+}} <<invalid sloc>> <invalid sloc> implicit {{.*}}mips_slice_type definition
// CHECK-NEXT: HLSLNonAutoDeducibleAttr {{0x[0-9a-fA-F]+}} <<invalid sloc>> Implicit
// CHECK: CXXRecordDecl {{0x[0-9a-fA-F]+}} <<invalid sloc>> <invalid sloc> implicit {{.*}}mips_type definition
// CHECK-NEXT: HLSLNonAutoDeducibleAttr {{0x[0-9a-fA-F]+}} <<invalid sloc>> Implicit
// CHECK: CXXRecordDecl {{0x[0-9a-fA-F]+}} <<invalid sloc>> <invalid sloc> implicit {{.*}}sample_slice_type definition
// CHECK-NEXT: HLSLNonAutoDeducibleAttr {{0x[0-9a-fA-F]+}} <<invalid sloc>> Implicit
// CHECK: CXXRecordDecl {{0x[0-9a-fA-F]+}} <<invalid sloc>> <invalid sloc> implicit {{.*}}sample_type definition
// CHECK-NEXT: HLSLNonAutoDeducibleAttr {{0x[0-9a-fA-F]+}} <<invalid sloc>> Implicit
9 changes: 9 additions & 0 deletions tools/clang/test/SemaHLSL/subobjects-ast-dump.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -8,43 +8,52 @@

// ASTIMPL: CXXRecordDecl 0x{{.+}} <<invalid sloc>> <invalid sloc> implicit referenced struct StateObjectConfig definition
// ASTIMPL-NEXT: HLSLSubObjectAttr 0x{{.+}} <<invalid sloc>> Implicit 0 2
// ASTIMPL-NEXT: HLSLNonAutoDeducibleAttr 0x{{.+}} <<invalid sloc>> Implicit
// ASTIMPL-NEXT: FinalAttr 0x{{.+}} <<invalid sloc>> Implicit final
// ASTIMPL-NEXT: FieldDecl 0x{{.+}} <<invalid sloc>> <invalid sloc> implicit Flags 'unsigned int'
// ASTIMPL-NEXT: CXXRecordDecl 0x{{.+}} <<invalid sloc>> <invalid sloc> implicit referenced struct GlobalRootSignature definition
// ASTIMPL-NEXT: HLSLSubObjectAttr 0x{{.+}} <<invalid sloc>> Implicit 1 2
// ASTIMPL-NEXT: HLSLNonAutoDeducibleAttr 0x{{.+}} <<invalid sloc>> Implicit
// ASTIMPL-NEXT: FinalAttr 0x{{.+}} <<invalid sloc>> Implicit final
// ASTIMPL-NEXT: FieldDecl 0x{{.+}} <<invalid sloc>> <invalid sloc> implicit Data 'string'
// ASTIMPL-NEXT: CXXRecordDecl 0x{{.+}} <<invalid sloc>> <invalid sloc> implicit referenced struct LocalRootSignature definition
// ASTIMPL-NEXT: HLSLSubObjectAttr 0x{{.+}} <<invalid sloc>> Implicit 2 2
// ASTIMPL-NEXT: HLSLNonAutoDeducibleAttr 0x{{.+}} <<invalid sloc>> Implicit
// ASTIMPL-NEXT: FinalAttr 0x{{.+}} <<invalid sloc>> Implicit final
// ASTIMPL-NEXT: FieldDecl 0x{{.+}} <<invalid sloc>> <invalid sloc> implicit Data 'string'
// ASTIMPL-NEXT: CXXRecordDecl 0x{{.+}} <<invalid sloc>> <invalid sloc> implicit referenced struct SubobjectToExportsAssociation definition
// ASTIMPL-NEXT: HLSLSubObjectAttr 0x{{.+}} <<invalid sloc>> Implicit 8 2
// ASTIMPL-NEXT: HLSLNonAutoDeducibleAttr 0x{{.+}} <<invalid sloc>> Implicit
// ASTIMPL-NEXT: FinalAttr 0x{{.+}} <<invalid sloc>> Implicit final
// ASTIMPL-NEXT: FieldDecl 0x{{.+}} <<invalid sloc>> <invalid sloc> implicit Subobject 'string'
// ASTIMPL-NEXT: FieldDecl 0x{{.+}} <<invalid sloc>> <invalid sloc> implicit Exports 'string'
// ASTIMPL-NEXT: CXXRecordDecl 0x{{.+}} <<invalid sloc>> <invalid sloc> implicit referenced struct RaytracingShaderConfig definition
// ASTIMPL-NEXT: HLSLSubObjectAttr 0x{{.+}} <<invalid sloc>> Implicit 9 2
// ASTIMPL-NEXT: HLSLNonAutoDeducibleAttr 0x{{.+}} <<invalid sloc>> Implicit
// ASTIMPL-NEXT: FinalAttr 0x{{.+}} <<invalid sloc>> Implicit final
// ASTIMPL-NEXT: FieldDecl 0x{{.+}} <<invalid sloc>> <invalid sloc> implicit MaxPayloadSizeInBytes 'unsigned int'
// ASTIMPL-NEXT: FieldDecl 0x{{.+}} <<invalid sloc>> <invalid sloc> implicit MaxAttributeSizeInBytes 'unsigned int'
// ASTIMPL-NEXT: CXXRecordDecl 0x{{.+}} <<invalid sloc>> <invalid sloc> implicit struct RaytracingPipelineConfig definition
// ASTIMPL-NEXT: HLSLSubObjectAttr 0x{{.+}} <<invalid sloc>> Implicit 10 2
// ASTIMPL-NEXT: HLSLNonAutoDeducibleAttr 0x{{.+}} <<invalid sloc>> Implicit
// ASTIMPL-NEXT: FinalAttr 0x{{.+}} <<invalid sloc>> Implicit final
// ASTIMPL-NEXT: FieldDecl 0x{{.+}} <<invalid sloc>> <invalid sloc> implicit MaxTraceRecursionDepth 'unsigned int'
// ASTIMPL-NEXT: CXXRecordDecl 0x{{.+}} <<invalid sloc>> <invalid sloc> implicit referenced struct TriangleHitGroup definition
// ASTIMPL-NEXT: HLSLSubObjectAttr 0x{{.+}} <<invalid sloc>> Implicit 11 0
// ASTIMPL-NEXT: HLSLNonAutoDeducibleAttr 0x{{.+}} <<invalid sloc>> Implicit
// ASTIMPL-NEXT: FinalAttr 0x{{.+}} <<invalid sloc>> Implicit final
// ASTIMPL-NEXT: FieldDecl 0x{{.+}} <<invalid sloc>> <invalid sloc> implicit AnyHit 'string'
// ASTIMPL-NEXT: FieldDecl 0x{{.+}} <<invalid sloc>> <invalid sloc> implicit ClosestHit 'string'
// ASTIMPL-NEXT: CXXRecordDecl 0x{{.+}} <<invalid sloc>> <invalid sloc> implicit referenced struct ProceduralPrimitiveHitGroup definition
// ASTIMPL-NEXT: HLSLSubObjectAttr 0x{{.+}} <<invalid sloc>> Implicit 11 1
// ASTIMPL-NEXT: HLSLNonAutoDeducibleAttr 0x{{.+}} <<invalid sloc>> Implicit
// ASTIMPL-NEXT: FinalAttr 0x{{.+}} <<invalid sloc>> Implicit final
// ASTIMPL-NEXT: FieldDecl 0x{{.+}} <<invalid sloc>> <invalid sloc> implicit AnyHit 'string'
// ASTIMPL-NEXT: FieldDecl 0x{{.+}} <<invalid sloc>> <invalid sloc> implicit ClosestHit 'string'
// ASTIMPL-NEXT: FieldDecl 0x{{.+}} <<invalid sloc>> <invalid sloc> implicit Intersection 'string'
// ASTIMPL-NEXT: CXXRecordDecl 0x{{.+}} <<invalid sloc>> <invalid sloc> implicit referenced struct RaytracingPipelineConfig1 definition
// ASTIMPL-NEXT: HLSLSubObjectAttr 0x{{.+}} <<invalid sloc>> Implicit 12 2
// ASTIMPL-NEXT: HLSLNonAutoDeducibleAttr 0x{{.+}} <<invalid sloc>> Implicit
// ASTIMPL-NEXT: FinalAttr 0x{{.+}} <<invalid sloc>> Implicit final
// ASTIMPL-NEXT: FieldDecl 0x{{.+}} <<invalid sloc>> <invalid sloc> implicit MaxTraceRecursionDepth 'unsigned int'
// ASTIMPL-NEXT: FieldDecl 0x{{.+}} <<invalid sloc>> <invalid sloc> implicit Flags 'unsigned int'
Expand Down
Loading