From 54d9b345bff4b01949e875366cb1e7cf1c021c61 Mon Sep 17 00:00:00 2001 From: "James Helferty (NVIDIA)" Date: Wed, 8 Oct 2025 19:11:10 -0400 Subject: parser: Avoid dropping modifiers when splitting list (#8546) Fix for a linked list usage bug; avoids dropping any modifiers when moving type modifiers from a linked list of modifiers into their own linked list. Since this change results in no_diff modifiers to traditional functions ending up on the return type instead of the function (due to the order they're parsed in), we duplicate the no_diff modifier onto the function declaration after the fact. Includes a test for the original issue. The no_diff redistribution case is covered by a slangpy device test case. Fixes #8332 --------- Co-authored-by: slangbot <186143334+slangbot@users.noreply.github.com> --- source/slang/slang-check-decl.cpp | 18 ++++++++++++++++++ source/slang/slang-parser.cpp | 21 ++++++++------------- 2 files changed, 26 insertions(+), 13 deletions(-) (limited to 'source') diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index 4bfbde584..867c1daad 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -10241,6 +10241,17 @@ void SemanticsDeclHeaderVisitor::checkInterfaceRequirement(Decl* decl) } } +bool doesTypeHaveNoDiffModifier(Type* type) +{ + if (auto modifiedType = as(type)) + { + if (modifiedType->findModifier() != nullptr) + return true; + return doesTypeHaveNoDiffModifier(modifiedType->getBase()); + } + return false; +} + void SemanticsDeclHeaderVisitor::checkCallableDeclCommon(CallableDecl* decl) { for (auto paramDecl : decl->getParameters()) @@ -10259,6 +10270,13 @@ void SemanticsDeclHeaderVisitor::checkCallableDeclCommon(CallableDecl* decl) } decl->errorType = errorType; + if (doesTypeHaveNoDiffModifier(decl->returnType.type)) + { + auto noDiffMod = m_astBuilder->create(); + noDiffMod->loc = decl->loc; + addModifier(decl, noDiffMod); + } + checkDifferentiableCallableCommon(decl); // If this method is intended to be a CUDA kernel, verify that the return type is void. diff --git a/source/slang/slang-parser.cpp b/source/slang/slang-parser.cpp index 3519b6d43..7208ab67e 100644 --- a/source/slang/slang-parser.cpp +++ b/source/slang/slang-parser.cpp @@ -2708,14 +2708,14 @@ static Expr* _applyModifiersToTypeExpr(Parser* parser, Expr* typeExpr, Modifiers } } -/// Apply any type modifier in `ioBaseModifiers` to the given `typeExpr`. +/// Move any type modifier in `ioBaseModifiers` to the given `typeExpr`. /// /// If any type modifiers were present, `ioBaseModifiers` will be updated /// to only include those modifiers that were not type modifiers (if any). /// /// If no type modifiers were present, `ioBaseModifiers` will remain unchanged. /// -static Expr* _applyTypeModifiersToTypeExpr( +static Expr* _moveTypeModifiersToTypeExpr( Parser* parser, Expr* typeExpr, Modifiers& ioBaseModifiers) @@ -2763,7 +2763,7 @@ static Expr* _applyTypeModifiersToTypeExpr( // a pointer to the type modifier into the "link" for // the type modifier list, and updating the link to point // to the `next` field of the current modifier (since that - // fill be the location any further type modifiers need + // will be the location any further type modifiers need // to be linked). // *typeModifierLink = typeModifier; @@ -2792,10 +2792,7 @@ static Expr* _applyTypeModifiersToTypeExpr( return _applyModifiersToTypeExpr(parser, typeExpr, typeModifiers); } -static TypeSpec _applyModifiersToTypeSpec( - Parser* parser, - TypeSpec typeSpec, - Modifiers const& inModifiers) +static TypeSpec _applyModifiersToTypeSpec(Parser* parser, TypeSpec typeSpec, Modifiers& modifiers) { // It is possible that the form of the type specifier will have // included a declaration directly (e.g., using `struct { ... }` @@ -2809,8 +2806,7 @@ static TypeSpec _applyModifiersToTypeSpec( // and any modifiers that logically belong to the declaration to // the declaration. // - Modifiers modifiers = inModifiers; - typeSpec.expr = _applyTypeModifiersToTypeExpr(parser, typeSpec.expr, modifiers); + typeSpec.expr = _moveTypeModifiersToTypeExpr(parser, typeSpec.expr, modifiers); // Any remaining modifiers should instead be applied to the declaration. _addModifiers(decl, modifiers); @@ -2821,7 +2817,7 @@ static TypeSpec _applyModifiersToTypeSpec( // This may result in modifiers being applied that do not belong on a type; // in that case we rely on downstream semantic checking to diagnose any error. // - typeSpec.expr = _applyModifiersToTypeExpr(parser, typeSpec.expr, inModifiers); + typeSpec.expr = _applyModifiersToTypeExpr(parser, typeSpec.expr, modifiers); } return typeSpec; @@ -2962,7 +2958,7 @@ static TypeSpec _parseTypeSpec(Parser* parser, Modifiers& ioModifiers) // or which of them might be type modifiers, so we will delegate // figuring that out to a subroutine. // - typeSpec.expr = _applyTypeModifiersToTypeExpr(parser, typeSpec.expr, ioModifiers); + typeSpec.expr = _moveTypeModifiersToTypeExpr(parser, typeSpec.expr, ioModifiers); return typeSpec; } @@ -2992,11 +2988,10 @@ static TypeSpec _parseTypeSpec(Parser* parser) static DeclBase* ParseDeclaratorDecl( Parser* parser, ContainerDecl* containerDecl, - Modifiers const& inModifiers) + Modifiers& modifiers) { SourceLoc startPosition = parser->tokenReader.peekLoc(); - Modifiers modifiers = inModifiers; auto typeSpec = _parseTypeSpec(parser, modifiers); if (typeSpec.expr == nullptr && typeSpec.decl == nullptr) -- cgit v1.2.3