[clang] [HLSL] Add `[[hlsl::contained_type()]]` attribute (PR #108456)
Helena Kotas via cfe-commits
cfe-commits at lists.llvm.org
Thu Sep 12 15:42:27 PDT 2024
https://github.com/hekota updated https://github.com/llvm/llvm-project/pull/108456
>From 9906af110af550643d816b1ed729c19e16027288 Mon Sep 17 00:00:00 2001
From: Helena Kotas <hekotas at microsoft.com>
Date: Tue, 10 Sep 2024 14:38:19 -0700
Subject: [PATCH 1/4] [HLSL] Add `[[hlsl::contained_type()]]` resource type
attribute
---
clang/include/clang/Basic/Attr.td | 7 +++++
clang/lib/AST/TypePrinter.cpp | 9 ++++++
clang/lib/Sema/HLSLExternalSemaSource.cpp | 18 +++++++++--
clang/lib/Sema/SemaHLSL.cpp | 31 +++++++++++++++++++
clang/lib/Sema/SemaType.cpp | 6 ++--
clang/lib/Sema/TreeTransform.h | 10 ++++--
.../ParserHLSL/hlsl_contained_type_attr.hlsl | 19 ++++++++++++
.../hlsl_contained_type_attr_error.hlsl | 24 ++++++++++++++
.../hlsl_resource_handle_attrs.hlsl | 4 +--
9 files changed, 119 insertions(+), 9 deletions(-)
create mode 100644 clang/test/ParserHLSL/hlsl_contained_type_attr.hlsl
create mode 100644 clang/test/ParserHLSL/hlsl_contained_type_attr_error.hlsl
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/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..cfda57e17e5a43 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -10,6 +10,7 @@
#include "clang/Sema/SemaHLSL.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/Attrs.inc"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclBase.h"
#include "clang/AST/DeclCXX.h"
@@ -593,6 +594,18 @@ bool clang::CreateHLSLAttributedResourceType(Sema &S, QualType Wrapped,
case attr::HLSLROV:
ResAttrs.IsROV = true;
break;
+ case attr::HLSLContainedType: {
+ QualType Ty = cast<HLSLContainedTypeAttr>(A)->getType();
+ if (!Contained.isNull()) {
+ S.Diag(A->getLocation(), Contained == Ty
+ ? diag::warn_duplicate_attribute_exact
+ : diag::warn_duplicate_attribute)
+ << A;
+ return false;
+ }
+ Contained = Ty;
+ break;
+ }
default:
llvm_unreachable("unhandled resource attribute type");
}
@@ -642,9 +655,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");
}
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index 520dce870b7b78..44e603fe892355 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -8843,8 +8843,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..4b515d53d12885 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -7470,8 +7470,14 @@ QualType TreeTransform<Derived>::TransformHLSLAttributedResourceType(
return QualType();
QualType ContainedTy = QualType();
- if (!oldType->getContainedType().isNull())
- ContainedTy = getDerived().TransformType(TLB, TL.getContainedLoc());
+ if (!oldType->getContainedType().isNull()) {
+ TypeLocBuilder ContainedTyTLB;
+ TypeLoc ContainedTL = TL.getContainedLoc();
+ ContainedTyTLB.reserve(ContainedTL.getFullDataSize());
+ ContainedTy = getDerived().TransformType(ContainedTyTLB, ContainedTL);
+ if (ContainedTy.isNull())
+ return QualType();
+ }
QualType Result = TL.getType();
if (getDerived().AlwaysRebuild() || WrappedTy != oldType->getWrappedType() ||
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..3e02edcd6232d5
--- /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:47>
+// 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:79> col:79 h '__hlsl_resource_t [[hlsl::resource_class(UAV)]] [[hlsl::contained_type(T)]]':'__hlsl_resource_t'
+template <typename T> struct S {
+ __hlsl_resource_t [[hlsl::resource_class(UAV)]] [[hlsl::contained_type(T)]] h;
+};
diff --git a/clang/test/ParserHLSL/hlsl_contained_type_attr_error.hlsl b/clang/test/ParserHLSL/hlsl_contained_type_attr_error.hlsl
new file mode 100644
index 00000000000000..1c37d72de86148
--- /dev/null
+++ b/clang/test/ParserHLSL/hlsl_contained_type_attr_error.hlsl
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -std=hlsl202x -x hlsl -o - %s -verify
+
+typedef vector<float, 4> float4;
+
+// expected-error at +1{{'contained_type' attribute cannot be applied to a declaration}}
+[[hlsl::contained_type(float4)]] __hlsl_resource_t h1;
+
+// expected-error at +1{{'contained_type' attribute takes one argument}}
+__hlsl_resource_t [[hlsl::resource_class(UAV)]] [[hlsl::contained_type()]] h3;
+
+// expected-error at +1{{expected a type}}
+__hlsl_resource_t [[hlsl::resource_class(UAV)]] [[hlsl::contained_type(0)]] h4;
+
+// expected-error at +1{{unknown type name 'a'}}
+__hlsl_resource_t [[hlsl::resource_class(UAV)]] [[hlsl::contained_type(a)]] h5;
+
+// expected-error at +1{{expected a type}}
+__hlsl_resource_t [[hlsl::resource_class(UAV)]] [[hlsl::contained_type("b", c)]] h6;
+
+// expected-warning at +1{{attribute 'contained_type' is already applied}}
+__hlsl_resource_t [[hlsl::resource_class(UAV)]] [[hlsl::contained_type(float)]] [[hlsl::contained_type(float)]] h7;
+
+// expected-warning at +1{{attribute 'contained_type' is already applied with different arguments}}
+__hlsl_resource_t [[hlsl::resource_class(UAV)]] [[hlsl::contained_type(float)]] [[hlsl::contained_type(int)]] h8;
diff --git a/clang/test/ParserHLSL/hlsl_resource_handle_attrs.hlsl b/clang/test/ParserHLSL/hlsl_resource_handle_attrs.hlsl
index 6324a11fc8a2df..705baa57f5fbeb 100644
--- a/clang/test/ParserHLSL/hlsl_resource_handle_attrs.hlsl
+++ b/clang/test/ParserHLSL/hlsl_resource_handle_attrs.hlsl
@@ -3,7 +3,7 @@
// CHECK: -ClassTemplateSpecializationDecl 0x{{[0-9a-f]+}} <<invalid sloc>> <invalid sloc> class RWBuffer definition implicit_instantiation
// CHECK: -TemplateArgument type 'float'
// CHECK: `-BuiltinType 0x{{[0-9a-f]+}} 'float'
-// CHECK: -FieldDecl 0x{{[0-9a-f]+}} <<invalid sloc>> <invalid sloc> implicit referenced h 'float * {{\[\[}}hlsl::resource_class(UAV)]]':'float *'
+// CHECK: -FieldDecl 0x{{[0-9a-f]+}} <<invalid sloc>> <invalid sloc> implicit referenced h 'float * {{\[\[}}hlsl::resource_class(UAV)]] {{\[\[}}hlsl::contained_type(float)]]':'float *'
// CHECK: -HLSLResourceAttr 0x{{[0-9a-f]+}} <<invalid sloc>> Implicit TypedBuffer
RWBuffer<float> Buffer1;
@@ -11,6 +11,6 @@ RWBuffer<float> Buffer1;
// CHECK: -TemplateArgument type 'vector<float, 4>'
// CHECK: `-ExtVectorType 0x{{[0-9a-f]+}} 'vector<float, 4>' 4
// CHECK: `-BuiltinType 0x{{[0-9a-f]+}} 'float'
-// CHECK: -FieldDecl 0x{{[0-9a-f]+}} <<invalid sloc>> <invalid sloc> implicit referenced h 'vector<float *, 4> {{\[\[}}hlsl::resource_class(UAV)]] {{\[\[}}hlsl::is_rov()]]':'vector<float *, 4>'
+// CHECK: -FieldDecl 0x{{[0-9a-f]+}} <<invalid sloc>> <invalid sloc> implicit referenced h 'vector<float *, 4> {{\[\[}}hlsl::resource_class(UAV)]] {{\[\[}}hlsl::is_rov()]] {{\[\[}}hlsl::contained_type(vector<float, 4>)]]':'vector<float *, 4>'
// CHECK: -HLSLResourceAttr 0x{{[0-9a-f]+}} <<invalid sloc>> Implicit TypedBuffer
RasterizerOrderedBuffer<vector<float, 4> > BufferArray3[4];
>From 336266394b3a62f1adb83a3c9e1071a7c455a85f Mon Sep 17 00:00:00 2001
From: Helena Kotas <hekotas at microsoft.com>
Date: Wed, 11 Sep 2024 14:58:28 -0700
Subject: [PATCH 2/4] Add TypeLoc for contained type; update tests
---
clang/include/clang/AST/TypeLoc.h | 8 ++-
clang/include/clang/Sema/SemaHLSL.h | 15 +++--
clang/lib/Sema/SemaHLSL.cpp | 60 ++++++++++++-------
clang/lib/Sema/SemaType.cpp | 6 +-
clang/lib/Sema/TreeTransform.h | 15 +++--
clang/test/AST/HLSL/RWBuffer-AST.hlsl | 9 ++-
.../ParserHLSL/hlsl_contained_type_attr.hlsl | 2 +-
7 files changed, 72 insertions(+), 43 deletions(-)
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/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/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index cfda57e17e5a43..4fc8eb170b396e 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -10,6 +10,7 @@
#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"
@@ -17,6 +18,7 @@
#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"
@@ -564,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 =
@@ -595,15 +602,17 @@ bool clang::CreateHLSLAttributedResourceType(Sema &S, QualType Wrapped,
ResAttrs.IsROV = true;
break;
case attr::HLSLContainedType: {
- QualType Ty = cast<HLSLContainedTypeAttr>(A)->getType();
- if (!Contained.isNull()) {
- S.Diag(A->getLocation(), Contained == Ty
+ 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;
}
- Contained = Ty;
+ ContainedTy = Ty;
+ ContainedTyTSI = CTAttr->getTypeLoc();
break;
}
default:
@@ -617,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;
}
@@ -690,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 44e603fe892355..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,
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 4b515d53d12885..af38d1cd34b219 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -7470,13 +7470,16 @@ QualType TreeTransform<Derived>::TransformHLSLAttributedResourceType(
return QualType();
QualType ContainedTy = QualType();
- if (!oldType->getContainedType().isNull()) {
- TypeLocBuilder ContainedTyTLB;
- TypeLoc ContainedTL = TL.getContainedLoc();
- ContainedTyTLB.reserve(ContainedTL.getFullDataSize());
- ContainedTy = getDerived().TransformType(ContainedTyTLB, ContainedTL);
- if (ContainedTy.isNull())
+ 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();
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
index 3e02edcd6232d5..ff90208acd0978 100644
--- a/clang/test/ParserHLSL/hlsl_contained_type_attr.hlsl
+++ b/clang/test/ParserHLSL/hlsl_contained_type_attr.hlsl
@@ -2,7 +2,7 @@
typedef vector<float, 4> float4;
-// CHECK: -TypeAliasDecl 0x{{[0-9a-f]+}} <line:[[# @LINE + 2]]:1, col:47>
+// 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;
>From 12d27293a40f3ba420f1f02469174fe81aab7f1e Mon Sep 17 00:00:00 2001
From: Helena Kotas <hekotas at microsoft.com>
Date: Thu, 12 Sep 2024 14:49:01 -0700
Subject: [PATCH 3/4] cleanup
---
clang/lib/Sema/HLSLExternalSemaSource.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/lib/Sema/HLSLExternalSemaSource.cpp b/clang/lib/Sema/HLSLExternalSemaSource.cpp
index 407430a51e5c2f..5f6662dd273352 100644
--- a/clang/lib/Sema/HLSLExternalSemaSource.cpp
+++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp
@@ -120,7 +120,7 @@ struct BuiltinTypeDeclBuilder {
QualType Ty = Record->getASTContext().VoidPtrTy;
if (Template) {
- if (const TemplateTypeParmDecl *TTD = dyn_cast<TemplateTypeParmDecl>(
+ if (const auto *TTD = dyn_cast<TemplateTypeParmDecl>(
Template->getTemplateParameters()->getParam(0))) {
Ty = Record->getASTContext().getPointerType(
QualType(TTD->getTypeForDecl(), 0));
>From 6dd737283d33d6ba177f3176863c243aa13c7338 Mon Sep 17 00:00:00 2001
From: Helena Kotas <hekotas at microsoft.com>
Date: Thu, 12 Sep 2024 15:42:00 -0700
Subject: [PATCH 4/4] fix merge, update structured buffer AST test
---
clang/lib/AST/TypePrinter.cpp | 2 +-
clang/test/AST/HLSL/StructuredBuffer-AST.hlsl | 8 ++++----
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp
index bf5a1669c31a86..8b943f01519ddc 100644
--- a/clang/lib/AST/TypePrinter.cpp
+++ b/clang/lib/AST/TypePrinter.cpp
@@ -2078,7 +2078,7 @@ void TypePrinter::printHLSLAttributedResourceAfter(
<< HLSLResourceClassAttr::ConvertResourceClassToStr(Attrs.ResourceClass)
<< ")]]";
if (Attrs.IsROV)
- OS << " [[hlsl::is_rov()]]";
+ OS << " [[hlsl::is_rov]]";
QualType ContainedTy = T->getContainedType();
if (!ContainedTy.isNull()) {
diff --git a/clang/test/AST/HLSL/StructuredBuffer-AST.hlsl b/clang/test/AST/HLSL/StructuredBuffer-AST.hlsl
index 11d84ac7b85db2..821b29ace81d2d 100644
--- a/clang/test/AST/HLSL/StructuredBuffer-AST.hlsl
+++ b/clang/test/AST/HLSL/StructuredBuffer-AST.hlsl
@@ -30,7 +30,7 @@ StructuredBuffer<float> Buffer;
// CHECK-NEXT: CXXRecordDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> implicit class StructuredBuffer definition
// CHECK: FinalAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit final
-// CHECK-NEXT: FieldDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> implicit h 'element_type * {{\[\[}}hlsl::resource_class(UAV)]]':'element_type *'
+// CHECK-NEXT: FieldDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> 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 +38,7 @@ StructuredBuffer<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 StructuredBuffer<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 +48,7 @@ StructuredBuffer<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>> 'StructuredBuffer<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 +58,5 @@ StructuredBuffer<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
More information about the cfe-commits
mailing list