-
Notifications
You must be signed in to change notification settings - Fork 12.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[HLSL] Add [[hlsl::contained_type()]]
attribute
#108456
Conversation
@llvm/pr-subscribers-hlsl @llvm/pr-subscribers-clang Author: Helena Kotas (hekota) ChangesIntroducing a new HLSL resource type attribute
Patch is 23.47 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/108456.diff 12 Files Affected:
diff --git a/clang/include/clang/AST/TypeLoc.h b/clang/include/clang/AST/TypeLoc.h
index 03fbdcf60140df..80519fbd91ed3e 100644
--- a/clang/include/clang/AST/TypeLoc.h
+++ b/clang/include/clang/AST/TypeLoc.h
@@ -942,6 +942,7 @@ class BTFTagAttributedTypeLoc
struct HLSLAttributedResourceLocInfo {
SourceRange Range;
+ TypeSourceInfo *ContainedTyTSI;
};
/// Type source information for HLSL attributed resource type.
@@ -952,8 +953,11 @@ class HLSLAttributedResourceTypeLoc
public:
TypeLoc getWrappedLoc() const { return getInnerTypeLoc(); }
- TypeLoc getContainedLoc() const {
- return TypeLoc(getTypePtr()->getContainedType(), getNonLocalData());
+ TypeSourceInfo *getContainedTypeSourceInfo() const {
+ return getLocalData()->ContainedTyTSI;
+ }
+ void setContainedTypeSourceInfo(TypeSourceInfo *TSI) const {
+ getLocalData()->ContainedTyTSI = TSI;
}
void setSourceRange(const SourceRange &R) { getLocalData()->Range = R; }
diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index 9a7b163b2c6da8..531e9d3eccf9be 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -4669,6 +4669,13 @@ def HLSLResourceClass : TypeAttr {
let Documentation = [InternalOnly];
}
+def HLSLContainedType : TypeAttr {
+ let Spellings = [CXX11<"hlsl", "contained_type">];
+ let LangOpts = [HLSL];
+ let Args = [TypeArgument<"Type", /*opt=*/0>];
+ let Documentation = [InternalOnly];
+}
+
def HLSLGroupSharedAddressSpace : TypeAttr {
let Spellings = [CustomKeyword<"groupshared">];
let Subjects = SubjectList<[Var]>;
diff --git a/clang/include/clang/Sema/SemaHLSL.h b/clang/include/clang/Sema/SemaHLSL.h
index 64b39ca7712eeb..e088254c566d3e 100644
--- a/clang/include/clang/Sema/SemaHLSL.h
+++ b/clang/include/clang/Sema/SemaHLSL.h
@@ -16,6 +16,7 @@
#include "clang/AST/ASTFwd.h"
#include "clang/AST/Attr.h"
#include "clang/AST/Type.h"
+#include "clang/AST/TypeLoc.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Sema/SemaBase.h"
#include "llvm/ADT/SmallVector.h"
@@ -30,9 +31,9 @@ class Scope;
// FIXME: This can be hidden (as static function in SemaHLSL.cpp) once we no
// longer need to create builtin buffer types in HLSLExternalSemaSource.
-bool CreateHLSLAttributedResourceType(Sema &S, QualType Wrapped,
- ArrayRef<const Attr *> AttrList,
- QualType &ResType);
+bool CreateHLSLAttributedResourceType(
+ Sema &S, QualType Wrapped, ArrayRef<const Attr *> AttrList,
+ QualType &ResType, HLSLAttributedResourceLocInfo *LocInfo = nullptr);
class SemaHLSL : public SemaBase {
public:
@@ -73,7 +74,8 @@ class SemaHLSL : public SemaBase {
bool CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall);
QualType ProcessResourceTypeAttributes(QualType Wrapped);
- SourceLocation TakeLocForHLSLAttribute(const HLSLAttributedResourceType *RT);
+ HLSLAttributedResourceLocInfo
+ TakeLocForHLSLAttribute(const HLSLAttributedResourceType *RT);
// HLSL Type trait implementations
bool IsScalarizedLayoutCompatible(QualType T1, QualType T2) const;
@@ -90,9 +92,10 @@ class SemaHLSL : public SemaBase {
// This is a list to collect them.
llvm::SmallVector<const Attr *> HLSLResourcesTypeAttrs;
- /// SourceLocation corresponding to HLSLAttributedResourceTypeLocs that we
+ /// TypeLoc data for HLSLAttributedResourceType instances that we
/// have not yet populated.
- llvm::DenseMap<const HLSLAttributedResourceType *, SourceLocation>
+ llvm::DenseMap<const HLSLAttributedResourceType *,
+ HLSLAttributedResourceLocInfo>
LocsForHLSLAttributedResources;
};
diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp
index add6a5d10d61f7..bf5a1669c31a86 100644
--- a/clang/lib/AST/TypePrinter.cpp
+++ b/clang/lib/AST/TypePrinter.cpp
@@ -1945,6 +1945,7 @@ void TypePrinter::printAttributedAfter(const AttributedType *T,
case attr::HLSLResourceClass:
case attr::HLSLROV:
+ case attr::HLSLContainedType:
llvm_unreachable("HLSL resource type attributes handled separately");
case attr::OpenCLPrivateAddressSpace:
@@ -2078,6 +2079,14 @@ void TypePrinter::printHLSLAttributedResourceAfter(
<< ")]]";
if (Attrs.IsROV)
OS << " [[hlsl::is_rov()]]";
+
+ QualType ContainedTy = T->getContainedType();
+ if (!ContainedTy.isNull()) {
+ OS << " [[hlsl::contained_type(";
+ printBefore(ContainedTy, OS);
+ printAfter(ContainedTy, OS);
+ OS << ")]]";
+ }
}
void TypePrinter::printObjCInterfaceBefore(const ObjCInterfaceType *T,
diff --git a/clang/lib/Sema/HLSLExternalSemaSource.cpp b/clang/lib/Sema/HLSLExternalSemaSource.cpp
index 071e64fe56d48a..407430a51e5c2f 100644
--- a/clang/lib/Sema/HLSLExternalSemaSource.cpp
+++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp
@@ -16,6 +16,7 @@
#include "clang/AST/Type.h"
#include "clang/Basic/AttrKinds.h"
#include "clang/Basic/HLSLRuntime.h"
+#include "clang/Basic/SourceLocation.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/Sema.h"
#include "clang/Sema/SemaHLSL.h"
@@ -114,19 +115,30 @@ struct BuiltinTypeDeclBuilder {
AccessSpecifier Access = AccessSpecifier::AS_private) {
if (Record->isCompleteDefinition())
return *this;
+
+ TypeSourceInfo *ElementTypeTSI = nullptr;
+
QualType Ty = Record->getASTContext().VoidPtrTy;
if (Template) {
- if (const auto *TTD = dyn_cast<TemplateTypeParmDecl>(
- Template->getTemplateParameters()->getParam(0)))
+ if (const TemplateTypeParmDecl *TTD = dyn_cast<TemplateTypeParmDecl>(
+ Template->getTemplateParameters()->getParam(0))) {
Ty = Record->getASTContext().getPointerType(
QualType(TTD->getTypeForDecl(), 0));
+ QualType ElemType = QualType(TTD->getTypeForDecl(), 0);
+ ElementTypeTSI = S.getASTContext().getTrivialTypeSourceInfo(
+ ElemType, SourceLocation());
+ }
}
// add handle member with resource type attributes
QualType AttributedResTy = QualType();
SmallVector<const Attr *> Attrs = {
HLSLResourceClassAttr::CreateImplicit(Record->getASTContext(), RC),
- IsROV ? HLSLROVAttr::CreateImplicit(Record->getASTContext()) : nullptr};
+ IsROV ? HLSLROVAttr::CreateImplicit(Record->getASTContext()) : nullptr,
+ ElementTypeTSI ? HLSLContainedTypeAttr::CreateImplicit(
+ Record->getASTContext(), ElementTypeTSI)
+ : nullptr,
+ };
Attr *ResourceAttr =
HLSLResourceAttr::CreateImplicit(Record->getASTContext(), RK);
if (CreateHLSLAttributedResourceType(S, Ty, Attrs, AttributedResTy))
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 3b91303ac8cb8a..4fc8eb170b396e 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -10,12 +10,15 @@
#include "clang/Sema/SemaHLSL.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/Attr.h"
+#include "clang/AST/Attrs.inc"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclBase.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/Expr.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/Type.h"
+#include "clang/AST/TypeLoc.h"
#include "clang/Basic/DiagnosticSema.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/SourceLocation.h"
@@ -563,18 +566,23 @@ void SemaHLSL::handleShaderAttr(Decl *D, const ParsedAttr &AL) {
D->addAttr(NewAttr);
}
-bool clang::CreateHLSLAttributedResourceType(Sema &S, QualType Wrapped,
- ArrayRef<const Attr *> AttrList,
- QualType &ResType) {
+bool clang::CreateHLSLAttributedResourceType(
+ Sema &S, QualType Wrapped, ArrayRef<const Attr *> AttrList,
+ QualType &ResType, HLSLAttributedResourceLocInfo *LocInfo /*= nullptr*/) {
assert(AttrList.size() && "expected list of resource attributes");
- QualType Contained = QualType();
+ QualType ContainedTy = QualType();
+ TypeSourceInfo *ContainedTyTSI;
+ SourceLocation LocBegin = AttrList[0]->getRange().getBegin();
+ SourceLocation LocEnd = SourceLocation();
+
HLSLAttributedResourceType::Attributes ResAttrs = {};
bool HasResourceClass = false;
for (const Attr *A : AttrList) {
if (!A)
continue;
+ LocEnd = A->getRange().getEnd();
switch (A->getKind()) {
case attr::HLSLResourceClass: {
llvm::dxil::ResourceClass RC =
@@ -593,6 +601,20 @@ bool clang::CreateHLSLAttributedResourceType(Sema &S, QualType Wrapped,
case attr::HLSLROV:
ResAttrs.IsROV = true;
break;
+ case attr::HLSLContainedType: {
+ const HLSLContainedTypeAttr *CTAttr = cast<HLSLContainedTypeAttr>(A);
+ QualType Ty = CTAttr->getType();
+ if (!ContainedTy.isNull()) {
+ S.Diag(A->getLocation(), ContainedTy == Ty
+ ? diag::warn_duplicate_attribute_exact
+ : diag::warn_duplicate_attribute)
+ << A;
+ return false;
+ }
+ ContainedTy = Ty;
+ ContainedTyTSI = CTAttr->getTypeLoc();
+ break;
+ }
default:
llvm_unreachable("unhandled resource attribute type");
}
@@ -604,8 +626,13 @@ bool clang::CreateHLSLAttributedResourceType(Sema &S, QualType Wrapped,
return false;
}
- ResType = S.getASTContext().getHLSLAttributedResourceType(Wrapped, Contained,
- ResAttrs);
+ ResType = S.getASTContext().getHLSLAttributedResourceType(
+ Wrapped, ContainedTy, ResAttrs);
+
+ if (LocInfo) {
+ LocInfo->Range = SourceRange(LocBegin, LocEnd);
+ LocInfo->ContainedTyTSI = ContainedTyTSI;
+ }
return true;
}
@@ -642,9 +669,27 @@ bool SemaHLSL::handleResourceTypeAttr(const ParsedAttr &AL) {
A = HLSLResourceClassAttr::Create(getASTContext(), RC, AL.getLoc());
break;
}
+
case ParsedAttr::AT_HLSLROV:
A = HLSLROVAttr::Create(getASTContext(), AL.getLoc());
break;
+
+ case ParsedAttr::AT_HLSLContainedType: {
+ if (AL.getNumArgs() != 1 && !AL.hasParsedType()) {
+ Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) << AL << 1;
+ return false;
+ }
+
+ TypeSourceInfo *TSI = nullptr;
+ QualType QT = SemaRef.GetTypeFromParser(AL.getTypeArg(), &TSI);
+ assert(TSI && "no type source info for attribute argument");
+ if (SemaRef.RequireCompleteType(TSI->getTypeLoc().getBeginLoc(), QT,
+ diag::err_incomplete_type))
+ return false;
+ A = HLSLContainedTypeAttr::Create(getASTContext(), TSI, AL.getLoc());
+ break;
+ }
+
default:
llvm_unreachable("unhandled HLSL attribute");
}
@@ -659,30 +704,34 @@ QualType SemaHLSL::ProcessResourceTypeAttributes(QualType CurrentType) {
return CurrentType;
QualType QT = CurrentType;
+ HLSLAttributedResourceLocInfo LocInfo;
if (CreateHLSLAttributedResourceType(SemaRef, CurrentType,
- HLSLResourcesTypeAttrs, QT)) {
+ HLSLResourcesTypeAttrs, QT, &LocInfo)) {
const HLSLAttributedResourceType *RT =
- dyn_cast<HLSLAttributedResourceType>(QT.getTypePtr());
- // Use the location of the first attribute as the location of the aggregated
- // type. The attributes are stored in HLSLResourceTypeAttrs in the same
- // order as they are parsed.
- SourceLocation Loc = HLSLResourcesTypeAttrs[0]->getLoc();
- LocsForHLSLAttributedResources.insert(std::pair(RT, Loc));
+ cast<HLSLAttributedResourceType>(QT.getTypePtr());
+
+ // Temporarily store TypeLoc information for the new type.
+ // It will be transferred to HLSLAttributesResourceTypeLoc
+ // shortly after the type is created by TypeSpecLocFiller which
+ // will call the TakeLocForHLSLAttribute method below.
+ LocsForHLSLAttributedResources.insert(std::pair(RT, LocInfo));
}
HLSLResourcesTypeAttrs.clear();
return QT;
}
// Returns source location for the HLSLAttributedResourceType
-SourceLocation
+HLSLAttributedResourceLocInfo
SemaHLSL::TakeLocForHLSLAttribute(const HLSLAttributedResourceType *RT) {
+ HLSLAttributedResourceLocInfo LocInfo = {};
auto I = LocsForHLSLAttributedResources.find(RT);
if (I != LocsForHLSLAttributedResources.end()) {
- SourceLocation Loc = I->second;
+ LocInfo = I->second;
LocsForHLSLAttributedResources.erase(I);
- return Loc;
+ return LocInfo;
}
- return SourceLocation();
+ LocInfo.Range = SourceRange();
+ return LocInfo;
}
struct RegisterBindingFlags {
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index 520dce870b7b78..a64fe360ddbc3a 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -5801,8 +5801,10 @@ static void fillAttributedTypeLoc(AttributedTypeLoc TL,
static void fillHLSLAttributedResourceTypeLoc(HLSLAttributedResourceTypeLoc TL,
TypeProcessingState &State) {
- TL.setSourceRange(
- State.getSema().HLSL().TakeLocForHLSLAttribute(TL.getTypePtr()));
+ HLSLAttributedResourceLocInfo LocInfo =
+ State.getSema().HLSL().TakeLocForHLSLAttribute(TL.getTypePtr());
+ TL.setSourceRange(LocInfo.Range);
+ TL.setContainedTypeSourceInfo(LocInfo.ContainedTyTSI);
}
static void fillMatrixTypeLoc(MatrixTypeLoc MTL,
@@ -8843,8 +8845,10 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
break;
}
case ParsedAttr::AT_HLSLResourceClass:
- case ParsedAttr::AT_HLSLROV: {
- if (state.getSema().HLSL().handleResourceTypeAttr(attr))
+ case ParsedAttr::AT_HLSLROV:
+ case ParsedAttr::AT_HLSLContainedType: {
+ if (TAL == TAL_DeclSpec &&
+ state.getSema().HLSL().handleResourceTypeAttr(attr))
attr.setUsedAsTypeAttr();
break;
}
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 0daf620b4123e4..af38d1cd34b219 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -7470,8 +7470,17 @@ QualType TreeTransform<Derived>::TransformHLSLAttributedResourceType(
return QualType();
QualType ContainedTy = QualType();
- if (!oldType->getContainedType().isNull())
- ContainedTy = getDerived().TransformType(TLB, TL.getContainedLoc());
+ QualType OldContainedTy = oldType->getContainedType();
+ if (!OldContainedTy.isNull()) {
+ TypeSourceInfo *oldContainedTSI = TL.getContainedTypeSourceInfo();
+ if (!oldContainedTSI)
+ oldContainedTSI = getSema().getASTContext().getTrivialTypeSourceInfo(
+ OldContainedTy, SourceLocation());
+ TypeSourceInfo *ContainedTSI = getDerived().TransformType(oldContainedTSI);
+ if (!ContainedTSI)
+ return QualType();
+ ContainedTy = ContainedTSI->getType();
+ }
QualType Result = TL.getType();
if (getDerived().AlwaysRebuild() || WrappedTy != oldType->getWrappedType() ||
diff --git a/clang/test/AST/HLSL/RWBuffer-AST.hlsl b/clang/test/AST/HLSL/RWBuffer-AST.hlsl
index 0e7803ce50a890..bad9961c10b02d 100644
--- a/clang/test/AST/HLSL/RWBuffer-AST.hlsl
+++ b/clang/test/AST/HLSL/RWBuffer-AST.hlsl
@@ -1,7 +1,6 @@
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -x hlsl -ast-dump -DEMPTY %s | FileCheck -check-prefix=EMPTY %s
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -x hlsl -ast-dump %s | FileCheck %s
-
// This test tests two different AST generations. The "EMPTY" test mode verifies
// the AST generated by forward declaration of the HLSL types which happens on
// initializing the HLSL external AST with an AST Context.
@@ -30,7 +29,7 @@ RWBuffer<float> Buffer;
// CHECK-NEXT: CXXRecordDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> implicit class RWBuffer definition
// CHECK: FinalAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit final
-// CHECK-NEXT: implicit h 'element_type * {{\[\[}}hlsl::resource_class(UAV)]]':'element_type *'
+// CHECK-NEXT: implicit h 'element_type * {{\[\[}}hlsl::resource_class(UAV)]] {{\[\[}}hlsl::contained_type(element_type)]]':'element_type *'
// CHECK-NEXT: HLSLResourceAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit TypedBuffer
// CHECK: CXXMethodDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> operator[] 'element_type &const (unsigned int) const'
@@ -38,7 +37,7 @@ RWBuffer<float> Buffer;
// CHECK-NEXT: CompoundStmt 0x{{[0-9A-Fa-f]+}} <<invalid sloc>>
// CHECK-NEXT: ReturnStmt 0x{{[0-9A-Fa-f]+}} <<invalid sloc>>
// CHECK-NEXT: ArraySubscriptExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'element_type' lvalue
-// CHECK-NEXT: MemberExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'element_type * {{\[\[}}hlsl::resource_class(UAV)]]':'element_type *' lvalue .h 0x{{[0-9A-Fa-f]+}}
+// CHECK-NEXT: MemberExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'element_type * {{\[\[}}hlsl::resource_class(UAV)]] {{\[\[}}hlsl::contained_type(element_type)]]':'element_type *' lvalue .h 0x{{[0-9A-Fa-f]+}}
// CHECK-NEXT: CXXThisExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'const RWBuffer<element_type>' lvalue implicit this
// CHECK-NEXT: DeclRefExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'unsigned int' ParmVar 0x{{[0-9A-Fa-f]+}} 'Idx' 'unsigned int'
// CHECK-NEXT: AlwaysInlineAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit always_inline
@@ -48,7 +47,7 @@ RWBuffer<float> Buffer;
// CHECK-NEXT: CompoundStmt 0x{{[0-9A-Fa-f]+}} <<invalid sloc>>
// CHECK-NEXT: ReturnStmt 0x{{[0-9A-Fa-f]+}} <<invalid sloc>>
// CHECK-NEXT: ArraySubscriptExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'element_type' lvalue
-// CHECK-NEXT: MemberExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'element_type * {{\[\[}}hlsl::resource_class(UAV)]]':'element_type *' lvalue .h 0x{{[0-9A-Fa-f]+}}
+// CHECK-NEXT: MemberExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'element_type * {{\[\[}}hlsl::resource_class(UAV)]] {{\[\[}}hlsl::contained_type(element_type)]]':'element_type *' lvalue .h 0x{{[0-9A-Fa-f]+}}
// CHECK-NEXT: CXXThisExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'RWBuffer<element_type>' lvalue implicit this
// CHECK-NEXT: DeclRefExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'unsigned int' ParmVar 0x{{[0-9A-Fa-f]+}} 'Idx' 'unsigned int'
// CHECK-NEXT: AlwaysInlineAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit always_inline
@@ -58,5 +57,5 @@ RWBuffer<float> Buffer;
// CHECK: TemplateArgument type 'float'
// CHECK-NEXT: BuiltinType 0x{{[0-9A-Fa-f]+}} 'float'
// CHECK-NEXT: FinalAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit final
-// CHECK-NEXT: FieldDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> implicit referenced h 'float * {{\[\[}}hlsl::resource_class(UAV)]]':'float *'
+// CHECK-NEXT: FieldDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> implicit referenced h 'float * {{\[\[}}hlsl::resource_class(UAV)]] {{\[\[}}hlsl::contained_type(float)]]':'float *'
// CHECK-NEXT: HLSLResourceAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit TypedBuffer
diff --git a/clang/test/ParserHLSL/hlsl_contained_type_attr.hlsl b/clang/test/ParserHLSL/hlsl_contained_type_attr.hlsl
new file mode 100644
index 00000000000000..ff90208acd0978
--- /dev/null
+++ b/clang/test/ParserHLSL/hlsl_contained_type_attr.hlsl
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -std=hlsl202x -x hlsl -ast-dump -o - %s | FileCheck %s
+
+typedef vector<float, 4> float4;
+
+// CHECK: -TypeAliasDecl 0x{{[0-9a-f]+}} <line:[[# @LINE + 2]]:1, col:83>
+// CHECK: -HLSLAttributedResourceType 0x{{[0-9a-f]+}} '__hlsl_resource_t {{\[\[}}hlsl::resource_class(UAV)]] {{\[\[}}hlsl::contained_type(int)]]' sugar
+using ResourceIntAliasT = __hlsl_resource_t [[hlsl::resource_class(UAV)]] [[hlsl::contained_type(int)]];
+ResourceIntAliasT h1;
+
+// CHECK: -VarDecl 0x{{[0-9a-f]+}} <line:[[# @LINE + 1]]:1, col:82> col:82 h2 '__hlsl_resource_t {{\[\[}}hlsl::resource_class(UAV)]] {{\[\[}}hlsl::contained_type(float4)]]':'__hlsl_resource_t'
+__hlsl_resource_t [[hlsl::resource_class(UAV)]] [[hlsl::contained_type(float4)]] h2;
+
+// ClassTemplateDecl 0x{{[0-9a-f]+}} <line:[[# @LINE + 4]]:1, line:16:1> line:14:30 S
+// TemplateTypeParmDecl 0x{{[0-9a-f]+}} <col:[[# @LINE + 3]], col:20> col:20 referenced typename depth 0 index 0 T
+// CXXRecordDecl 0x{{[0-9a-f]+}} <col:23, line:[[# @LINE + 2]]:1> line:14:30 struct S definition
+// FieldDecl 0x{{[0-9a-f]+}} <line:[[# @LINE + 1]]:3, col:...
[truncated]
|
// CHECK-NEXT: MemberExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'element_type * {{\[\[}}hlsl::resource_class(UAV)]]':'element_type *' lvalue .h 0x{{[0-9A-Fa-f]+}} | ||
// CHECK-NEXT: MemberExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'element_type * {{\[\[}}hlsl::resource_class(UAV)]] {{\[\[}}hlsl::contained_type(element_type)]]':'element_type *' lvalue .h 0x{{[0-9A-Fa-f]+}} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These checks are starting to get a little unwieldy with multiple attributes and the somewhat awkward [[
escaping. I wonder whether these could all be made more readable with some use of CHECK-SAME
and FileCheck's "LITERAL" modifier? I'm not sure if that will make it more readable or less though since it will necessitate splitting the checks across a few lines.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, the lines are getting pretty long. I'll see what I can do.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could have it like this:
// CHECK-NEXT: implicit h 'element_type *
// CHECK-SAME{LITERAL}: [[hlsl::resource_class(UAV)]] [[hlsl::contained_type(element_type)]]
// CHECK-SAME: ':'element_type *'
or even have the resource attributes on individual lines. Either way, I'd like to do in a separate PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why the name is contained_type instead of element_type?
I am not sure if the name was discussed but |
Introducing a new HLSL resource type attribute
[[contained_type(T)]]
which describes the "contained type" of a buffer or resource type. Specifically, the attribute will be used on the resource handle in templated buffer types like so:Fixes #104855