Skip to content

Commit 9efe377

Browse files
authored
[HLSL] Implement '__builtin_hlsl_is_intangible' type trait (#104544)
Implements `__builtin_hlsl_is_intangible` type trait. HLSL intangible types are special implementation-defined types such as resource handles or samplers. Any class that is an array of intangible type or contains base class or members of intangible types is also an intangible type. Fixes #[102954](#102954)
1 parent 950bb68 commit 9efe377

File tree

10 files changed

+162
-2
lines changed

10 files changed

+162
-2
lines changed

clang/include/clang/AST/CXXRecordDeclDefinitionBits.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,4 +249,8 @@ FIELD(HasDeclaredCopyAssignmentWithConstParam, 1, MERGE_OR)
249249
/// base classes or fields have a no-return destructor
250250
FIELD(IsAnyDestructorNoReturn, 1, NO_MERGE)
251251

252+
/// Whether the record type is intangible (if any base classes or fields have
253+
/// type that is intangible). HLSL only.
254+
FIELD(IsHLSLIntangible, 1, NO_MERGE)
255+
252256
#undef FIELD

clang/include/clang/AST/DeclCXX.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1547,6 +1547,10 @@ class CXXRecordDecl : public RecordDecl {
15471547
/// destructors are marked noreturn.
15481548
bool isAnyDestructorNoReturn() const { return data().IsAnyDestructorNoReturn; }
15491549

1550+
/// Returns true if the class contains HLSL intangible type, either as
1551+
/// a field or in base class.
1552+
bool isHLSLIntangible() const { return data().IsHLSLIntangible; }
1553+
15501554
/// If the class is a local class [class.local], returns
15511555
/// the enclosing function declaration.
15521556
const FunctionDecl *isLocalClass() const {

clang/include/clang/AST/Type.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2658,6 +2658,7 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase {
26582658
#define HLSL_INTANGIBLE_TYPE(Name, Id, SingletonId) bool is##Id##Type() const;
26592659
#include "clang/Basic/HLSLIntangibleTypes.def"
26602660
bool isHLSLSpecificType() const; // Any HLSL specific type
2661+
bool isHLSLIntangibleType() const; // Any HLSL intangible type
26612662

26622663
/// Determines if this type, which must satisfy
26632664
/// isObjCLifetimeType(), is implicitly __unsafe_unretained rather
@@ -8341,6 +8342,12 @@ inline bool Type::isHLSLSpecificType() const {
83418342
false; // end boolean or operation
83428343
}
83438344

8345+
inline bool Type::isHLSLIntangibleType() const {
8346+
// All HLSL specific types are currently intangible type as well, but that
8347+
// might change in the future.
8348+
return isHLSLSpecificType();
8349+
}
8350+
83448351
inline bool Type::isTemplateTypeParmType() const {
83458352
return isa<TemplateTypeParmType>(CanonicalType);
83468353
}

clang/include/clang/Basic/TokenKinds.def

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -660,8 +660,9 @@ KEYWORD(out , KEYHLSL)
660660
#define HLSL_INTANGIBLE_TYPE(Name, Id, SingletonId) KEYWORD(Name, KEYHLSL)
661661
#include "clang/Basic/HLSLIntangibleTypes.def"
662662

663-
// HLSL Type traits.
663+
// HLSL Type traits
664664
TYPE_TRAIT_2(__builtin_hlsl_is_scalarized_layout_compatible, IsScalarizedLayoutCompatible, KEYHLSL)
665+
TYPE_TRAIT_1(__builtin_hlsl_is_intangible, IsIntangibleType, KEYHLSL)
665666

666667
// OpenMP Type Traits
667668
UNARY_EXPR_OR_TYPE_TRAIT(__builtin_omp_required_simd_align, OpenMPRequiredSimdAlign, KEYALL)

clang/include/clang/Sema/SemaHLSL.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ class SemaHLSL : public SemaBase {
7171

7272
// HLSL Type trait implementations
7373
bool IsScalarizedLayoutCompatible(QualType T1, QualType T2) const;
74+
bool IsIntangibleType(QualType T1);
7475

7576
bool CheckCompatibleParameterABI(FunctionDecl *New, FunctionDecl *Old);
7677

clang/lib/AST/DeclCXX.cpp

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D)
109109
ImplicitCopyAssignmentHasConstParam(true),
110110
HasDeclaredCopyConstructorWithConstParam(false),
111111
HasDeclaredCopyAssignmentWithConstParam(false),
112-
IsAnyDestructorNoReturn(false), IsLambda(false),
112+
IsAnyDestructorNoReturn(false), IsHLSLIntangible(false), IsLambda(false),
113113
IsParsingBaseSpecifiers(false), ComputedVisibleConversions(false),
114114
HasODRHash(false), Definition(D) {}
115115

@@ -431,6 +431,9 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
431431
if (BaseClassDecl->isAnyDestructorNoReturn())
432432
data().IsAnyDestructorNoReturn = true;
433433

434+
if (BaseClassDecl->isHLSLIntangible())
435+
data().IsHLSLIntangible = true;
436+
434437
// C++11 [class.copy]p18:
435438
// The implicitly-declared copy assignment operator for a class X will
436439
// have the form 'X& X::operator=(const X&)' if each direct base class B
@@ -1401,6 +1404,18 @@ void CXXRecordDecl::addedMember(Decl *D) {
14011404
// than subobjects of zero size
14021405
if (data().Empty && !IsZeroSize)
14031406
data().Empty = false;
1407+
1408+
if (getLangOpts().HLSL) {
1409+
const Type *Ty = Field->getType()->getUnqualifiedDesugaredType();
1410+
while (isa<ConstantArrayType>(Ty))
1411+
Ty = Ty->getArrayElementTypeNoTypeQual();
1412+
1413+
Ty = Ty->getUnqualifiedDesugaredType();
1414+
if (Ty->isBuiltinType())
1415+
data().IsHLSLIntangible |= Ty->isHLSLIntangibleType();
1416+
else if (const RecordType *RT = dyn_cast<RecordType>(Ty))
1417+
data().IsHLSLIntangible |= RT->getAsCXXRecordDecl()->isHLSLIntangible();
1418+
}
14041419
}
14051420

14061421
// Handle using declarations of conversion functions.

clang/lib/Sema/SemaExprCXX.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5111,6 +5111,7 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S, TypeTrait UTT,
51115111
case UTT_IsDestructible:
51125112
case UTT_IsNothrowDestructible:
51135113
case UTT_IsTriviallyDestructible:
5114+
case UTT_IsIntangibleType:
51145115
if (ArgTy->isIncompleteArrayType() || ArgTy->isVoidType())
51155116
return true;
51165117

@@ -5696,6 +5697,16 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
56965697
return true;
56975698
return false;
56985699
}
5700+
case UTT_IsIntangibleType:
5701+
assert(Self.getLangOpts().HLSL && "intangible types are HLSL-only feature");
5702+
if (!T->isVoidType() && !T->isIncompleteArrayType())
5703+
if (Self.RequireCompleteType(TInfo->getTypeLoc().getBeginLoc(), T,
5704+
diag::err_incomplete_type))
5705+
return false;
5706+
if (DiagnoseVLAInCXXTypeTrait(Self, TInfo,
5707+
tok::kw___builtin_hlsl_is_intangible))
5708+
return false;
5709+
return Self.HLSL().IsIntangibleType(T);
56995710
}
57005711
}
57015712

clang/lib/Sema/SemaHLSL.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,11 @@
1010

1111
#include "clang/Sema/SemaHLSL.h"
1212
#include "clang/AST/Decl.h"
13+
#include "clang/AST/DeclBase.h"
14+
#include "clang/AST/DeclCXX.h"
1315
#include "clang/AST/Expr.h"
1416
#include "clang/AST/RecursiveASTVisitor.h"
17+
#include "clang/AST/Type.h"
1518
#include "clang/Basic/DiagnosticSema.h"
1619
#include "clang/Basic/LLVM.h"
1720
#include "clang/Basic/SourceLocation.h"
@@ -1609,6 +1612,31 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
16091612
return false;
16101613
}
16111614

