clang  16.0.0git
ParseHLSL.cpp
Go to the documentation of this file.
1 //===--- ParseHLSL.cpp - HLSL-specific parsing support --------------------===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file implements the parsing logic for HLSL language features.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "clang/AST/Attr.h"
16 #include "clang/Parse/Parser.h"
18 
19 using namespace clang;
20 
22  SourceLocation BufferLoc,
23  bool IsCBuffer, Parser &P) {
24  // The parse is failed, just return false.
25  if (!DG)
26  return false;
27  DeclGroupRef Decls = DG.get();
28  bool IsValid = true;
29  // Only allow function, variable, record decls inside HLSLBuffer.
30  for (DeclGroupRef::iterator I = Decls.begin(), E = Decls.end(); I != E; ++I) {
31  Decl *D = *I;
32  if (isa<CXXRecordDecl, RecordDecl, FunctionDecl, VarDecl>(D))
33  continue;
34 
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)
38  << IsCBuffer;
39  IsValid = false;
40  continue;
41  }
42 
43  IsValid = false;
44  P.Diag(D->getLocation(), diag::err_invalid_declaration_in_hlsl_buffer)
45  << IsCBuffer;
46  }
47  return IsValid;
48 }
49 
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'.
55 
56  if (!Tok.is(tok::identifier)) {
57  Diag(Tok, diag::err_expected) << tok::identifier;
58  return nullptr;
59  }
60 
63 
64  ParsedAttributes Attrs(AttrFactory);
65  MaybeParseHLSLSemantics(Attrs, nullptr);
66 
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;
71  return nullptr;
72  }
73 
74  Decl *D = Actions.ActOnStartHLSLBuffer(getCurScope(), IsCBuffer, BufferLoc,
76  T.getOpenLocation());
77 
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);
82 
83  DeclGroupPtrTy Result =
84  ParseExternalDeclaration(DeclAttrs, EmptyDeclSpecAttrs);
85  if (!validateDeclsInsideHLSLBuffer(Result, IdentifierLoc, IsCBuffer,
86  *this)) {
87  T.skipToEnd();
88  DeclEnd = T.getCloseLocation();
89  BufferScope.Exit();
90  Actions.ActOnFinishHLSLBuffer(D, DeclEnd);
91  return nullptr;
92  }
93  }
94 
95  T.consumeClose();
96  DeclEnd = T.getCloseLocation();
97  BufferScope.Exit();
98  Actions.ActOnFinishHLSLBuffer(D, DeclEnd);
99 
100  Actions.ProcessDeclAttributeList(Actions.CurScope, D, Attrs);
101  return D;
102 }
103 
104 static void fixSeparateAttrArgAndNumber(StringRef ArgStr, SourceLocation ArgLoc,
105  Token Tok, ArgsVector &ArgExprs,
106  Parser &P, ASTContext &Ctx,
107  Preprocessor &PP) {
108  StringRef Num = StringRef(Tok.getLiteralData(), Tok.getLength());
109  SourceLocation EndNumLoc = Tok.getEndLoc();
110 
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)
114  << FixedArg
115  << FixItHint::CreateReplacement(SourceRange(ArgLoc, EndNumLoc), FixedArg);
116  ArgsUnion &Slot = ArgExprs.back();
117  Slot = IdentifierLoc::create(Ctx, ArgLoc, PP.getIdentifierInfo(FixedArg));
118 }
119 
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");
126  ConsumeToken();
127 
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();
133 
134  if (!II) {
135  Diag(Tok.getLocation(), diag::err_expected_semantic_identifier);
136  return;
137  }
138 
140  if (EndLoc)
141  *EndLoc = Tok.getLocation();
142  ParsedAttr::Kind AttrKind =
144 
145  ArgsVector ArgExprs;
146  switch (AttrKind) {
147  case ParsedAttr::AT_HLSLResourceBinding: {
148  if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after)) {
149  SkipUntil(tok::r_paren, StopAtSemi); // skip through )
150  return;
151  }
152  if (!Tok.is(tok::identifier)) {
153  Diag(Tok.getLocation(), diag::err_expected) << tok::identifier;
154  SkipUntil(tok::r_paren, StopAtSemi); // skip through )
155  return;
156  }
157  StringRef SlotStr = Tok.getIdentifierInfo()->getName();
158  SourceLocation SlotLoc = Tok.getLocation();
159  ArgExprs.push_back(ParseIdentifierLoc());
160 
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);
165 
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 )
171  return;
172  }
173  StringRef SpaceStr = Tok.getIdentifierInfo()->getName();
174  SourceLocation SpaceLoc = Tok.getLocation();
175  ArgExprs.push_back(ParseIdentifierLoc());
176 
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);
181  }
182  if (ExpectAndConsume(tok::r_paren, diag::err_expected)) {
183  SkipUntil(tok::r_paren, StopAtSemi); // skip through )
184  return;
185  }
186  } break;
188  Diag(Loc, diag::err_unknown_hlsl_semantic) << II;
189  return;
190  case ParsedAttr::AT_HLSLSV_GroupIndex:
191  case ParsedAttr::AT_HLSLSV_DispatchThreadID:
192  break;
193  default:
194  llvm_unreachable("invalid HLSL Semantic");
195  break;
196  }
197 
198  Attrs.addNew(II, Loc, nullptr, SourceLocation(), ArgExprs.data(),
199  ArgExprs.size(), ParsedAttr::AS_HLSLSemantic);
200 }
clang::AttributeCommonInfo::getParsedKind
Kind getParsedKind() const
Definition: AttributeCommonInfo.h:129
clang::OpaquePtr::get
PtrTy get() const
Definition: Ownership.h:80
clang::AttributeCommonInfo::Kind
Kind
Definition: AttributeCommonInfo.h:55
AttributeCommonInfo.h
clang::SourceRange
A trivial tuple used to represent a source range.
Definition: SourceLocation.h:210
string
string(SUBSTRING ${CMAKE_CURRENT_BINARY_DIR} 0 ${PATH_LIB_START} PATH_HEAD) string(SUBSTRING $
Definition: CMakeLists.txt:22
clang::Parser::SkipUntil
bool SkipUntil(tok::TokenKind T, SkipUntilFlags Flags=static_cast< SkipUntilFlags >(0))
SkipUntil - Read tokens until we get to the specified token, then consume it (unless StopBeforeMatch ...
Definition: Parser.h:1231
clang::Token::getLiteralData
const char * getLiteralData() const
getLiteralData - For a literal token (numeric constant, string, etc), this returns a pointer to the s...
Definition: Token.h:218
clang::ArgsUnion
llvm::PointerUnion< Expr *, IdentifierLoc * > ArgsUnion
A union of the various pointer types that can be passed to an ParsedAttr as an argument.
Definition: ParsedAttr.h:221
llvm::SmallVector
Definition: LLVM.h:38
clang::SourceLocation
Encodes a location in the source.
Definition: SourceLocation.h:86
fixSeparateAttrArgAndNumber
static void fixSeparateAttrArgAndNumber(StringRef ArgStr, SourceLocation ArgLoc, Token Tok, ArgsVector &ArgExprs, Parser &P, ASTContext &Ctx, Preprocessor &PP)
Definition: ParseHLSL.cpp:104
clang::Token::getEndLoc
SourceLocation getEndLoc() const
Definition: Token.h:152
validateDeclsInsideHLSLBuffer
static bool validateDeclsInsideHLSLBuffer(Parser::DeclGroupPtrTy DG, SourceLocation BufferLoc, bool IsCBuffer, Parser &P)
Definition: ParseHLSL.cpp:21
Attr.h
clang::Token::getIdentifierInfo
IdentifierInfo * getIdentifierInfo() const
Definition: Token.h:180
clang::Parser
Parser - This implements a parser for the C family of languages.
Definition: Parser.h:60
clang::DeclGroupRef::begin
iterator begin()
Definition: DeclGroup.h:99
RAIIObjectsForParser.h
clang::Sema::ActOnFinishHLSLBuffer
void ActOnFinishHLSLBuffer(Decl *Dcl, SourceLocation RBrace)
Definition: SemaHLSL.cpp:30
clang::DeclGroupRef::end
iterator end()
Definition: DeclGroup.h:105
Identifier
StringRef Identifier
Definition: Format.cpp:2723
clang::Token
Token - This structure provides full information about a lexed token.
Definition: Token.h:34
clang::BalancedDelimiterTracker
RAII class that helps handle the parsing of an open/close delimiter pair, such as braces { ....
Definition: RAIIObjectsForParser.h:388
clang::Sema::Context
ASTContext & Context
Definition: Sema.h:409
clang::AttributeCommonInfo::UnknownAttribute
@ UnknownAttribute
Definition: AttributeCommonInfo.h:61
clang::ASTContext
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:209
clang::Token::is
bool is(tok::TokenKind K) const
is/isNot - Predicates to check if this token is a specific kind, as in "if (Tok.is(tok::l_brace)) {....
Definition: Token.h:97
clang::ParsedAttributes::addNew
ParsedAttr * addNew(IdentifierInfo *attrName, SourceRange attrRange, IdentifierInfo *scopeName, SourceLocation scopeLoc, ArgsUnion *args, unsigned numArgs, ParsedAttr::Syntax syntax, SourceLocation ellipsisLoc=SourceLocation())
Add attribute with expression arguments.
Definition: ParsedAttr.h:1054
clang::AttributeCommonInfo::AS_HLSLSemantic
@ AS_HLSLSemantic
<vardecl> : <semantic>
Definition: AttributeCommonInfo.h:53
clang::Parser::getCurScope
Scope * getCurScope() const
Definition: Parser.h:449
clang::Parser::Diag
DiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID)
Definition: Parser.cpp:73
clang::Token::isNot
bool isNot(tok::TokenKind K) const
Definition: Token.h:98
clang::Parser::StopAtSemi
@ StopAtSemi
Stop skipping at semicolon.
Definition: Parser.h:1210
clang::Token::getLength
unsigned getLength() const
Definition: Token.h:128
clang::OpaquePtr
Wrapper for void* pointer.
Definition: Ownership.h:50
clang::Sema::ActOnStartHLSLBuffer
Decl * ActOnStartHLSLBuffer(Scope *BufferScope, bool CBuffer, SourceLocation KwLoc, IdentifierInfo *Ident, SourceLocation IdentLoc, SourceLocation LBrace)
Definition: SemaHLSL.cpp:15
P
StringRef P
Definition: ASTMatchersInternal.cpp:563
clang::Parser::ConsumeToken
SourceLocation ConsumeToken()
ConsumeToken - Consume the current 'peek token' and lex the next one.
Definition: Parser.h:492
clang::Sema::ProcessDeclAttributeList
void ProcessDeclAttributeList(Scope *S, Decl *D, const ParsedAttributesView &AttrList, const ProcessDeclAttributeOptions &Options=ProcessDeclAttributeOptions())
ProcessDeclAttributeList - Apply all the decl attributes in the specified attribute list to the speci...
Definition: SemaDeclAttr.cpp:9238
clang::Decl
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:83
clang::DeclGroupRef
Definition: DeclGroup.h:51
clang::Parser::DeclGroupPtrTy
OpaquePtr< DeclGroupRef > DeclGroupPtrTy
Definition: Parser.h:460
clang::ParsedAttributes
ParsedAttributes - A collection of parsed attributes.
Definition: ParsedAttr.h:1023
clang::IdentifierInfo
One of these records is kept for each identifier that is lexed.
Definition: IdentifierTable.h:85
clang::Token::getLocation
SourceLocation getLocation() const
Return a source location identifier for the specified offset in the current file.
Definition: Token.h:125
clang::IdentifierInfo::getName
StringRef getName() const
Return the actual identifier string.
Definition: IdentifierTable.h:196
clang
Definition: CalledOnceCheck.h:17
ParseDiagnostic.h
clang::comments::tok::eof
@ eof
Definition: CommentLexer.h:33
clang::Scope::DeclScope
@ DeclScope
This is a scope that can contain a declaration.
Definition: Scope.h:59
clang::Preprocessor
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
Definition: Preprocessor.h:129
clang::IdentifierLoc
Wraps an identifier and optional source location for the identifier.
Definition: ParsedAttr.h:211
clang::Decl::getLocation
SourceLocation getLocation() const
Definition: DeclBase.h:432
clang::Preprocessor::getIdentifierInfo
IdentifierInfo * getIdentifierInfo(StringRef Name) const
Return information about the specified preprocessor identifier token.
Definition: Preprocessor.h:1383
clang::FixItHint::CreateReplacement
static FixItHint CreateReplacement(CharSourceRange RemoveRange, StringRef Code)
Create a code modification hint that replaces the given source range with the given code string.
Definition: Diagnostic.h:134
clang::IdentifierLoc::create
static IdentifierLoc * create(ASTContext &Ctx, SourceLocation Loc, IdentifierInfo *Ident)
Definition: ParsedAttr.cpp:31
Parser.h