[clang] 90a2a8e - [HLSL] Add type traits for ConstantBuffers templates (#195154)
via cfe-commits
cfe-commits at lists.llvm.org
Fri May 8 07:06:57 PDT 2026
Author: Steven Perron
Date: 2026-05-08T14:06:51Z
New Revision: 90a2a8e6d0427804233b0aa58969b65bae87e425
URL: https://github.com/llvm/llvm-project/commit/90a2a8e6d0427804233b0aa58969b65bae87e425
DIFF: https://github.com/llvm/llvm-project/commit/90a2a8e6d0427804233b0aa58969b65bae87e425.diff
LOG: [HLSL] Add type traits for ConstantBuffers templates (#195154)
This commit adds the type traits to restrict the template type in a
ConstantBuffer to structs or classes that do not contain a resource
type.
Assisted-by: Gemini
<!-- branch-stack-start -->
-------------------------
- main
- https://github.com/llvm/llvm-project/pull/195151
- https://github.com/llvm/llvm-project/pull/195152
- https://github.com/llvm/llvm-project/pull/195153
- https://github.com/llvm/llvm-project/pull/195154 :point_left:
<sup>[Stack](https://www.git-town.com/how-to/proposal-breadcrumb.html)
generated by [Git Town](https://github.com/git-town/git-town)</sup>
<!-- branch-stack-end -->
Added:
clang/test/SemaHLSL/Resources/ConstantBuffers.hlsl
Modified:
clang/include/clang/Basic/TokenKinds.def
clang/include/clang/Sema/SemaHLSL.h
clang/lib/Sema/HLSLExternalSemaSource.cpp
clang/lib/Sema/SemaHLSL.cpp
clang/lib/Sema/SemaTypeTraits.cpp
Removed:
clang/test/SemaHLSL/BuiltIns/ConstantBuffers.hlsl
################################################################################
diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def
index 005d81b5b9282..f07d8ebb75035 100644
--- a/clang/include/clang/Basic/TokenKinds.def
+++ b/clang/include/clang/Basic/TokenKinds.def
@@ -691,6 +691,7 @@ KEYWORD(column_major , KEYHLSL)
TYPE_TRAIT_2(__builtin_hlsl_is_scalarized_layout_compatible, IsScalarizedLayoutCompatible, KEYHLSL)
TYPE_TRAIT_1(__builtin_hlsl_is_intangible, IsIntangibleType, KEYHLSL)
TYPE_TRAIT_1(__builtin_hlsl_is_typed_resource_element_compatible, IsTypedResourceElementCompatible, KEYHLSL)
+TYPE_TRAIT_1(__builtin_hlsl_is_constant_buffer_element_compatible, IsConstantBufferElementCompatible, KEYHLSL)
// OpenMP Type Traits
UNARY_EXPR_OR_TYPE_TRAIT(__builtin_omp_required_simd_align, OpenMPRequiredSimdAlign, KEYALL)
diff --git a/clang/include/clang/Sema/SemaHLSL.h b/clang/include/clang/Sema/SemaHLSL.h
index 68c2f209976c4..e65de5d4aa4c3 100644
--- a/clang/include/clang/Sema/SemaHLSL.h
+++ b/clang/include/clang/Sema/SemaHLSL.h
@@ -216,6 +216,7 @@ class SemaHLSL : public SemaBase {
// HLSL Type trait implementations
bool IsScalarizedLayoutCompatible(QualType T1, QualType T2) const;
bool IsTypedResourceElementCompatible(QualType T1);
+ bool IsConstantBufferElementCompatible(QualType T1);
bool CheckCompatibleParameterABI(FunctionDecl *New, FunctionDecl *Old);
diff --git a/clang/lib/Sema/HLSLExternalSemaSource.cpp b/clang/lib/Sema/HLSLExternalSemaSource.cpp
index 9769eee10ae2f..449b32a215631 100644
--- a/clang/lib/Sema/HLSLExternalSemaSource.cpp
+++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp
@@ -365,6 +365,32 @@ static Expr *constructTypedBufferConstraintExpr(Sema &S, SourceLocation NameLoc,
return TypedResExpr;
}
+// This function is responsible for constructing the constraint expression for
+// this concept:
+// template<typename T> concept is_constant_buffer_element_compatible =
+// std::is_class_v<T> && !__is_intangible(T);
+static Expr *constructConstantBufferConstraintExpr(Sema &S,
+ SourceLocation NameLoc,
+ TemplateTypeParmDecl *T) {
+ ASTContext &Context = S.getASTContext();
+
+ // Obtain the QualType for 'bool'
+ QualType BoolTy = Context.BoolTy;
+
+ // Create a QualType that points to this TemplateTypeParmDecl
+ QualType TType = Context.getTypeDeclType(T);
+
+ // Create a TypeSourceInfo for the template type parameter 'T'
+ TypeSourceInfo *TTypeSourceInfo =
+ Context.getTrivialTypeSourceInfo(TType, NameLoc);
+
+ TypeTraitExpr *ResExpr = TypeTraitExpr::Create(
+ Context, BoolTy, NameLoc, UTT_IsConstantBufferElementCompatible,
+ {TTypeSourceInfo}, NameLoc, true);
+
+ return ResExpr;
+}
+
// This function is responsible for constructing the constraint expression for
// this concept:
// template<typename T> concept is_structured_resource_element_compatible =
@@ -415,8 +441,10 @@ static Expr *constructStructuredBufferConstraintExpr(Sema &S,
return CombinedExpr;
}
+enum class HLSLBufferType { Typed, Structured, Constant };
+
static ConceptDecl *constructBufferConceptDecl(Sema &S, NamespaceDecl *NSD,
- bool isTypedBuffer) {
+ HLSLBufferType BT) {
ASTContext &Context = S.getASTContext();
DeclContext *DC = NSD->getDeclContext();
SourceLocation DeclLoc = SourceLocation();
@@ -440,14 +468,22 @@ static ConceptDecl *constructBufferConceptDecl(Sema &S, NamespaceDecl *NSD,
DeclarationName DeclName;
Expr *ConstraintExpr = nullptr;
- if (isTypedBuffer) {
+ switch (BT) {
+ case HLSLBufferType::Typed:
DeclName = DeclarationName(
&Context.Idents.get("__is_typed_resource_element_compatible"));
ConstraintExpr = constructTypedBufferConstraintExpr(S, DeclLoc, T);
- } else {
+ break;
+ case HLSLBufferType::Structured:
DeclName = DeclarationName(
&Context.Idents.get("__is_structured_resource_element_compatible"));
ConstraintExpr = constructStructuredBufferConstraintExpr(S, DeclLoc, T);
+ break;
+ case HLSLBufferType::Constant:
+ DeclName = DeclarationName(
+ &Context.Idents.get("__is_constant_buffer_element_compatible"));
+ ConstraintExpr = constructConstantBufferConstraintExpr(S, DeclLoc, T);
+ break;
}
// Create a ConceptDecl
@@ -468,12 +504,14 @@ void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() {
ASTContext &AST = SemaPtr->getASTContext();
CXXRecordDecl *Decl;
ConceptDecl *TypedBufferConcept = constructBufferConceptDecl(
- *SemaPtr, HLSLNamespace, /*isTypedBuffer*/ true);
+ *SemaPtr, HLSLNamespace, HLSLBufferType::Typed);
ConceptDecl *StructuredBufferConcept = constructBufferConceptDecl(
- *SemaPtr, HLSLNamespace, /*isTypedBuffer*/ false);
+ *SemaPtr, HLSLNamespace, HLSLBufferType::Structured);
+ ConceptDecl *ConstantBufferConcept = constructBufferConceptDecl(
+ *SemaPtr, HLSLNamespace, HLSLBufferType::Constant);
Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "ConstantBuffer")
- .addSimpleTemplateParams({"element_type"})
+ .addSimpleTemplateParams({"element_type"}, ConstantBufferConcept)
.finalizeForwardDeclaration();
onCompletion(Decl, [this](CXXRecordDecl *Decl) {
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 594a18f0b8c78..4a7df5b4266f6 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -4700,6 +4700,19 @@ static void BuildFlattenedTypeList(QualType BaseTy,
}
}
+bool SemaHLSL::IsConstantBufferElementCompatible(clang::QualType QT) {
+ if (QT.isNull())
+ return false;
+
+ // Must be a class/struct.
+ const auto *RD = QT->getAsCXXRecordDecl();
+ if (!RD || RD->isUnion())
+ return false;
+
+ // Cannot be a resource type or contain one.
+ return !QT->isHLSLIntangibleType();
+}
+
bool SemaHLSL::IsTypedResourceElementCompatible(clang::QualType QT) {
// null and array types are not allowed.
if (QT.isNull() || QT->isArrayType())
diff --git a/clang/lib/Sema/SemaTypeTraits.cpp b/clang/lib/Sema/SemaTypeTraits.cpp
index a94a59e8add7b..c79b3f7045ca6 100644
--- a/clang/lib/Sema/SemaTypeTraits.cpp
+++ b/clang/lib/Sema/SemaTypeTraits.cpp
@@ -367,6 +367,7 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S, TypeTrait UTT,
case UTT_IsCompound:
case UTT_IsMemberPointer:
case UTT_IsTypedResourceElementCompatible:
+ case UTT_IsConstantBufferElementCompatible:
// Fall-through
// These traits are modeled on type predicates in C++0x [meta.unary.prop]
@@ -1131,6 +1132,14 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
return false;
return Self.HLSL().IsTypedResourceElementCompatible(T);
+
+ case UTT_IsConstantBufferElementCompatible:
+ assert(Self.getLangOpts().HLSL &&
+ "constant buffer element compatible types are an HLSL-only feature");
+ if (T->isIncompleteType())
+ return false;
+
+ return Self.HLSL().IsConstantBufferElementCompatible(T);
}
}
diff --git a/clang/test/SemaHLSL/BuiltIns/ConstantBuffers.hlsl b/clang/test/SemaHLSL/BuiltIns/ConstantBuffers.hlsl
deleted file mode 100644
index 10c65031b79f2..0000000000000
--- a/clang/test/SemaHLSL/BuiltIns/ConstantBuffers.hlsl
+++ /dev/null
@@ -1,35 +0,0 @@
-// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -x hlsl -finclude-default-header -fsyntax-only -verify %s
-
-struct S { // expected-note 3 {{candidate constructor}}
- float a;
- int b;
-};
-
-struct Empty {};
-
-struct ContainsResource {
- Texture2D tex;
-};
-
-union U {
- float a;
- int b;
-};
-
-// Valid
-ConstantBuffer<S> cb;
-ConstantBuffer<Empty> cb_empty;
-
-void takes_inout_s(inout S s) {}
-
-void foo() {
- // This case should fail because we cannot writeback to `cb` after the call.
- // expected-error at +1 {{no viable constructor copying parameter of type 'const hlsl_constant S'}}
- takes_inout_s(cb);
-}
-
-void test_direct_assignment() {
- // expected-error at +2 {{cannot assign to return value because function 'operator const hlsl_constant S &' returns a const value}}
- // expected-note@* {{function 'operator const hlsl_constant S &' which returns const-qualified type 'const hlsl_constant S &' declared here}}
- cb.a = 5.0;
-}
diff --git a/clang/test/SemaHLSL/Resources/ConstantBuffers.hlsl b/clang/test/SemaHLSL/Resources/ConstantBuffers.hlsl
new file mode 100644
index 0000000000000..0ef3ada50c988
--- /dev/null
+++ b/clang/test/SemaHLSL/Resources/ConstantBuffers.hlsl
@@ -0,0 +1,74 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -x hlsl -finclude-default-header -fsyntax-only -verify %s
+
+struct S { // expected-note 3 {{candidate constructor}}
+ float a;
+ int b;
+};
+
+struct Empty {};
+
+struct ContainsResource {
+ Texture2D tex;
+};
+
+union U {
+ float a;
+ int b;
+};
+
+// Valid
+ConstantBuffer<S> cb;
+ConstantBuffer<Empty> cb_empty;
+
+// Invalid: non-struct/class
+// expected-error at +1 {{constraints not satisfied for class template 'ConstantBuffer'}}
+ConstantBuffer<float> cb_float;
+// expected-note@* {{because 'float' does not satisfy '__is_constant_buffer_element_compatible'}}
+// expected-note@* {{because '__builtin_hlsl_is_constant_buffer_element_compatible(float)' evaluated to false}}
+
+// expected-error at +1 {{constraints not satisfied for class template 'ConstantBuffer'}}
+ConstantBuffer<float4> cb_float4;
+// expected-note@* {{because 'float4' (aka 'vector<float, 4>') does not satisfy '__is_constant_buffer_element_compatible'}}
+// expected-note@* {{because '__builtin_hlsl_is_constant_buffer_element_compatible(vector<float, 4>)' evaluated to false}}
+
+// expected-error at +1 {{constraints not satisfied for class template 'ConstantBuffer'}}
+ConstantBuffer<float[4]> cb_array;
+// expected-note@* {{because 'float[4]' does not satisfy '__is_constant_buffer_element_compatible'}}
+// expected-note@* {{because '__builtin_hlsl_is_constant_buffer_element_compatible(float[4])' evaluated to false}}
+
+// Invalid: contains resource
+// expected-error at +1 {{constraints not satisfied for class template 'ConstantBuffer'}}
+ConstantBuffer<ContainsResource> cb_res;
+// expected-note@* {{because 'ContainsResource' does not satisfy '__is_constant_buffer_element_compatible'}}
+// expected-note@* {{because '__builtin_hlsl_is_constant_buffer_element_compatible(ContainsResource)' evaluated to false}}
+
+// Invalid: intangible type
+// expected-error at +1 {{use of class template 'Texture2D' requires template arguments}}
+ConstantBuffer<Texture2D> cb_tex;
+// expected-note@* {{template declaration from hidden source}}
+
+// Invalid: intangible type
+// expected-error at +1 {{constraints not satisfied for class template 'ConstantBuffer'}}
+ConstantBuffer<Texture2D<float>> cb_tex;
+// expected-note@* {{because 'Texture2D<float>' does not satisfy '__is_constant_buffer_element_compatible'}}
+// expected-note@*:* {{because '__builtin_hlsl_is_constant_buffer_element_compatible(hlsl::Texture2D<float>)' evaluated to false}}
+
+// Invalid: union
+// expected-error at +1 {{constraints not satisfied for class template 'ConstantBuffer'}}
+ConstantBuffer<U> cb_union;
+// expected-note@* {{because 'U' does not satisfy '__is_constant_buffer_element_compatible'}}
+// expected-note@* {{because '__builtin_hlsl_is_constant_buffer_element_compatible(U)' evaluated to false}}
+
+void takes_inout_s(inout S s) {}
+
+void foo() {
+ // This case should fail because we cannot writeback to `cb` after the call.
+ // expected-error at +1 {{no viable constructor copying parameter of type 'const hlsl_constant S'}}
+ takes_inout_s(cb);
+}
+
+void test_direct_assignment() {
+ // expected-error at +2 {{cannot assign to return value because function 'operator const hlsl_constant S &' returns a const value}}
+ // expected-note@* {{function 'operator const hlsl_constant S &' which returns const-qualified type 'const hlsl_constant S &' declared here}}
+ cb.a = 5.0;
+}
More information about the cfe-commits
mailing list