//===--- ParseHLSL.cpp - HLSL Parsing -------------------------------------===// /////////////////////////////////////////////////////////////////////////////// // // // ParseHLSL.cpp // // Copyright (C) Microsoft Corporation. All rights reserved. // // This file is distributed under the University of Illinois Open Source // // License. See LICENSE.TXT for details. // // // // This file implements the HLSLportions of the Parser interfaces. // // // /////////////////////////////////////////////////////////////////////////////// #include "clang/Parse/Parser.h" #include "RAIIObjectsForParser.h" #include "clang/Basic/CharInfo.h" #include "clang/Basic/OperatorKinds.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclTemplate.h" #include "clang/Parse/ParseDiagnostic.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/PrettyDeclStackTrace.h" #include "clang/Sema/Scope.h" #include "clang/Sema/SemaDiagnostic.h" #include "llvm/ADT/SmallString.h" using namespace clang; Decl *Parser::ParseCTBuffer(unsigned Context, SourceLocation &DeclEnd, ParsedAttributesWithRange &CTBAttrs, SourceLocation InlineLoc) { 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(); // consume identifier std::vector hlslAttrs; MaybeParseHLSLAttributes(hlslAttrs); 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 *decl = Actions.ActOnStartHLSLBuffer(getCurScope(), isCBuffer, BufferLoc, identifier, identifierLoc, hlslAttrs, T.getOpenLocation()); // Process potential C++11 attribute specifiers Actions.ProcessDeclAttributeList(getCurScope(), decl, CTBAttrs.getList()); while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { ParsedAttributesWithRange attrs(AttrFactory); MaybeParseCXX11Attributes(attrs); MaybeParseHLSLAttributes(attrs); MaybeParseMicrosoftAttributes(attrs); ParseExternalDeclaration(attrs); } T.consumeClose(); DeclEnd = T.getCloseLocation(); BufferScope.Exit(); Actions.ActOnFinishHLSLBuffer(decl, DeclEnd); return decl; } Decl *Parser::ParseConstBuffer(unsigned Context, SourceLocation &DeclEnd, ParsedAttributesWithRange &attrs, SourceLocation InlineLoc) { bool isCBuffer = Tok.is(tok::kw_ConstantBuffer); assert((isCBuffer || Tok.is(tok::kw_TextureBuffer)) && "Not a ConstantBuffer or TextureBuffer!"); SourceLocation BufferLoc = ConsumeToken(); // eat the 'ConstantBuffer'. if (!Tok.is(tok::less)) { Diag(Tok, diag::err_expected) << tok::less; return nullptr; } ConsumeToken(); // eat the < ParsingDeclSpec PDS(*this); ParseDeclarationSpecifiers(PDS); if (!Tok.is(tok::greater)) { Diag(Tok, diag::err_expected) << tok::greater; return nullptr; } ConsumeToken(); // eat the > PDS.takeAttributesFrom(attrs); Actions.ActOnStartHLSLBufferView(); Parser::DeclGroupPtrTy dcl = ParseDeclGroup(PDS, Declarator::FileContext); // Check if the register type is valid NamedDecl *namedDecl = cast(dcl.get().getSingleDecl()); ArrayRef annotations = namedDecl->getUnusualAnnotations(); for (hlsl::UnusualAnnotation* annotation : annotations) { if (annotation->getKind() == hlsl::UnusualAnnotation::UnusualAnnotationKind::UA_RegisterAssignment) { hlsl::RegisterAssignment *regAssignment = (hlsl::RegisterAssignment *)(annotation); if (isCBuffer && regAssignment->RegisterType != 'b' && regAssignment->RegisterType != 'B') { Diag(namedDecl->getLocation(), diag::err_hlsl_unsupported_cbuffer_register); } else if (!isCBuffer && regAssignment->RegisterType != 't' && regAssignment->RegisterType != 'T') { Diag(namedDecl->getLocation(), diag::err_hlsl_unsupported_tbuffer_register); } } } Decl *decl = Actions.ActOnHLSLBufferView(getCurScope(), BufferLoc, dcl, isCBuffer); return decl; } /// ParseHLSLAttributeSpecifier - Parse an HLSL attribute-specifier. /// /// [HLSL] attribute-specifier: /// '[' attribute[opt] ']' /// /// [HLSL] attribute: /// attribute-token attribute-argument-clause[opt] /// /// [HLSL] attribute-token: /// identifier /// /// [HLSL] attribute-argument-clause: /// '(' attribute-params ')' /// /// [HLSL] attribute-params: /// constant-expr /// attribute-params ',' constant-expr /// void Parser::ParseHLSLAttributeSpecifier(ParsedAttributes &attrs, SourceLocation *endLoc) { assert(getLangOpts().HLSL); assert(Tok.is(tok::l_square) && "Not an HLSL attribute list"); ConsumeBracket(); llvm::SmallDenseMap SeenAttrs; // '[]' is valid. if (Tok.is(tok::r_square)) { *endLoc = ConsumeBracket(); return; } if (!Tok.isAnyIdentifier()) { Diag(Tok, diag::err_expected) << tok::identifier; SkipUntil(tok::r_square); return; } SourceLocation AttrLoc; IdentifierInfo *AttrName = 0; AttrName = TryParseCXX11AttributeIdentifier(AttrLoc); assert(AttrName != nullptr && "already called isAnyIdenfier before"); // Parse attribute arguments if (Tok.is(tok::l_paren)) { if (AttrName == &this->Actions.getASTContext().Idents.get("clipplanes")) { ArgsVector ArgExprs; ConsumeParen(); for (;;) { ExprResult ArgExpr(ParseAssignmentExpression()); if (ArgExpr.isInvalid()) { SkipUntil(tok::r_paren, StopAtSemi); return; } ArgExprs.push_back(ArgExpr.get()); // Consume a comma and process the next argument. if (!Tok.is(tok::comma)) { break; } ConsumeToken(); } SourceLocation EndLoc = Tok.getLocation(); if (ExpectAndConsume(tok::r_paren, diag::err_expected)) SkipUntil(tok::r_paren); attrs.addNew(AttrName, SourceRange(AttrLoc, EndLoc), nullptr, SourceLocation(), ArgExprs.data(), ArgExprs.size(), AttributeList::AS_CXX11); } else { ParseGNUAttributeArgs(AttrName, AttrLoc, attrs, endLoc, nullptr, SourceLocation(), AttributeList::AS_CXX11, nullptr); } } else { attrs.addNew(AttrName, AttrLoc, nullptr, SourceLocation(), 0, 0, AttributeList::AS_CXX11); } if (endLoc) *endLoc = Tok.getLocation(); if (ExpectAndConsume(tok::r_square, diag::err_expected)) SkipUntil(tok::r_square); } /// ParseHLSLAttributes - Parse an HLSL attribute-specifier-seq. /// /// attribute-specifier-seq: /// attribute-specifier-seq[opt] attribute-specifier void Parser::ParseHLSLAttributes(ParsedAttributesWithRange &attrs, SourceLocation *endLoc) { assert(getLangOpts().HLSL); SourceLocation StartLoc = Tok.getLocation(), Loc; if (!endLoc) endLoc = &Loc; do { ParseHLSLAttributeSpecifier(attrs, endLoc); } while (Tok.is(tok::l_square)); attrs.Range = SourceRange(StartLoc, *endLoc); }