diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -2220,6 +2220,9 @@ /// object for a subclass of NSFoo". bool isObjCClassOrClassKindOfType() const; + /// Whether the type is HLSL SRV/UAV/ConstantBuffer/Sampler type. + bool isHLSLResourceType() const; + bool isBlockCompatibleObjCPointerType(ASTContext &ctx) const; bool isObjCSelType() const; // Class bool isObjCBuiltinType() const; // 'id' or 'Class' diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -572,6 +572,19 @@ return false; } +bool Type::isHLSLResourceType() const { + if (const auto *RT = getAs()) { + if (const auto *D = + llvm::dyn_cast(RT->getDecl())) { + if (D->isCompleteDefinition()) + return D->hasAttr(); + ClassTemplateDecl *CTD = D->getSpecializedTemplate(); + return CTD->getTemplatedDecl()->hasAttr(); + } + } + return false; +} + bool Type::isInterfaceType() const { if (const auto *RT = getAs()) return RT->getDecl()->isInterface(); diff --git a/clang/lib/Sema/HLSLExternalSemaSource.cpp b/clang/lib/Sema/HLSLExternalSemaSource.cpp --- a/clang/lib/Sema/HLSLExternalSemaSource.cpp +++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp @@ -474,6 +474,8 @@ .addTemplateArgumentList() .addTypeParameter("element_type", SemaPtr->getASTContext().FloatTy) .finalizeTemplateArgs() + .annotateResourceClass(HLSLResourceAttr::UAV, + HLSLResourceAttr::TypedBuffer) .Record; if (!Decl->isCompleteDefinition()) Completions.insert( @@ -503,7 +505,5 @@ .addHandleMember() .addDefaultHandleConstructor(*SemaPtr, ResourceClass::UAV) .addArraySubscriptOperators() - .annotateResourceClass(HLSLResourceAttr::UAV, - HLSLResourceAttr::TypedBuffer) .completeDefinition(); } diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -13504,7 +13504,9 @@ // Provide a specific diagnostic for uninitialized variable // definitions with incomplete array type. - if (Type->isIncompleteArrayType()) { + if (Type->isIncompleteArrayType() && + !(getLangOpts().HLSL && Var->hasExternalFormalLinkage() && + Type->getArrayElementTypeNoTypeQual()->isHLSLResourceType())) { if (Var->isConstexpr()) Diag(Var->getLocation(), diag::err_constexpr_var_requires_const_init) << Var; @@ -13576,6 +13578,12 @@ if (getLangOpts().OpenCL && Var->getType().getAddressSpace() == LangAS::opencl_local) return; + + // In HLSL, global resource array is allowed to be incomplete. + // Skip initializing incomplate array here. + if (getLangOpts().HLSL && Var->getType()->isIncompleteArrayType()) + return; + // C++03 [dcl.init]p9: // If no initializer is specified for an object, and the // object is of (possibly cv-qualified) non-POD class type (or diff --git a/clang/test/AST/HLSL/unbounded_global_resource_array.hlsl b/clang/test/AST/HLSL/unbounded_global_resource_array.hlsl new file mode 100644 --- /dev/null +++ b/clang/test/AST/HLSL/unbounded_global_resource_array.hlsl @@ -0,0 +1,7 @@ +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -x hlsl -fsyntax-only -ast-dump %s | FileCheck %s + + +// CHECK:VarDecl 0x{{[0-9a-f]+}} <{{.*}}:7:1, col:19> col:17 B 'RWBuffer[]' +// Make sure no CXXConstructExpr created for unbounded resource array. +// CHECK-NOT:CXXConstructExpr +RWBuffer B[]; diff --git a/clang/test/SemaHLSL/unbounded_global_resource_array.hlsl b/clang/test/SemaHLSL/unbounded_global_resource_array.hlsl new file mode 100644 --- /dev/null +++ b/clang/test/SemaHLSL/unbounded_global_resource_array.hlsl @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple dxil--shadermodel6.7-library %s -verify + +// expected-error@+1 {{definition of variable with array type needs an explicit size or an initializer}} +static RWBuffer A[]; +// expected-error@+1 {{definition of variable with array type needs an explicit size or an initializer}} +float F[]; + +// Make sure extern global resource unbounded array compiles. +RWBuffer B[];