diff options
| author | Gangzheng Tong <tonggangzheng@gmail.com> | 2025-09-16 12:51:43 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-09-16 19:51:43 +0000 |
| commit | afb8146e10626887e3eb9f479480d4f8a1ad6128 (patch) | |
| tree | 4a11668df1005f4c15e7e25d27615e3116961356 /source/slang/slang-ir-constexpr.cpp | |
| parent | 8ad0ae17880480abe587617c997ab28b23abc146 (diff) | |
Diagnose error when the function args can't satisfy constexpr parameter requirements (#7269)
## Summary
This PR enhances constexpr validation by adding proper error checking
when function arguments cannot satisfy constexpr parameter requirements,
addressing issue #6370.
## Problem
Previously, when a function declared constexpr parameters, the compiler
would attempt to propagate constexpr-ness to the call site arguments,
but there was insufficient validation and error reporting when this
propagation failed. This could lead silent failures where constexpr
requirements weren't properly enforced
## Solution
This PR adds checks that:
1. **Validates constexpr arguments**: When a function parameter is
marked as `constexpr`, the compiler now explicitly checks that the
corresponding argument can be marked as `constexpr`
2. **Issues clear compilation errors**: added
`Diagnostics::argIsNotConstexpr`)
3. **Handles both call scenarios**: The validation works for both:
- Direct function calls with IR-level function definitions
- Calls to function from external modules
Fixes #6370
---------
Co-authored-by: slangbot <ellieh+slangbot@nvidia.com>
Co-authored-by: slangbot <186143334+slangbot@users.noreply.github.com>
Diffstat (limited to 'source/slang/slang-ir-constexpr.cpp')
| -rw-r--r-- | source/slang/slang-ir-constexpr.cpp | 92 |
1 files changed, 32 insertions, 60 deletions
diff --git a/source/slang/slang-ir-constexpr.cpp b/source/slang/slang-ir-constexpr.cpp index 0bdbe260a..825bc5c98 100644 --- a/source/slang/slang-ir-constexpr.cpp +++ b/source/slang/slang-ir-constexpr.cpp @@ -3,6 +3,7 @@ #include "slang-ir-dominators.h" #include "slang-ir-insts.h" +#include "slang-ir-util.h" #include "slang-ir.h" namespace Slang @@ -59,8 +60,12 @@ bool isConstExpr(IRInst* value) case kIROp_StructKey: case kIROp_WitnessTable: case kIROp_Generic: + case kIROp_GlobalConstant: return true; - + case kIROp_Param: + if (isGenericParam(value)) + return true; + break; default: break; } @@ -156,8 +161,10 @@ bool opCanBeConstExprByForwardPass(IRInst* value) { // TODO: handle call inst here. - if (value->getOp() == kIROp_Param) + if (value->getOp() == kIROp_Param || value->getOp() == kIROp_Specialize) + { return false; + } return opCanBeConstExpr(value->getOp()); } @@ -393,12 +400,6 @@ bool propagateConstExprBackward(PropagateConstExprContext* context, IRGlobalValu // the callee for this call statically, and if so try to propagate // constexpr from the parameters back to the arguments. auto callInst = (IRCall*)ii; - - UInt operandCount = callInst->getOperandCount(); - - UInt firstCallArg = 1; - UInt callArgCount = operandCount - firstCallArg; - auto callee = callInst->getOperand(0); // If we are calling a generic operation, then @@ -423,64 +424,35 @@ bool propagateConstExprBackward(PropagateConstExprContext* context, IRGlobalValu } auto calleeFunc = as<IRFunc>(callee); - if (calleeFunc && isDefinition(calleeFunc)) + auto calleeType = callee->getDataType(); + if (auto caleeFuncType = as<IRFuncType>(calleeType)) { - // We have an IR-level function definition we are calling, - // and thus we can propagate `constexpr` information - // through its `IRParam`s. - - auto calleeFuncType = calleeFunc->getDataType(); - - UInt callParamCount = calleeFuncType->getParamCount(); - SLANG_RELEASE_ASSERT(callParamCount == callArgCount); - - // If the callee has a definition, then we can read `constexpr` - // information off of the parameters of its first IR block. - if (auto calleeFirstBlock = calleeFunc->getFirstBlock()) + UInt operandCount = callInst->getOperandCount(); + UInt firstCallArg = 1; + UInt callArgCount = operandCount - firstCallArg; + auto paramCount = caleeFuncType->getParamCount(); + SLANG_RELEASE_ASSERT(paramCount == callArgCount); + for (UInt pp = 0; pp < paramCount; ++pp) { - UInt paramCounter = 0; - for (auto pp = calleeFirstBlock->getFirstParam(); pp; - pp = pp->getNextParam()) + auto paramType = caleeFuncType->getParamType(pp); + if (isConstExpr(paramType)) { - UInt paramIndex = paramCounter++; - - auto param = pp; - auto arg = callInst->getOperand(firstCallArg + paramIndex); - - if (isConstExpr(param)) + auto arg = callInst->getOperand(firstCallArg + pp); + if (maybeMarkConstExprBackwardPass(context, arg)) { - if (maybeMarkConstExprBackwardPass(context, arg)) - { - changedThisIteration = true; - } + changedThisIteration = true; } - } - } - } - else - { - // If we don't have a concrete callee function - // definition, then we need to extract the - // type of the callee instruction, and try to work - // with that. - // - // Note that this does not allow us to propagate - // `constexpr` information from the body of a callee - // back to call sites. - auto calleeType = callee->getDataType(); - if (auto caleeFuncType = as<IRFuncType>(calleeType)) - { - auto paramCount = caleeFuncType->getParamCount(); - for (UInt pp = 0; pp < paramCount; ++pp) - { - auto paramType = caleeFuncType->getParamType(pp); - auto arg = callInst->getOperand(firstCallArg + pp); - if (isConstExpr(paramType)) + // If arg is not constexpr after this, meaning it can't be + // marked constexpr for some reason, but the param requires + // that. This is not expected. + if (!isConstExpr(arg)) { - if (maybeMarkConstExprBackwardPass(context, arg)) - { - changedThisIteration = true; - } + context->getSink()->diagnose( + callInst->sourceLoc, + Diagnostics::argIsNotConstexpr, + pp + 1, + calleeFunc); + return false; } } } |
