[llvm-branch-commits] [clang] [HLSL] Add type traits for ConstantBuffers templates (PR #195154)
via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Thu Apr 30 11:54:38 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Steven Perron (s-perron)
<details>
<summary>Changes</summary>
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
- users/s-perron/constantbuffer-type-trait :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 -->
---
Full diff: https://github.com/llvm/llvm-project/pull/195154.diff
6 Files Affected:
- (modified) clang/include/clang/Basic/TokenKinds.def (+1)
- (modified) clang/include/clang/Sema/SemaHLSL.h (+1)
- (modified) clang/lib/Sema/HLSLExternalSemaSource.cpp (+44-6)
- (modified) clang/lib/Sema/SemaHLSL.cpp (+13)
- (modified) clang/lib/Sema/SemaTypeTraits.cpp (+9)
- (modified) clang/test/SemaHLSL/BuiltIns/ConstantBuffers.hlsl (+33)
``````````diff
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 7a8fb5492f8df..75cb00e2eb316 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 10ffa7d6ab370..e4fafb2c0645e 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 3280ea2338bb6..e3ce06e89c2c7 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -4699,6 +4699,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
index 10c65031b79f2..e6c42429a7d97 100644
--- a/clang/test/SemaHLSL/BuiltIns/ConstantBuffers.hlsl
+++ b/clang/test/SemaHLSL/BuiltIns/ConstantBuffers.hlsl
@@ -20,6 +20,39 @@ union U {
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: 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() {
``````````
</details>
https://github.com/llvm/llvm-project/pull/195154
More information about the llvm-branch-commits
mailing list