python3kgae updated this revision to Diff 455672.
python3kgae marked 10 inline comments as done.
python3kgae added a comment.
Herald added a reviewer: jdoerfert.
Herald added a subscriber: sstefan1.
Add more comment about no name conflict for cbuffer.
Add Serialize and JSON dump for HLSLBufferDecl.
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D129883/new/
https://reviews.llvm.org/D129883
Files:
clang/include/clang/AST/Decl.h
clang/include/clang/AST/JSONNodeDumper.h
clang/include/clang/AST/RecursiveASTVisitor.h
clang/include/clang/AST/TextNodeDumper.h
clang/include/clang/Basic/DeclNodes.td
clang/include/clang/Basic/DiagnosticParseKinds.td
clang/include/clang/Basic/TokenKinds.def
clang/include/clang/Parse/Parser.h
clang/include/clang/Sema/Sema.h
clang/include/clang/Serialization/ASTBitCodes.h
clang/lib/AST/Decl.cpp
clang/lib/AST/DeclBase.cpp
clang/lib/AST/DeclPrinter.cpp
clang/lib/AST/JSONNodeDumper.cpp
clang/lib/AST/TextNodeDumper.cpp
clang/lib/Basic/IdentifierTable.cpp
clang/lib/Parse/ParseDecl.cpp
clang/lib/Parse/ParseHLSL.cpp
clang/lib/Parse/Parser.cpp
clang/lib/Sema/CMakeLists.txt
clang/lib/Sema/IdentifierResolver.cpp
clang/lib/Sema/SemaDecl.cpp
clang/lib/Sema/SemaHLSL.cpp
clang/lib/Sema/SemaLookup.cpp
clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
clang/lib/Serialization/ASTCommon.cpp
clang/lib/Serialization/ASTReaderDecl.cpp
clang/lib/Serialization/ASTWriter.cpp
clang/lib/Serialization/ASTWriterDecl.cpp
clang/test/AST/HLSL/Inputs/empty.hlsl
clang/test/AST/HLSL/ast-dump-comment-cbuffe-tbufferr.hlsl
clang/test/AST/HLSL/cbuffer_tbuffer.hlsl
clang/test/AST/HLSL/pch_hlsl_buffer.hlsl
clang/test/ParserHLSL/cb_error.hlsl
clang/test/ParserHLSL/invalid_inside_cb.hlsl
clang/test/SemaHLSL/cb_error.hlsl
Index: clang/test/SemaHLSL/cb_error.hlsl
===================================================================
--- /dev/null
+++ clang/test/SemaHLSL/cb_error.hlsl
@@ -0,0 +1,49 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -o - -fsyntax-only %s -verify
+
+// expected-note@+1 {{declared here}}
+cbuffer a {
+ int x;
+};
+
+int foo() {
+ // expected-error@+1 {{'a' does not refer to a value}}
+ return sizeof(a);
+}
+
+// expected-error@+1 {{expected unqualified-id}}
+template <typename Ty> cbuffer a { Ty f; };
+
+// For back-compat reason, it is OK for multiple cbuffer/tbuffer use same name in hlsl.
+// And these cbuffer name only used for reflection, cannot be removed.
+cbuffer A {
+ float A;
+}
+
+cbuffer A {
+ float b;
+}
+
+tbuffer A {
+ float a;
+}
+
+float bar() {
+ // cbuffer/tbuffer name will not conflict with other variables.
+ return A;
+}
+
+cbuffer a {
+ // expected-error@+2 {{unknown type name 'oh'}}
+ // expected-error@+1 {{expected ';' after top level declarator}}
+ oh no!
+ // expected-warning@+1 {{missing terminating ' character}}
+ this isn't even valid HLSL code
+ despite seeming totally reasonable
+ once you understand that HLSL
+ is so flaming weird.
+}
+
+tbuffer B {
+ // expected-error@+1 {{unknown type name 'flaot'}}
+ flaot f;
+}
Index: clang/test/ParserHLSL/invalid_inside_cb.hlsl
===================================================================
--- /dev/null
+++ clang/test/ParserHLSL/invalid_inside_cb.hlsl
@@ -0,0 +1,46 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -o - -fsyntax-only %s -verify
+
+cbuffer A {
+// expected-error@+1 {{invalid declaration inside cbuffer/tbuffer}}
+ namespace N {
+
+ }
+
+}
+
+cbuffer A {
+// expected-error@+1 {{invalid declaration inside cbuffer/tbuffer}}
+ cbuffer B {
+
+ }
+}
+
+tbuffer A {
+// expected-error@+1 {{invalid declaration inside cbuffer/tbuffer}}
+ -
+}
+cbuffer A {
+// expected-error@+1 {{invalid declaration inside cbuffer/tbuffer}}
+ +
+}
+cbuffer A {
+// expected-error@+1 {{invalid declaration inside cbuffer/tbuffer}}
+ export
+}
+tbuffer A {
+// expected-error@+1 {{invalid declaration inside cbuffer/tbuffer}}
+ using
+}
+tbuffer A {
+// expected-error@+1 {{invalid declaration inside cbuffer/tbuffer}}
+ typedef
+}
+cbuffer A {
+// expected-error@+1 {{invalid declaration inside cbuffer/tbuffer}}
+ template
+}
+cbuffer A {
+// expected-error@+1 {{invalid declaration inside cbuffer/tbuffer}}
+ static template
+}
+
Index: clang/test/ParserHLSL/cb_error.hlsl
===================================================================
--- /dev/null
+++ clang/test/ParserHLSL/cb_error.hlsl
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -o - -fsyntax-only %s -verify
+
+// expected-error@+2 {{expected identifier}}
+// expected-error@+1 {{expected unqualified-id}}
+cbuffer { ... };
+// expected-error@+1 {{expected '{'}}
+cbuffer missing_definition;
+// expected-error@+1 {{expected unqualified-id}}
+int cbuffer;
+// expected-error@+1 {{expected identifier}}
+cbuffer;
+
+// expected-error@+2 {{expected identifier}}
+// expected-error@+1 {{expected unqualified-id}}
+tbuffer { ... };
+// expected-error@+1 {{expected '{'}}
+tbuffer missing_definition;
+// expected-error@+1 {{expected unqualified-id}}
+int tbuffer;
+// expected-error@+1 {{expected identifier}}
+tbuffer;
+
+// expected-error@+1 {{expected unqualified-id}}
+cbuffer A {}, B{}
Index: clang/test/AST/HLSL/pch_hlsl_buffer.hlsl
===================================================================
--- /dev/null
+++ clang/test/AST/HLSL/pch_hlsl_buffer.hlsl
@@ -0,0 +1,30 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl \
+// RUN: -emit-pch -o %t %s
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl \
+// RUN: -include-pch %t -fsyntax-only -ast-dump-all %S/Inputs/empty.hlsl \
+// RUN: | FileCheck %s
+
+cbuffer A {
+ float a;
+}
+
+tbuffer B {
+ float b;
+}
+
+float foo() {
+ return a + b;
+}
+// Make sure cbuffer/tbuffer works for PCH.
+// CHECK:HLSLBufferDecl 0x{{[0-9a-f]+}} <{{.*}}:7:1, line:9:1> line:7:9 imported <undeserialized declarations> cbuffer A
+// CHECK-NEXT:`-VarDecl 0x[[A:[0-9a-f]+]] <line:8:3, col:9> col:9 imported used a 'float'
+// CHECK-NEXT:HLSLBufferDecl 0x{{[0-9a-f]+}} <line:11:1, line:13:1> line:11:9 imported <undeserialized declarations> tbuffer B
+// CHECK-NEXT:`-VarDecl 0x[[B:[0-9a-f]+]] <line:12:3, col:9> col:9 imported used b 'float'
+// CHECK-NEXT:FunctionDecl 0x{{[0-9a-f]+}} <line:15:1, line:17:1> line:15:7 imported foo 'float ()'
+// CHECK-NEXT:CompoundStmt 0x{{[0-9a-f]+}} <col:13, line:17:1>
+// CHECK-NEXT:ReturnStmt 0x{{[0-9a-f]+}} <line:16:3, col:14>
+// CHECK-NEXT:BinaryOperator 0x{{[0-9a-f]+}} <col:10, col:14> 'float' '+'
+// CHECK-NEXT:ImplicitCastExpr 0x{{[0-9a-f]+}} <col:10> 'float' <LValueToRValue>
+// CHECK-NEXT:`-DeclRefExpr 0x{{[0-9a-f]+}} <col:10> 'float' lvalue Var 0x[[A]] 'a' 'float'
+// CHECK-NEXT:`-ImplicitCastExpr 0x{{[0-9a-f]+}} <col:14> 'float' <LValueToRValue>
+// CHECK-NEXT:`-DeclRefExpr 0x{{[0-9a-f]+}} <col:14> 'float' lvalue Var 0x[[B]] 'b' 'float'
Index: clang/test/AST/HLSL/cbuffer_tbuffer.hlsl
===================================================================
--- /dev/null
+++ clang/test/AST/HLSL/cbuffer_tbuffer.hlsl
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -ast-dump -o - %s | FileCheck %s
+
+// CHECK:HLSLBufferDecl 0x[[CB:[0-9a-f]+]] {{.*}} line:5:9 cbuffer CB
+// CHECK-NEXT:VarDecl 0x[[A:[0-9a-f]+]] {{.*}} col:9 used a 'float'
+cbuffer CB {
+ float a;
+}
+
+// CHECK:HLSLBufferDecl 0x[[TB:[0-9a-f]+]] {{.*}} line:11:9 tbuffer TB
+// CHECK-NEXT:VarDecl 0x[[B:[0-9a-f]+]] {{.*}} col:9 used b 'float'
+tbuffer TB {
+ float b;
+}
+
+float foo() {
+// CHECK: BinaryOperator 0x{{[0-9a-f]+}} <col:10, col:14> 'float' '+'
+// CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-f]+}} <col:10> 'float' <LValueToRValue>
+// CHECK-NEXT: DeclRefExpr 0x{{[0-9a-f]+}} <col:10> 'float' lvalue Var 0x[[A]] 'a' 'float'
+// CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-f]+}} <col:14> 'float' <LValueToRValue>
+// CHECK-NEXT: DeclRefExpr 0x{{[0-9a-f]+}} <col:14> 'float' lvalue Var 0x[[B]] 'b' 'float'
+ return a + b;
+}
Index: clang/test/AST/HLSL/ast-dump-comment-cbuffe-tbufferr.hlsl
===================================================================
--- /dev/null
+++ clang/test/AST/HLSL/ast-dump-comment-cbuffe-tbufferr.hlsl
@@ -0,0 +1,51 @@
+// RUN: %clang_cc1 -Wdocumentation -ast-dump=json -x hlsl -triple dxil-pc-shadermodel6.3-library %s | FileCheck %s --check-prefix=JSON
+// RUN: %clang_cc1 -Wdocumentation -ast-dump -x hlsl -triple dxil-pc-shadermodel6.3-library %s | FileCheck %s --check-prefix=AST
+
+// JSON:"kind": "HLSLBufferDecl",
+// JSON:"name": "A",
+// JSON-NEXT:"buffer_kind": "cbuffer",
+// JSON:"kind": "TextComment",
+// JSON:"text": " CBuffer decl."
+
+/// CBuffer decl.
+cbuffer A {
+ // JSON: "kind": "VarDecl",
+ // JSON: "name": "a",
+ // JSON: "qualType": "float"
+ float a;
+ // JSON: "kind": "VarDecl",
+ // JSON: "name": "b",
+ // JSON: "qualType": "int"
+ int b;
+}
+
+// JSON:"kind": "HLSLBufferDecl",
+// JSON:"name": "B",
+// JSON-NEXT:"buffer_kind": "tbuffer",
+// JSON:"kind": "TextComment",
+// JSON:"text": " TBuffer decl."
+
+/// TBuffer decl.
+tbuffer B {
+ // JSON: "kind": "VarDecl",
+ // JSON: "name": "c",
+ // JSON: "qualType": "float"
+ float c;
+ // JSON: "kind": "VarDecl",
+ // JSON: "name": "d",
+ // JSON: "qualType": "int"
+ int d;
+}
+
+// AST:HLSLBufferDecl {{.*}}:11:1, line:20:1> line:11:9 cbuffer A
+// AST-NEXT:FullComment {{.*}}<line:10:4, col:17>
+// AST-NEXT:`-ParagraphComment {{.*}}<col:4, col:17>
+// AST-NEXT:`-TextComment {{.*}}<col:4, col:17> Text=" CBuffer decl."
+// AST-NEXT:-VarDecl {{.*}}<line:15:5, col:11> col:11 a 'float'
+// AST-NEXT:`-VarDecl {{.*}}<line:19:5, col:9> col:9 b 'int'
+// AST-NEXT:HLSLBufferDecl {{.*}}<line:29:1, line:38:1> line:29:9 tbuffer B
+// AST-NEXT:-FullComment {{.*}}<line:28:4, col:17>
+// AST-NEXT: `-ParagraphComment {{.*}}<col:4, col:17>
+// AST-NEXT: `-TextComment {{.*}}<col:4, col:17> Text=" TBuffer decl."
+// AST-NEXT:-VarDecl {{.*}}<line:33:5, col:11> col:11 c 'float'
+// AST-NEXT:`-VarDecl {{.*}} <line:37:5, col:9> col:9 d 'int'
Index: clang/lib/Serialization/ASTWriterDecl.cpp
===================================================================
--- clang/lib/Serialization/ASTWriterDecl.cpp
+++ clang/lib/Serialization/ASTWriterDecl.cpp
@@ -131,10 +131,9 @@
void VisitCapturedDecl(CapturedDecl *D);
void VisitEmptyDecl(EmptyDecl *D);
void VisitLifetimeExtendedTemporaryDecl(LifetimeExtendedTemporaryDecl *D);
-
void VisitDeclContext(DeclContext *DC);
template <typename T> void VisitRedeclarable(Redeclarable<T> *D);
-
+ void VisitHLSLBufferDecl(HLSLBufferDecl *D);
// FIXME: Put in the same order is DeclNodes.td?
void VisitObjCMethodDecl(ObjCMethodDecl *D);
@@ -1864,6 +1863,17 @@
}
}
+void ASTDeclWriter::VisitHLSLBufferDecl(HLSLBufferDecl *D) {
+ VisitNamedDecl(D);
+ VisitDeclContext(D);
+ Record.push_back(D->isCBuffer());
+ Record.AddSourceLocation(D->getLocStart());
+ Record.AddSourceLocation(D->getLBraceLoc());
+ Record.AddSourceLocation(D->getRBraceLoc());
+
+ Code = serialization::DECL_HLSL_BUFFER;
+}
+
void ASTDeclWriter::VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D) {
Record.writeOMPChildren(D->Data);
VisitDecl(D);
Index: clang/lib/Serialization/ASTWriter.cpp
===================================================================
--- clang/lib/Serialization/ASTWriter.cpp
+++ clang/lib/Serialization/ASTWriter.cpp
@@ -1016,6 +1016,7 @@
RECORD(DECL_PRAGMA_DETECT_MISMATCH);
RECORD(DECL_OMP_DECLARE_REDUCTION);
RECORD(DECL_OMP_ALLOCATE);
+ RECORD(DECL_HLSL_BUFFER);
// Statements and Exprs can occur in the Decls and Types block.
AddStmtsExprs(Stream, Record);
Index: clang/lib/Serialization/ASTReaderDecl.cpp
===================================================================
--- clang/lib/Serialization/ASTReaderDecl.cpp
+++ clang/lib/Serialization/ASTReaderDecl.cpp
@@ -322,6 +322,7 @@
void VisitNamedDecl(NamedDecl *ND);
void VisitLabelDecl(LabelDecl *LD);
void VisitNamespaceDecl(NamespaceDecl *D);
+ void VisitHLSLBufferDecl(HLSLBufferDecl *D);
void VisitUsingDirectiveDecl(UsingDirectiveDecl *D);
void VisitNamespaceAliasDecl(NamespaceAliasDecl *D);
void VisitTypeDecl(TypeDecl *TD);
@@ -1735,6 +1736,15 @@
}
}
+void ASTDeclReader::VisitHLSLBufferDecl(HLSLBufferDecl *D) {
+ VisitNamedDecl(D);
+ VisitDeclContext(D);
+ D->IsCBuffer = Record.readBool();
+ D->KwLoc = readSourceLocation();
+ D->LBraceLoc = readSourceLocation();
+ D->RBraceLoc = readSourceLocation();
+}
+
void ASTDeclReader::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) {
RedeclarableResult Redecl = VisitRedeclarable(D);
VisitNamedDecl(D);
@@ -3853,6 +3863,9 @@
case DECL_OBJC_TYPE_PARAM:
D = ObjCTypeParamDecl::CreateDeserialized(Context, ID);
break;
+ case DECL_HLSL_BUFFER:
+ D = HLSLBufferDecl::CreateDeserialized(Context, ID);
+ break;
}
assert(D && "Unknown declaration reading AST file");
Index: clang/lib/Serialization/ASTCommon.cpp
===================================================================
--- clang/lib/Serialization/ASTCommon.cpp
+++ clang/lib/Serialization/ASTCommon.cpp
@@ -433,6 +433,7 @@
case Decl::LifetimeExtendedTemporary:
case Decl::RequiresExprBody:
case Decl::UnresolvedUsingIfExists:
+ case Decl::HLSLBuffer:
return false;
// These indirectly derive from Redeclarable<T> but are not actually
Index: clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
===================================================================
--- clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -873,6 +873,10 @@
llvm_unreachable("Translation units cannot be instantiated");
}
+Decl *TemplateDeclInstantiator::VisitHLSLBufferDecl(HLSLBufferDecl *Decl) {
+ llvm_unreachable("HLSL buffer declarations cannot be instantiated");
+}
+
Decl *
TemplateDeclInstantiator::VisitPragmaCommentDecl(PragmaCommentDecl *D) {
llvm_unreachable("pragma comment cannot be instantiated");
Index: clang/lib/Sema/SemaLookup.cpp
===================================================================
--- clang/lib/Sema/SemaLookup.cpp
+++ clang/lib/Sema/SemaLookup.cpp
@@ -519,7 +519,8 @@
D = cast<NamedDecl>(D->getCanonicalDecl());
// Ignore an invalid declaration unless it's the only one left.
- if (D->isInvalidDecl() && !(I == 0 && N == 1)) {
+ // Also ignore HLSLBufferDecl which not have name conflict with other Decls.
+ if ((D->isInvalidDecl() || isa<HLSLBufferDecl>(D)) && !(I == 0 && N == 1)) {
Decls[I] = Decls[--N];
continue;
}
Index: clang/lib/Sema/SemaHLSL.cpp
===================================================================
--- /dev/null
+++ clang/lib/Sema/SemaHLSL.cpp
@@ -0,0 +1,35 @@
+//===- SemaHLSL.cpp - Semantic Analysis for HLSL constructs ---------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// This implements Semantic Analysis for HLSL constructs.
+//===----------------------------------------------------------------------===//
+
+#include "clang/Sema/Sema.h"
+
+using namespace clang;
+
+Decl *Sema::ActOnStartHLSLBuffer(Scope *BufferScope, bool CBuffer,
+ SourceLocation KwLoc, IdentifierInfo *Ident,
+ SourceLocation IdentLoc,
+ SourceLocation LBrace) {
+ // For anonymous namespace, take the location of the left brace.
+ DeclContext *LexicalParent = getCurLexicalContext();
+ HLSLBufferDecl *Result = HLSLBufferDecl::Create(
+ Context, LexicalParent, CBuffer, KwLoc, Ident, IdentLoc, LBrace);
+
+ PushOnScopeChains(Result, BufferScope);
+ PushDeclContext(BufferScope, Result);
+
+ return Result;
+}
+
+void Sema::ActOnFinishHLSLBuffer(Decl *Dcl, SourceLocation RBrace) {
+ auto *BufDecl = dyn_cast_if_present<HLSLBufferDecl>(Dcl);
+ assert(BufDecl && "Invalid parameter, expected HLSLBufferDecl");
+ BufDecl->setRBraceLoc(RBrace);
+ PopDeclContext();
+}
Index: clang/lib/Sema/SemaDecl.cpp
===================================================================
--- clang/lib/Sema/SemaDecl.cpp
+++ clang/lib/Sema/SemaDecl.cpp
@@ -7122,6 +7122,9 @@
return true;
if (DC->isRecord())
return false;
+ if (DC->getDeclKind() == Decl::HLSLBuffer)
+ return false;
+
if (isa<RequiresExprBodyDecl>(DC))
return false;
llvm_unreachable("Unexpected context");
Index: clang/lib/Sema/IdentifierResolver.cpp
===================================================================
--- clang/lib/Sema/IdentifierResolver.cpp
+++ clang/lib/Sema/IdentifierResolver.cpp
@@ -99,7 +99,11 @@
bool IdentifierResolver::isDeclInScope(Decl *D, DeclContext *Ctx, Scope *S,
bool AllowInlineNamespace) const {
Ctx = Ctx->getRedeclContext();
-
+ // The names for HLSL cbuffer/tbuffers only used by the CPU-side
+ // reflection API which supports querying bindings. It will not have name
+ // conflict with other Decls.
+ if (LangOpt.HLSL && isa<HLSLBufferDecl>(D))
+ return false;
if (Ctx->isFunctionOrMethod() || (S && S->isFunctionPrototypeScope())) {
// Ignore the scopes associated within transparent declaration contexts.
while (S->getEntity() && S->getEntity()->isTransparentContext())
Index: clang/lib/Sema/CMakeLists.txt
===================================================================
--- clang/lib/Sema/CMakeLists.txt
+++ clang/lib/Sema/CMakeLists.txt
@@ -44,6 +44,7 @@
SemaExprMember.cpp
SemaExprObjC.cpp
SemaFixItUtils.cpp
+ SemaHLSL.cpp
SemaInit.cpp
SemaLambda.cpp
SemaLookup.cpp
Index: clang/lib/Parse/Parser.cpp
===================================================================
--- clang/lib/Parse/Parser.cpp
+++ clang/lib/Parse/Parser.cpp
@@ -947,6 +947,16 @@
EmptyDeclSpecAttrs);
}
+ case tok::kw_cbuffer:
+ case tok::kw_tbuffer:
+ if (getLangOpts().HLSL) {
+ SourceLocation DeclEnd;
+ ParsedAttributes EmptyDeclSpecAttrs(AttrFactory);
+ return ParseDeclaration(DeclaratorContext::File, DeclEnd, Attrs,
+ EmptyDeclSpecAttrs);
+ }
+ goto dont_know;
+
case tok::kw_static:
// Parse (then ignore) 'static' prior to a template instantiation. This is
// a GCC extension that we intentionally do not support.
Index: clang/lib/Parse/ParseHLSL.cpp
===================================================================
--- clang/lib/Parse/ParseHLSL.cpp
+++ clang/lib/Parse/ParseHLSL.cpp
@@ -13,9 +13,138 @@
#include "clang/Basic/AttributeCommonInfo.h"
#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Parse/Parser.h"
+#include "clang/Parse/RAIIObjectsForParser.h"
using namespace clang;
+Decl *Parser::ParseHLSLBuffer(SourceLocation &DeclEnd,
+ SourceLocation InlineLoc) {
+ assert((Tok.is(tok::kw_cbuffer) || Tok.is(tok::kw_tbuffer)) &&
+ "Not a cbuffer or tbuffer!");
+ bool IsCBuffer = Tok.is(tok::kw_cbuffer);
+ SourceLocation BufferLoc = ConsumeToken(); // eat the 'cbuffer or tbuffer'.
+
+ if (!Tok.is(tok::identifier)) {
+ Diag(Tok, diag::err_expected) << tok::identifier;
+ return nullptr;
+ }
+
+ IdentifierInfo *Identifier = Tok.getIdentifierInfo();
+ SourceLocation IdentifierLoc = ConsumeToken(); // consume identifier
+
+ ParseScope BufferScope(this, Scope::DeclScope);
+ BalancedDelimiterTracker T(*this, tok::l_brace);
+ if (T.consumeOpen()) {
+ Diag(Tok, diag::err_expected) << tok::l_brace;
+ return nullptr;
+ }
+
+ Decl *D = Actions.ActOnStartHLSLBuffer(getCurScope(), IsCBuffer, BufferLoc,
+ Identifier, IdentifierLoc,
+ T.getOpenLocation());
+
+ // FIXME: support attribute on cbuffer/tbuffer.
+
+ while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {
+ SourceLocation Loc = Tok.getLocation();
+ // FIXME: support attribute on constants inside cbuffer/tbuffer.
+ ParsedAttributes Attrs(AttrFactory);
+ ParsedAttributes DeclSpecAttrs(AttrFactory);
+
+ if (PP.isCodeCompletionReached()) {
+ cutOffParsing();
+ return nullptr;
+ }
+
+ switch (Tok.getKind()) {
+ case tok::kw_namespace:
+ // FIXME: support namespace inside HLSLBuffer if required for back-compat.
+ Diag(Tok.getLocation(), diag::err_invalid_declaration_in_hlsl_buffer);
+ T.skipToEnd();
+ return nullptr;
+ break;
+ case tok::kw_cbuffer:
+ case tok::kw_tbuffer:
+ // FIXME: support nested HLSLBuffer if required for back-compat.
+ Diag(Tok.getLocation(), diag::err_invalid_declaration_in_hlsl_buffer);
+ T.skipToEnd();
+ return nullptr;
+
+ [[fallthrough]];
+ case tok::annot_pragma_vis:
+ case tok::annot_pragma_pack:
+ case tok::annot_pragma_msstruct:
+ case tok::annot_pragma_align:
+ case tok::annot_pragma_weak:
+ case tok::annot_pragma_weakalias:
+ case tok::annot_pragma_redefine_extname:
+ case tok::annot_pragma_fp_contract:
+ case tok::annot_pragma_fenv_access:
+ case tok::annot_pragma_fenv_access_ms:
+ case tok::annot_pragma_fenv_round:
+ case tok::annot_pragma_float_control:
+ case tok::annot_pragma_fp:
+ case tok::annot_pragma_opencl_extension:
+ case tok::annot_attr_openmp:
+ case tok::annot_pragma_openmp:
+ case tok::annot_pragma_ms_pointers_to_members:
+ case tok::annot_pragma_ms_vtordisp:
+ case tok::annot_pragma_ms_pragma:
+ case tok::annot_pragma_dump:
+ case tok::annot_pragma_attribute:
+ case tok::kw___extension__:
+ case tok::kw_asm:
+ case tok::at:
+ case tok::minus:
+ case tok::plus:
+ case tok::code_completion:
+ case tok::kw_import:
+ case tok::kw_export:
+ case tok::kw_using:
+ case tok::kw_typedef:
+ case tok::kw_template:
+ case tok::kw_static_assert:
+ case tok::kw__Static_assert:
+ case tok::kw_inline:
+ case tok::kw_extern:
+ case tok::kw___if_exists:
+ case tok::kw___if_not_exists:
+ case tok::kw_module:
+ Diag(Tok.getLocation(), diag::err_invalid_declaration_in_hlsl_buffer);
+ T.skipToEnd();
+ return nullptr;
+
+ case tok::semi:
+ ConsumeExtraSemi(InsideStruct);
+ break;
+
+ case tok::kw_static:
+ // Parse (then ignore) 'static' prior to a template instantiation. This
+ // is a GCC extension that we intentionally do not support.
+ if (getLangOpts().CPlusPlus && NextToken().is(tok::kw_template)) {
+ Diag(Tok.getLocation(), diag::err_invalid_declaration_in_hlsl_buffer);
+ T.skipToEnd();
+ return nullptr;
+ }
+ default:
+ if (Tok.isEditorPlaceholder()) {
+ ConsumeToken();
+ break;
+ }
+ ParseSimpleDeclaration(DeclaratorContext::File, DeclEnd, Attrs,
+ DeclSpecAttrs, true, nullptr, &Loc);
+ break;
+ }
+ }
+
+ T.consumeClose();
+ DeclEnd = T.getCloseLocation();
+ BufferScope.Exit();
+ Actions.ActOnFinishHLSLBuffer(D, DeclEnd);
+
+ return D;
+}
+
void Parser::ParseHLSLSemantics(ParsedAttributes &Attrs,
SourceLocation *EndLoc) {
assert(Tok.is(tok::colon) && "Not a HLSL Semantic");
Index: clang/lib/Parse/ParseDecl.cpp
===================================================================
--- clang/lib/Parse/ParseDecl.cpp
+++ clang/lib/Parse/ParseDecl.cpp
@@ -1787,6 +1787,11 @@
}
return ParseSimpleDeclaration(Context, DeclEnd, DeclAttrs, DeclSpecAttrs,
true, nullptr, DeclSpecStart);
+
+ case tok::kw_cbuffer:
+ case tok::kw_tbuffer:
+ SingleDecl = ParseHLSLBuffer(DeclEnd);
+ break;
case tok::kw_namespace:
ProhibitAttributes(DeclAttrs);
ProhibitAttributes(DeclSpecAttrs);
Index: clang/lib/Basic/IdentifierTable.cpp
===================================================================
--- clang/lib/Basic/IdentifierTable.cpp
+++ clang/lib/Basic/IdentifierTable.cpp
@@ -108,7 +108,8 @@
KEYMSCOMPAT = 0x400000,
KEYSYCL = 0x800000,
KEYCUDA = 0x1000000,
- KEYMAX = KEYCUDA, // The maximum key
+ KEYHLSL = 0x2000000,
+ KEYMAX = KEYHLSL, // The maximum key
KEYALLCXX = KEYCXX | KEYCXX11 | KEYCXX20,
KEYALL = (KEYMAX | (KEYMAX-1)) & ~KEYNOMS18 &
~KEYNOOPENCL // KEYNOMS18 and KEYNOOPENCL are used to exclude.
@@ -199,6 +200,8 @@
return LangOpts.isSYCL() ? KS_Enabled : KS_Unknown;
case KEYCUDA:
return LangOpts.CUDA ? KS_Enabled : KS_Unknown;
+ case KEYHLSL:
+ return LangOpts.HLSL ? KS_Enabled : KS_Unknown;
case KEYNOCXX:
// This is enabled in all non-C++ modes, but might be enabled for other
// reasons as well.
Index: clang/lib/AST/TextNodeDumper.cpp
===================================================================
--- clang/lib/AST/TextNodeDumper.cpp
+++ clang/lib/AST/TextNodeDumper.cpp
@@ -2386,3 +2386,11 @@
if (S->hasStoredFPFeatures())
printFPOptions(S->getStoredFPFeatures());
}
+
+void TextNodeDumper::VisitHLSLBufferDecl(const HLSLBufferDecl *D) {
+ if (D->isCBuffer())
+ OS << " cbuffer";
+ else
+ OS << " tbuffer";
+ dumpName(D);
+}
Index: clang/lib/AST/JSONNodeDumper.cpp
===================================================================
--- clang/lib/AST/JSONNodeDumper.cpp
+++ clang/lib/AST/JSONNodeDumper.cpp
@@ -899,6 +899,11 @@
}
}
+void JSONNodeDumper::VisitHLSLBufferDecl(const HLSLBufferDecl *D) {
+ VisitNamedDecl(D);
+ JOS.attribute("buffer_kind", D->isCBuffer() ? "cbuffer" : "tbuffer");
+}
+
void JSONNodeDumper::VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D) {
VisitNamedDecl(D);
JOS.attribute("tagUsed", D->wasDeclaredWithTypename() ? "typename" : "class");
Index: clang/lib/AST/DeclPrinter.cpp
===================================================================
--- clang/lib/AST/DeclPrinter.cpp
+++ clang/lib/AST/DeclPrinter.cpp
@@ -108,6 +108,7 @@
void VisitOMPCapturedExprDecl(OMPCapturedExprDecl *D);
void VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *TTP);
void VisitNonTypeTemplateParmDecl(const NonTypeTemplateParmDecl *NTTP);
+ void VisitHLSLBufferDecl(HLSLBufferDecl *D);
void printTemplateParameters(const TemplateParameterList *Params,
bool OmitTemplateKW = false);
@@ -462,12 +463,9 @@
Terminator = nullptr;
else
Terminator = ";";
- } else if (isa<NamespaceDecl>(*D) || isa<LinkageSpecDecl>(*D) ||
- isa<ObjCImplementationDecl>(*D) ||
- isa<ObjCInterfaceDecl>(*D) ||
- isa<ObjCProtocolDecl>(*D) ||
- isa<ObjCCategoryImplDecl>(*D) ||
- isa<ObjCCategoryDecl>(*D))
+ } else if (isa<NamespaceDecl, LinkageSpecDecl, ObjCImplementationDecl,
+ ObjCInterfaceDecl, ObjCProtocolDecl, ObjCCategoryImplDecl,
+ ObjCCategoryDecl, HLSLBufferDecl>(*D))
Terminator = nullptr;
else if (isa<EnumConstantDecl>(*D)) {
DeclContext::decl_iterator Next = D;
@@ -1658,6 +1656,21 @@
}
}
+void DeclPrinter::VisitHLSLBufferDecl(HLSLBufferDecl *D) {
+ if (D->isCBuffer())
+ Out << "cbuffer ";
+ else
+ Out << "tbuffer ";
+
+ Out << *D;
+
+ prettyPrintAttributes(D);
+
+ Out << " {\n";
+ VisitDeclContext(D);
+ Indent() << "}";
+}
+
void DeclPrinter::VisitOMPAllocateDecl(OMPAllocateDecl *D) {
Out << "#pragma omp allocate";
if (!D->varlist_empty()) {
Index: clang/lib/AST/DeclBase.cpp
===================================================================
--- clang/lib/AST/DeclBase.cpp
+++ clang/lib/AST/DeclBase.cpp
@@ -750,6 +750,7 @@
case ObjCMethod:
case ObjCProperty:
case MSProperty:
+ case HLSLBuffer:
return IDNS_Ordinary;
case Label:
return IDNS_Label;
@@ -1193,7 +1194,7 @@
if (getDeclKind() == Decl::Enum)
return !cast<EnumDecl>(this)->isScoped();
- return getDeclKind() == Decl::LinkageSpec || getDeclKind() == Decl::Export;
+ return isa<LinkageSpecDecl, ExportDecl, HLSLBufferDecl>(this);
}
static bool isLinkageSpecContext(const DeclContext *DC,
@@ -1258,6 +1259,15 @@
// There is only one DeclContext for these entities.
return this;
+ case Decl::HLSLBuffer:
+ // Each buffer, even with the same name, is a distinct construct.
+ // Multiple buffers with the same name are allowed for backward
+ // compatibility.
+ // As long as buffers have unique resource bindings the names don't matter.
+ // The names get exposed via the CPU-side reflection API which
+ // supports querying bindings, so we cannot remove them.
+ return this;
+
case Decl::TranslationUnit:
return static_cast<TranslationUnitDecl *>(this)->getFirstDecl();
case Decl::Namespace:
Index: clang/lib/AST/Decl.cpp
===================================================================
--- clang/lib/AST/Decl.cpp
+++ clang/lib/AST/Decl.cpp
@@ -5210,6 +5210,40 @@
return new (C, ID) EmptyDecl(nullptr, SourceLocation());
}
+HLSLBufferDecl::HLSLBufferDecl(DeclContext *DC, bool CBuffer,
+ SourceLocation KwLoc, IdentifierInfo *ID,
+ SourceLocation IDLoc, SourceLocation LBrace)
+ : NamedDecl(Decl::Kind::HLSLBuffer, DC, IDLoc, DeclarationName(ID)),
+ DeclContext(Decl::Kind::HLSLBuffer), LBraceLoc(LBrace), KwLoc(KwLoc),
+ IsCBuffer(CBuffer) {}
+
+HLSLBufferDecl *HLSLBufferDecl::Create(ASTContext &C,
+ DeclContext *LexicalParent, bool CBuffer,
+ SourceLocation KwLoc, IdentifierInfo *ID,
+ SourceLocation IDLoc,
+ SourceLocation LBrace) {
+ // For hlsl like this
+ // cbuffer A {
+ // cbuffer B {
+ // }
+ // }
+ // compiler should treat it as
+ // cbuffer A {
+ // }
+ // cbuffer B {
+ // }
+ // FIXME: support nested buffers if required for back-compat.
+ DeclContext *DC = LexicalParent;
+ HLSLBufferDecl *Result =
+ new (C, DC) HLSLBufferDecl(DC, CBuffer, KwLoc, ID, IDLoc, LBrace);
+ return Result;
+}
+
+HLSLBufferDecl *HLSLBufferDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
+ return new (C, ID) HLSLBufferDecl(nullptr, false, SourceLocation(), nullptr,
+ SourceLocation(), SourceLocation());
+}
+
//===----------------------------------------------------------------------===//
// ImportDecl Implementation
//===----------------------------------------------------------------------===//
Index: clang/include/clang/Serialization/ASTBitCodes.h
===================================================================
--- clang/include/clang/Serialization/ASTBitCodes.h
+++ clang/include/clang/Serialization/ASTBitCodes.h
@@ -1508,7 +1508,10 @@
/// A UnnamedGlobalConstantDecl record.
DECL_UNNAMED_GLOBAL_CONSTANT,
- DECL_LAST = DECL_UNNAMED_GLOBAL_CONSTANT
+ /// A HLSLBufferDecl record.
+ DECL_HLSL_BUFFER,
+
+ DECL_LAST = DECL_HLSL_BUFFER
};
/// Record codes for each kind of statement or expression.
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -5926,6 +5926,12 @@
SourceLocation BuiltinLoc,
SourceLocation RParenLoc);
+ //===---------------------------- HLSL Features -------------------------===//
+ Decl *ActOnStartHLSLBuffer(Scope *BufferScope, bool CBuffer,
+ SourceLocation KwLoc, IdentifierInfo *Ident,
+ SourceLocation IdentLoc, SourceLocation LBrace);
+ void ActOnFinishHLSLBuffer(Decl *Dcl, SourceLocation RBrace);
+
//===---------------------------- C++ Features --------------------------===//
// Act on C++ namespaces
Index: clang/include/clang/Parse/Parser.h
===================================================================
--- clang/include/clang/Parse/Parser.h
+++ clang/include/clang/Parse/Parser.h
@@ -2818,6 +2818,8 @@
void ParseHLSLSemantics(ParsedAttributes &Attrs,
SourceLocation *EndLoc = nullptr);
+ Decl *ParseHLSLBuffer(SourceLocation &DeclEnd,
+ SourceLocation InlineLoc = SourceLocation());
void MaybeParseMicrosoftAttributes(ParsedAttributes &Attrs) {
if ((getLangOpts().MicrosoftExt || getLangOpts().HLSL) &&
Index: clang/include/clang/Basic/TokenKinds.def
===================================================================
--- clang/include/clang/Basic/TokenKinds.def
+++ clang/include/clang/Basic/TokenKinds.def
@@ -595,6 +595,10 @@
// CUDA/HIP function attributes
KEYWORD(__noinline__ , KEYCUDA)
+// HLSL keywords.
+KEYWORD(cbuffer , KEYHLSL)
+KEYWORD(tbuffer , KEYHLSL)
+
// OpenMP Type Traits
UNARY_EXPR_OR_TYPE_TRAIT(__builtin_omp_required_simd_align, OpenMPRequiredSimdAlign, KEYALL)
Index: clang/include/clang/Basic/DiagnosticParseKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticParseKinds.td
+++ clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -1605,6 +1605,7 @@
def err_expected_semantic_identifier : Error<
"expected HLSL Semantic identifier">;
+def err_invalid_declaration_in_hlsl_buffer : Error<"invalid declaration inside cbuffer/tbuffer">;
def err_unknown_hlsl_semantic : Error<"unknown HLSL semantic %0">;
def ext_hlsl_access_specifiers : ExtWarn<
"access specifiers are a clang HLSL extension">,
Index: clang/include/clang/Basic/DeclNodes.td
===================================================================
--- clang/include/clang/Basic/DeclNodes.td
+++ clang/include/clang/Basic/DeclNodes.td
@@ -108,4 +108,4 @@
def Empty : DeclNode<Decl>;
def RequiresExprBody : DeclNode<Decl>, DeclContext;
def LifetimeExtendedTemporary : DeclNode<Decl>;
-
+def HLSLBuffer : DeclNode<Named, "HLSLBuffer">, DeclContext;
Index: clang/include/clang/AST/TextNodeDumper.h
===================================================================
--- clang/include/clang/AST/TextNodeDumper.h
+++ clang/include/clang/AST/TextNodeDumper.h
@@ -381,6 +381,7 @@
void VisitConceptDecl(const ConceptDecl *D);
void
VisitLifetimeExtendedTemporaryDecl(const LifetimeExtendedTemporaryDecl *D);
+ void VisitHLSLBufferDecl(const HLSLBufferDecl *D);
};
} // namespace clang
Index: clang/include/clang/AST/RecursiveASTVisitor.h
===================================================================
--- clang/include/clang/AST/RecursiveASTVisitor.h
+++ clang/include/clang/AST/RecursiveASTVisitor.h
@@ -1551,6 +1551,8 @@
DEF_TRAVERSE_DECL(EmptyDecl, {})
+DEF_TRAVERSE_DECL(HLSLBufferDecl, {})
+
DEF_TRAVERSE_DECL(LifetimeExtendedTemporaryDecl, {
TRY_TO(TraverseStmt(D->getTemporaryExpr()));
})
Index: clang/include/clang/AST/JSONNodeDumper.h
===================================================================
--- clang/include/clang/AST/JSONNodeDumper.h
+++ clang/include/clang/AST/JSONNodeDumper.h
@@ -246,6 +246,7 @@
void VisitEnumConstantDecl(const EnumConstantDecl *ECD);
void VisitRecordDecl(const RecordDecl *RD);
void VisitCXXRecordDecl(const CXXRecordDecl *RD);
+ void VisitHLSLBufferDecl(const HLSLBufferDecl *D);
void VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D);
void VisitNonTypeTemplateParmDecl(const NonTypeTemplateParmDecl *D);
void VisitTemplateTemplateParmDecl(const TemplateTemplateParmDecl *D);
Index: clang/include/clang/AST/Decl.h
===================================================================
--- clang/include/clang/AST/Decl.h
+++ clang/include/clang/AST/Decl.h
@@ -4671,6 +4671,51 @@
static bool classofKind(Kind K) { return K == Empty; }
};
+/// HLSLBufferDecl - Represent a cbuffer or tbuffer declaration.
+class HLSLBufferDecl final : public NamedDecl, public DeclContext {
+ /// LBraceLoc - The ending location of the source range.
+ SourceLocation LBraceLoc;
+ /// RBraceLoc - The ending location of the source range.
+ SourceLocation RBraceLoc;
+ /// KwLoc - The location of the cbuffer or tbuffer keyword.
+ SourceLocation KwLoc;
+ /// IsCBuffer - Whether the buffer is a cbuffer (and not a tbuffer).
+ bool IsCBuffer;
+
+ HLSLBufferDecl(DeclContext *DC, bool CBuffer, SourceLocation KwLoc,
+ IdentifierInfo *ID, SourceLocation IDLoc,
+ SourceLocation LBrace);
+
+public:
+ static HLSLBufferDecl *Create(ASTContext &C, DeclContext *LexicalParent,
+ bool CBuffer, SourceLocation KwLoc,
+ IdentifierInfo *ID, SourceLocation IDLoc,
+ SourceLocation LBrace);
+ static HLSLBufferDecl *CreateDeserialized(ASTContext &C, unsigned ID);
+
+ SourceRange getSourceRange() const LLVM_READONLY {
+ return SourceRange(getLocStart(), RBraceLoc);
+ }
+ SourceLocation getLocStart() const LLVM_READONLY { return KwLoc; }
+ SourceLocation getLBraceLoc() const { return LBraceLoc; }
+ SourceLocation getRBraceLoc() const { return RBraceLoc; }
+ void setRBraceLoc(SourceLocation L) { RBraceLoc = L; }
+ bool isCBuffer() const { return IsCBuffer; }
+
+ // Implement isa/cast/dyncast/etc.
+ static bool classof(const Decl *D) { return classofKind(D->getKind()); }
+ static bool classofKind(Kind K) { return K == HLSLBuffer; }
+ static DeclContext *castToDeclContext(const HLSLBufferDecl *D) {
+ return static_cast<DeclContext *>(const_cast<HLSLBufferDecl *>(D));
+ }
+ static HLSLBufferDecl *castFromDeclContext(const DeclContext *DC) {
+ return static_cast<HLSLBufferDecl *>(const_cast<DeclContext *>(DC));
+ }
+
+ friend class ASTDeclReader;
+ friend class ASTDeclWriter;
+};
+
/// Insertion operator for diagnostics. This allows sending NamedDecl's
/// into a diagnostic with <<.
inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &PD,
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits