https://github.com/s-perron updated 
https://github.com/llvm/llvm-project/pull/195154

>From 18e85499053dc9811c98bce4667244d471462125 Mon Sep 17 00:00:00 2001
From: Steven Perron <[email protected]>
Date: Thu, 30 Apr 2026 11:52:48 -0400
Subject: [PATCH 1/2] [HLSL] Add type traits for ConstantBuffers templates

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
---
 clang/include/clang/Basic/TokenKinds.def      |  1 +
 clang/include/clang/Sema/SemaHLSL.h           |  1 +
 clang/lib/Sema/HLSLExternalSemaSource.cpp     | 50 ++++++++++++++++---
 clang/lib/Sema/SemaHLSL.cpp                   | 13 +++++
 clang/lib/Sema/SemaTypeTraits.cpp             |  9 ++++
 .../SemaHLSL/BuiltIns/ConstantBuffers.hlsl    | 33 ++++++++++++
 6 files changed, 101 insertions(+), 6 deletions(-)

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
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@+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@+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@+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@+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@+1 {{use of class template 'Texture2D' requires template 
arguments}}
+ConstantBuffer<Texture2D> cb_tex;
+// expected-note@* {{template declaration from hidden source}}
+
+// Invalid: union
+// expected-error@+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() {

>From 14dd30edaeb6f2b8cc2e4588a1b057e505211a35 Mon Sep 17 00:00:00 2001
From: Steven Perron <[email protected]>
Date: Thu, 7 May 2026 16:30:50 -0400
Subject: [PATCH 2/2] Move test file, and add new test.

---
 .../SemaHLSL/{BuiltIns => Resources}/ConstantBuffers.hlsl   | 6 ++++++
 1 file changed, 6 insertions(+)
 rename clang/test/SemaHLSL/{BuiltIns => Resources}/ConstantBuffers.hlsl (88%)

diff --git a/clang/test/SemaHLSL/BuiltIns/ConstantBuffers.hlsl 
b/clang/test/SemaHLSL/Resources/ConstantBuffers.hlsl
similarity index 88%
rename from clang/test/SemaHLSL/BuiltIns/ConstantBuffers.hlsl
rename to clang/test/SemaHLSL/Resources/ConstantBuffers.hlsl
index e6c42429a7d97..0ef3ada50c988 100644
--- a/clang/test/SemaHLSL/BuiltIns/ConstantBuffers.hlsl
+++ b/clang/test/SemaHLSL/Resources/ConstantBuffers.hlsl
@@ -47,6 +47,12 @@ ConstantBuffer<ContainsResource> cb_res;
 ConstantBuffer<Texture2D> cb_tex;
 // expected-note@* {{template declaration from hidden source}}
 
+// Invalid: intangible type
+// expected-error@+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@+1 {{constraints not satisfied for class template 
'ConstantBuffer'}}
 ConstantBuffer<U> cb_union;

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to