diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -133,6 +133,12 @@ def GlobalVar : SubsetSubjecthasGlobalStorage()}], "global variables">; +def ExternalGlobalVar : SubsetSubjecthasGlobalStorage() && + S->getStorageClass()!=StorageClass::SC_Static && + !S->isLocalExternDecl()}], + "external global variables">; + def InlineFunction : SubsetSubjectisInlineSpecified()}], "inline functions">; @@ -4046,7 +4052,7 @@ def HLSLResourceBinding: InheritableAttr { let Spellings = [HLSLSemantic<"register">]; - let Subjects = SubjectList<[HLSLBufferObj, GlobalVar]>; + let Subjects = SubjectList<[HLSLBufferObj, ExternalGlobalVar]>; let LangOpts = [HLSL]; let Args = [StringArgument<"Slot">, StringArgument<"Space", 1>]; let Documentation = [HLSLResourceBindingDocs]; diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -2814,8 +2814,19 @@ Sema::AttributeCompletion Completion = Sema::AttributeCompletion::None, const IdentifierInfo *EnclosingScope = nullptr); + void MaybeParseHLSLSemantics(Declarator &D, + SourceLocation *EndLoc = nullptr) { + assert(getLangOpts().HLSL && "MaybeParseHLSLSemantics is for HLSL only"); + if (Tok.is(tok::colon)) { + ParsedAttributes Attrs(AttrFactory); + ParseHLSLSemantics(Attrs, EndLoc); + D.takeAttributes(Attrs); + } + } + void MaybeParseHLSLSemantics(ParsedAttributes &Attrs, SourceLocation *EndLoc = nullptr) { + assert(getLangOpts().HLSL && "MaybeParseHLSLSemantics is for HLSL only"); if (getLangOpts().HLSL && Tok.is(tok::colon)) ParseHLSLSemantics(Attrs, EndLoc); } diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -2054,6 +2054,9 @@ return nullptr; } + if (getLangOpts().HLSL) + MaybeParseHLSLSemantics(D); + if (Tok.is(tok::kw_requires)) ParseTrailingRequiresClause(D); @@ -2223,6 +2226,10 @@ DiagnoseAndSkipExtendedMicrosoftTypeAttributes(); ParseDeclarator(D); + + if (getLangOpts().HLSL) + MaybeParseHLSLSemantics(D); + if (!D.isInvalidType()) { // C++2a [dcl.decl]p1 // init-declarator: @@ -7061,7 +7068,8 @@ // Parse GNU attributes, if present. MaybeParseGNUAttributes(ParmDeclarator); - MaybeParseHLSLSemantics(DS.getAttributes()); + if (getLangOpts().HLSL) + MaybeParseHLSLSemantics(DS.getAttributes()); if (Tok.is(tok::kw_requires)) { // User tried to define a requires clause in a parameter declaration, diff --git a/clang/test/AST/HLSL/resource_binding_attr.hlsl b/clang/test/AST/HLSL/resource_binding_attr.hlsl --- a/clang/test/AST/HLSL/resource_binding_attr.hlsl +++ b/clang/test/AST/HLSL/resource_binding_attr.hlsl @@ -22,3 +22,16 @@ // CHECK-NEXT: DeclRefExpr 0x{{[0-9a-f]+}} 'float' lvalue Var 0x[[B]] 'b' 'float' return a + b; } + +// CHECK: VarDecl 0x{{[0-9a-f]+}} <{{.*}}> col:17 UAV 'RWBuffer':'hlsl::RWBuffer<>' callinit +// CHECK-NEXT:-CXXConstructExpr 0x{{[0-9a-f]+}} 'RWBuffer':'hlsl::RWBuffer<>' 'void ()' +// CHECK-NEXT:-HLSLResourceBindingAttr 0x{{[0-9a-f]+}} "u3" "space0" +RWBuffer UAV : register(u3); + +// CHECK: -VarDecl 0x{{[0-9a-f]+}} <{{.*}}> col:17 UAV1 'RWBuffer':'hlsl::RWBuffer<>' callinit +// CHECK-NEXT:-CXXConstructExpr 0x{{[0-9a-f]+}} 'RWBuffer':'hlsl::RWBuffer<>' 'void ()' +// CHECK-NEXT:-HLSLResourceBindingAttr 0x{{[0-9a-f]+}} "u2" "space0" +// CHECK-NEXT:-VarDecl 0x{{[0-9a-f]+}} col:38 UAV2 'RWBuffer':'hlsl::RWBuffer<>' callinit +// CHECK-NEXT:-CXXConstructExpr 0x{{[0-9a-f]+}} 'RWBuffer':'hlsl::RWBuffer<>' 'void ()' +// CHECK-NEXT:-HLSLResourceBindingAttr 0x{{[0-9a-f]+}} "u4" "space0" +RWBuffer UAV1 : register(u2), UAV2 : register(u4); diff --git a/clang/test/SemaHLSL/resource_binding_attr_error.hlsl b/clang/test/SemaHLSL/resource_binding_attr_error.hlsl --- a/clang/test/SemaHLSL/resource_binding_attr_error.hlsl +++ b/clang/test/SemaHLSL/resource_binding_attr_error.hlsl @@ -1,10 +1,6 @@ // RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -o - -fsyntax-only %s -verify -// expected-error@+5 {{expected ';' after top level declarator}} -// expected-error@+4 {{expected ')'}} -// expected-note@+3 {{to match this '('}} -// expected-error@+2 {{a type specifier is required for all declarations}} -// expected-error@+1 {{illegal storage class on file-scoped variable}} +// expected-error@+1 {{invalid resource class specifier 'c' used; expected 'b', 's', 't', or 'u'}} float a : register(c0, space1); // expected-error@+1 {{invalid resource class specifier 'i' used; expected 'b', 's', 't', or 'u'}} @@ -36,3 +32,29 @@ // expected-error@+2 {{wrong argument format for hlsl attribute, use b2 instead}} // expected-error@+1 {{wrong argument format for hlsl attribute, use space3 instead}} cbuffer D : register(b 2, space 3) {} + +// expected-warning@+1 {{'register' attribute only applies to cbuffer/tbuffer and external global variables}} +static RWBuffer U : register(u5); + +void foo() { + // expected-warning@+1 {{'register' attribute only applies to cbuffer/tbuffer and external global variables}} + RWBuffer U : register(u3); +} +void foo2() { + // expected-warning@+1 {{'register' attribute only applies to cbuffer/tbuffer and external global variables}} + extern RWBuffer U2 : register(u5); +} +// FIXME: expect-error once fix https://github.com/llvm/llvm-project/issues/57886. +float b : register(u0, space1); + +// expected-warning@+1 {{'register' attribute only applies to cbuffer/tbuffer and external global variables}} +void bar(RWBuffer U : register(u3)) { + +} + +struct S { + // FIXME: generate better error when support semantic on struct field. + // See https://github.com/llvm/llvm-project/issues/57889. + // expected-error@+1 {{expected expression}} + RWBuffer U : register(u3); +};