1615+
bool SemaHLSL::IsIntangibleType(clang::QualType QT) {
1616+
if (QT.isNull())
1617+
return false;
1618+
1619+
const Type *Ty = QT->getUnqualifiedDesugaredType();
1620+
1621+
// check if it's a builtin type first (simple check, no need to cache it)
1622+
if (Ty->isBuiltinType())
1623+
return Ty->isHLSLIntangibleType();
1624+
1625+
// unwrap arrays
1626+
while (isa<ConstantArrayType>(Ty))
1627+
Ty = Ty->getArrayElementTypeNoTypeQual();
1628+
1629+
const RecordType *RT =
1630+
dyn_cast<RecordType>(Ty->getUnqualifiedDesugaredType());
1631+
if (!RT)
1632+
return false;
1633+
1634+
CXXRecordDecl *RD = RT->getAsCXXRecordDecl();
1635+
assert(RD != nullptr &&
1636+
"all HLSL struct and classes should be CXXRecordDecl");
1637+
return RD->isHLSLIntangible();
1638+
}
1639+
16121640
static void BuildFlattenedTypeList(QualType BaseTy,
16131641
llvm::SmallVectorImpl<QualType> &List) {
16141642
llvm::SmallVector<QualType, 16> WorkList;
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.6-library -finclude-default-header -verify %s
2+
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.6-library -finclude-default-header -fnative-half-type -verify %s
3+
// expected-no-diagnostics
4+
5+
_Static_assert(__builtin_hlsl_is_intangible(__hlsl_resource_t), "");
6+
// no need to check array of __hlsl_resource_t, arrays of sizeless types are not supported
7+
8+
_Static_assert(!__builtin_hlsl_is_intangible(int), "");
9+
_Static_assert(!__builtin_hlsl_is_intangible(float3), "");
10+
_Static_assert(!__builtin_hlsl_is_intangible(half[4]), "");
11+
12+
typedef __hlsl_resource_t Res;
13+
_Static_assert(__builtin_hlsl_is_intangible(const Res), "");
14+
// no need to check array of Res, arrays of sizeless types are not supported
15+
16+
struct ABuffer {
17+
const int i[10];
18+
__hlsl_resource_t h;
19+
};
20+
_Static_assert(__builtin_hlsl_is_intangible(ABuffer), "");
21+
_Static_assert(__builtin_hlsl_is_intangible(ABuffer[10]), "");
22+
23+
struct MyStruct {
24+
half2 h2;
25+
int3 i3;
26+
};
27+
_Static_assert(!__builtin_hlsl_is_intangible(MyStruct), "");
28+
_Static_assert(!__builtin_hlsl_is_intangible(MyStruct[10]), "");
29+
30+
class MyClass {
31+
int3 ivec;
32+
float farray[12];
33+
MyStruct ms;
34+
ABuffer buf;
35+
};
36+
_Static_assert(__builtin_hlsl_is_intangible(MyClass), "");
37+
_Static_assert(__builtin_hlsl_is_intangible(MyClass[2]), "");
38+
39+
union U {
40+
double d[4];
41+
Res buf;
42+
};
43+
_Static_assert(__builtin_hlsl_is_intangible(U), "");
44+
_Static_assert(__builtin_hlsl_is_intangible(U[100]), "");
45+
46+
class MyClass2 {
47+
int3 ivec;
48+
float farray[12];
49+
U u;
50+
};
51+
_Static_assert(__builtin_hlsl_is_intangible(MyClass2), "");
52+
_Static_assert(__builtin_hlsl_is_intangible(MyClass2[5]), "");
53+
54+
class Simple {
55+
int a;
56+
};
57+
58+
template<typename T> struct TemplatedBuffer {
59+
T a;
60+
__hlsl_resource_t h;
61+
};
62+
_Static_assert(__builtin_hlsl_is_intangible(TemplatedBuffer<int>), "");
63+
64+
struct MyStruct2 : TemplatedBuffer<float> {
65+
float x;
66+
};
67+
_Static_assert(__builtin_hlsl_is_intangible(MyStruct2), "");
68+
69+
struct MyStruct3 {
70+
const TemplatedBuffer<float> TB[10];
71+
};
72+
_Static_assert(__builtin_hlsl_is_intangible(MyStruct3), "");
73+
74+
template<typename T> struct SimpleTemplate {
75+
T a;
76+
};
77+
_Static_assert(__builtin_hlsl_is_intangible(SimpleTemplate<__hlsl_resource_t>), "");
78+
_Static_assert(!__builtin_hlsl_is_intangible(SimpleTemplate<float>), "");
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.6-library -finclude-default-header -verify %s
2+
3+
struct Undefined; // expected-note {{forward declaration of 'Undefined'}}
4+
_Static_assert(!__builtin_hlsl_is_intangible(Undefined), ""); // expected-error{{incomplete type 'Undefined' used in type trait expression}}
5+
6+
void fn(int X) {
7+
// expected-error@#vla {{variable length arrays are not supported for the current target}}
8+
// expected-error@#vla {{variable length arrays are not supported in '__builtin_hlsl_is_intangible'}}
9+
// expected-warning@#vla {{variable length arrays in C++ are a Clang extension}}
10+
_Static_assert(!__builtin_hlsl_is_intangible(int[X]), ""); // #vla
11+
}

0 commit comments

Comments
 (0)