Skip to content

Commit deb1306

Browse files
authored
Add warning for returning without initializing out parameter (shader-slang#2807)
* Add warning for returning without initializing out parameter * Add unused prelude function to squash uninitialized out variable warnings
1 parent 8177fff commit deb1306

7 files changed

+97
-11
lines changed

source/slang/core.meta.slang

+9
Original file line numberDiff line numberDiff line change
@@ -2649,6 +2649,15 @@ __generic<T, U>
26492649
__intrinsic_op($(kIROp_Reinterpret))
26502650
T reinterpret(U value);
26512651

2652+
// Use an otherwise unused value
2653+
//
2654+
// This can be used to silence the warning about returning before initializing
2655+
// an out paramter.
2656+
__generic<T>
2657+
[__readNone]
2658+
[ForceInline]
2659+
void unused(inout T){}
2660+
26522661
// Specialized function
26532662

26542663
/// Given a string returns an integer hash of that string.

source/slang/slang-diagnostic-defs.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -595,7 +595,9 @@ DIAGNOSTIC(40020, Error, cannotUnrollLoop, "loop does not terminate within the l
595595
DIAGNOSTIC(41000, Warning, unreachableCode, "unreachable code detected")
596596

597597
DIAGNOSTIC(41010, Warning, missingReturn, "control flow may reach end of non-'void' function")
598-
DIAGNOSTIC(41015, Error, usingUninitializedValue, "use of uninitialized value.")
598+
DIAGNOSTIC(41015, Error, usingUninitializedValue, "use of uninitialized value '$0'")
599+
DIAGNOSTIC(41016, Warning, returningWithUninitializedOut, "returning without initializing out parameter '$0'")
600+
DIAGNOSTIC(41017, Warning, returningWithPartiallyUninitializedOut, "returning without fully initializing out parameter '$0'")
599601

600602
DIAGNOSTIC(41011, Error, typeDoesNotFitAnyValueSize, "type '$0' does not fit in the size required by its conforming interface.")
601603
DIAGNOSTIC(41012, Note, typeAndLimit, "sizeof($0) is $1, limit is $2")

source/slang/slang-ir-use-uninitialized-out-param.cpp

+20-9
Original file line numberDiff line numberDiff line change
@@ -75,27 +75,33 @@ namespace Slang
7575
}
7676
}
7777
// Check all address loads.
78-
List<IRLoad*> loads;
78+
List<IRInst*> loadsAndReturns;
7979
for (auto addr : addresses)
8080
{
8181
for (auto use = addr->firstUse; use; use = use->nextUse)
8282
{
8383
if (auto load = as<IRLoad>(use->getUser()))
84-
loads.add(load);
84+
loadsAndReturns.add(load);
8585
}
8686
}
87+
for(const auto& b : func->getBlocks())
88+
{
89+
auto t = b->getTerminator();
90+
if (t->m_op == kIROp_Return)
91+
loadsAndReturns.add(t);
92+
}
8793

8894
for (auto store : stores)
8995
{
9096
// Remove insts from `loads` that is reachable from the store.
91-
for (Index i = 0; i < loads.getCount();)
97+
for (Index i = 0; i < loadsAndReturns.getCount();)
9298
{
93-
auto load = loads[i];
94-
if (!canAddressesPotentiallyAlias(func, store.address, loads[i]->getPtr()))
99+
auto load = as<IRLoad>(loadsAndReturns[i]);
100+
if (load && !canAddressesPotentiallyAlias(func, store.address, load->getPtr()))
95101
continue;
96-
if (reachability.isInstReachable(store.storeInst, load))
102+
if (reachability.isInstReachable(store.storeInst, loadsAndReturns[i]))
97103
{
98-
loads.fastRemoveAt(i);
104+
loadsAndReturns.fastRemoveAt(i);
99105
}
100106
else
101107
{
@@ -104,9 +110,14 @@ namespace Slang
104110
}
105111
}
106112
// If there are any loads left, it means they are using uninitialized out params.
107-
for (auto load : loads)
113+
for (auto load : loadsAndReturns)
108114
{
109-
sink->diagnose(load, Diagnostics::usingUninitializedValue);
115+
sink->diagnose(
116+
load,
117+
load->m_op == kIROp_Return
118+
? Diagnostics::returningWithUninitializedOut
119+
: Diagnostics::usingUninitializedValue,
120+
param);
110121
}
111122
}
112123
}

tests/autodiff/bsdf/bsdf-auto-rev.slang

+1
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ bool bsdfGGXSample(in ShadingData sd, in Auto_Bwd_BSDFParameters params, out Aut
3939

4040
if (wiLocal.z < 1e-6)
4141
{
42+
unused(result);
4243
return false;
4344
}
4445

tests/compute/ray-tracing-inline.slang

+1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ bool traceRayClosestHit(
3333
//primitiveIndex = q.CommittedPrimitiveIndex();
3434
return true;
3535
}
36+
unused(t);
3637
return false;
3738
}
3839

tests/diagnostics/uninitialized-out.slang

+50
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,56 @@
22

33
float foo(out float3 v)
44
{
5+
// This should error as we haven't set v before we read from it
56
float r = v.x + 1.0;
7+
// This should warn as we haven't set v before we return
68
return r;
79
}
10+
11+
// This should warn as we return without x being initialized
12+
float bar(out float x)
13+
{
14+
return 0;
15+
}
16+
17+
// This should also warn pointing at the implicit return
18+
void baz(out float x) {}
19+
20+
void twoReturns(bool b, out float y)
21+
{
22+
if(b)
23+
{
24+
// Should warn
25+
return;
26+
}
27+
y = 0;
28+
// Shouldn't warn
29+
return;
30+
}
31+
32+
void twoOkReturns(bool b, out float y)
33+
{
34+
if(b)
35+
{
36+
// Shouldn't warn
37+
unused(y);
38+
return;
39+
}
40+
y = 0;
41+
// Shouldn't warn
42+
return;
43+
}
44+
45+
// TODO: This should warn that n is potentially uninitialized
46+
int ok(bool b, out int n)
47+
{
48+
if(b)
49+
n = 0;
50+
return n;
51+
}
52+
53+
// TODO: This should warn that arr isn't fully initialized
54+
void partial(out float arr[2])
55+
{
56+
arr[0] = 1;
57+
}
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,20 @@
11
result code = -1
22
standard error = {
3-
tests/diagnostics/uninitialized-out.slang(5): error 41015: use of uninitialized value.
3+
tests/diagnostics/uninitialized-out.slang(6): error 41015: use of uninitialized value 'v'
44
float r = v.x + 1.0;
55
^
6+
tests/diagnostics/uninitialized-out.slang(8): warning 41016: returning without initializing out parameter 'v'
7+
return r;
8+
^~~~~~
9+
tests/diagnostics/uninitialized-out.slang(14): warning 41016: returning without initializing out parameter 'x'
10+
return 0;
11+
^~~~~~
12+
tests/diagnostics/uninitialized-out.slang(18): warning 41016: returning without initializing out parameter 'x'
13+
void baz(out float x) {}
14+
^
15+
tests/diagnostics/uninitialized-out.slang(25): warning 41016: returning without initializing out parameter 'y'
16+
return;
17+
^~~~~~
618
}
719
standard output = {
820
}

0 commit comments

Comments
 (0)