123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200 |
- //===--- ParseHLSL.cpp - HLSL-specific parsing support --------------------===//
- //
- // 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 file implements the parsing logic for HLSL language features.
- //
- //===----------------------------------------------------------------------===//
- #include "clang/AST/Attr.h"
- #include "clang/Basic/AttributeCommonInfo.h"
- #include "clang/Parse/ParseDiagnostic.h"
- #include "clang/Parse/Parser.h"
- #include "clang/Parse/RAIIObjectsForParser.h"
- using namespace clang;
- static bool validateDeclsInsideHLSLBuffer(Parser::DeclGroupPtrTy DG,
- SourceLocation BufferLoc,
- bool IsCBuffer, Parser &P) {
- // The parse is failed, just return false.
- if (!DG)
- return false;
- DeclGroupRef Decls = DG.get();
- bool IsValid = true;
- // Only allow function, variable, record decls inside HLSLBuffer.
- for (DeclGroupRef::iterator I = Decls.begin(), E = Decls.end(); I != E; ++I) {
- Decl *D = *I;
- if (isa<CXXRecordDecl, RecordDecl, FunctionDecl, VarDecl>(D))
- continue;
- // FIXME: support nested HLSLBuffer and namespace inside HLSLBuffer.
- if (isa<HLSLBufferDecl, NamespaceDecl>(D)) {
- P.Diag(D->getLocation(), diag::err_invalid_declaration_in_hlsl_buffer)
- << IsCBuffer;
- IsValid = false;
- continue;
- }
- IsValid = false;
- P.Diag(D->getLocation(), diag::err_invalid_declaration_in_hlsl_buffer)
- << IsCBuffer;
- }
- return IsValid;
- }
- Decl *Parser::ParseHLSLBuffer(SourceLocation &DeclEnd) {
- 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();
- ParsedAttributes Attrs(AttrFactory);
- MaybeParseHLSLSemantics(Attrs, nullptr);
- 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());
- while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {
- // FIXME: support attribute on constants inside cbuffer/tbuffer.
- ParsedAttributes DeclAttrs(AttrFactory);
- ParsedAttributes EmptyDeclSpecAttrs(AttrFactory);
- DeclGroupPtrTy Result =
- ParseExternalDeclaration(DeclAttrs, EmptyDeclSpecAttrs);
- if (!validateDeclsInsideHLSLBuffer(Result, IdentifierLoc, IsCBuffer,
- *this)) {
- T.skipToEnd();
- DeclEnd = T.getCloseLocation();
- BufferScope.Exit();
- Actions.ActOnFinishHLSLBuffer(D, DeclEnd);
- return nullptr;
- }
- }
- T.consumeClose();
- DeclEnd = T.getCloseLocation();
- BufferScope.Exit();
- Actions.ActOnFinishHLSLBuffer(D, DeclEnd);
- Actions.ProcessDeclAttributeList(Actions.CurScope, D, Attrs);
- return D;
- }
- static void fixSeparateAttrArgAndNumber(StringRef ArgStr, SourceLocation ArgLoc,
- Token Tok, ArgsVector &ArgExprs,
- Parser &P, ASTContext &Ctx,
- Preprocessor &PP) {
- StringRef Num = StringRef(Tok.getLiteralData(), Tok.getLength());
- SourceLocation EndNumLoc = Tok.getEndLoc();
- P.ConsumeToken(); // consume constant.
- std::string FixedArg = ArgStr.str() + Num.str();
- P.Diag(ArgLoc, diag::err_hlsl_separate_attr_arg_and_number)
- << FixedArg
- << FixItHint::CreateReplacement(SourceRange(ArgLoc, EndNumLoc), FixedArg);
- ArgsUnion &Slot = ArgExprs.back();
- Slot = IdentifierLoc::create(Ctx, ArgLoc, PP.getIdentifierInfo(FixedArg));
- }
- void Parser::ParseHLSLSemantics(ParsedAttributes &Attrs,
- SourceLocation *EndLoc) {
- // FIXME: HLSLSemantic is shared for Semantic and resource binding which is
- // confusing. Need a better name to avoid misunderstanding. Issue
- // https://github.com/llvm/llvm-project/issues/57882
- assert(Tok.is(tok::colon) && "Not a HLSL Semantic");
- ConsumeToken();
- IdentifierInfo *II = nullptr;
- if (Tok.is(tok::kw_register))
- II = PP.getIdentifierInfo("register");
- else if (Tok.is(tok::identifier))
- II = Tok.getIdentifierInfo();
- if (!II) {
- Diag(Tok.getLocation(), diag::err_expected_semantic_identifier);
- return;
- }
- SourceLocation Loc = ConsumeToken();
- if (EndLoc)
- *EndLoc = Tok.getLocation();
- ParsedAttr::Kind AttrKind =
- ParsedAttr::getParsedKind(II, nullptr, ParsedAttr::AS_HLSLSemantic);
- ArgsVector ArgExprs;
- switch (AttrKind) {
- case ParsedAttr::AT_HLSLResourceBinding: {
- if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after)) {
- SkipUntil(tok::r_paren, StopAtSemi); // skip through )
- return;
- }
- if (!Tok.is(tok::identifier)) {
- Diag(Tok.getLocation(), diag::err_expected) << tok::identifier;
- SkipUntil(tok::r_paren, StopAtSemi); // skip through )
- return;
- }
- StringRef SlotStr = Tok.getIdentifierInfo()->getName();
- SourceLocation SlotLoc = Tok.getLocation();
- ArgExprs.push_back(ParseIdentifierLoc());
- // Add numeric_constant for fix-it.
- if (SlotStr.size() == 1 && Tok.is(tok::numeric_constant))
- fixSeparateAttrArgAndNumber(SlotStr, SlotLoc, Tok, ArgExprs, *this,
- Actions.Context, PP);
- if (Tok.is(tok::comma)) {
- ConsumeToken(); // consume comma
- if (!Tok.is(tok::identifier)) {
- Diag(Tok.getLocation(), diag::err_expected) << tok::identifier;
- SkipUntil(tok::r_paren, StopAtSemi); // skip through )
- return;
- }
- StringRef SpaceStr = Tok.getIdentifierInfo()->getName();
- SourceLocation SpaceLoc = Tok.getLocation();
- ArgExprs.push_back(ParseIdentifierLoc());
- // Add numeric_constant for fix-it.
- if (SpaceStr.equals("space") && Tok.is(tok::numeric_constant))
- fixSeparateAttrArgAndNumber(SpaceStr, SpaceLoc, Tok, ArgExprs, *this,
- Actions.Context, PP);
- }
- if (ExpectAndConsume(tok::r_paren, diag::err_expected)) {
- SkipUntil(tok::r_paren, StopAtSemi); // skip through )
- return;
- }
- } break;
- case ParsedAttr::UnknownAttribute:
- Diag(Loc, diag::err_unknown_hlsl_semantic) << II;
- return;
- case ParsedAttr::AT_HLSLSV_GroupIndex:
- case ParsedAttr::AT_HLSLSV_DispatchThreadID:
- break;
- default:
- llvm_unreachable("invalid HLSL Semantic");
- break;
- }
- Attrs.addNew(II, Loc, nullptr, SourceLocation(), ArgExprs.data(),
- ArgExprs.size(), ParsedAttr::AS_HLSLSemantic);
- }
|