xref: /freebsd-src/contrib/llvm-project/clang/lib/Parse/ParseHLSL.cpp (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
181ad6265SDimitry Andric //===--- ParseHLSL.cpp - HLSL-specific parsing support --------------------===//
281ad6265SDimitry Andric //
381ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
481ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
581ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
681ad6265SDimitry Andric //
781ad6265SDimitry Andric //===----------------------------------------------------------------------===//
881ad6265SDimitry Andric //
981ad6265SDimitry Andric // This file implements the parsing logic for HLSL language features.
1081ad6265SDimitry Andric //
1181ad6265SDimitry Andric //===----------------------------------------------------------------------===//
1281ad6265SDimitry Andric 
13*bdd1243dSDimitry Andric #include "clang/AST/Attr.h"
1481ad6265SDimitry Andric #include "clang/Basic/AttributeCommonInfo.h"
1581ad6265SDimitry Andric #include "clang/Parse/ParseDiagnostic.h"
1681ad6265SDimitry Andric #include "clang/Parse/Parser.h"
17*bdd1243dSDimitry Andric #include "clang/Parse/RAIIObjectsForParser.h"
1881ad6265SDimitry Andric 
1981ad6265SDimitry Andric using namespace clang;
2081ad6265SDimitry Andric 
21*bdd1243dSDimitry Andric static bool validateDeclsInsideHLSLBuffer(Parser::DeclGroupPtrTy DG,
22*bdd1243dSDimitry Andric                                           SourceLocation BufferLoc,
23*bdd1243dSDimitry Andric                                           bool IsCBuffer, Parser &P) {
24*bdd1243dSDimitry Andric   // The parse is failed, just return false.
25*bdd1243dSDimitry Andric   if (!DG)
26*bdd1243dSDimitry Andric     return false;
27*bdd1243dSDimitry Andric   DeclGroupRef Decls = DG.get();
28*bdd1243dSDimitry Andric   bool IsValid = true;
29*bdd1243dSDimitry Andric   // Only allow function, variable, record decls inside HLSLBuffer.
30*bdd1243dSDimitry Andric   for (DeclGroupRef::iterator I = Decls.begin(), E = Decls.end(); I != E; ++I) {
31*bdd1243dSDimitry Andric     Decl *D = *I;
32*bdd1243dSDimitry Andric     if (isa<CXXRecordDecl, RecordDecl, FunctionDecl, VarDecl>(D))
33*bdd1243dSDimitry Andric       continue;
34*bdd1243dSDimitry Andric 
35*bdd1243dSDimitry Andric     // FIXME: support nested HLSLBuffer and namespace inside HLSLBuffer.
36*bdd1243dSDimitry Andric     if (isa<HLSLBufferDecl, NamespaceDecl>(D)) {
37*bdd1243dSDimitry Andric       P.Diag(D->getLocation(), diag::err_invalid_declaration_in_hlsl_buffer)
38*bdd1243dSDimitry Andric           << IsCBuffer;
39*bdd1243dSDimitry Andric       IsValid = false;
40*bdd1243dSDimitry Andric       continue;
41*bdd1243dSDimitry Andric     }
42*bdd1243dSDimitry Andric 
43*bdd1243dSDimitry Andric     IsValid = false;
44*bdd1243dSDimitry Andric     P.Diag(D->getLocation(), diag::err_invalid_declaration_in_hlsl_buffer)
45*bdd1243dSDimitry Andric         << IsCBuffer;
46*bdd1243dSDimitry Andric   }
47*bdd1243dSDimitry Andric   return IsValid;
48*bdd1243dSDimitry Andric }
49*bdd1243dSDimitry Andric 
50*bdd1243dSDimitry Andric Decl *Parser::ParseHLSLBuffer(SourceLocation &DeclEnd) {
51*bdd1243dSDimitry Andric   assert((Tok.is(tok::kw_cbuffer) || Tok.is(tok::kw_tbuffer)) &&
52*bdd1243dSDimitry Andric          "Not a cbuffer or tbuffer!");
53*bdd1243dSDimitry Andric   bool IsCBuffer = Tok.is(tok::kw_cbuffer);
54*bdd1243dSDimitry Andric   SourceLocation BufferLoc = ConsumeToken(); // Eat the 'cbuffer' or 'tbuffer'.
55*bdd1243dSDimitry Andric 
56*bdd1243dSDimitry Andric   if (!Tok.is(tok::identifier)) {
57*bdd1243dSDimitry Andric     Diag(Tok, diag::err_expected) << tok::identifier;
58*bdd1243dSDimitry Andric     return nullptr;
59*bdd1243dSDimitry Andric   }
60*bdd1243dSDimitry Andric 
61*bdd1243dSDimitry Andric   IdentifierInfo *Identifier = Tok.getIdentifierInfo();
62*bdd1243dSDimitry Andric   SourceLocation IdentifierLoc = ConsumeToken();
63*bdd1243dSDimitry Andric 
64*bdd1243dSDimitry Andric   ParsedAttributes Attrs(AttrFactory);
65*bdd1243dSDimitry Andric   MaybeParseHLSLSemantics(Attrs, nullptr);
66*bdd1243dSDimitry Andric 
67*bdd1243dSDimitry Andric   ParseScope BufferScope(this, Scope::DeclScope);
68*bdd1243dSDimitry Andric   BalancedDelimiterTracker T(*this, tok::l_brace);
69*bdd1243dSDimitry Andric   if (T.consumeOpen()) {
70*bdd1243dSDimitry Andric     Diag(Tok, diag::err_expected) << tok::l_brace;
71*bdd1243dSDimitry Andric     return nullptr;
72*bdd1243dSDimitry Andric   }
73*bdd1243dSDimitry Andric 
74*bdd1243dSDimitry Andric   Decl *D = Actions.ActOnStartHLSLBuffer(getCurScope(), IsCBuffer, BufferLoc,
75*bdd1243dSDimitry Andric                                          Identifier, IdentifierLoc,
76*bdd1243dSDimitry Andric                                          T.getOpenLocation());
77*bdd1243dSDimitry Andric 
78*bdd1243dSDimitry Andric   while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {
79*bdd1243dSDimitry Andric     // FIXME: support attribute on constants inside cbuffer/tbuffer.
80*bdd1243dSDimitry Andric     ParsedAttributes DeclAttrs(AttrFactory);
81*bdd1243dSDimitry Andric     ParsedAttributes EmptyDeclSpecAttrs(AttrFactory);
82*bdd1243dSDimitry Andric 
83*bdd1243dSDimitry Andric     DeclGroupPtrTy Result =
84*bdd1243dSDimitry Andric         ParseExternalDeclaration(DeclAttrs, EmptyDeclSpecAttrs);
85*bdd1243dSDimitry Andric     if (!validateDeclsInsideHLSLBuffer(Result, IdentifierLoc, IsCBuffer,
86*bdd1243dSDimitry Andric                                        *this)) {
87*bdd1243dSDimitry Andric       T.skipToEnd();
88*bdd1243dSDimitry Andric       DeclEnd = T.getCloseLocation();
89*bdd1243dSDimitry Andric       BufferScope.Exit();
90*bdd1243dSDimitry Andric       Actions.ActOnFinishHLSLBuffer(D, DeclEnd);
91*bdd1243dSDimitry Andric       return nullptr;
92*bdd1243dSDimitry Andric     }
93*bdd1243dSDimitry Andric   }
94*bdd1243dSDimitry Andric 
95*bdd1243dSDimitry Andric   T.consumeClose();
96*bdd1243dSDimitry Andric   DeclEnd = T.getCloseLocation();
97*bdd1243dSDimitry Andric   BufferScope.Exit();
98*bdd1243dSDimitry Andric   Actions.ActOnFinishHLSLBuffer(D, DeclEnd);
99*bdd1243dSDimitry Andric 
100*bdd1243dSDimitry Andric   Actions.ProcessDeclAttributeList(Actions.CurScope, D, Attrs);
101*bdd1243dSDimitry Andric   return D;
102*bdd1243dSDimitry Andric }
103*bdd1243dSDimitry Andric 
104*bdd1243dSDimitry Andric static void fixSeparateAttrArgAndNumber(StringRef ArgStr, SourceLocation ArgLoc,
105*bdd1243dSDimitry Andric                                         Token Tok, ArgsVector &ArgExprs,
106*bdd1243dSDimitry Andric                                         Parser &P, ASTContext &Ctx,
107*bdd1243dSDimitry Andric                                         Preprocessor &PP) {
108*bdd1243dSDimitry Andric   StringRef Num = StringRef(Tok.getLiteralData(), Tok.getLength());
109*bdd1243dSDimitry Andric   SourceLocation EndNumLoc = Tok.getEndLoc();
110*bdd1243dSDimitry Andric 
111*bdd1243dSDimitry Andric   P.ConsumeToken(); // consume constant.
112*bdd1243dSDimitry Andric   std::string FixedArg = ArgStr.str() + Num.str();
113*bdd1243dSDimitry Andric   P.Diag(ArgLoc, diag::err_hlsl_separate_attr_arg_and_number)
114*bdd1243dSDimitry Andric       << FixedArg
115*bdd1243dSDimitry Andric       << FixItHint::CreateReplacement(SourceRange(ArgLoc, EndNumLoc), FixedArg);
116*bdd1243dSDimitry Andric   ArgsUnion &Slot = ArgExprs.back();
117*bdd1243dSDimitry Andric   Slot = IdentifierLoc::create(Ctx, ArgLoc, PP.getIdentifierInfo(FixedArg));
118*bdd1243dSDimitry Andric }
119*bdd1243dSDimitry Andric 
12081ad6265SDimitry Andric void Parser::ParseHLSLSemantics(ParsedAttributes &Attrs,
12181ad6265SDimitry Andric                                 SourceLocation *EndLoc) {
122*bdd1243dSDimitry Andric   // FIXME: HLSLSemantic is shared for Semantic and resource binding which is
123*bdd1243dSDimitry Andric   // confusing. Need a better name to avoid misunderstanding. Issue
124*bdd1243dSDimitry Andric   // https://github.com/llvm/llvm-project/issues/57882
12581ad6265SDimitry Andric   assert(Tok.is(tok::colon) && "Not a HLSL Semantic");
12681ad6265SDimitry Andric   ConsumeToken();
12781ad6265SDimitry Andric 
128*bdd1243dSDimitry Andric   IdentifierInfo *II = nullptr;
129*bdd1243dSDimitry Andric   if (Tok.is(tok::kw_register))
130*bdd1243dSDimitry Andric     II = PP.getIdentifierInfo("register");
131*bdd1243dSDimitry Andric   else if (Tok.is(tok::identifier))
132*bdd1243dSDimitry Andric     II = Tok.getIdentifierInfo();
133*bdd1243dSDimitry Andric 
134*bdd1243dSDimitry Andric   if (!II) {
13581ad6265SDimitry Andric     Diag(Tok.getLocation(), diag::err_expected_semantic_identifier);
13681ad6265SDimitry Andric     return;
13781ad6265SDimitry Andric   }
13881ad6265SDimitry Andric 
13981ad6265SDimitry Andric   SourceLocation Loc = ConsumeToken();
14081ad6265SDimitry Andric   if (EndLoc)
14181ad6265SDimitry Andric     *EndLoc = Tok.getLocation();
14281ad6265SDimitry Andric   ParsedAttr::Kind AttrKind =
14381ad6265SDimitry Andric       ParsedAttr::getParsedKind(II, nullptr, ParsedAttr::AS_HLSLSemantic);
14481ad6265SDimitry Andric 
145*bdd1243dSDimitry Andric   ArgsVector ArgExprs;
146*bdd1243dSDimitry Andric   switch (AttrKind) {
147*bdd1243dSDimitry Andric   case ParsedAttr::AT_HLSLResourceBinding: {
148*bdd1243dSDimitry Andric     if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after)) {
149*bdd1243dSDimitry Andric       SkipUntil(tok::r_paren, StopAtSemi); // skip through )
15081ad6265SDimitry Andric       return;
15181ad6265SDimitry Andric     }
152*bdd1243dSDimitry Andric     if (!Tok.is(tok::identifier)) {
153*bdd1243dSDimitry Andric       Diag(Tok.getLocation(), diag::err_expected) << tok::identifier;
154*bdd1243dSDimitry Andric       SkipUntil(tok::r_paren, StopAtSemi); // skip through )
155*bdd1243dSDimitry Andric       return;
156*bdd1243dSDimitry Andric     }
157*bdd1243dSDimitry Andric     StringRef SlotStr = Tok.getIdentifierInfo()->getName();
158*bdd1243dSDimitry Andric     SourceLocation SlotLoc = Tok.getLocation();
159*bdd1243dSDimitry Andric     ArgExprs.push_back(ParseIdentifierLoc());
160*bdd1243dSDimitry Andric 
161*bdd1243dSDimitry Andric     // Add numeric_constant for fix-it.
162*bdd1243dSDimitry Andric     if (SlotStr.size() == 1 && Tok.is(tok::numeric_constant))
163*bdd1243dSDimitry Andric       fixSeparateAttrArgAndNumber(SlotStr, SlotLoc, Tok, ArgExprs, *this,
164*bdd1243dSDimitry Andric                                   Actions.Context, PP);
165*bdd1243dSDimitry Andric 
166*bdd1243dSDimitry Andric     if (Tok.is(tok::comma)) {
167*bdd1243dSDimitry Andric       ConsumeToken(); // consume comma
168*bdd1243dSDimitry Andric       if (!Tok.is(tok::identifier)) {
169*bdd1243dSDimitry Andric         Diag(Tok.getLocation(), diag::err_expected) << tok::identifier;
170*bdd1243dSDimitry Andric         SkipUntil(tok::r_paren, StopAtSemi); // skip through )
171*bdd1243dSDimitry Andric         return;
172*bdd1243dSDimitry Andric       }
173*bdd1243dSDimitry Andric       StringRef SpaceStr = Tok.getIdentifierInfo()->getName();
174*bdd1243dSDimitry Andric       SourceLocation SpaceLoc = Tok.getLocation();
175*bdd1243dSDimitry Andric       ArgExprs.push_back(ParseIdentifierLoc());
176*bdd1243dSDimitry Andric 
177*bdd1243dSDimitry Andric       // Add numeric_constant for fix-it.
178*bdd1243dSDimitry Andric       if (SpaceStr.equals("space") && Tok.is(tok::numeric_constant))
179*bdd1243dSDimitry Andric         fixSeparateAttrArgAndNumber(SpaceStr, SpaceLoc, Tok, ArgExprs, *this,
180*bdd1243dSDimitry Andric                                     Actions.Context, PP);
181*bdd1243dSDimitry Andric     }
182*bdd1243dSDimitry Andric     if (ExpectAndConsume(tok::r_paren, diag::err_expected)) {
183*bdd1243dSDimitry Andric       SkipUntil(tok::r_paren, StopAtSemi); // skip through )
184*bdd1243dSDimitry Andric       return;
185*bdd1243dSDimitry Andric     }
186*bdd1243dSDimitry Andric   } break;
187*bdd1243dSDimitry Andric   case ParsedAttr::UnknownAttribute:
188*bdd1243dSDimitry Andric     Diag(Loc, diag::err_unknown_hlsl_semantic) << II;
189*bdd1243dSDimitry Andric     return;
190*bdd1243dSDimitry Andric   case ParsedAttr::AT_HLSLSV_GroupIndex:
191*bdd1243dSDimitry Andric   case ParsedAttr::AT_HLSLSV_DispatchThreadID:
192*bdd1243dSDimitry Andric     break;
193*bdd1243dSDimitry Andric   default:
194*bdd1243dSDimitry Andric     llvm_unreachable("invalid HLSL Semantic");
195*bdd1243dSDimitry Andric     break;
196*bdd1243dSDimitry Andric   }
197*bdd1243dSDimitry Andric 
198*bdd1243dSDimitry Andric   Attrs.addNew(II, Loc, nullptr, SourceLocation(), ArgExprs.data(),
199*bdd1243dSDimitry Andric                ArgExprs.size(), ParsedAttr::AS_HLSLSemantic);
20081ad6265SDimitry Andric }
201