diff --git a/tools/clang/lib/Analysis/UninitializedValues.cpp b/tools/clang/lib/Analysis/UninitializedValues.cpp index dfd689bdf3..0bcccc7e6b 100644 --- a/tools/clang/lib/Analysis/UninitializedValues.cpp +++ b/tools/clang/lib/Analysis/UninitializedValues.cpp @@ -171,6 +171,12 @@ class CFGBlockValues { return declToIndex.getHLSLOutParams(); } // HLSL Change End - Treat `out` parameters as uninitialized values. + + // HLSL Change Begin - check the variable is in the declToIndex map + bool hasValueIndex(const VarDecl *vd) { + return declToIndex.getValueIndex(vd).hasValue(); + } + // HLSL Change End - check the variable is in the declToIndex map }; } // end anonymous namespace @@ -781,10 +787,23 @@ void TransferFunctions::VisitDeclRefExpr(DeclRefExpr *dr) { case ClassifyRefs::Ignore: break; case ClassifyRefs::Use: - reportUse(dr, cast(dr->getDecl())); + // HLSL Change Begin - check the variable is in the declToIndex map + // before calling reportUse(). HLSL out parameters or local variables from + // template instantiations may not be mapped in the current DeclContext. + if (const VarDecl *VD = cast(dr->getDecl())) { + if (vals.hasValueIndex(VD)) + reportUse(dr, VD); + } + // HLSL Change End - check the variable is in the declToIndex map break; case ClassifyRefs::Init: - vals[cast(dr->getDecl())] = Initialized; + // HLSL Change Begin - check the variable is in the declToIndex map + // before marking it Initialized. + if (const VarDecl *VD = cast(dr->getDecl())) { + if (vals.hasValueIndex(VD)) + vals[VD] = Initialized; + } + // HLSL Change End - check the variable is in the declToIndex map break; case ClassifyRefs::SelfInit: handler.handleSelfInit(cast(dr->getDecl())); @@ -795,8 +814,12 @@ void TransferFunctions::VisitDeclRefExpr(DeclRefExpr *dr) { void TransferFunctions::VisitBinaryOperator(BinaryOperator *BO) { if (BO->getOpcode() == BO_Assign) { FindVarResult Var = findVar(BO->getLHS()); + // HLSL Change Begin - check the variable is in the declToIndex map + // before marking it Initialized. if (const VarDecl *VD = Var.getDecl()) - vals[VD] = Initialized; + if (vals.hasValueIndex(VD)) + vals[VD] = Initialized; + // HLSL Change End - check the variable is in the declToIndex map } } diff --git a/tools/clang/test/DXC/template_uninitialized_values.hlsl b/tools/clang/test/DXC/template_uninitialized_values.hlsl new file mode 100644 index 0000000000..43d334d82c --- /dev/null +++ b/tools/clang/test/DXC/template_uninitialized_values.hlsl @@ -0,0 +1,63 @@ +// RUN: dxc -E main -T cs_6_6 -HV 2021 -Wno-unused-value %s | FileCheck %s + +// Asserts in UnitializedValues.cpp were triggered by the following code +// examples. The cause was that HLSL out parameters or local variables from +// template instantiations may not be present in the declToIndex map when the +// variable's DeclContext differs from the analysis context (common in +// template instantiations). +// The fix was to add defensive checks so that if the variable isn't tracked +// it is silently ignored. + +// CHECK: define void @main() + +template +void test(R x, out uint result) { + uint repro = 0; + result = 10; +} + +[numthreads(32, 32, 1)] void main(uint2 threadId: SV_DispatchThreadID) { + uint x; + test(10, x); +} + +template +void func2(out uint var1) +{ + uint var3; + uint var4; + uint var5; + uint var6; + uint var7; + uint var8; + uint var9; + uint var10; + uint var11; + uint var12; + uint var13; + uint var14; + uint var15; + uint var16; + uint var17; + uint var18; + uint var19; + uint var20; + uint var21; + uint var22; + uint var23; + uint var24; + uint var25; + uint var26; + uint var27; + uint var28; + uint var29; + uint var30; + uint var31; + var1; +} + +void func1() +{ + uint var33; + func2(var33); +}