[clang] [HLSL] Add __is_scalarized_layout_compatible (PR #102227)
Chris B via cfe-commits
cfe-commits at lists.llvm.org
Thu Aug 15 13:26:30 PDT 2024
https://github.com/llvm-beanz updated https://github.com/llvm/llvm-project/pull/102227
>From 5361c74f0130839870dae2b84abd9d9e75cf787b Mon Sep 17 00:00:00 2001
From: Chris Bieneman <chris.bieneman at me.com>
Date: Mon, 5 Aug 2024 13:22:47 -0500
Subject: [PATCH 1/2] [HLSL] Add __is_scalarized_layout_compatible
HLSL tends to rely pretty aggressively on scalarization occuring in the
complier, which allows for some relaxed language behaviors when types
are fully sclarized to equivalent scalar representations.
This change adds a new queryable trait builtin for scalarized layout
compatability.
Resolves #100614
---
clang/include/clang/Basic/TokenKinds.def | 3 +
clang/include/clang/Sema/SemaHLSL.h | 3 +
clang/lib/Headers/hlsl/hlsl_basic_types.h | 4 +
clang/lib/Sema/SemaExprCXX.cpp | 18 +++
clang/lib/Sema/SemaHLSL.cpp | 84 ++++++++++-
.../Traits/ScalarizedLayoutCompatible.hlsl | 132 ++++++++++++++++++
.../ScalarizedLayoutCompatibleErrors.hlsl | 23 +++
7 files changed, 266 insertions(+), 1 deletion(-)
create mode 100644 clang/test/SemaHLSL/Types/Traits/ScalarizedLayoutCompatible.hlsl
create mode 100644 clang/test/SemaHLSL/Types/Traits/ScalarizedLayoutCompatibleErrors.hlsl
diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def
index 2cea64e2bd590b..ede1bb081a2648 100644
--- a/clang/include/clang/Basic/TokenKinds.def
+++ b/clang/include/clang/Basic/TokenKinds.def
@@ -658,6 +658,9 @@ KEYWORD(out , KEYHLSL)
#define HLSL_INTANGIBLE_TYPE(Name, Id, SingletonId) KEYWORD(Name, KEYHLSL)
#include "clang/Basic/HLSLIntangibleTypes.def"
+// HLSL Type traits.
+TYPE_TRAIT_2(__is_scalarized_layout_compatible, IsScalarizedLayoutCompatible, 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 2ddbee67c414bb..4caa08e63aeb6d 100644
--- a/clang/include/clang/Sema/SemaHLSL.h
+++ b/clang/include/clang/Sema/SemaHLSL.h
@@ -61,6 +61,9 @@ class SemaHLSL : public SemaBase {
void handleParamModifierAttr(Decl *D, const ParsedAttr &AL);
bool CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall);
+
+ // HLSL Type trait implementations
+ bool IsScalarizedLayoutCompatible(QualType T1, QualType T2) const;
};
} // namespace clang
diff --git a/clang/lib/Headers/hlsl/hlsl_basic_types.h b/clang/lib/Headers/hlsl/hlsl_basic_types.h
index da6903df65ffed..cfcbb1d4fb231d 100644
--- a/clang/lib/Headers/hlsl/hlsl_basic_types.h
+++ b/clang/lib/Headers/hlsl/hlsl_basic_types.h
@@ -25,8 +25,12 @@ typedef unsigned short uint16_t;
typedef short int16_t;
#endif
+// 32-bit integer.
+typedef int int32_t;
+
// unsigned 32-bit integer.
typedef unsigned int uint;
+typedef unsigned int uint32_t;
// 64-bit integer.
typedef unsigned long uint64_t;
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 1b56b4cabd133e..58c44b695b268e 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -39,6 +39,7 @@
#include "clang/Sema/Scope.h"
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/SemaCUDA.h"
+#include "clang/Sema/SemaHLSL.h"
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/SemaLambda.h"
#include "clang/Sema/SemaObjC.h"
@@ -6188,6 +6189,23 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, const TypeSourceI
TSTToBeDeduced->getTemplateName().getAsTemplateDecl(), RhsT,
Info) == TemplateDeductionResult::Success;
}
+ case BTT_IsScalarizedLayoutCompatible: {
+ if (!LhsT->isVoidType() && !LhsT->isIncompleteArrayType())
+ if (Self.RequireCompleteType(Lhs->getTypeLoc().getBeginLoc(), LhsT,
+ diag::err_incomplete_type))
+ return true;
+ if (!RhsT->isVoidType() && !RhsT->isIncompleteArrayType())
+ if (Self.RequireCompleteType(Rhs->getTypeLoc().getBeginLoc(), RhsT,
+ diag::err_incomplete_type))
+ return true;
+
+ DiagnoseVLAInCXXTypeTrait(Self, Lhs,
+ tok::kw___is_scalarized_layout_compatible);
+ DiagnoseVLAInCXXTypeTrait(Self, Rhs,
+ tok::kw___is_scalarized_layout_compatible);
+
+ return Self.HLSL().IsScalarizedLayoutCompatible(LhsT, RhsT);
+ }
default:
llvm_unreachable("not a BTT");
}
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index a9c0c57e88221d..77d083f36effa8 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -356,7 +356,7 @@ static bool isLegalTypeForHLSLSV_DispatchThreadID(QualType T) {
return true;
}
-void SemaHLSL::handleSV_DispatchThreadIDAttr(Decl *D, const ParsedAttr &AL) {
+void SemaHLSL::handleSV_DispatchThreadIDAttr(Decl *D, const ParsedAttr &AL) {
auto *VD = cast<ValueDecl>(D);
if (!isLegalTypeForHLSLSV_DispatchThreadID(VD->getType())) {
Diag(AL.getLoc(), diag::err_hlsl_attr_invalid_type)
@@ -1142,3 +1142,85 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
}
return false;
}
+
+static void BuildFlattenedTypeList(QualType BaseTy,
+ llvm::SmallVectorImpl<QualType> &List) {
+ llvm::SmallVector<QualType, 16> WorkList;
+ WorkList.push_back(BaseTy);
+ while (!WorkList.empty()) {
+ QualType T = WorkList.pop_back_val();
+ T = T.getCanonicalType().getUnqualifiedType();
+ assert(!isa<MatrixType>(T) && "Matrix types not yet supported in HLSL");
+ if (const auto *AT = dyn_cast<ConstantArrayType>(T)) {
+ llvm::SmallVector<QualType, 16> ElementFields;
+ // Generally I've avoided recursion in this algorithm, but arrays of
+ // structs could be time-consuming to flatten and churn through on the
+ // work list. Hopefully nesting arrays of structs containing arrays
+ // of structs too many levels deep is unlikely.
+ BuildFlattenedTypeList(AT->getElementType(), ElementFields);
+ // Repeat the element's field list n times.
+ for (uint64_t Ct = 0; Ct < AT->getZExtSize(); ++Ct)
+ List.insert(List.end(), ElementFields.begin(), ElementFields.end());
+ continue;
+ }
+ // Vectors can only have element types that are builtin types, so this can
+ // add directly to the list instead of to the WorkList.
+ if (const auto *VT = dyn_cast<VectorType>(T)) {
+ List.insert(List.end(), VT->getNumElements(), VT->getElementType());
+ continue;
+ }
+ if (const auto *RT = dyn_cast<RecordType>(T)) {
+ const RecordDecl *RD = RT->getDecl();
+ if (RD->isUnion()) {
+ List.push_back(T);
+ continue;
+ }
+ const CXXRecordDecl *CXXD = dyn_cast<CXXRecordDecl>(RD);
+
+ llvm::SmallVector<QualType, 16> FieldTypes;
+ if (CXXD && CXXD->isStandardLayout())
+ RD = CXXD->getStandardLayoutBaseWithFields();
+
+ for (const auto *FD : RD->fields())
+ FieldTypes.push_back(FD->getType());
+ // Reverse the newly added sub-range.
+ std::reverse(FieldTypes.begin(), FieldTypes.end());
+ WorkList.insert(WorkList.end(), FieldTypes.begin(), FieldTypes.end());
+
+ // If this wasn't a standard layout type we may also have some base
+ // classes to deal with.
+ if (CXXD && !CXXD->isStandardLayout()) {
+ FieldTypes.clear();
+ for (const auto &Base : CXXD->bases())
+ FieldTypes.push_back(Base.getType());
+ std::reverse(FieldTypes.begin(), FieldTypes.end());
+ WorkList.insert(WorkList.end(), FieldTypes.begin(), FieldTypes.end());
+ }
+ continue;
+ }
+ List.push_back(T);
+ }
+}
+
+bool SemaHLSL::IsScalarizedLayoutCompatible(QualType T1, QualType T2) const {
+ if (T1.isNull() || T2.isNull())
+ return false;
+
+ T1 = T1.getCanonicalType().getUnqualifiedType();
+ T2 = T2.getCanonicalType().getUnqualifiedType();
+
+ // If both types are the same canonical type, they're obviously compatible.
+ if (SemaRef.getASTContext().hasSameType(T1, T2))
+ return true;
+
+ llvm::SmallVector<QualType, 16> T1Types;
+ BuildFlattenedTypeList(T1, T1Types);
+ llvm::SmallVector<QualType, 16> T2Types;
+ BuildFlattenedTypeList(T2, T2Types);
+
+ // Check the flattened type list
+ return llvm::equal(T1Types, T2Types,
+ [this](QualType LHS, QualType RHS) -> bool {
+ return SemaRef.IsLayoutCompatible(LHS, RHS);
+ });
+}
diff --git a/clang/test/SemaHLSL/Types/Traits/ScalarizedLayoutCompatible.hlsl b/clang/test/SemaHLSL/Types/Traits/ScalarizedLayoutCompatible.hlsl
new file mode 100644
index 00000000000000..41ffb7ee2f8916
--- /dev/null
+++ b/clang/test/SemaHLSL/Types/Traits/ScalarizedLayoutCompatible.hlsl
@@ -0,0 +1,132 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.6-library -finclude-default-header -verify %s
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.6-library -finclude-default-header -fnative-half-type -verify %s
+// expected-no-diagnostics
+
+// Case 1: How many ways can I come up with to represent three float values?
+struct ThreeFloats1 {
+ float X, Y, Z;
+};
+
+struct ThreeFloats2 {
+ float X[3];
+};
+
+struct ThreeFloats3 {
+ float3 V;
+};
+
+struct ThreeFloats4 {
+ float2 V;
+ float F;
+};
+
+_Static_assert(__is_scalarized_layout_compatible(float3, float[3]), "");
+_Static_assert(__is_scalarized_layout_compatible(float3, ThreeFloats1), "");
+_Static_assert(__is_scalarized_layout_compatible(float3, ThreeFloats2), "");
+_Static_assert(__is_scalarized_layout_compatible(float3, ThreeFloats3), "");
+_Static_assert(__is_scalarized_layout_compatible(float3, ThreeFloats4), "");
+
+// Case 2: structs and base classes and arrays, oh my!
+struct Dog {
+ int Leg[4];
+ bool Tail;
+ float Fur;
+};
+
+struct Shiba {
+ int4 StubbyLegs;
+ bool CurlyTail;
+ struct Coating {
+ float Fur;
+ } F;
+};
+
+struct FourLegged {
+ int FR, FL, BR, BL;
+};
+
+struct Doggo : FourLegged {
+ bool WaggyBit;
+ float Fuzz;
+};
+
+_Static_assert(__is_scalarized_layout_compatible(Dog, Shiba), "");
+_Static_assert(__is_scalarized_layout_compatible(Dog, Doggo), "");
+
+// Case 3: Arrays of structs inside structs
+
+struct Cat {
+ struct Leg {
+ int L;
+ } Legs[4];
+ struct Other {
+ bool Tail;
+ float Furs;
+ } Bits;
+};
+
+_Static_assert(__is_scalarized_layout_compatible(Dog, Cat), "");
+
+// case 4: Arrays of structs inside arrays of structs.
+struct Pets {
+ Dog Puppers[6];
+ Cat Kitties[4];
+};
+
+struct Animals {
+ Dog Puppers[2];
+ Cat Kitties[8];
+};
+
+_Static_assert(__is_scalarized_layout_compatible(Pets, Animals), "");
+
+// Case 5: Turtles all the way down...
+
+typedef int Turtle;
+
+enum Ninja : Turtle {
+ Leonardo,
+ Donatello,
+ Michelangelo,
+ Raphael,
+};
+
+enum NotNinja : Turtle {
+ Fred,
+ Mikey,
+};
+
+enum Mammals : uint {
+ Dog,
+ Cat,
+};
+
+_Static_assert(__is_scalarized_layout_compatible(Ninja, NotNinja), "");
+_Static_assert(!__is_scalarized_layout_compatible(Ninja, Mammals), "");
+
+// Case 6: Some basic types.
+_Static_assert(__is_scalarized_layout_compatible(int, int32_t), "");
+_Static_assert(__is_scalarized_layout_compatible(uint, uint32_t), "");
+_Static_assert(!__is_scalarized_layout_compatible(int, uint), "");
+_Static_assert(!__is_scalarized_layout_compatible(int, float), "");
+
+// Even though half and float may be the same size we don't want them to be
+// layout compatible since they are different types.
+_Static_assert(!__is_scalarized_layout_compatible(half, float), "");
+
+// Case 6: Empty classes... because they're fun.
+
+struct NotEmpty { int X; };
+struct Empty {};
+struct AlsoEmpty {};
+
+struct DerivedEmpty : Empty {};
+
+struct DerivedNotEmpty : Empty { int X; };
+struct DerivedEmptyNotEmptyBase : NotEmpty {};
+
+_Static_assert(__is_scalarized_layout_compatible(Empty, AlsoEmpty), "");
+_Static_assert(__is_scalarized_layout_compatible(Empty, DerivedEmpty), "");
+
+_Static_assert(__is_scalarized_layout_compatible(NotEmpty, DerivedNotEmpty), "");
+_Static_assert(__is_scalarized_layout_compatible(NotEmpty, DerivedEmptyNotEmptyBase), "");
diff --git a/clang/test/SemaHLSL/Types/Traits/ScalarizedLayoutCompatibleErrors.hlsl b/clang/test/SemaHLSL/Types/Traits/ScalarizedLayoutCompatibleErrors.hlsl
new file mode 100644
index 00000000000000..ccd1dec7e4de09
--- /dev/null
+++ b/clang/test/SemaHLSL/Types/Traits/ScalarizedLayoutCompatibleErrors.hlsl
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.6-library -finclude-default-header -verify %s
+
+// Some things that don't work!
+
+// Case 1: Both types must be complete!
+struct Defined {
+ int X;
+};
+
+
+struct Undefined; // expected-note {{forward declaration of 'Undefined'}}
+
+_Static_assert(__is_scalarized_layout_compatible(Undefined, Defined), ""); // expected-error{{incomplete type 'Undefined' where a complete type is required}}
+
+// Case 2: No variable length arrays!
+
+void fn(int X) {
+ // expected-error@#vla {{variable length arrays are not supported for the current target}}
+ // expected-error@#vla {{variable length arrays are not supported in '__is_scalarized_layout_compatible'}}
+ // expected-error@#vla {{static assertion failed due to requirement '__is_scalarized_layout_compatible(int[4], int[X])'}}
+ // expected-warning@#vla {{variable length arrays in C++ are a Clang extension}}
+ _Static_assert(__is_scalarized_layout_compatible(int[4], int[X]), ""); // #vla
+}
>From f1204453733faec7df428f6d6aa708c0b02db22b Mon Sep 17 00:00:00 2001
From: Chris Bieneman <chris.bieneman at me.com>
Date: Thu, 15 Aug 2024 15:25:45 -0500
Subject: [PATCH 2/2] Update to PR feedback
* Prefix the trait builtin with `__builtin`
* Add test cases for unions
---
clang/include/clang/Basic/TokenKinds.def | 2 +-
clang/lib/Sema/SemaExprCXX.cpp | 4 +-
.../Traits/ScalarizedLayoutCompatible.hlsl | 40 +++++++--------
.../ScalarizedLayoutCompatibleErrors.hlsl | 49 +++++++++++++++++--
4 files changed, 68 insertions(+), 27 deletions(-)
diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def
index ede1bb081a2648..74c0f7681c53bb 100644
--- a/clang/include/clang/Basic/TokenKinds.def
+++ b/clang/include/clang/Basic/TokenKinds.def
@@ -659,7 +659,7 @@ KEYWORD(out , KEYHLSL)
#include "clang/Basic/HLSLIntangibleTypes.def"
// HLSL Type traits.
-TYPE_TRAIT_2(__is_scalarized_layout_compatible, IsScalarizedLayoutCompatible, KEYHLSL)
+TYPE_TRAIT_2(__builtin_is_scalarized_layout_compatible, IsScalarizedLayoutCompatible, KEYHLSL)
// OpenMP Type Traits
UNARY_EXPR_OR_TYPE_TRAIT(__builtin_omp_required_simd_align, OpenMPRequiredSimdAlign, KEYALL)
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 58c44b695b268e..de9879e25c4e33 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -6200,9 +6200,9 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, const TypeSourceI
return true;
DiagnoseVLAInCXXTypeTrait(Self, Lhs,
- tok::kw___is_scalarized_layout_compatible);
+ tok::kw___builtin_is_scalarized_layout_compatible);
DiagnoseVLAInCXXTypeTrait(Self, Rhs,
- tok::kw___is_scalarized_layout_compatible);
+ tok::kw___builtin_is_scalarized_layout_compatible);
return Self.HLSL().IsScalarizedLayoutCompatible(LhsT, RhsT);
}
diff --git a/clang/test/SemaHLSL/Types/Traits/ScalarizedLayoutCompatible.hlsl b/clang/test/SemaHLSL/Types/Traits/ScalarizedLayoutCompatible.hlsl
index 41ffb7ee2f8916..7913df2d769cb6 100644
--- a/clang/test/SemaHLSL/Types/Traits/ScalarizedLayoutCompatible.hlsl
+++ b/clang/test/SemaHLSL/Types/Traits/ScalarizedLayoutCompatible.hlsl
@@ -20,11 +20,11 @@ struct ThreeFloats4 {
float F;
};
-_Static_assert(__is_scalarized_layout_compatible(float3, float[3]), "");
-_Static_assert(__is_scalarized_layout_compatible(float3, ThreeFloats1), "");
-_Static_assert(__is_scalarized_layout_compatible(float3, ThreeFloats2), "");
-_Static_assert(__is_scalarized_layout_compatible(float3, ThreeFloats3), "");
-_Static_assert(__is_scalarized_layout_compatible(float3, ThreeFloats4), "");
+_Static_assert(__builtin_is_scalarized_layout_compatible(float3, float[3]), "");
+_Static_assert(__builtin_is_scalarized_layout_compatible(float3, ThreeFloats1), "");
+_Static_assert(__builtin_is_scalarized_layout_compatible(float3, ThreeFloats2), "");
+_Static_assert(__builtin_is_scalarized_layout_compatible(float3, ThreeFloats3), "");
+_Static_assert(__builtin_is_scalarized_layout_compatible(float3, ThreeFloats4), "");
// Case 2: structs and base classes and arrays, oh my!
struct Dog {
@@ -50,8 +50,8 @@ struct Doggo : FourLegged {
float Fuzz;
};
-_Static_assert(__is_scalarized_layout_compatible(Dog, Shiba), "");
-_Static_assert(__is_scalarized_layout_compatible(Dog, Doggo), "");
+_Static_assert(__builtin_is_scalarized_layout_compatible(Dog, Shiba), "");
+_Static_assert(__builtin_is_scalarized_layout_compatible(Dog, Doggo), "");
// Case 3: Arrays of structs inside structs
@@ -65,7 +65,7 @@ struct Cat {
} Bits;
};
-_Static_assert(__is_scalarized_layout_compatible(Dog, Cat), "");
+_Static_assert(__builtin_is_scalarized_layout_compatible(Dog, Cat), "");
// case 4: Arrays of structs inside arrays of structs.
struct Pets {
@@ -78,7 +78,7 @@ struct Animals {
Cat Kitties[8];
};
-_Static_assert(__is_scalarized_layout_compatible(Pets, Animals), "");
+_Static_assert(__builtin_is_scalarized_layout_compatible(Pets, Animals), "");
// Case 5: Turtles all the way down...
@@ -101,18 +101,18 @@ enum Mammals : uint {
Cat,
};
-_Static_assert(__is_scalarized_layout_compatible(Ninja, NotNinja), "");
-_Static_assert(!__is_scalarized_layout_compatible(Ninja, Mammals), "");
+_Static_assert(__builtin_is_scalarized_layout_compatible(Ninja, NotNinja), "");
+_Static_assert(!__builtin_is_scalarized_layout_compatible(Ninja, Mammals), "");
// Case 6: Some basic types.
-_Static_assert(__is_scalarized_layout_compatible(int, int32_t), "");
-_Static_assert(__is_scalarized_layout_compatible(uint, uint32_t), "");
-_Static_assert(!__is_scalarized_layout_compatible(int, uint), "");
-_Static_assert(!__is_scalarized_layout_compatible(int, float), "");
+_Static_assert(__builtin_is_scalarized_layout_compatible(int, int32_t), "");
+_Static_assert(__builtin_is_scalarized_layout_compatible(uint, uint32_t), "");
+_Static_assert(!__builtin_is_scalarized_layout_compatible(int, uint), "");
+_Static_assert(!__builtin_is_scalarized_layout_compatible(int, float), "");
// Even though half and float may be the same size we don't want them to be
// layout compatible since they are different types.
-_Static_assert(!__is_scalarized_layout_compatible(half, float), "");
+_Static_assert(!__builtin_is_scalarized_layout_compatible(half, float), "");
// Case 6: Empty classes... because they're fun.
@@ -125,8 +125,8 @@ struct DerivedEmpty : Empty {};
struct DerivedNotEmpty : Empty { int X; };
struct DerivedEmptyNotEmptyBase : NotEmpty {};
-_Static_assert(__is_scalarized_layout_compatible(Empty, AlsoEmpty), "");
-_Static_assert(__is_scalarized_layout_compatible(Empty, DerivedEmpty), "");
+_Static_assert(__builtin_is_scalarized_layout_compatible(Empty, AlsoEmpty), "");
+_Static_assert(__builtin_is_scalarized_layout_compatible(Empty, DerivedEmpty), "");
-_Static_assert(__is_scalarized_layout_compatible(NotEmpty, DerivedNotEmpty), "");
-_Static_assert(__is_scalarized_layout_compatible(NotEmpty, DerivedEmptyNotEmptyBase), "");
+_Static_assert(__builtin_is_scalarized_layout_compatible(NotEmpty, DerivedNotEmpty), "");
+_Static_assert(__builtin_is_scalarized_layout_compatible(NotEmpty, DerivedEmptyNotEmptyBase), "");
diff --git a/clang/test/SemaHLSL/Types/Traits/ScalarizedLayoutCompatibleErrors.hlsl b/clang/test/SemaHLSL/Types/Traits/ScalarizedLayoutCompatibleErrors.hlsl
index ccd1dec7e4de09..06eadd66cb4309 100644
--- a/clang/test/SemaHLSL/Types/Traits/ScalarizedLayoutCompatibleErrors.hlsl
+++ b/clang/test/SemaHLSL/Types/Traits/ScalarizedLayoutCompatibleErrors.hlsl
@@ -10,14 +10,55 @@ struct Defined {
struct Undefined; // expected-note {{forward declaration of 'Undefined'}}
-_Static_assert(__is_scalarized_layout_compatible(Undefined, Defined), ""); // expected-error{{incomplete type 'Undefined' where a complete type is required}}
+_Static_assert(__builtin_is_scalarized_layout_compatible(Undefined, Defined), ""); // expected-error{{incomplete type 'Undefined' where a complete type is required}}
// Case 2: No variable length arrays!
void fn(int X) {
// expected-error@#vla {{variable length arrays are not supported for the current target}}
- // expected-error@#vla {{variable length arrays are not supported in '__is_scalarized_layout_compatible'}}
- // expected-error@#vla {{static assertion failed due to requirement '__is_scalarized_layout_compatible(int[4], int[X])'}}
+ // expected-error@#vla {{variable length arrays are not supported in '__builtin_is_scalarized_layout_compatible'}}
+ // expected-error@#vla {{static assertion failed due to requirement '__builtin_is_scalarized_layout_compatible(int[4], int[X])'}}
// expected-warning@#vla {{variable length arrays in C++ are a Clang extension}}
- _Static_assert(__is_scalarized_layout_compatible(int[4], int[X]), ""); // #vla
+ _Static_assert(__builtin_is_scalarized_layout_compatible(int[4], int[X]), ""); // #vla
}
+
+// Case 3: Make this always fail for unions.
+// HLSL doesn't really support unions, and the places where scalarized layouts
+// are valid is probably going to be really confusing for unions, so we should
+// just make sure unions are never scalarized compatible with anything other
+// than themselves.
+
+union Wah {
+ int OhNo;
+ float NotAgain;
+};
+
+struct OneInt {
+ int I;
+};
+
+struct OneFloat {
+ float F;
+};
+
+struct HasUnion {
+ int I;
+ Wah W;
+};
+
+struct HasUnionSame {
+ int I;
+ Wah W;
+};
+
+struct HasUnionDifferent {
+ Wah W;
+ int I;
+};
+
+_Static_assert(__builtin_is_scalarized_layout_compatible(Wah, Wah), "Identical types are always compatible");
+_Static_assert(!__builtin_is_scalarized_layout_compatible(Wah, OneInt), "Unions are not compatible with anything else");
+_Static_assert(!__builtin_is_scalarized_layout_compatible(Wah, OneFloat), "Unions are not compatible with anything else");
+
+_Static_assert(__builtin_is_scalarized_layout_compatible(HasUnion, HasUnionSame), "");
+_Static_assert(!__builtin_is_scalarized_layout_compatible(HasUnion, HasUnionDifferent), "");
More information about the cfe-commits
mailing list