[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