diff --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp index e5c6220bfb47d..87f9ae07550c2 100644 --- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp +++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp @@ -697,7 +697,9 @@ BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addArraySubscriptOperators() { AST.DeclarationNames.getCXXOperatorName(OO_Subscript); addHandleAccessFunction(Subscript, /*IsConst=*/true, /*IsRef=*/true); - addHandleAccessFunction(Subscript, /*IsConst=*/false, /*IsRef=*/true); + if (getResourceAttrs().ResourceClass == llvm::dxil::ResourceClass::UAV) + addHandleAccessFunction(Subscript, /*IsConst=*/false, /*IsRef=*/true); + return *this; } @@ -714,7 +716,7 @@ BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addLoadMethods() { return *this; } -FieldDecl *BuiltinTypeDeclBuilder::getResourceHandleField() { +FieldDecl *BuiltinTypeDeclBuilder::getResourceHandleField() const { auto I = Fields.find("__handle"); assert(I != Fields.end() && I->second->getType()->isHLSLAttributedResourceType() && @@ -738,6 +740,12 @@ QualType BuiltinTypeDeclBuilder::getHandleElementType() { return SemaRef.getASTContext().Char8Ty; } +HLSLAttributedResourceType::Attributes +BuiltinTypeDeclBuilder::getResourceAttrs() const { + QualType HandleType = getResourceHandleField()->getType(); + return cast(HandleType)->getAttrs(); +} + // BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::startDefinition() { // assert(!Record->isCompleteDefinition() && "record is already complete"); // Record->startDefinition(); diff --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h index a52e2938104c7..36c4add20b225 100644 --- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h +++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h @@ -91,10 +91,11 @@ class BuiltinTypeDeclBuilder { BuiltinTypeDeclBuilder &addConsumeMethod(); private: - FieldDecl *getResourceHandleField(); + FieldDecl *getResourceHandleField() const; QualType getFirstTemplateTypeParam(); QualType getHandleElementType(); Expr *getConstantIntExpr(int value); + HLSLAttributedResourceType::Attributes getResourceAttrs() const; }; } // namespace hlsl diff --git a/clang/test/AST/HLSL/StructuredBuffers-AST.hlsl b/clang/test/AST/HLSL/StructuredBuffers-AST.hlsl index b74e183eec9cc..1c8b9c10f5a98 100644 --- a/clang/test/AST/HLSL/StructuredBuffers-AST.hlsl +++ b/clang/test/AST/HLSL/StructuredBuffers-AST.hlsl @@ -12,7 +12,7 @@ // // RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -x hlsl -ast-dump \ // RUN: -DRESOURCE=RWStructuredBuffer %s | FileCheck -DRESOURCE=RWStructuredBuffer \ -// RUN: -check-prefixes=CHECK,CHECK-UAV,CHECK-SUBSCRIPT,CHECK-COUNTER,CHECK-LOAD %s +// RUN: -check-prefixes=CHECK,CHECK-UAV,CHECK-SUBSCRIPT,CHECK-SUBSCRIPT-UAV,CHECK-COUNTER,CHECK-LOAD %s // // RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -x hlsl -ast-dump -DEMPTY \ // RUN: -DRESOURCE=AppendStructuredBuffer %s | FileCheck -DRESOURCE=AppendStructuredBuffer \ @@ -36,7 +36,7 @@ // // RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -x hlsl -ast-dump \ // RUN: -DRESOURCE=RasterizerOrderedStructuredBuffer %s | FileCheck -DRESOURCE=RasterizerOrderedStructuredBuffer \ -// RUN: -check-prefixes=CHECK,CHECK-UAV,CHECK-ROV,CHECK-SUBSCRIPT,CHECK-LOAD %s +// RUN: -check-prefixes=CHECK,CHECK-UAV,CHECK-ROV,CHECK-SUBSCRIPT,CHECK-SUBSCRIPT-UAV,CHECK-LOAD %s // This test tests two different AST generations for each structured buffer. // The "EMPTY" test mode verifies the AST generated by forward declaration @@ -170,22 +170,22 @@ RESOURCE Buffer; // CHECK-SUBSCRIPT-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Index' 'unsigned int' // CHECK-SUBSCRIPT-NEXT: AlwaysInlineAttr {{.*}} Implicit always_inline -// CHECK-SUBSCRIPT-NEXT: CXXMethodDecl {{.*}} operator[] 'hlsl_device element_type &(unsigned int)' -// CHECK-SUBSCRIPT-NEXT: ParmVarDecl {{.*}} Index 'unsigned int' -// CHECK-SUBSCRIPT-NEXT: CompoundStmt -// CHECK-SUBSCRIPT-NEXT: ReturnStmt -// CHECK-SUBSCRIPT-NEXT: UnaryOperator {{.*}} 'hlsl_device element_type' prefix '*' cannot overflow -// CHECK-SUBSCRIPT-NEXT: CallExpr {{.*}} 'hlsl_device element_type *' -// CHECK-SUBSCRIPT-NEXT: ImplicitCastExpr {{.*}} -// CHECK-SUBSCRIPT-NEXT: DeclRefExpr {{.*}} '' Function {{.*}} '__builtin_hlsl_resource_getpointer' 'void (...) noexcept' -// CHECK-SUBSCRIPT-NEXT: MemberExpr {{.*}} '__hlsl_resource_t -// CHECK-SUBSCRIPT-SAME{LITERAL}: [[hlsl::resource_class( -// CHECK-SUBSCRIPT-SAME{LITERAL}: [[hlsl::raw_buffer]] -// CHECK-SUBSCRIPT-SAME{LITERAL}: [[hlsl::contained_type(element_type)]] -// CHECK-SUBSCRIPT-SAME: ' lvalue .__handle {{.*}} -// CHECK-SUBSCRIPT-NEXT: CXXThisExpr {{.*}} '[[RESOURCE]]' lvalue implicit this -// CHECK-SUBSCRIPT-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Index' 'unsigned int' -// CHECK-SUBSCRIPT-NEXT: AlwaysInlineAttr {{.*}} Implicit always_inline +// CHECK-SUBSCRIPT-UAV-NEXT: CXXMethodDecl {{.*}} operator[] 'hlsl_device element_type &(unsigned int)' +// CHECK-SUBSCRIPT-UAV-NEXT: ParmVarDecl {{.*}} Index 'unsigned int' +// CHECK-SUBSCRIPT-UAV-NEXT: CompoundStmt +// CHECK-SUBSCRIPT-UAV-NEXT: ReturnStmt +// CHECK-SUBSCRIPT-UAV-NEXT: UnaryOperator {{.*}} 'hlsl_device element_type' prefix '*' cannot overflow +// CHECK-SUBSCRIPT-UAV-NEXT: CallExpr {{.*}} 'hlsl_device element_type *' +// CHECK-SUBSCRIPT-UAV-NEXT: ImplicitCastExpr {{.*}} +// CHECK-SUBSCRIPT-UAV-NEXT: DeclRefExpr {{.*}} '' Function {{.*}} '__builtin_hlsl_resource_getpointer' 'void (...) noexcept' +// CHECK-SUBSCRIPT-UAV-NEXT: MemberExpr {{.*}} '__hlsl_resource_t +// CHECK-SUBSCRIPT-UAV-SAME{LITERAL}: [[hlsl::resource_class( +// CHECK-SUBSCRIPT-UAV-SAME{LITERAL}: [[hlsl::raw_buffer]] +// CHECK-SUBSCRIPT-UAV-SAME{LITERAL}: [[hlsl::contained_type(element_type)]] +// CHECK-SUBSCRIPT-UAV-SAME: ' lvalue .__handle {{.*}} +// CHECK-SUBSCRIPT-UAV-NEXT: CXXThisExpr {{.*}} '[[RESOURCE]]' lvalue implicit this +// CHECK-SUBSCRIPT-UAV-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Index' 'unsigned int' +// CHECK-SUBSCRIPT-UAV-NEXT: AlwaysInlineAttr {{.*}} Implicit always_inline // CHECK-NOSUBSCRIPT-NOT: CXXMethodDecl {{.*}} operator[] 'const hlsl_device element_type &(unsigned int) const' // CHECK-NOSUBSCRIPT-NOT: CXXMethodDecl {{.*}} operator[] 'hlsl_device element_type &(unsigned int)' diff --git a/clang/test/AST/HLSL/TypedBuffers-AST.hlsl b/clang/test/AST/HLSL/TypedBuffers-AST.hlsl index d098e5a323ca7..d6b88e276762e 100644 --- a/clang/test/AST/HLSL/TypedBuffers-AST.hlsl +++ b/clang/test/AST/HLSL/TypedBuffers-AST.hlsl @@ -126,7 +126,7 @@ RESOURCE Buffer; // CHECK-NEXT: DeclRefExpr {{.*}} 'const char *' ParmVar {{.*}} 'name' 'const char *' // CHECK-NEXT: AlwaysInlineAttr -// Subsctript operators +// Subscript operators // CHECK: CXXMethodDecl {{.*}} operator[] 'const hlsl_device element_type &(unsigned int) const' // CHECK-NEXT: ParmVarDecl {{.*}} Index 'unsigned int' @@ -145,22 +145,21 @@ RESOURCE Buffer; // CHECK-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Index' 'unsigned int' // CHECK-NEXT: AlwaysInlineAttr {{.*}} Implicit always_inline -// CHECK-NEXT: CXXMethodDecl {{.*}} operator[] 'hlsl_device element_type &(unsigned int)' -// CHECK-NEXT: ParmVarDecl {{.*}} Index 'unsigned int' -// CHECK-NEXT: CompoundStmt -// CHECK-NEXT: ReturnStmt -// CHECK-NEXT: UnaryOperator {{.*}} 'hlsl_device element_type' prefix '*' cannot overflow -// CHECK-NEXT: CallExpr {{.*}} 'hlsl_device element_type *' -// CHECK-NEXT: ImplicitCastExpr {{.*}} -// CHECK-NEXT: DeclRefExpr {{.*}} '' Function {{.*}} '__builtin_hlsl_resource_getpointer' 'void (...) noexcept' -// CHECK-NEXT: MemberExpr {{.*}} '__hlsl_resource_t +// CHECK-UAV-NEXT: CXXMethodDecl {{.*}} operator[] 'hlsl_device element_type &(unsigned int)' +// CHECK-UAV-NEXT: ParmVarDecl {{.*}} Index 'unsigned int' +// CHECK-UAV-NEXT: CompoundStmt +// CHECK-UAV-NEXT: ReturnStmt +// CHECK-UAV-NEXT: UnaryOperator {{.*}} 'hlsl_device element_type' prefix '*' cannot overflow +// CHECK-UAV-NEXT: CallExpr {{.*}} 'hlsl_device element_type *' +// CHECK-UAV-NEXT: ImplicitCastExpr {{.*}} +// CHECK-UAV-NEXT: DeclRefExpr {{.*}} '' Function {{.*}} '__builtin_hlsl_resource_getpointer' 'void (...) noexcept' +// CHECK-UAV-NEXT: MemberExpr {{.*}} '__hlsl_resource_t // CHECK-UAV-SAME{LITERAL}: [[hlsl::resource_class(UAV)]] -// CHECK-SRV-SAME{LITERAL}: [[hlsl::resource_class(SRV)]] -// CHECK-SAME{LITERAL}: [[hlsl::contained_type(element_type)]] -// CHECK-SAME: ' lvalue .__handle {{.*}} -// CHECK-NEXT: CXXThisExpr {{.*}} '[[RESOURCE]]' lvalue implicit this -// CHECK-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Index' 'unsigned int' -// CHECK-NEXT: AlwaysInlineAttr {{.*}} Implicit always_inline +// CHECK-UAV-SAME{LITERAL}: [[hlsl::contained_type(element_type)]] +// CHECK-UAV-SAME: ' lvalue .__handle {{.*}} +// CHECK-UAV-NEXT: CXXThisExpr {{.*}} '[[RESOURCE]]' lvalue implicit this +// CHECK-UAV-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'Index' 'unsigned int' +// CHECK-UAV-NEXT: AlwaysInlineAttr {{.*}} Implicit always_inline // Load method diff --git a/clang/test/SemaHLSL/BuiltIns/Buffers.hlsl b/clang/test/SemaHLSL/BuiltIns/Buffers.hlsl index 477a16a454a9c..d7c6876d3b9e3 100644 --- a/clang/test/SemaHLSL/BuiltIns/Buffers.hlsl +++ b/clang/test/SemaHLSL/BuiltIns/Buffers.hlsl @@ -111,4 +111,8 @@ Buffer BufferErr3; void main() { (void)Buff.__handle; // expected-error {{'__handle' is a private member of 'hlsl::Buffer>'}} // expected-note@* {{implicitly declared private here}} + + // expected-error@+2 {{cannot assign to return value because function 'operator[]' returns a const value}} + // expected-note@* {{function 'operator[]' which returns const-qualified type 'vector' declared here}} + Buff[0] = 0.0; } diff --git a/clang/test/SemaHLSL/BuiltIns/StructuredBuffers.hlsl b/clang/test/SemaHLSL/BuiltIns/StructuredBuffers.hlsl index bf541f4a07da7..fbd9288590adc 100644 --- a/clang/test/SemaHLSL/BuiltIns/StructuredBuffers.hlsl +++ b/clang/test/SemaHLSL/BuiltIns/StructuredBuffers.hlsl @@ -28,4 +28,8 @@ StructuredBuffer BufferErr4; void main() { (void)Buff.__handle; // expected-error {{'__handle' is a private member of 'hlsl::StructuredBuffer>'}} // expected-note@* {{implicitly declared private here}} + + // expected-error@+2 {{cannot assign to return value because function 'operator[]' returns a const value}} + // expected-note@* {{function 'operator[]' which returns const-qualified type 'vector' declared here}} + Buff[0] = 0.0; }