[clang] 06b1455 - [HLSL] Update type for `out` arguments only for dependent params types (#163832)
via cfe-commits
cfe-commits at lists.llvm.org
Thu Oct 16 20:31:45 PDT 2025
Author: Helena Kotas
Date: 2025-10-16T20:31:41-07:00
New Revision: 06b14558ad8f572c95afb5860361c981978a8e8b
URL: https://github.com/llvm/llvm-project/commit/06b14558ad8f572c95afb5860361c981978a8e8b
DIFF: https://github.com/llvm/llvm-project/commit/06b14558ad8f572c95afb5860361c981978a8e8b.diff
LOG: [HLSL] Update type for `out` arguments only for dependent params types (#163832)
When a template function with `out` arguments is instantiated, only the arguments with dependent types need to have their `out` type updated to a restricted reference. Non-dependent argument types have already been converted and the template instantiation should not change that.
Fixes #163648
Added:
Modified:
clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
clang/test/SemaHLSL/Language/TemplateOutArg.hlsl
Removed:
################################################################################
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 468bc1d677ac2..4ace03dd1d130 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<ParmVarDecl>(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<ParmVarDecl>(New);
+ NewParm->addAttr(Attr->clone(S.getASTContext()));
+
+ const Type *OldParmTy = cast<ParmVarDecl>(Old)->getType().getTypePtr();
+ 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");
}
void Sema::InstantiateAttrsForDecl(
@@ -923,7 +931,7 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs,
if (const auto *ParamAttr = dyn_cast<HLSLParamModifierAttr>(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..3365dbefabfcd 100644
--- a/clang/test/SemaHLSL/Language/TemplateOutArg.hlsl
+++ b/clang/test/SemaHLSL/Language/TemplateOutArg.hlsl
@@ -195,6 +195,81 @@ 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 <typename T>
+void fizz_two(inout T V, out int I) {
+ V += 2;
+ 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 <typename T>
+int buzz_two(in T A, in int B) {
+ return A + B;
+}
+
export void caller() {
int X = 2;
float Y = 3.3;
@@ -211,4 +286,12 @@ 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);
+
+ X = buzz_two(X, X);
+ X = buzz_two(Y, X);
+ X = buzz_two(Z, X);
}
More information about the cfe-commits
mailing list