clang  19.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 #include "clang/Sema/SemaHLSL.h"
19 
20 using namespace clang;
21 
23  SourceLocation BufferLoc,
24  bool IsCBuffer, Parser &P) {
25  // The parse is failed, just return false.
26  if (!DG)
27  return false;
28  DeclGroupRef Decls = DG.get();
29  bool IsValid = true;
30  // Only allow function, variable, record decls inside HLSLBuffer.
31  for (DeclGroupRef::iterator I = Decls.begin(), E = Decls.end(); I != E; ++I) {
32  Decl *D = *I;
33  if (isa<CXXRecordDecl, RecordDecl, FunctionDecl, VarDecl>(D))
34  continue;
35 
36  // FIXME: support nested HLSLBuffer and namespace inside HLSLBuffer.
37  if (isa<HLSLBufferDecl, NamespaceDecl>(D)) {
38  P.Diag(D->getLocation(), diag::err_invalid_declaration_in_hlsl_buffer)
39  << IsCBuffer;
40  IsValid = false;
41  continue;
42  }
43 
44  IsValid = false;
45  P.Diag(D->getLocation(), diag::err_invalid_declaration_in_hlsl_buffer)
46  << IsCBuffer;
47  }
48  return IsValid;
49 }
50 
51 Decl *Parser::ParseHLSLBuffer(SourceLocation &DeclEnd) {
52  assert((Tok.is(tok::kw_cbuffer) || Tok.is(tok::kw_tbuffer)) &&
53  "Not a cbuffer or tbuffer!");
54  bool IsCBuffer = Tok.is(tok::kw_cbuffer);
55  SourceLocation BufferLoc = ConsumeToken(); // Eat the 'cbuffer' or 'tbuffer'.
56 
57  if (!Tok.is(tok::identifier)) {
58  Diag(Tok, diag::err_expected) << tok::identifier;
59  return nullptr;
60  }
61 
64 
65  ParsedAttributes Attrs(AttrFactory);
66  MaybeParseHLSLAnnotations(Attrs, nullptr);
67 
68  ParseScope BufferScope(this, Scope::DeclScope);
69  BalancedDelimiterTracker T(*this, tok::l_brace);
70  if (T.consumeOpen()) {
71  Diag(Tok, diag::err_expected) << tok::l_brace;
72  return nullptr;
73  }
74 
75  Decl *D = Actions.HLSL().ActOnStartBuffer(getCurScope(), IsCBuffer, BufferLoc,
77  T.getOpenLocation());
78 
79  while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {
80  // FIXME: support attribute on constants inside cbuffer/tbuffer.
81  ParsedAttributes DeclAttrs(AttrFactory);
82  ParsedAttributes EmptyDeclSpecAttrs(AttrFactory);
83 
84  DeclGroupPtrTy Result =
85  ParseExternalDeclaration(DeclAttrs, EmptyDeclSpecAttrs);
86  if (!validateDeclsInsideHLSLBuffer(Result, IdentifierLoc, IsCBuffer,
87  *this)) {
88  T.skipToEnd();
89  DeclEnd = T.getCloseLocation();
90  BufferScope.Exit();
91  Actions.HLSL().ActOnFinishBuffer(D, DeclEnd);
92  return nullptr;
93  }
94  }
95 
96  T.consumeClose();
97  DeclEnd = T.getCloseLocation();
98  BufferScope.Exit();
99  Actions.HLSL().ActOnFinishBuffer(D, DeclEnd);
100 
101  Actions.ProcessDeclAttributeList(Actions.CurScope, D, Attrs);
102  return D;
103 }
104 
105 static void fixSeparateAttrArgAndNumber(StringRef ArgStr, SourceLocation ArgLoc,
106  Token Tok, ArgsVector &ArgExprs,
107  Parser &P, ASTContext &Ctx,
108  Preprocessor &PP) {
109  StringRef Num = StringRef(Tok.getLiteralData(), Tok.getLength());
110  SourceLocation EndNumLoc = Tok.getEndLoc();
111 
112  P.ConsumeToken(); // consume constant.
113  std::string FixedArg = ArgStr.str() + Num.str();
114  P.Diag(ArgLoc, diag::err_hlsl_separate_attr_arg_and_number)
115  << FixedArg
116  << FixItHint::CreateReplacement(SourceRange(ArgLoc, EndNumLoc), FixedArg);
117  ArgsUnion &Slot = ArgExprs.back();
118  Slot = IdentifierLoc::create(Ctx, ArgLoc, PP.getIdentifierInfo(FixedArg));
119 }
120 
121 void Parser::ParseHLSLAnnotations(ParsedAttributes &Attrs,
122  SourceLocation *EndLoc) {
123 
124  assert(Tok.is(tok::colon) && "Not a HLSL Annotation");
125  ConsumeToken();
126 
127  IdentifierInfo *II = nullptr;
128  if (Tok.is(tok::kw_register))
129  II = PP.getIdentifierInfo("register");
130  else if (Tok.is(tok::identifier))
131  II = Tok.getIdentifierInfo();
132 
133  if (!II) {
134  Diag(Tok.getLocation(), diag::err_expected_semantic_identifier);
135  return;
136  }
137 
139  if (EndLoc)
140  *EndLoc = Tok.getLocation();
141  ParsedAttr::Kind AttrKind =
143 
144  ArgsVector ArgExprs;
145  switch (AttrKind) {
146  case ParsedAttr::AT_HLSLResourceBinding: {
147  if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after)) {
148  SkipUntil(tok::r_paren, StopAtSemi); // skip through )
149  return;
150  }
151  if (!Tok.is(tok::identifier)) {
152  Diag(Tok.getLocation(), diag::err_expected) << tok::identifier;
153  SkipUntil(tok::r_paren, StopAtSemi); // skip through )
154  return;
155  }
156  StringRef SlotStr = Tok.getIdentifierInfo()->getName();
157  SourceLocation SlotLoc = Tok.getLocation();
158  ArgExprs.push_back(ParseIdentifierLoc());
159 
160  // Add numeric_constant for fix-it.
161  if (SlotStr.size() == 1 && Tok.is(tok::numeric_constant))
162  fixSeparateAttrArgAndNumber(SlotStr, SlotLoc, Tok, ArgExprs, *this,
163  Actions.Context, PP);
164 
165  if (Tok.is(tok::comma)) {
166  ConsumeToken(); // consume comma
167  if (!Tok.is(tok::identifier)) {
168  Diag(Tok.getLocation(), diag::err_expected) << tok::identifier;
169  SkipUntil(tok::r_paren, StopAtSemi); // skip through )
170  return;
171  }
172  StringRef SpaceStr = Tok.getIdentifierInfo()->getName();
173  SourceLocation SpaceLoc = Tok.getLocation();
174  ArgExprs.push_back(ParseIdentifierLoc());
175 
176  // Add numeric_constant for fix-it.
177  if (SpaceStr == "space" && Tok.is(tok::numeric_constant))
178  fixSeparateAttrArgAndNumber(SpaceStr, SpaceLoc, Tok, ArgExprs, *this,
179  Actions.Context, PP);
180  }
181  if (ExpectAndConsume(tok::r_paren, diag::err_expected)) {
182  SkipUntil(tok::r_paren, StopAtSemi); // skip through )
183  return;
184  }
185  } break;
186  case ParsedAttr::AT_HLSLPackOffset: {
187  // Parse 'packoffset( c[Subcomponent][.component] )'.
188  // Check '('.
189  if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after)) {
190  SkipUntil(tok::r_paren, StopAtSemi); // skip through )
191  return;
192  }
193  // Check c[Subcomponent] as an identifier.
194  if (!Tok.is(tok::identifier)) {
195  Diag(Tok.getLocation(), diag::err_expected) << tok::identifier;
196  SkipUntil(tok::r_paren, StopAtSemi); // skip through )
197  return;
198  }
199  StringRef OffsetStr = Tok.getIdentifierInfo()->getName();
200  SourceLocation SubComponentLoc = Tok.getLocation();
201  if (OffsetStr[0] != 'c') {
202  Diag(Tok.getLocation(), diag::err_hlsl_packoffset_invalid_reg)
203  << OffsetStr;
204  SkipUntil(tok::r_paren, StopAtSemi); // skip through )
205  return;
206  }
207  OffsetStr = OffsetStr.substr(1);
208  unsigned SubComponent = 0;
209  if (!OffsetStr.empty()) {
210  // Make sure SubComponent is a number.
211  if (OffsetStr.getAsInteger(10, SubComponent)) {
212  Diag(SubComponentLoc.getLocWithOffset(1),
213  diag::err_hlsl_unsupported_register_number);
214  SkipUntil(tok::r_paren, StopAtSemi); // skip through )
215  return;
216  }
217  }
218  unsigned Component = 0;
219  ConsumeToken(); // consume identifier.
220  SourceLocation ComponentLoc;
221  if (Tok.is(tok::period)) {
222  ConsumeToken(); // consume period.
223  if (!Tok.is(tok::identifier)) {
224  Diag(Tok.getLocation(), diag::err_expected) << tok::identifier;
225  SkipUntil(tok::r_paren, StopAtSemi); // skip through )
226  return;
227  }
228  StringRef ComponentStr = Tok.getIdentifierInfo()->getName();
229  ComponentLoc = Tok.getLocation();
230  ConsumeToken(); // consume identifier.
231  // Make sure Component is a single character.
232  if (ComponentStr.size() != 1) {
233  Diag(ComponentLoc, diag::err_hlsl_unsupported_component)
234  << ComponentStr;
235  SkipUntil(tok::r_paren, StopAtSemi); // skip through )
236  return;
237  }
238  switch (ComponentStr[0]) {
239  case 'x':
240  case 'r':
241  Component = 0;
242  break;
243  case 'y':
244  case 'g':
245  Component = 1;
246  break;
247  case 'z':
248  case 'b':
249  Component = 2;
250  break;
251  case 'w':
252  case 'a':
253  Component = 3;
254  break;
255  default:
256  Diag(ComponentLoc, diag::err_hlsl_unsupported_component)
257  << ComponentStr;
258  SkipUntil(tok::r_paren, StopAtSemi); // skip through )
259  return;
260  }
261  }
262  ASTContext &Ctx = Actions.getASTContext();
263  QualType SizeTy = Ctx.getSizeType();
264  uint64_t SizeTySize = Ctx.getTypeSize(SizeTy);
265  ArgExprs.push_back(IntegerLiteral::Create(
266  Ctx, llvm::APInt(SizeTySize, SubComponent), SizeTy, SubComponentLoc));
267  ArgExprs.push_back(IntegerLiteral::Create(
268  Ctx, llvm::APInt(SizeTySize, Component), SizeTy, ComponentLoc));
269  if (ExpectAndConsume(tok::r_paren, diag::err_expected)) {
270  SkipUntil(tok::r_paren, StopAtSemi); // skip through )
271  return;
272  }
273  } break;
275  Diag(Loc, diag::err_unknown_hlsl_semantic) << II;
276  return;
277  case ParsedAttr::AT_HLSLSV_GroupIndex:
278  case ParsedAttr::AT_HLSLSV_DispatchThreadID:
279  break;
280  default:
281  llvm_unreachable("invalid HLSL Annotation");
282  break;
283  }
284 
285  Attrs.addNew(II, Loc, nullptr, SourceLocation(), ArgExprs.data(),
286  ArgExprs.size(), ParsedAttr::Form::HLSLAnnotation());
287 }
StringRef P
StringRef Identifier
Definition: Format.cpp:2984
static bool validateDeclsInsideHLSLBuffer(Parser::DeclGroupPtrTy DG, SourceLocation BufferLoc, bool IsCBuffer, Parser &P)
Definition: ParseHLSL.cpp:22
static void fixSeparateAttrArgAndNumber(StringRef ArgStr, SourceLocation ArgLoc, Token Tok, ArgsVector &ArgExprs, Parser &P, ASTContext &Ctx, Preprocessor &PP)
Definition: ParseHLSL.cpp:105
This file declares semantic analysis for HLSL constructs.
SourceLocation Loc
Definition: SemaObjC.cpp:755
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:185
CanQualType getSizeType() const
Return the unique type for "size_t" (C99 7.17), defined in <stddef.h>.
uint64_t getTypeSize(QualType T) const
Return the size of the specified (complete) type T, in bits.
Definition: ASTContext.h:2355
@ AS_HLSLAnnotation
<vardecl> : <annotation>
RAII class that helps handle the parsing of an open/close delimiter pair, such as braces { ....
iterator begin()
Definition: DeclGroup.h:99
iterator end()
Definition: DeclGroup.h:105
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:86
SourceLocation getLocation() const
Definition: DeclBase.h:445
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:135
One of these records is kept for each identifier that is lexed.
StringRef getName() const
Return the actual identifier string.
static IntegerLiteral * Create(const ASTContext &C, const llvm::APInt &V, QualType type, SourceLocation l)
Returns a new integer literal with value 'V' and type 'type'.
Definition: Expr.cpp:1032
Wrapper for void* pointer.
Definition: Ownership.h:50
PtrTy get() const
Definition: Ownership.h:80
ParsedAttributes - A collection of parsed attributes.
Definition: ParsedAttr.h:963
ParsedAttr * addNew(IdentifierInfo *attrName, SourceRange attrRange, IdentifierInfo *scopeName, SourceLocation scopeLoc, ArgsUnion *args, unsigned numArgs, ParsedAttr::Form form, SourceLocation ellipsisLoc=SourceLocation())
Add attribute with expression arguments.
Definition: ParsedAttr.h:996
Parser - This implements a parser for the C family of languages.
Definition: Parser.h:58
DiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID)
Definition: Parser.cpp:81
SourceLocation ConsumeToken()
ConsumeToken - Consume the current 'peek token' and lex the next one.
Definition: Parser.h:545
Scope * getCurScope() const
Definition: Parser.h:499
OpaquePtr< DeclGroupRef > DeclGroupPtrTy
Definition: Parser.h:510
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:1291
@ StopAtSemi
Stop skipping at semicolon.
Definition: Parser.h:1270
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
Definition: Preprocessor.h:128
IdentifierInfo * getIdentifierInfo(StringRef Name) const
Return information about the specified preprocessor identifier token.
A (possibly-)qualified type.
Definition: Type.h:940
@ DeclScope
This is a scope that can contain a declaration.
Definition: Scope.h:63
void ActOnFinishBuffer(Decl *Dcl, SourceLocation RBrace)
Definition: SemaHLSL.cpp:77
Decl * ActOnStartBuffer(Scope *BufferScope, bool CBuffer, SourceLocation KwLoc, IdentifierInfo *Ident, SourceLocation IdentLoc, SourceLocation LBrace)
Definition: SemaHLSL.cpp:27
ASTContext & Context
Definition: Sema.h:857
void ProcessDeclAttributeList(Scope *S, Decl *D, const ParsedAttributesView &AttrList, const ProcessDeclAttributeOptions &Options=ProcessDeclAttributeOptions())
SemaHLSL & HLSL()
Definition: Sema.h:1007
ASTContext & getASTContext() const
Definition: Sema.h:526
Encodes a location in the source.
SourceLocation getLocWithOffset(IntTy Offset) const
Return a source location with the specified offset from this SourceLocation.
A trivial tuple used to represent a source range.
Token - This structure provides full information about a lexed token.
Definition: Token.h:36
SourceLocation getEndLoc() const
Definition: Token.h:159
SourceLocation getLocation() const
Return a source location identifier for the specified offset in the current file.
Definition: Token.h:132
unsigned getLength() const
Definition: Token.h:135
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:99
const char * getLiteralData() const
getLiteralData - For a literal token (numeric constant, string, etc), this returns a pointer to the s...
Definition: Token.h:225
IdentifierInfo * getIdentifierInfo() const
Definition: Token.h:187
bool isNot(tok::TokenKind K) const
Definition: Token.h:100
llvm::APInt APInt
Definition: Integral.h:29
The JSON file list parser is used to communicate input to InstallAPI.
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:113
const FunctionProtoType * T
unsigned long uint64_t
Wraps an identifier and optional source location for the identifier.
Definition: ParsedAttr.h:103
static IdentifierLoc * create(ASTContext &Ctx, SourceLocation Loc, IdentifierInfo *Ident)
Definition: ParsedAttr.cpp:28