From 26e25f6e73a9808ad93c98ad34907e3a27b6726c Mon Sep 17 00:00:00 2001 From: Yong He Date: Mon, 18 Mar 2024 17:21:48 -0700 Subject: Check for cylic types. (#3790) --- build/visual-studio/slang/slang.vcxproj | 2 + build/visual-studio/slang/slang.vcxproj.filters | 6 +++ source/slang/slang-diagnostic-defs.h | 2 + source/slang/slang-ir-check-recursive-type.cpp | 59 +++++++++++++++++++++++++ source/slang/slang-ir-check-recursive-type.h | 11 +++++ source/slang/slang-lower-to-ir.cpp | 4 ++ tests/bugs/cyclic-type.slang | 21 +++++++++ 7 files changed, 105 insertions(+) create mode 100644 source/slang/slang-ir-check-recursive-type.cpp create mode 100644 source/slang/slang-ir-check-recursive-type.h create mode 100644 tests/bugs/cyclic-type.slang diff --git a/build/visual-studio/slang/slang.vcxproj b/build/visual-studio/slang/slang.vcxproj index c503e8f4d..aca22890b 100644 --- a/build/visual-studio/slang/slang.vcxproj +++ b/build/visual-studio/slang/slang.vcxproj @@ -373,6 +373,7 @@ IF EXIST ..\..\..\external\slang-glslang\bin\windows-aarch64\release\slang-glsla + @@ -598,6 +599,7 @@ IF EXIST ..\..\..\external\slang-glslang\bin\windows-aarch64\release\slang-glsla + diff --git a/build/visual-studio/slang/slang.vcxproj.filters b/build/visual-studio/slang/slang.vcxproj.filters index 9c274990d..7b6b7de2c 100644 --- a/build/visual-studio/slang/slang.vcxproj.filters +++ b/build/visual-studio/slang/slang.vcxproj.filters @@ -207,6 +207,9 @@ Header Files + + Header Files + Header Files @@ -878,6 +881,9 @@ Source Files + + Source Files + Source Files diff --git a/source/slang/slang-diagnostic-defs.h b/source/slang/slang-diagnostic-defs.h index ba57e63f9..7a72daa5e 100644 --- a/source/slang/slang-diagnostic-defs.h +++ b/source/slang/slang-diagnostic-defs.h @@ -691,6 +691,7 @@ DIAGNOSTIC(40010, Note, seeInterfaceUsage, "see usage of interface '$0'.") DIAGNOSTIC(40011, Error, unconstrainedGenericParameterNotAllowedInDynamicFunction, "unconstrained generic paramter '$0' is not allowed in a dynamic function.") + DIAGNOSTIC(40020, Error, cannotUnrollLoop, "loop does not terminate within the limited number of iterations, unrolling is aborted.") DIAGNOSTIC(40030, Fatal, functionNeverReturnsFatal, "function '$0' never returns, compilation ceased.") @@ -698,6 +699,7 @@ DIAGNOSTIC(40030, Fatal, functionNeverReturnsFatal, "function '$0' never returns // 41000 - IR-level validation issues DIAGNOSTIC(41000, Warning, unreachableCode, "unreachable code detected") +DIAGNOSTIC(41001, Error, recursiveType, "type '$0' contains cyclic reference to itself.") DIAGNOSTIC(41010, Warning, missingReturn, "control flow may reach end of non-'void' function") DIAGNOSTIC(41015, Error, usingUninitializedValue, "use of uninitialized value '$0'") diff --git a/source/slang/slang-ir-check-recursive-type.cpp b/source/slang/slang-ir-check-recursive-type.cpp new file mode 100644 index 000000000..8679801d0 --- /dev/null +++ b/source/slang/slang-ir-check-recursive-type.cpp @@ -0,0 +1,59 @@ +#include "slang-ir-check-recursive-type.h" +#include "slang-ir-util.h" + +namespace Slang +{ + bool checkTypeRecursionImpl(HashSet& checkedTypes, HashSet& stack, IRInst* type, IRInst* field, DiagnosticSink* sink) + { + auto visitElementType = [&](IRInst* elementType, IRInst* field) -> bool + { + if (!stack.add(elementType)) + { + sink->diagnose(field ? field : type, Diagnostics::recursiveType, type); + return false; + } + if (checkedTypes.add(elementType)) + checkTypeRecursionImpl(checkedTypes, stack, elementType, field, sink); + stack.remove(elementType); + return true; + }; + if (auto arrayType = as(type)) + { + return visitElementType(arrayType->getElementType(), field); + } + else if (auto structType = as(type)) + { + for (auto sfield : structType->getFields()) + if (!visitElementType(sfield->getFieldType(), sfield)) + return false; + } + return true; + } + + void checkTypeRecursion(HashSet& checkedTypes, IRInst* type, DiagnosticSink* sink) + { + HashSet stack; + if (checkedTypes.add(type)) + { + stack.add(type); + checkTypeRecursionImpl(checkedTypes, stack, type, nullptr, sink); + } + } + + void checkForRecursiveTypes(IRModule* module, DiagnosticSink* sink) + { + HashSet checkedTypes; + for (auto globalInst : module->getGlobalInsts()) + { + switch (globalInst->getOp()) + { + case kIROp_StructType: + { + checkTypeRecursion(checkedTypes, globalInst, sink); + } + break; + } + } + } + +} diff --git a/source/slang/slang-ir-check-recursive-type.h b/source/slang/slang-ir-check-recursive-type.h new file mode 100644 index 000000000..0ab911e79 --- /dev/null +++ b/source/slang/slang-ir-check-recursive-type.h @@ -0,0 +1,11 @@ +#pragma once + +namespace Slang +{ + struct IRModule; + class DiagnosticSink; + + void checkForRecursiveTypes( + IRModule* module, + DiagnosticSink* sink); +} diff --git a/source/slang/slang-lower-to-ir.cpp b/source/slang/slang-lower-to-ir.cpp index 4e564f703..5a3b0c2c5 100644 --- a/source/slang/slang-lower-to-ir.cpp +++ b/source/slang/slang-lower-to-ir.cpp @@ -20,6 +20,7 @@ #include "slang-ir-insts.h" #include "slang-ir-insert-debug-value-store.h" #include "slang-ir-check-differentiability.h" +#include "slang-ir-check-recursive-type.h" #include "slang-ir-missing-return.h" #include "slang-ir-sccp.h" #include "slang-ir-ssa.h" @@ -10665,6 +10666,9 @@ RefPtr generateIRForTranslationUnit( checkForMissingReturns(module, compileRequest->getSink()); + // We don't allow recursive types. + checkForRecursiveTypes(module, compileRequest->getSink()); + // Check for invalid differentiable function body. checkAutoDiffUsages(module, compileRequest->getSink()); diff --git a/tests/bugs/cyclic-type.slang b/tests/bugs/cyclic-type.slang new file mode 100644 index 000000000..49591fbe6 --- /dev/null +++ b/tests/bugs/cyclic-type.slang @@ -0,0 +1,21 @@ + +//TEST:SIMPLE(filecheck=CHECK):-target spirv -emit-spirv-directly + +// CHECK: error 41001: + +struct TA +{ + TB tb; +} + +struct TB +{ + TA ta[2]; +} + +[numthreads(1,1,1)] +void main() +{ + TA ta; + ta.tb.ta[0] = ta; +} \ No newline at end of file -- cgit v1.2.3