1 //===--- ParseHLSL.cpp - HLSL-specific parsing support --------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // This file implements the parsing logic for HLSL language features.
11 //===----------------------------------------------------------------------===//
13 #include "clang/AST/Attr.h"
14 #include "clang/Basic/AttributeCommonInfo.h"
15 #include "clang/Parse/ParseDiagnostic.h"
16 #include "clang/Parse/Parser.h"
17 #include "clang/Parse/RAIIObjectsForParser.h"
19 using namespace clang
;
21 static bool validateDeclsInsideHLSLBuffer(Parser::DeclGroupPtrTy DG
,
22 SourceLocation BufferLoc
,
23 bool IsCBuffer
, Parser
&P
) {
24 // The parse is failed, just return false.
27 DeclGroupRef Decls
= DG
.get();
29 // Only allow function, variable, record decls inside HLSLBuffer.
30 for (DeclGroupRef::iterator I
= Decls
.begin(), E
= Decls
.end(); I
!= E
; ++I
) {
32 if (isa
<CXXRecordDecl
, RecordDecl
, FunctionDecl
, VarDecl
>(D
))
35 // FIXME: support nested HLSLBuffer and namespace inside HLSLBuffer.
36 if (isa
<HLSLBufferDecl
, NamespaceDecl
>(D
)) {
37 P
.Diag(D
->getLocation(), diag::err_invalid_declaration_in_hlsl_buffer
)
44 P
.Diag(D
->getLocation(), diag::err_invalid_declaration_in_hlsl_buffer
)
50 Decl
*Parser::ParseHLSLBuffer(SourceLocation
&DeclEnd
) {
51 assert((Tok
.is(tok::kw_cbuffer
) || Tok
.is(tok::kw_tbuffer
)) &&
52 "Not a cbuffer or tbuffer!");
53 bool IsCBuffer
= Tok
.is(tok::kw_cbuffer
);
54 SourceLocation BufferLoc
= ConsumeToken(); // Eat the 'cbuffer' or 'tbuffer'.
56 if (!Tok
.is(tok::identifier
)) {
57 Diag(Tok
, diag::err_expected
) << tok::identifier
;
61 IdentifierInfo
*Identifier
= Tok
.getIdentifierInfo();
62 SourceLocation IdentifierLoc
= ConsumeToken();
64 ParsedAttributes
Attrs(AttrFactory
);
65 MaybeParseHLSLSemantics(Attrs
, nullptr);
67 ParseScope
BufferScope(this, Scope::DeclScope
);
68 BalancedDelimiterTracker
T(*this, tok::l_brace
);
69 if (T
.consumeOpen()) {
70 Diag(Tok
, diag::err_expected
) << tok::l_brace
;
74 Decl
*D
= Actions
.ActOnStartHLSLBuffer(getCurScope(), IsCBuffer
, BufferLoc
,
75 Identifier
, IdentifierLoc
,
78 while (Tok
.isNot(tok::r_brace
) && Tok
.isNot(tok::eof
)) {
79 // FIXME: support attribute on constants inside cbuffer/tbuffer.
80 ParsedAttributes
DeclAttrs(AttrFactory
);
81 ParsedAttributes
EmptyDeclSpecAttrs(AttrFactory
);
83 DeclGroupPtrTy Result
=
84 ParseExternalDeclaration(DeclAttrs
, EmptyDeclSpecAttrs
);
85 if (!validateDeclsInsideHLSLBuffer(Result
, IdentifierLoc
, IsCBuffer
,
88 DeclEnd
= T
.getCloseLocation();
90 Actions
.ActOnFinishHLSLBuffer(D
, DeclEnd
);
96 DeclEnd
= T
.getCloseLocation();
98 Actions
.ActOnFinishHLSLBuffer(D
, DeclEnd
);
100 Actions
.ProcessDeclAttributeList(Actions
.CurScope
, D
, Attrs
);
104 static void fixSeparateAttrArgAndNumber(StringRef ArgStr
, SourceLocation ArgLoc
,
105 Token Tok
, ArgsVector
&ArgExprs
,
106 Parser
&P
, ASTContext
&Ctx
,
108 StringRef Num
= StringRef(Tok
.getLiteralData(), Tok
.getLength());
109 SourceLocation EndNumLoc
= Tok
.getEndLoc();
111 P
.ConsumeToken(); // consume constant.
112 std::string FixedArg
= ArgStr
.str() + Num
.str();
113 P
.Diag(ArgLoc
, diag::err_hlsl_separate_attr_arg_and_number
)
115 << FixItHint::CreateReplacement(SourceRange(ArgLoc
, EndNumLoc
), FixedArg
);
116 ArgsUnion
&Slot
= ArgExprs
.back();
117 Slot
= IdentifierLoc::create(Ctx
, ArgLoc
, PP
.getIdentifierInfo(FixedArg
));
120 void Parser::ParseHLSLSemantics(ParsedAttributes
&Attrs
,
121 SourceLocation
*EndLoc
) {
122 // FIXME: HLSLSemantic is shared for Semantic and resource binding which is
123 // confusing. Need a better name to avoid misunderstanding. Issue
124 // https://github.com/llvm/llvm-project/issues/57882
125 assert(Tok
.is(tok::colon
) && "Not a HLSL Semantic");
128 IdentifierInfo
*II
= nullptr;
129 if (Tok
.is(tok::kw_register
))
130 II
= PP
.getIdentifierInfo("register");
131 else if (Tok
.is(tok::identifier
))
132 II
= Tok
.getIdentifierInfo();
135 Diag(Tok
.getLocation(), diag::err_expected_semantic_identifier
);
139 SourceLocation Loc
= ConsumeToken();
141 *EndLoc
= Tok
.getLocation();
142 ParsedAttr::Kind AttrKind
=
143 ParsedAttr::getParsedKind(II
, nullptr, ParsedAttr::AS_HLSLSemantic
);
147 case ParsedAttr::AT_HLSLResourceBinding
: {
148 if (ExpectAndConsume(tok::l_paren
, diag::err_expected_lparen_after
)) {
149 SkipUntil(tok::r_paren
, StopAtSemi
); // skip through )
152 if (!Tok
.is(tok::identifier
)) {
153 Diag(Tok
.getLocation(), diag::err_expected
) << tok::identifier
;
154 SkipUntil(tok::r_paren
, StopAtSemi
); // skip through )
157 StringRef SlotStr
= Tok
.getIdentifierInfo()->getName();
158 SourceLocation SlotLoc
= Tok
.getLocation();
159 ArgExprs
.push_back(ParseIdentifierLoc());
161 // Add numeric_constant for fix-it.
162 if (SlotStr
.size() == 1 && Tok
.is(tok::numeric_constant
))
163 fixSeparateAttrArgAndNumber(SlotStr
, SlotLoc
, Tok
, ArgExprs
, *this,
164 Actions
.Context
, PP
);
166 if (Tok
.is(tok::comma
)) {
167 ConsumeToken(); // consume comma
168 if (!Tok
.is(tok::identifier
)) {
169 Diag(Tok
.getLocation(), diag::err_expected
) << tok::identifier
;
170 SkipUntil(tok::r_paren
, StopAtSemi
); // skip through )
173 StringRef SpaceStr
= Tok
.getIdentifierInfo()->getName();
174 SourceLocation SpaceLoc
= Tok
.getLocation();
175 ArgExprs
.push_back(ParseIdentifierLoc());
177 // Add numeric_constant for fix-it.
178 if (SpaceStr
.equals("space") && Tok
.is(tok::numeric_constant
))
179 fixSeparateAttrArgAndNumber(SpaceStr
, SpaceLoc
, Tok
, ArgExprs
, *this,
180 Actions
.Context
, PP
);
182 if (ExpectAndConsume(tok::r_paren
, diag::err_expected
)) {
183 SkipUntil(tok::r_paren
, StopAtSemi
); // skip through )
187 case ParsedAttr::UnknownAttribute
:
188 Diag(Loc
, diag::err_unknown_hlsl_semantic
) << II
;
190 case ParsedAttr::AT_HLSLSV_GroupIndex
:
191 case ParsedAttr::AT_HLSLSV_DispatchThreadID
:
194 llvm_unreachable("invalid HLSL Semantic");
198 Attrs
.addNew(II
, Loc
, nullptr, SourceLocation(), ArgExprs
.data(),
199 ArgExprs
.size(), ParsedAttr::AS_HLSLSemantic
);