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