ParseStmtAsm.cpp revision 341825
133965Sjdp//===---- ParseStmtAsm.cpp - Assembly Statement Parser --------------------===// 278828Sobrien// 3218822Sdim// The LLVM Compiler Infrastructure 438889Sjdp// 533965Sjdp// This file is distributed under the University of Illinois Open Source 633965Sjdp// License. See LICENSE.TXT for details. 7130561Sobrien// 833965Sjdp//===----------------------------------------------------------------------===// 9130561Sobrien// 10130561Sobrien// This file implements parsing for GCC and Microsoft inline assembly. 11130561Sobrien// 12130561Sobrien//===----------------------------------------------------------------------===// 1333965Sjdp 14130561Sobrien#include "clang/Parse/Parser.h" 15130561Sobrien#include "clang/AST/ASTContext.h" 16130561Sobrien#include "clang/Basic/Diagnostic.h" 17130561Sobrien#include "clang/Basic/TargetInfo.h" 1833965Sjdp#include "clang/Parse/RAIIObjectsForParser.h" 19130561Sobrien#include "llvm/ADT/SmallString.h" 20130561Sobrien#include "llvm/ADT/StringExtras.h" 21218822Sdim#include "llvm/MC/MCAsmInfo.h" 2233965Sjdp#include "llvm/MC/MCContext.h" 23218822Sdim#include "llvm/MC/MCInstPrinter.h" 24218822Sdim#include "llvm/MC/MCInstrInfo.h" 2533965Sjdp#include "llvm/MC/MCObjectFileInfo.h" 2633965Sjdp#include "llvm/MC/MCParser/MCAsmParser.h" 2733965Sjdp#include "llvm/MC/MCParser/MCTargetAsmParser.h" 2833965Sjdp#include "llvm/MC/MCRegisterInfo.h" 2933965Sjdp#include "llvm/MC/MCStreamer.h" 3033965Sjdp#include "llvm/MC/MCSubtargetInfo.h" 3133965Sjdp#include "llvm/MC/MCTargetOptions.h" 3233965Sjdp#include "llvm/Support/SourceMgr.h" 3333965Sjdp#include "llvm/Support/TargetRegistry.h" 3433965Sjdp#include "llvm/Support/TargetSelect.h" 3533965Sjdpusing namespace clang; 3633965Sjdp 3733965Sjdpnamespace { 3833965Sjdpclass ClangAsmParserCallback : public llvm::MCAsmParserSemaCallback { 3933965Sjdp Parser &TheParser; 4033965Sjdp SourceLocation AsmLoc; 4133965Sjdp StringRef AsmString; 4233965Sjdp 4333965Sjdp /// The tokens we streamed into AsmString and handed off to MC. 4433965Sjdp ArrayRef<Token> AsmToks; 4533965Sjdp 4633965Sjdp /// The offset of each token in AsmToks within AsmString. 4733965Sjdp ArrayRef<unsigned> AsmTokOffsets; 4833965Sjdp 4933965Sjdppublic: 5033965Sjdp ClangAsmParserCallback(Parser &P, SourceLocation Loc, StringRef AsmString, 5133965Sjdp ArrayRef<Token> Toks, ArrayRef<unsigned> Offsets) 5233965Sjdp : TheParser(P), AsmLoc(Loc), AsmString(AsmString), AsmToks(Toks), 5333965Sjdp AsmTokOffsets(Offsets) { 5433965Sjdp assert(AsmToks.size() == AsmTokOffsets.size()); 5533965Sjdp } 5633965Sjdp 5733965Sjdp void LookupInlineAsmIdentifier(StringRef &LineBuf, 5833965Sjdp llvm::InlineAsmIdentifierInfo &Info, 5933965Sjdp bool IsUnevaluatedContext) override; 6033965Sjdp 6133965Sjdp StringRef LookupInlineAsmLabel(StringRef Identifier, llvm::SourceMgr &LSM, 6233965Sjdp llvm::SMLoc Location, 6333965Sjdp bool Create) override; 6433965Sjdp 6533965Sjdp bool LookupInlineAsmField(StringRef Base, StringRef Member, 6633965Sjdp unsigned &Offset) override { 6733965Sjdp return TheParser.getActions().LookupInlineAsmField(Base, Member, Offset, 6833965Sjdp AsmLoc); 6933965Sjdp } 7033965Sjdp 7133965Sjdp static void DiagHandlerCallback(const llvm::SMDiagnostic &D, void *Context) { 7233965Sjdp ((ClangAsmParserCallback *)Context)->handleDiagnostic(D); 7333965Sjdp } 7433965Sjdp 7533965Sjdpprivate: 7633965Sjdp /// Collect the appropriate tokens for the given string. 7733965Sjdp void findTokensForString(StringRef Str, SmallVectorImpl<Token> &TempToks, 7833965Sjdp const Token *&FirstOrigToken) const; 7933965Sjdp 8033965Sjdp SourceLocation translateLocation(const llvm::SourceMgr &LSM, 8133965Sjdp llvm::SMLoc SMLoc); 8233965Sjdp 8333965Sjdp void handleDiagnostic(const llvm::SMDiagnostic &D); 8433965Sjdp}; 8533965Sjdp} 8633965Sjdp 8733965Sjdpvoid ClangAsmParserCallback::LookupInlineAsmIdentifier( 8833965Sjdp StringRef &LineBuf, llvm::InlineAsmIdentifierInfo &Info, 8933965Sjdp bool IsUnevaluatedContext) { 9033965Sjdp // Collect the desired tokens. 9133965Sjdp SmallVector<Token, 16> LineToks; 9233965Sjdp const Token *FirstOrigToken = nullptr; 9333965Sjdp findTokensForString(LineBuf, LineToks, FirstOrigToken); 9433965Sjdp 9533965Sjdp unsigned NumConsumedToks; 9633965Sjdp ExprResult Result = TheParser.ParseMSAsmIdentifier(LineToks, NumConsumedToks, 9733965Sjdp IsUnevaluatedContext); 9833965Sjdp 9933965Sjdp // If we consumed the entire line, tell MC that. 10033965Sjdp // Also do this if we consumed nothing as a way of reporting failure. 10133965Sjdp if (NumConsumedToks == 0 || NumConsumedToks == LineToks.size()) { 10233965Sjdp // By not modifying LineBuf, we're implicitly consuming it all. 10333965Sjdp 10433965Sjdp // Otherwise, consume up to the original tokens. 10533965Sjdp } else { 10633965Sjdp assert(FirstOrigToken && "not using original tokens?"); 10733965Sjdp 10833965Sjdp // Since we're using original tokens, apply that offset. 10933965Sjdp assert(FirstOrigToken[NumConsumedToks].getLocation() == 11033965Sjdp LineToks[NumConsumedToks].getLocation()); 11133965Sjdp unsigned FirstIndex = FirstOrigToken - AsmToks.begin(); 11233965Sjdp unsigned LastIndex = FirstIndex + NumConsumedToks - 1; 11333965Sjdp 11433965Sjdp // The total length we've consumed is the relative offset 11533965Sjdp // of the last token we consumed plus its length. 11633965Sjdp unsigned TotalOffset = 11733965Sjdp (AsmTokOffsets[LastIndex] + AsmToks[LastIndex].getLength() - 11833965Sjdp AsmTokOffsets[FirstIndex]); 11933965Sjdp LineBuf = LineBuf.substr(0, TotalOffset); 12033965Sjdp } 12133965Sjdp 12233965Sjdp // Initialize Info with the lookup result. 12333965Sjdp if (!Result.isUsable()) 12433965Sjdp return; 12533965Sjdp TheParser.getActions().FillInlineAsmIdentifierInfo(Result.get(), Info); 12633965Sjdp} 12733965Sjdp 12833965SjdpStringRef ClangAsmParserCallback::LookupInlineAsmLabel(StringRef Identifier, 12933965Sjdp llvm::SourceMgr &LSM, 13033965Sjdp llvm::SMLoc Location, 13133965Sjdp bool Create) { 13260484Sobrien SourceLocation Loc = translateLocation(LSM, Location); 13333965Sjdp LabelDecl *Label = 13433965Sjdp TheParser.getActions().GetOrCreateMSAsmLabel(Identifier, Loc, Create); 13533965Sjdp return Label->getMSAsmLabel(); 13633965Sjdp} 13733965Sjdp 13833965Sjdpvoid ClangAsmParserCallback::findTokensForString( 13933965Sjdp StringRef Str, SmallVectorImpl<Token> &TempToks, 14033965Sjdp const Token *&FirstOrigToken) const { 14133965Sjdp // For now, assert that the string we're working with is a substring 14233965Sjdp // of what we gave to MC. This lets us use the original tokens. 14333965Sjdp assert(!std::less<const char *>()(Str.begin(), AsmString.begin()) && 14433965Sjdp !std::less<const char *>()(AsmString.end(), Str.end())); 14533965Sjdp 14633965Sjdp // Try to find a token whose offset matches the first token. 14733965Sjdp unsigned FirstCharOffset = Str.begin() - AsmString.begin(); 14833965Sjdp const unsigned *FirstTokOffset = std::lower_bound( 14933965Sjdp AsmTokOffsets.begin(), AsmTokOffsets.end(), FirstCharOffset); 15033965Sjdp 15133965Sjdp // For now, assert that the start of the string exactly 15233965Sjdp // corresponds to the start of a token. 15333965Sjdp assert(*FirstTokOffset == FirstCharOffset); 15433965Sjdp 15533965Sjdp // Use all the original tokens for this line. (We assume the 15633965Sjdp // end of the line corresponds cleanly to a token break.) 15733965Sjdp unsigned FirstTokIndex = FirstTokOffset - AsmTokOffsets.begin(); 15833965Sjdp FirstOrigToken = &AsmToks[FirstTokIndex]; 15933965Sjdp unsigned LastCharOffset = Str.end() - AsmString.begin(); 16033965Sjdp for (unsigned i = FirstTokIndex, e = AsmTokOffsets.size(); i != e; ++i) { 16133965Sjdp if (AsmTokOffsets[i] >= LastCharOffset) 16233965Sjdp break; 16333965Sjdp TempToks.push_back(AsmToks[i]); 16433965Sjdp } 16533965Sjdp} 16633965Sjdp 16733965SjdpSourceLocation 16833965SjdpClangAsmParserCallback::translateLocation(const llvm::SourceMgr &LSM, 16933965Sjdp llvm::SMLoc SMLoc) { 17033965Sjdp // Compute an offset into the inline asm buffer. 17133965Sjdp // FIXME: This isn't right if .macro is involved (but hopefully, no 17233965Sjdp // real-world code does that). 17333965Sjdp const llvm::MemoryBuffer *LBuf = 17433965Sjdp LSM.getMemoryBuffer(LSM.FindBufferContainingLoc(SMLoc)); 17533965Sjdp unsigned Offset = SMLoc.getPointer() - LBuf->getBufferStart(); 17633965Sjdp 17733965Sjdp // Figure out which token that offset points into. 17833965Sjdp const unsigned *TokOffsetPtr = 17933965Sjdp std::lower_bound(AsmTokOffsets.begin(), AsmTokOffsets.end(), Offset); 18033965Sjdp unsigned TokIndex = TokOffsetPtr - AsmTokOffsets.begin(); 18133965Sjdp unsigned TokOffset = *TokOffsetPtr; 18233965Sjdp 18333965Sjdp // If we come up with an answer which seems sane, use it; otherwise, 18433965Sjdp // just point at the __asm keyword. 18533965Sjdp // FIXME: Assert the answer is sane once we handle .macro correctly. 18633965Sjdp SourceLocation Loc = AsmLoc; 18733965Sjdp if (TokIndex < AsmToks.size()) { 18833965Sjdp const Token &Tok = AsmToks[TokIndex]; 18933965Sjdp Loc = Tok.getLocation(); 19033965Sjdp Loc = Loc.getLocWithOffset(Offset - TokOffset); 19133965Sjdp } 19233965Sjdp return Loc; 19333965Sjdp} 19433965Sjdp 19533965Sjdpvoid ClangAsmParserCallback::handleDiagnostic(const llvm::SMDiagnostic &D) { 19633965Sjdp const llvm::SourceMgr &LSM = *D.getSourceMgr(); 19733965Sjdp SourceLocation Loc = translateLocation(LSM, D.getLoc()); 19833965Sjdp TheParser.Diag(Loc, diag::err_inline_ms_asm_parsing) << D.getMessage(); 19933965Sjdp} 20033965Sjdp 20133965Sjdp/// Parse an identifier in an MS-style inline assembly block. 20233965SjdpExprResult Parser::ParseMSAsmIdentifier(llvm::SmallVectorImpl<Token> &LineToks, 20333965Sjdp unsigned &NumLineToksConsumed, 20433965Sjdp bool IsUnevaluatedContext) { 20533965Sjdp // Push a fake token on the end so that we don't overrun the token 20633965Sjdp // stream. We use ';' because it expression-parsing should never 20733965Sjdp // overrun it. 20833965Sjdp const tok::TokenKind EndOfStream = tok::semi; 20933965Sjdp Token EndOfStreamTok; 21033965Sjdp EndOfStreamTok.startToken(); 21133965Sjdp EndOfStreamTok.setKind(EndOfStream); 21233965Sjdp LineToks.push_back(EndOfStreamTok); 21333965Sjdp 21433965Sjdp // Also copy the current token over. 21533965Sjdp LineToks.push_back(Tok); 21633965Sjdp 21733965Sjdp PP.EnterTokenStream(LineToks, /*DisableMacroExpansions*/ true); 21833965Sjdp 21933965Sjdp // Clear the current token and advance to the first token in LineToks. 22033965Sjdp ConsumeAnyToken(); 22133965Sjdp 22233965Sjdp // Parse an optional scope-specifier if we're in C++. 22333965Sjdp CXXScopeSpec SS; 22433965Sjdp if (getLangOpts().CPlusPlus) { 225130561Sobrien ParseOptionalCXXScopeSpecifier(SS, nullptr, /*EnteringContext=*/false); 22633965Sjdp } 22733965Sjdp 22833965Sjdp // Require an identifier here. 22933965Sjdp SourceLocation TemplateKWLoc; 23033965Sjdp UnqualifiedId Id; 23133965Sjdp bool Invalid = true; 23233965Sjdp ExprResult Result; 23333965Sjdp if (Tok.is(tok::kw_this)) { 23433965Sjdp Result = ParseCXXThis(); 23533965Sjdp Invalid = false; 23633965Sjdp } else { 23733965Sjdp Invalid = ParseUnqualifiedId(SS, 23833965Sjdp /*EnteringContext=*/false, 23933965Sjdp /*AllowDestructorName=*/false, 24033965Sjdp /*AllowConstructorName=*/false, 24133965Sjdp /*AllowDeductionGuide=*/false, 24233965Sjdp /*ObjectType=*/nullptr, &TemplateKWLoc, Id); 24333965Sjdp // Perform the lookup. 24433965Sjdp Result = Actions.LookupInlineAsmIdentifier(SS, TemplateKWLoc, Id, 24533965Sjdp IsUnevaluatedContext); 24633965Sjdp } 24733965Sjdp // While the next two tokens are 'period' 'identifier', repeatedly parse it as 24889857Sobrien // a field access. We have to avoid consuming assembler directives that look 24989857Sobrien // like '.' 'else'. 25089857Sobrien while (Result.isUsable() && Tok.is(tok::period)) { 25133965Sjdp Token IdTok = PP.LookAhead(0); 25289857Sobrien if (IdTok.isNot(tok::identifier)) 25389857Sobrien break; 25489857Sobrien ConsumeToken(); // Consume the period. 25533965Sjdp IdentifierInfo *Id = Tok.getIdentifierInfo(); 25689857Sobrien ConsumeToken(); // Consume the identifier. 25789857Sobrien Result = Actions.LookupInlineAsmVarDeclField(Result.get(), Id->getName(), 25889857Sobrien Tok.getLocation()); 25933965Sjdp } 26089857Sobrien 26189857Sobrien // Figure out how many tokens we are into LineToks. 26289857Sobrien unsigned LineIndex = 0; 26333965Sjdp if (Tok.is(EndOfStream)) { 26489857Sobrien LineIndex = LineToks.size() - 2; 26589857Sobrien } else { 26689857Sobrien while (LineToks[LineIndex].getLocation() != Tok.getLocation()) { 26733965Sjdp LineIndex++; 26889857Sobrien assert(LineIndex < LineToks.size() - 2); // we added two extra tokens 26989857Sobrien } 27089857Sobrien } 27133965Sjdp 27289857Sobrien // If we've run into the poison token we inserted before, or there 27389857Sobrien // was a parsing error, then claim the entire line. 27489857Sobrien if (Invalid || Tok.is(EndOfStream)) { 27589857Sobrien NumLineToksConsumed = LineToks.size() - 2; 27689857Sobrien } else { 27789857Sobrien // Otherwise, claim up to the start of the next token. 27889857Sobrien NumLineToksConsumed = LineIndex; 27933965Sjdp } 28033965Sjdp 28133965Sjdp // Finally, restore the old parsing state by consuming all the tokens we 28233965Sjdp // staged before, implicitly killing off the token-lexer we pushed. 28333965Sjdp for (unsigned i = 0, e = LineToks.size() - LineIndex - 2; i != e; ++i) { 28433965Sjdp ConsumeAnyToken(); 28533965Sjdp } 28689857Sobrien assert(Tok.is(EndOfStream)); 28789857Sobrien ConsumeToken(); 28833965Sjdp 28989857Sobrien // Leave LineToks in its original state. 29089857Sobrien LineToks.pop_back(); 29133965Sjdp LineToks.pop_back(); 29289857Sobrien 29389857Sobrien return Result; 29433965Sjdp} 29589857Sobrien 296130561Sobrien/// Turn a sequence of our tokens back into a string that we can hand 29733965Sjdp/// to the MC asm parser. 29833965Sjdpstatic bool buildMSAsmString(Preprocessor &PP, SourceLocation AsmLoc, 29933965Sjdp ArrayRef<Token> AsmToks, 30033965Sjdp SmallVectorImpl<unsigned> &TokOffsets, 30133965Sjdp SmallString<512> &Asm) { 30233965Sjdp assert(!AsmToks.empty() && "Didn't expect an empty AsmToks!"); 30333965Sjdp 30433965Sjdp // Is this the start of a new assembly statement? 30533965Sjdp bool isNewStatement = true; 30633965Sjdp 307218822Sdim for (unsigned i = 0, e = AsmToks.size(); i < e; ++i) { 30833965Sjdp const Token &Tok = AsmToks[i]; 309218822Sdim 310218822Sdim // Start each new statement with a newline and a tab. 311218822Sdim if (!isNewStatement && (Tok.is(tok::kw_asm) || Tok.isAtStartOfLine())) { 312130561Sobrien Asm += "\n\t"; 313218822Sdim isNewStatement = true; 314130561Sobrien } 315218822Sdim 316130561Sobrien // Preserve the existence of leading whitespace except at the 317218822Sdim // start of a statement. 31860484Sobrien if (!isNewStatement && Tok.hasLeadingSpace()) 319218822Sdim Asm += ' '; 320218822Sdim 321130561Sobrien // Remember the offset of this token. 322218822Sdim TokOffsets.push_back(Asm.size()); 323130561Sobrien 324218822Sdim // Don't actually write '__asm' into the assembly stream. 325130561Sobrien if (Tok.is(tok::kw_asm)) { 326218822Sdim // Complain about __asm at the end of the stream. 327130561Sobrien if (i + 1 == e) { 328218822Sdim PP.Diag(AsmLoc, diag::err_asm_empty); 329130561Sobrien return true; 330218822Sdim } 331130561Sobrien 332218822Sdim continue; 333130561Sobrien } 334218822Sdim 335130561Sobrien // Append the spelling of the token. 336218822Sdim SmallString<32> SpellingBuffer; 337218822Sdim bool SpellingInvalid = false; 338218822Sdim Asm += PP.getSpelling(Tok, SpellingBuffer, &SpellingInvalid); 339130561Sobrien assert(!SpellingInvalid && "spelling was invalid after correct parse?"); 340218822Sdim 341130561Sobrien // We are no longer at the start of a statement. 342218822Sdim isNewStatement = false; 34360484Sobrien } 344218822Sdim 345130561Sobrien // Ensure that the buffer is null-terminated. 346218822Sdim Asm.push_back('\0'); 34733965Sjdp Asm.pop_back(); 348218822Sdim 34933965Sjdp assert(TokOffsets.size() == AsmToks.size()); 350218822Sdim return false; 351218822Sdim} 35233965Sjdp 35378828Sobrien/// isTypeQualifier - Return true if the current token could be the 354130561Sobrien/// start of a type-qualifier-list. 355218822Sdimstatic bool isTypeQualifier(const Token &Tok) { 35678828Sobrien switch (Tok.getKind()) { 357104834Sobrien default: return false; 358130561Sobrien // type-qualifier 359218822Sdim case tok::kw_const: 360130561Sobrien case tok::kw_volatile: 361218822Sdim case tok::kw_restrict: 362130561Sobrien case tok::kw___private: 363218822Sdim case tok::kw___local: 364104834Sobrien case tok::kw___global: 365130561Sobrien case tok::kw___constant: 366130561Sobrien case tok::kw___generic: 367218822Sdim case tok::kw___read_only: 368130561Sobrien case tok::kw___read_write: 369218822Sdim case tok::kw___write_only: 370130561Sobrien return true; 37133965Sjdp } 37233965Sjdp} 37333965Sjdp 37460484Sobrien// Determine if this is a GCC-style asm statement. 37560484Sobrienstatic bool isGCCAsmStatement(const Token &TokAfterAsm) { 37660484Sobrien return TokAfterAsm.is(tok::l_paren) || TokAfterAsm.is(tok::kw_goto) || 37760484Sobrien isTypeQualifier(TokAfterAsm); 37860484Sobrien} 37960484Sobrien 38060484Sobrien/// ParseMicrosoftAsmStatement. When -fms-extensions/-fasm-blocks is enabled, 38177298Sobrien/// this routine is called to collect the tokens for an MS asm statement. 382218822Sdim/// 38377298Sobrien/// [MS] ms-asm-statement: 38477298Sobrien/// ms-asm-block 38577298Sobrien/// ms-asm-block ms-asm-statement 38677298Sobrien/// 38777298Sobrien/// [MS] ms-asm-block: 38877298Sobrien/// '__asm' ms-asm-line '\n' 38977298Sobrien/// '__asm' '{' ms-asm-instruction-block[opt] '}' ';'[opt] 39077298Sobrien/// 39177298Sobrien/// [MS] ms-asm-instruction-block 39277298Sobrien/// ms-asm-line 39377298Sobrien/// ms-asm-line '\n' ms-asm-instruction-block 39477298Sobrien/// 39533965SjdpStmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) { 396218822Sdim SourceManager &SrcMgr = PP.getSourceManager(); 39733965Sjdp SourceLocation EndLoc = AsmLoc; 39833965Sjdp SmallVector<Token, 4> AsmToks; 39933965Sjdp 40033965Sjdp bool SingleLineMode = true; 40133965Sjdp unsigned BraceNesting = 0; 40233965Sjdp unsigned short savedBraceCount = BraceCount; 40333965Sjdp bool InAsmComment = false; 40433965Sjdp FileID FID; 40533965Sjdp unsigned LineNo = 0; 40633965Sjdp unsigned NumTokensRead = 0; 40733965Sjdp SmallVector<SourceLocation, 4> LBraceLocs; 40833965Sjdp bool SkippedStartOfLine = false; 40933965Sjdp 41033965Sjdp if (Tok.is(tok::l_brace)) { 41133965Sjdp // Braced inline asm: consume the opening brace. 41233965Sjdp SingleLineMode = false; 41333965Sjdp BraceNesting = 1; 41433965Sjdp EndLoc = ConsumeBrace(); 41533965Sjdp LBraceLocs.push_back(EndLoc); 41633965Sjdp ++NumTokensRead; 41733965Sjdp } else { 41833965Sjdp // Single-line inline asm; compute which line it is on. 41933965Sjdp std::pair<FileID, unsigned> ExpAsmLoc = 42033965Sjdp SrcMgr.getDecomposedExpansionLoc(EndLoc); 42133965Sjdp FID = ExpAsmLoc.first; 42233965Sjdp LineNo = SrcMgr.getLineNumber(FID, ExpAsmLoc.second); 42333965Sjdp LBraceLocs.push_back(SourceLocation()); 42433965Sjdp } 42533965Sjdp 42633965Sjdp SourceLocation TokLoc = Tok.getLocation(); 42733965Sjdp do { 42833965Sjdp // If we hit EOF, we're done, period. 42933965Sjdp if (isEofOrEom()) 430218822Sdim break; 43133965Sjdp 43277298Sobrien if (!InAsmComment && Tok.is(tok::l_brace)) { 43377298Sobrien // Consume the opening brace. 43477298Sobrien SkippedStartOfLine = Tok.isAtStartOfLine(); 43577298Sobrien AsmToks.push_back(Tok); 43677298Sobrien EndLoc = ConsumeBrace(); 43733965Sjdp BraceNesting++; 438218822Sdim LBraceLocs.push_back(EndLoc); 43933965Sjdp TokLoc = Tok.getLocation(); 44077298Sobrien ++NumTokensRead; 44133965Sjdp continue; 44277298Sobrien } else if (!InAsmComment && Tok.is(tok::semi)) { 443218822Sdim // A semicolon in an asm is the start of a comment. 44477298Sobrien InAsmComment = true; 44577298Sobrien if (!SingleLineMode) { 44677298Sobrien // Compute which line the comment is on. 44777298Sobrien std::pair<FileID, unsigned> ExpSemiLoc = 44833965Sjdp SrcMgr.getDecomposedExpansionLoc(TokLoc); 44933965Sjdp FID = ExpSemiLoc.first; 45033965Sjdp LineNo = SrcMgr.getLineNumber(FID, ExpSemiLoc.second); 45133965Sjdp } 45233965Sjdp } else if (SingleLineMode || InAsmComment) { 45333965Sjdp // If end-of-line is significant, check whether this token is on a 45433965Sjdp // new line. 45533965Sjdp std::pair<FileID, unsigned> ExpLoc = 45633965Sjdp SrcMgr.getDecomposedExpansionLoc(TokLoc); 45789857Sobrien if (ExpLoc.first != FID || 45889857Sobrien SrcMgr.getLineNumber(ExpLoc.first, ExpLoc.second) != LineNo) { 45989857Sobrien // If this is a single-line __asm, we're done, except if the next 46089857Sobrien // line is MS-style asm too, in which case we finish a comment 46189857Sobrien // if needed and then keep processing the next line as a single 46289857Sobrien // line __asm. 46389857Sobrien bool isAsm = Tok.is(tok::kw_asm); 46489857Sobrien if (SingleLineMode && (!isAsm || isGCCAsmStatement(NextToken()))) 46533965Sjdp break; 46633965Sjdp // We're no longer in a comment. 46733965Sjdp InAsmComment = false; 46833965Sjdp if (isAsm) { 46933965Sjdp // If this is a new __asm {} block we want to process it separately 47033965Sjdp // from the single-line __asm statements 47133965Sjdp if (PP.LookAhead(0).is(tok::l_brace)) 47233965Sjdp break; 47333965Sjdp LineNo = SrcMgr.getLineNumber(ExpLoc.first, ExpLoc.second); 47433965Sjdp SkippedStartOfLine = Tok.isAtStartOfLine(); 47533965Sjdp } else if (Tok.is(tok::semi)) { 47633965Sjdp // A multi-line asm-statement, where next line is a comment 47733965Sjdp InAsmComment = true; 47833965Sjdp FID = ExpLoc.first; 47933965Sjdp LineNo = SrcMgr.getLineNumber(FID, ExpLoc.second); 48033965Sjdp } 48133965Sjdp } else if (!InAsmComment && Tok.is(tok::r_brace)) { 48233965Sjdp // In MSVC mode, braces only participate in brace matching and 48333965Sjdp // separating the asm statements. This is an intentional 48433965Sjdp // departure from the Apple gcc behavior. 48533965Sjdp if (!BraceNesting) 48633965Sjdp break; 48733965Sjdp } 48833965Sjdp } 48933965Sjdp if (!InAsmComment && BraceNesting && Tok.is(tok::r_brace) && 49033965Sjdp BraceCount == (savedBraceCount + BraceNesting)) { 49133965Sjdp // Consume the closing brace. 49277298Sobrien SkippedStartOfLine = Tok.isAtStartOfLine(); 493218822Sdim // Don't want to add the closing brace of the whole asm block 49477298Sobrien if (SingleLineMode || BraceNesting > 1) { 49577298Sobrien Tok.clearFlag(Token::LeadingSpace); 49677298Sobrien AsmToks.push_back(Tok); 49777298Sobrien } 498218822Sdim EndLoc = ConsumeBrace(); 49977298Sobrien BraceNesting--; 50077298Sobrien // Finish if all of the opened braces in the inline asm section were 50177298Sobrien // consumed. 50233965Sjdp if (BraceNesting == 0 && !SingleLineMode) 50333965Sjdp break; 50433965Sjdp else { 50533965Sjdp LBraceLocs.pop_back(); 50633965Sjdp TokLoc = Tok.getLocation(); 50760484Sobrien ++NumTokensRead; 50860484Sobrien continue; 50960484Sobrien } 51060484Sobrien } 51160484Sobrien 51260484Sobrien // Consume the next token; make sure we don't modify the brace count etc. 51360484Sobrien // if we are in a comment. 51460484Sobrien EndLoc = TokLoc; 51560484Sobrien if (InAsmComment) 51660484Sobrien PP.Lex(Tok); 51760484Sobrien else { 51860484Sobrien // Set the token as the start of line if we skipped the original start 519218822Sdim // of line token in case it was a nested brace. 52060484Sobrien if (SkippedStartOfLine) 52160484Sobrien Tok.setFlag(Token::StartOfLine); 52260484Sobrien AsmToks.push_back(Tok); 52360484Sobrien ConsumeAnyToken(); 52460484Sobrien } 52560484Sobrien TokLoc = Tok.getLocation(); 52660484Sobrien ++NumTokensRead; 52760484Sobrien SkippedStartOfLine = false; 52860484Sobrien } while (1); 52960484Sobrien 53060484Sobrien if (BraceNesting && BraceCount != savedBraceCount) { 531218822Sdim // __asm without closing brace (this can happen at EOF). 532218822Sdim for (unsigned i = 0; i < BraceNesting; ++i) { 533218822Sdim Diag(Tok, diag::err_expected) << tok::r_brace; 534218822Sdim Diag(LBraceLocs.back(), diag::note_matching) << tok::l_brace; 535218822Sdim LBraceLocs.pop_back(); 53660484Sobrien } 53760484Sobrien return StmtError(); 53860484Sobrien } else if (NumTokensRead == 0) { 53960484Sobrien // Empty __asm. 54060484Sobrien Diag(Tok, diag::err_expected) << tok::l_brace; 54160484Sobrien return StmtError(); 54260484Sobrien } 54360484Sobrien 54460484Sobrien // Okay, prepare to use MC to parse the assembly. 54560484Sobrien SmallVector<StringRef, 4> ConstraintRefs; 54689857Sobrien SmallVector<Expr *, 4> Exprs; 54760484Sobrien SmallVector<StringRef, 4> ClobberRefs; 54860484Sobrien 54933965Sjdp // We need an actual supported target. 55060484Sobrien const llvm::Triple &TheTriple = Actions.Context.getTargetInfo().getTriple(); 55160484Sobrien llvm::Triple::ArchType ArchTy = TheTriple.getArch(); 55260484Sobrien const std::string &TT = TheTriple.getTriple(); 55360484Sobrien const llvm::Target *TheTarget = nullptr; 55460484Sobrien bool UnsupportedArch = 55560484Sobrien (ArchTy != llvm::Triple::x86 && ArchTy != llvm::Triple::x86_64); 55660484Sobrien if (UnsupportedArch) { 55760484Sobrien Diag(AsmLoc, diag::err_msasm_unsupported_arch) << TheTriple.getArchName(); 55877298Sobrien } else { 55977298Sobrien std::string Error; 56060484Sobrien TheTarget = llvm::TargetRegistry::lookupTarget(TT, Error); 56160484Sobrien if (!TheTarget) 56233965Sjdp Diag(AsmLoc, diag::err_msasm_unable_to_create_target) << Error; 563218822Sdim } 564218822Sdim 565218822Sdim assert(!LBraceLocs.empty() && "Should have at least one location here"); 566218822Sdim 567218822Sdim // If we don't support assembly, or the assembly is empty, we don't 568218822Sdim // need to instantiate the AsmParser, etc. 569218822Sdim if (!TheTarget || AsmToks.empty()) { 570218822Sdim return Actions.ActOnMSAsmStmt(AsmLoc, LBraceLocs[0], AsmToks, StringRef(), 571218822Sdim /*NumOutputs*/ 0, /*NumInputs*/ 0, 572218822Sdim ConstraintRefs, ClobberRefs, Exprs, EndLoc); 573218822Sdim } 574218822Sdim 575218822Sdim // Expand the tokens into a string buffer. 57660484Sobrien SmallString<512> AsmString; 57777298Sobrien SmallVector<unsigned, 8> TokOffsets; 57833965Sjdp if (buildMSAsmString(PP, AsmLoc, AsmToks, TokOffsets, AsmString)) 57960484Sobrien return StmtError(); 58060484Sobrien 58160484Sobrien const TargetOptions &TO = Actions.Context.getTargetInfo().getTargetOpts(); 58260484Sobrien std::string FeaturesStr = 58360484Sobrien llvm::join(TO.Features.begin(), TO.Features.end(), ","); 58460484Sobrien 58560484Sobrien std::unique_ptr<llvm::MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TT)); 58660484Sobrien std::unique_ptr<llvm::MCAsmInfo> MAI(TheTarget->createMCAsmInfo(*MRI, TT)); 58760484Sobrien // Get the instruction descriptor. 58860484Sobrien std::unique_ptr<llvm::MCInstrInfo> MII(TheTarget->createMCInstrInfo()); 589130561Sobrien std::unique_ptr<llvm::MCObjectFileInfo> MOFI(new llvm::MCObjectFileInfo()); 590218822Sdim std::unique_ptr<llvm::MCSubtargetInfo> STI( 591218822Sdim TheTarget->createMCSubtargetInfo(TT, TO.CPU, FeaturesStr)); 592218822Sdim 593218822Sdim llvm::SourceMgr TempSrcMgr; 594218822Sdim llvm::MCContext Ctx(MAI.get(), MRI.get(), MOFI.get(), &TempSrcMgr); 59533965Sjdp MOFI->InitMCObjectFileInfo(TheTriple, /*PIC*/ false, Ctx); 59633965Sjdp std::unique_ptr<llvm::MemoryBuffer> Buffer = 59733965Sjdp llvm::MemoryBuffer::getMemBuffer(AsmString, "<MS inline asm>"); 59833965Sjdp 59933965Sjdp // Tell SrcMgr about this buffer, which is what the parser will pick up. 60077298Sobrien TempSrcMgr.AddNewSourceBuffer(std::move(Buffer), llvm::SMLoc()); 60177298Sobrien 602218822Sdim std::unique_ptr<llvm::MCStreamer> Str(createNullStreamer(Ctx)); 60377298Sobrien std::unique_ptr<llvm::MCAsmParser> Parser( 60477298Sobrien createMCAsmParser(TempSrcMgr, Ctx, *Str.get(), *MAI)); 60577298Sobrien 60677298Sobrien // FIXME: init MCOptions from sanitizer flags here. 607218822Sdim llvm::MCTargetOptions MCOptions; 60877298Sobrien std::unique_ptr<llvm::MCTargetAsmParser> TargetParser( 60977298Sobrien TheTarget->createMCAsmParser(*STI, *Parser, *MII, MCOptions)); 61033965Sjdp 61133965Sjdp std::unique_ptr<llvm::MCInstPrinter> IP( 61289857Sobrien TheTarget->createMCInstPrinter(llvm::Triple(TT), 1, *MAI, *MII, *MRI)); 61333965Sjdp 61433965Sjdp // Change to the Intel dialect. 61533965Sjdp Parser->setAssemblerDialect(1); 61633965Sjdp Parser->setTargetParser(*TargetParser.get()); 61733965Sjdp Parser->setParsingInlineAsm(true); 61833965Sjdp TargetParser->setParsingInlineAsm(true); 61933965Sjdp 62033965Sjdp ClangAsmParserCallback Callback(*this, AsmLoc, AsmString, AsmToks, 62133965Sjdp TokOffsets); 62233965Sjdp TargetParser->setSemaCallback(&Callback); 62333965Sjdp TempSrcMgr.setDiagHandler(ClangAsmParserCallback::DiagHandlerCallback, 62433965Sjdp &Callback); 62533965Sjdp 62633965Sjdp unsigned NumOutputs; 62733965Sjdp unsigned NumInputs; 62833965Sjdp std::string AsmStringIR; 62933965Sjdp SmallVector<std::pair<void *, bool>, 4> OpExprs; 63033965Sjdp SmallVector<std::string, 4> Constraints; 63133965Sjdp SmallVector<std::string, 4> Clobbers; 63233965Sjdp if (Parser->parseMSInlineAsm(AsmLoc.getPtrEncoding(), AsmStringIR, NumOutputs, 63333965Sjdp NumInputs, OpExprs, Constraints, Clobbers, 63433965Sjdp MII.get(), IP.get(), Callback)) 63533965Sjdp return StmtError(); 63633965Sjdp 63733965Sjdp // Filter out "fpsw" and "mxcsr". They aren't valid GCC asm clobber 63833965Sjdp // constraints. Clang always adds fpsr to the clobber list anyway. 63933965Sjdp llvm::erase_if(Clobbers, [](const std::string &C) { 64033965Sjdp return C == "fpsw" || C == "mxcsr"; 64133965Sjdp }); 64233965Sjdp 64333965Sjdp // Build the vector of clobber StringRefs. 64433965Sjdp ClobberRefs.insert(ClobberRefs.end(), Clobbers.begin(), Clobbers.end()); 64533965Sjdp 64633965Sjdp // Recast the void pointers and build the vector of constraint StringRefs. 64733965Sjdp unsigned NumExprs = NumOutputs + NumInputs; 64838889Sjdp ConstraintRefs.resize(NumExprs); 64933965Sjdp Exprs.resize(NumExprs); 65033965Sjdp for (unsigned i = 0, e = NumExprs; i != e; ++i) { 65133965Sjdp Expr *OpExpr = static_cast<Expr *>(OpExprs[i].first); 65233965Sjdp if (!OpExpr) 65389857Sobrien return StmtError(); 65433965Sjdp 65533965Sjdp // Need address of variable. 65633965Sjdp if (OpExprs[i].second) 65733965Sjdp OpExpr = 65833965Sjdp Actions.BuildUnaryOp(getCurScope(), AsmLoc, UO_AddrOf, OpExpr).get(); 65933965Sjdp 66033965Sjdp ConstraintRefs[i] = StringRef(Constraints[i]); 66133965Sjdp Exprs[i] = OpExpr; 66233965Sjdp } 66333965Sjdp 66433965Sjdp // FIXME: We should be passing source locations for better diagnostics. 66533965Sjdp return Actions.ActOnMSAsmStmt(AsmLoc, LBraceLocs[0], AsmToks, AsmStringIR, 66633965Sjdp NumOutputs, NumInputs, ConstraintRefs, 66733965Sjdp ClobberRefs, Exprs, EndLoc); 66833965Sjdp} 66933965Sjdp 67033965Sjdp/// ParseAsmStatement - Parse a GNU extended asm statement. 67133965Sjdp/// asm-statement: 67233965Sjdp/// gnu-asm-statement 67333965Sjdp/// ms-asm-statement 67433965Sjdp/// 67533965Sjdp/// [GNU] gnu-asm-statement: 67633965Sjdp/// 'asm' type-qualifier[opt] '(' asm-argument ')' ';' 677218822Sdim/// 67833965Sjdp/// [GNU] asm-argument: 67933965Sjdp/// asm-string-literal 68033965Sjdp/// asm-string-literal ':' asm-operands[opt] 68177298Sobrien/// asm-string-literal ':' asm-operands[opt] ':' asm-operands[opt] 682218822Sdim/// asm-string-literal ':' asm-operands[opt] ':' asm-operands[opt] 68377298Sobrien/// ':' asm-clobbers 684218822Sdim/// 68533965Sjdp/// [GNU] asm-clobbers: 68633965Sjdp/// asm-string-literal 68733965Sjdp/// asm-clobbers ',' asm-string-literal 68833965Sjdp/// 68933965SjdpStmtResult Parser::ParseAsmStatement(bool &msAsm) { 69033965Sjdp assert(Tok.is(tok::kw_asm) && "Not an asm stmt"); 69133965Sjdp SourceLocation AsmLoc = ConsumeToken(); 69233965Sjdp 69333965Sjdp if (getLangOpts().AsmBlocks && !isGCCAsmStatement(Tok)) { 69433965Sjdp msAsm = true; 69533965Sjdp return ParseMicrosoftAsmStatement(AsmLoc); 69689857Sobrien } 69733965Sjdp 69833965Sjdp DeclSpec DS(AttrFactory); 69989857Sobrien SourceLocation Loc = Tok.getLocation(); 70033965Sjdp ParseTypeQualifierListOpt(DS, AR_VendorAttributesParsed); 701130561Sobrien 70233965Sjdp // GNU asms accept, but warn, about type-qualifiers other than volatile. 70389857Sobrien if (DS.getTypeQualifiers() & DeclSpec::TQ_const) 70433965Sjdp Diag(Loc, diag::warn_asm_qualifier_ignored) << "const"; 70589857Sobrien if (DS.getTypeQualifiers() & DeclSpec::TQ_restrict) 706130561Sobrien Diag(Loc, diag::warn_asm_qualifier_ignored) << "restrict"; 70733965Sjdp // FIXME: Once GCC supports _Atomic, check whether it permits it here. 70889857Sobrien if (DS.getTypeQualifiers() & DeclSpec::TQ_atomic) 70933965Sjdp Diag(Loc, diag::warn_asm_qualifier_ignored) << "_Atomic"; 71033965Sjdp 71160484Sobrien // Remember if this was a volatile asm. 71260484Sobrien bool isVolatile = DS.getTypeQualifiers() & DeclSpec::TQ_volatile; 71360484Sobrien 71460484Sobrien // TODO: support "asm goto" constructs (PR#9295). 71560484Sobrien if (Tok.is(tok::kw_goto)) { 71660484Sobrien Diag(Tok, diag::err_asm_goto_not_supported_yet); 71760484Sobrien SkipUntil(tok::r_paren, StopAtSemi); 718218822Sdim return StmtError(); 71960484Sobrien } 72060484Sobrien 72160484Sobrien if (Tok.isNot(tok::l_paren)) { 72289857Sobrien Diag(Tok, diag::err_expected_lparen_after) << "asm"; 723130561Sobrien SkipUntil(tok::r_paren, StopAtSemi); 72489857Sobrien return StmtError(); 72589857Sobrien } 726130561Sobrien BalancedDelimiterTracker T(*this, tok::l_paren); 72760484Sobrien T.consumeOpen(); 72860484Sobrien 72960484Sobrien ExprResult AsmString(ParseAsmStringLiteral()); 73060484Sobrien 73160484Sobrien // Check if GNU-style InlineAsm is disabled. 732218822Sdim // Error on anything other than empty string. 733218822Sdim if (!(getLangOpts().GNUAsm || AsmString.isInvalid())) { 734218822Sdim const auto *SL = cast<StringLiteral>(AsmString.get()); 735218822Sdim if (!SL->getString().trim().empty()) 736218822Sdim Diag(Loc, diag::err_gnu_inline_asm_disabled); 73760484Sobrien } 73860484Sobrien 73978828Sobrien if (AsmString.isInvalid()) { 74078828Sobrien // Consume up to and including the closing paren. 74178828Sobrien T.skipToEnd(); 74260484Sobrien return StmtError(); 74378828Sobrien } 74433965Sjdp 74578828Sobrien SmallVector<IdentifierInfo *, 4> Names; 74678828Sobrien ExprVector Constraints; 74778828Sobrien ExprVector Exprs; 74878828Sobrien ExprVector Clobbers; 74978828Sobrien 75078828Sobrien if (Tok.is(tok::r_paren)) { 75160484Sobrien // We have a simple asm expression like 'asm("foo")'. 75278828Sobrien T.consumeClose(); 75378828Sobrien return Actions.ActOnGCCAsmStmt(AsmLoc, /*isSimple*/ true, isVolatile, 75478828Sobrien /*NumOutputs*/ 0, /*NumInputs*/ 0, nullptr, 75578828Sobrien Constraints, Exprs, AsmString.get(), 75678828Sobrien Clobbers, T.getCloseLocation()); 75760484Sobrien } 75878828Sobrien 75978828Sobrien // Parse Outputs, if present. 76078828Sobrien bool AteExtraColon = false; 76160484Sobrien if (Tok.is(tok::colon) || Tok.is(tok::coloncolon)) { 76278828Sobrien // In C++ mode, parse "::" like ": :". 76378828Sobrien AteExtraColon = Tok.is(tok::coloncolon); 76489857Sobrien ConsumeToken(); 76578828Sobrien 76678828Sobrien if (!AteExtraColon && ParseAsmOperandsOpt(Names, Constraints, Exprs)) 76778828Sobrien return StmtError(); 76878828Sobrien } 76933965Sjdp 77078828Sobrien unsigned NumOutputs = Names.size(); 77178828Sobrien 77278828Sobrien // Parse Inputs, if present. 77333965Sjdp if (AteExtraColon || Tok.is(tok::colon) || Tok.is(tok::coloncolon)) { 774218822Sdim // In C++ mode, parse "::" like ": :". 77533965Sjdp if (AteExtraColon) 77678828Sobrien AteExtraColon = false; 77778828Sobrien else { 77878828Sobrien AteExtraColon = Tok.is(tok::coloncolon); 77978828Sobrien ConsumeToken(); 78078828Sobrien } 78178828Sobrien 78260484Sobrien if (!AteExtraColon && ParseAsmOperandsOpt(Names, Constraints, Exprs)) 78378828Sobrien return StmtError(); 78433965Sjdp } 78578828Sobrien 78678828Sobrien assert(Names.size() == Constraints.size() && 78778828Sobrien Constraints.size() == Exprs.size() && "Input operand size mismatch!"); 78878828Sobrien 78978828Sobrien unsigned NumInputs = Names.size() - NumOutputs; 79078828Sobrien 79178828Sobrien // Parse the clobbers, if present. 79233965Sjdp if (AteExtraColon || Tok.is(tok::colon)) { 79378828Sobrien if (!AteExtraColon) 79478828Sobrien ConsumeToken(); 79578828Sobrien 79633965Sjdp // Parse the asm-string list for clobbers if present. 79778828Sobrien if (Tok.isNot(tok::r_paren)) { 79878828Sobrien while (1) { 79978828Sobrien ExprResult Clobber(ParseAsmStringLiteral()); 80078828Sobrien 80133965Sjdp if (Clobber.isInvalid()) 80278828Sobrien break; 80378828Sobrien 80478828Sobrien Clobbers.push_back(Clobber.get()); 80578828Sobrien 80678828Sobrien if (!TryConsumeToken(tok::comma)) 80778828Sobrien break; 80833965Sjdp } 809130561Sobrien } 81078828Sobrien } 81133965Sjdp 81278828Sobrien T.consumeClose(); 81378828Sobrien return Actions.ActOnGCCAsmStmt( 81433965Sjdp AsmLoc, false, isVolatile, NumOutputs, NumInputs, Names.data(), 81578828Sobrien Constraints, Exprs, AsmString.get(), Clobbers, T.getCloseLocation()); 81678828Sobrien} 81778828Sobrien 81878828Sobrien/// ParseAsmOperands - Parse the asm-operands production as used by 81978828Sobrien/// asm-statement, assuming the leading ':' token was eaten. 82078828Sobrien/// 82160484Sobrien/// [GNU] asm-operands: 82278828Sobrien/// asm-operand 82378828Sobrien/// asm-operands ',' asm-operand 82478828Sobrien/// 82578828Sobrien/// [GNU] asm-operand: 82678828Sobrien/// asm-string-literal '(' expression ')' 82778828Sobrien/// '[' identifier ']' asm-string-literal '(' expression ')' 82878828Sobrien/// 82978828Sobrien// 83078828Sobrien// FIXME: Avoid unnecessary std::string trashing. 83178828Sobrienbool Parser::ParseAsmOperandsOpt(SmallVectorImpl<IdentifierInfo *> &Names, 83278828Sobrien SmallVectorImpl<Expr *> &Constraints, 83360484Sobrien SmallVectorImpl<Expr *> &Exprs) { 83478828Sobrien // 'asm-operands' isn't present? 83578828Sobrien if (!isTokenStringLiteral() && Tok.isNot(tok::l_square)) 83678828Sobrien return false; 83760484Sobrien 83878828Sobrien while (1) { 83978828Sobrien // Read the [id] if present. 84078828Sobrien if (Tok.is(tok::l_square)) { 84178828Sobrien BalancedDelimiterTracker T(*this, tok::l_square); 84233965Sjdp T.consumeOpen(); 84378828Sobrien 84478828Sobrien if (Tok.isNot(tok::identifier)) { 84578828Sobrien Diag(Tok, diag::err_expected) << tok::identifier; 84678828Sobrien SkipUntil(tok::r_paren, StopAtSemi); 84733965Sjdp return true; 84878828Sobrien } 849218822Sdim 850218822Sdim IdentifierInfo *II = Tok.getIdentifierInfo(); 85133965Sjdp ConsumeToken(); 852218822Sdim 853218822Sdim Names.push_back(II); 85478828Sobrien T.consumeClose(); 855218822Sdim } else 85678828Sobrien Names.push_back(nullptr); 857218822Sdim 85833965Sjdp ExprResult Constraint(ParseAsmStringLiteral()); 85978828Sobrien if (Constraint.isInvalid()) { 86078828Sobrien SkipUntil(tok::r_paren, StopAtSemi); 86178828Sobrien return true; 86278828Sobrien } 86378828Sobrien Constraints.push_back(Constraint.get()); 86478828Sobrien 86578828Sobrien if (Tok.isNot(tok::l_paren)) { 86678828Sobrien Diag(Tok, diag::err_expected_lparen_after) << "asm operand"; 86733965Sjdp SkipUntil(tok::r_paren, StopAtSemi); 86878828Sobrien return true; 86978828Sobrien } 87078828Sobrien 87178828Sobrien // Read the parenthesized expression. 87278828Sobrien BalancedDelimiterTracker T(*this, tok::l_paren); 87378828Sobrien T.consumeOpen(); 87478828Sobrien ExprResult Res = Actions.CorrectDelayedTyposInExpr(ParseExpression()); 87578828Sobrien T.consumeClose(); 87678828Sobrien if (Res.isInvalid()) { 87733965Sjdp SkipUntil(tok::r_paren, StopAtSemi); 87878828Sobrien return true; 87978828Sobrien } 88078828Sobrien Exprs.push_back(Res.get()); 88178828Sobrien // Eat the comma and continue parsing if it exists. 88278828Sobrien if (!TryConsumeToken(tok::comma)) 88333965Sjdp return false; 88478828Sobrien } 88578828Sobrien} 88678828Sobrien