From 607518b418053e4ef29c7b1a9b9a9bded4c48fb2 Mon Sep 17 00:00:00 2001 From: Helena Kotas Date: Thu, 16 Oct 2025 10:46:12 -0700 Subject: [PATCH 1/3] [HLSL] Update type for `out` arguments on template instantiation only for dependent params types Non-dependent argument types have already been converted to a reference and the template instantiation should not change that. Fixes #163648 --- .../lib/Sema/SemaTemplateInstantiateDecl.cpp | 18 +++++--- .../SemaHLSL/Language/TemplateOutArg.hlsl | 42 +++++++++++++++++++ 2 files changed, 55 insertions(+), 5 deletions(-) diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 468bc1d677ac2..f515704aca5b3 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -765,10 +765,18 @@ static bool isRelevantAttr(Sema &S, const Decl *D, const Attr *A) { static void instantiateDependentHLSLParamModifierAttr( Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs, - const HLSLParamModifierAttr *Attr, Decl *New) { - ParmVarDecl *P = cast(New); - P->addAttr(Attr->clone(S.getASTContext())); - P->setType(S.HLSL().getInoutParameterType(P->getType())); + const HLSLParamModifierAttr *Attr, const Decl *Old, Decl *New) { + ParmVarDecl *NewParm = cast(New); + NewParm->addAttr(Attr->clone(S.getASTContext())); + + const Type *OldParmTy = cast(Old)->getType().getTypePtr(); + if (OldParmTy->isDependentType()) + NewParm->setType(S.HLSL().getInoutParameterType(NewParm->getType())); + + assert(!Attr->isAnyOut() || (NewParm->getType().isRestrictQualified() && + NewParm->getType()->isReferenceType()) && + "out or inout parameter type must be a " + "reference and restrict qualified"); } void Sema::InstantiateAttrsForDecl( @@ -923,7 +931,7 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs, if (const auto *ParamAttr = dyn_cast(TmplAttr)) { instantiateDependentHLSLParamModifierAttr(*this, TemplateArgs, ParamAttr, - New); + Tmpl, New); continue; } diff --git a/clang/test/SemaHLSL/Language/TemplateOutArg.hlsl b/clang/test/SemaHLSL/Language/TemplateOutArg.hlsl index 2d6252cbb4d2b..543869ef058db 100644 --- a/clang/test/SemaHLSL/Language/TemplateOutArg.hlsl +++ b/clang/test/SemaHLSL/Language/TemplateOutArg.hlsl @@ -195,6 +195,44 @@ T buzz(int X, T Y) { return X + Y; } +// Case 4: Verify that the parameter modifier attributes are instantiated +// for both templated and non-templated arguments, and that the non-templated +// out argument type is not modified by the template instantiation. + +// CHECK-LABEL: FunctionTemplateDecl {{.*}} fizz_two + +// Check the pattern decl. +// CHECK: FunctionDecl {{.*}} fizz_two 'void (inout T, out int)' +// CHECK-NEXT: ParmVarDecl {{.*}} referenced V 'T' +// CHECK-NEXT: HLSLParamModifierAttr {{.*}} inout +// CHECK-NEXT: ParmVarDecl {{.*}} referenced I 'int &__restrict' +// CHECK-NEXT: HLSLParamModifierAttr {{.*}} out + +// Check the 3 instantiations (int, float, & double). + +// CHECK-LABEL: FunctionDecl {{.*}} used fizz_two 'void (inout int, out int)' implicit_instantiation +// CHECK: ParmVarDecl {{.*}} used V 'int &__restrict' +// CHECK-NEXT: HLSLParamModifierAttr {{.*}} inout +// CHECK: ParmVarDecl {{.*}} used I 'int &__restrict' +// CHECK-NEXT: HLSLParamModifierAttr {{.*}} out + +// CHECK-LABEL: FunctionDecl {{.*}} used fizz_two 'void (inout float, out int)' implicit_instantiation +// CHECK: ParmVarDecl {{.*}} used V 'float &__restrict' +// CHECK-NEXT: HLSLParamModifierAttr {{.*}} inout +// CHECK: ParmVarDecl {{.*}} used I 'int &__restrict' +// CHECK-NEXT: HLSLParamModifierAttr {{.*}} out + +// CHECK-LABEL: FunctionDecl {{.*}} used fizz_two 'void (inout double, out int)' implicit_instantiation +// CHECK: ParmVarDecl {{.*}} used V 'double &__restrict' +// CHECK-NEXT: HLSLParamModifierAttr {{.*}} inout +// CHECK: ParmVarDecl {{.*}} used I 'int &__restrict' +// CHECK-NEXT: HLSLParamModifierAttr {{.*}} out +template +void fizz_two(inout T V, out int I) { + V += 2; + I = V; +} + export void caller() { int X = 2; float Y = 3.3; @@ -211,4 +249,8 @@ export void caller() { X = buzz(X, X); Y = buzz(X, Y); Z = buzz(X, Z); + + fizz_two(X, X); + fizz_two(Y, X); + fizz_two(Z, X); } From f2ddce4c79549e0a865cef195efbd6bad934a7e9 Mon Sep 17 00:00:00 2001 From: Helena Kotas Date: Thu, 16 Oct 2025 13:41:56 -0700 Subject: [PATCH 2/3] Add fix and test case for `in` modifier --- .../lib/Sema/SemaTemplateInstantiateDecl.cpp | 2 +- .../SemaHLSL/Language/TemplateOutArg.hlsl | 41 +++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index f515704aca5b3..a62f84a413f2d 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -770,7 +770,7 @@ static void instantiateDependentHLSLParamModifierAttr( NewParm->addAttr(Attr->clone(S.getASTContext())); const Type *OldParmTy = cast(Old)->getType().getTypePtr(); - if (OldParmTy->isDependentType()) + if (OldParmTy->isDependentType() && Attr->isAnyOut()) NewParm->setType(S.HLSL().getInoutParameterType(NewParm->getType())); assert(!Attr->isAnyOut() || (NewParm->getType().isRestrictQualified() && diff --git a/clang/test/SemaHLSL/Language/TemplateOutArg.hlsl b/clang/test/SemaHLSL/Language/TemplateOutArg.hlsl index 543869ef058db..3365dbefabfcd 100644 --- a/clang/test/SemaHLSL/Language/TemplateOutArg.hlsl +++ b/clang/test/SemaHLSL/Language/TemplateOutArg.hlsl @@ -233,6 +233,43 @@ void fizz_two(inout T V, out int I) { I = V; } +// Case 5: Verify that `in` parameter modifier attributes are instantiated +// for both templated and non-templated arguments and argument types are not +// modified + +// CHECK-LABEL: FunctionTemplateDecl {{.*}} buzz_two + +// Check the pattern decl. +// CHECK: FunctionDecl {{.*}} buzz_two 'int (T, int)' +// CHECK-NEXT: ParmVarDecl {{.*}} referenced A 'T' +// CHECK-NEXT: HLSLParamModifierAttr {{.*}} in +// CHECK-NEXT: ParmVarDecl {{.*}} referenced B 'int' +// CHECK-NEXT: HLSLParamModifierAttr {{.*}} in + +// Check the 3 instantiations (int, float, & double). + +// CHECK-LABEL: FunctionDecl {{.*}} used buzz_two 'int (int, int)' implicit_instantiation +// CHECK: ParmVarDecl {{.*}} used A 'int' +// CHECK-NEXT: HLSLParamModifierAttr {{.*}} in +// CHECK: ParmVarDecl {{.*}} used B 'int' +// CHECK-NEXT: HLSLParamModifierAttr {{.*}} in + +// CHECK-LABEL: FunctionDecl {{.*}} used buzz_two 'int (float, int)' implicit_instantiation +// CHECK: ParmVarDecl {{.*}} used A 'float' +// CHECK-NEXT: HLSLParamModifierAttr {{.*}} in +// CHECK: ParmVarDecl {{.*}} used B 'int' +// CHECK-NEXT: HLSLParamModifierAttr {{.*}} in + +// CHECK-LABEL: FunctionDecl {{.*}} used buzz_two 'int (double, int)' implicit_instantiation +// CHECK: ParmVarDecl {{.*}} used A 'double' +// CHECK-NEXT: HLSLParamModifierAttr {{.*}} in +// CHECK: ParmVarDecl {{.*}} used B 'int' +// CHECK-NEXT: HLSLParamModifierAttr {{.*}} in +template +int buzz_two(in T A, in int B) { + return A + B; +} + export void caller() { int X = 2; float Y = 3.3; @@ -253,4 +290,8 @@ export void caller() { fizz_two(X, X); fizz_two(Y, X); fizz_two(Z, X); + + X = buzz_two(X, X); + X = buzz_two(Y, X); + X = buzz_two(Z, X); } From e3d70804b050e8529cdbf3902822f60c870eea33 Mon Sep 17 00:00:00 2001 From: Helena Kotas Date: Thu, 16 Oct 2025 14:25:50 -0700 Subject: [PATCH 3/3] add parens to assert --- clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index a62f84a413f2d..4ace03dd1d130 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -773,10 +773,10 @@ static void instantiateDependentHLSLParamModifierAttr( if (OldParmTy->isDependentType() && Attr->isAnyOut()) NewParm->setType(S.HLSL().getInoutParameterType(NewParm->getType())); - assert(!Attr->isAnyOut() || (NewParm->getType().isRestrictQualified() && - NewParm->getType()->isReferenceType()) && - "out or inout parameter type must be a " - "reference and restrict qualified"); + assert( + (!Attr->isAnyOut() || (NewParm->getType().isRestrictQualified() && + NewParm->getType()->isReferenceType())) && + "out or inout parameter type must be a reference and restrict qualified"); } void Sema::InstantiateAttrsForDecl(