<div dir="ltr">thanks!</div><div class="gmail_extra"><br><br><div class="gmail_quote">On Sat, Jun 7, 2014 at 10:40 PM, Alp Toker <span dir="ltr"><<a href="mailto:alp@nuanti.com" target="_blank">alp@nuanti.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: alp<br>
Date: Sun Jun  8 00:40:04 2014<br>
New Revision: 210420<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=210420&view=rev" target="_blank">http://llvm.org/viewvc/llvm-project?rev=210420&view=rev</a><br>
Log:<br>
Split out inline asm parsing into ParseStmtAsm.cpp<br>
<br>
This change isolates various llvm/MC headers from the rest of the parser and<br>
better aligns with the existing SemaStmtAsm.cpp.<br>
<br>
No change in functionality, code move only.<br>
<br>
Added:<br>
    cfe/trunk/lib/Parse/ParseStmtAsm.cpp<br>
Modified:<br>
    cfe/trunk/lib/Parse/CMakeLists.txt<br>
    cfe/trunk/lib/Parse/ParseStmt.cpp<br>
<br>
Modified: cfe/trunk/lib/Parse/CMakeLists.txt<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/CMakeLists.txt?rev=210420&r1=210419&r2=210420&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/CMakeLists.txt?rev=210420&r1=210419&r2=210420&view=diff</a><br>

==============================================================================<br>
--- cfe/trunk/lib/Parse/CMakeLists.txt (original)<br>
+++ cfe/trunk/lib/Parse/CMakeLists.txt Sun Jun  8 00:40:04 2014<br>
@@ -16,6 +16,7 @@ add_clang_library(clangParse<br>
   ParseOpenMP.cpp<br>
   ParsePragma.cpp<br>
   ParseStmt.cpp<br>
+  ParseStmtAsm.cpp<br>
   ParseTemplate.cpp<br>
   ParseTentative.cpp<br>
   Parser.cpp<br>
<br>
Modified: cfe/trunk/lib/Parse/ParseStmt.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseStmt.cpp?rev=210420&r1=210419&r2=210420&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseStmt.cpp?rev=210420&r1=210419&r2=210420&view=diff</a><br>

==============================================================================<br>
--- cfe/trunk/lib/Parse/ParseStmt.cpp (original)<br>
+++ cfe/trunk/lib/Parse/ParseStmt.cpp Sun Jun  8 00:40:04 2014<br>
@@ -18,28 +18,12 @@<br>
 #include "clang/Basic/Attributes.h"<br>
 #include "clang/Basic/Diagnostic.h"<br>
 #include "clang/Basic/PrettyStackTrace.h"<br>
-#include "clang/Basic/SourceManager.h"<br>
-#include "clang/Basic/TargetInfo.h"<br>
 #include "clang/Sema/DeclSpec.h"<br>
 #include "clang/Sema/LoopHint.h"<br>
 #include "clang/Sema/PrettyDeclStackTrace.h"<br>
 #include "clang/Sema/Scope.h"<br>
 #include "clang/Sema/TypoCorrection.h"<br>
 #include "llvm/ADT/SmallString.h"<br>
-#include "llvm/MC/MCAsmInfo.h"<br>
-#include "llvm/MC/MCContext.h"<br>
-#include "llvm/MC/MCInstPrinter.h"<br>
-#include "llvm/MC/MCInstrInfo.h"<br>
-#include "llvm/MC/MCObjectFileInfo.h"<br>
-#include "llvm/MC/MCParser/MCAsmParser.h"<br>
-#include "llvm/MC/MCRegisterInfo.h"<br>
-#include "llvm/MC/MCStreamer.h"<br>
-#include "llvm/MC/MCSubtargetInfo.h"<br>
-#include "llvm/MC/MCTargetAsmParser.h"<br>
-#include "llvm/MC/MCTargetOptions.h"<br>
-#include "llvm/Support/SourceMgr.h"<br>
-#include "llvm/Support/TargetRegistry.h"<br>
-#include "llvm/Support/TargetSelect.h"<br>
 using namespace clang;<br>
<br>
 //===----------------------------------------------------------------------===//<br>
@@ -1796,718 +1780,6 @@ StmtResult Parser::ParsePragmaLoopHint(S<br>
   return S;<br>
 }<br>
<br>
-namespace {<br>
-  class ClangAsmParserCallback : public llvm::MCAsmParserSemaCallback {<br>
-    Parser &TheParser;<br>
-    SourceLocation AsmLoc;<br>
-    StringRef AsmString;<br>
-<br>
-    /// The tokens we streamed into AsmString and handed off to MC.<br>
-    ArrayRef<Token> AsmToks;<br>
-<br>
-    /// The offset of each token in AsmToks within AsmString.<br>
-    ArrayRef<unsigned> AsmTokOffsets;<br>
-<br>
-  public:<br>
-    ClangAsmParserCallback(Parser &P, SourceLocation Loc,<br>
-                           StringRef AsmString,<br>
-                           ArrayRef<Token> Toks,<br>
-                           ArrayRef<unsigned> Offsets)<br>
-      : TheParser(P), AsmLoc(Loc), AsmString(AsmString),<br>
-        AsmToks(Toks), AsmTokOffsets(Offsets) {<br>
-      assert(AsmToks.size() == AsmTokOffsets.size());<br>
-    }<br>
-<br>
-    void *LookupInlineAsmIdentifier(StringRef &LineBuf,<br>
-                                    llvm::InlineAsmIdentifierInfo &Info,<br>
-                                    bool IsUnevaluatedContext) override {<br>
-      // Collect the desired tokens.<br>
-      SmallVector<Token, 16> LineToks;<br>
-      const Token *FirstOrigToken = nullptr;<br>
-      findTokensForString(LineBuf, LineToks, FirstOrigToken);<br>
-<br>
-      unsigned NumConsumedToks;<br>
-      ExprResult Result =<br>
-        TheParser.ParseMSAsmIdentifier(LineToks, NumConsumedToks, &Info,<br>
-                                       IsUnevaluatedContext);<br>
-<br>
-      // If we consumed the entire line, tell MC that.<br>
-      // Also do this if we consumed nothing as a way of reporting failure.<br>
-      if (NumConsumedToks == 0 || NumConsumedToks == LineToks.size()) {<br>
-        // By not modifying LineBuf, we're implicitly consuming it all.<br>
-<br>
-      // Otherwise, consume up to the original tokens.<br>
-      } else {<br>
-        assert(FirstOrigToken && "not using original tokens?");<br>
-<br>
-        // Since we're using original tokens, apply that offset.<br>
-        assert(FirstOrigToken[NumConsumedToks].getLocation()<br>
-                  == LineToks[NumConsumedToks].getLocation());<br>
-        unsigned FirstIndex = FirstOrigToken - AsmToks.begin();<br>
-        unsigned LastIndex = FirstIndex + NumConsumedToks - 1;<br>
-<br>
-        // The total length we've consumed is the relative offset<br>
-        // of the last token we consumed plus its length.<br>
-        unsigned TotalOffset = (AsmTokOffsets[LastIndex]<br>
-                                + AsmToks[LastIndex].getLength()<br>
-                                - AsmTokOffsets[FirstIndex]);<br>
-        LineBuf = LineBuf.substr(0, TotalOffset);<br>
-      }<br>
-<br>
-      // Initialize the "decl" with the lookup result.<br>
-      Info.OpDecl = static_cast<void*>(Result.get());<br>
-      return Info.OpDecl;<br>
-    }<br>
-<br>
-    bool LookupInlineAsmField(StringRef Base, StringRef Member,<br>
-                              unsigned &Offset) override {<br>
-      return TheParser.getActions().LookupInlineAsmField(Base, Member,<br>
-                                                         Offset, AsmLoc);<br>
-    }<br>
-<br>
-    static void DiagHandlerCallback(const llvm::SMDiagnostic &D,<br>
-                                    void *Context) {<br>
-      ((ClangAsmParserCallback*) Context)->handleDiagnostic(D);<br>
-    }<br>
-<br>
-  private:<br>
-    /// Collect the appropriate tokens for the given string.<br>
-    void findTokensForString(StringRef Str, SmallVectorImpl<Token> &TempToks,<br>
-                             const Token *&FirstOrigToken) const {<br>
-      // For now, assert that the string we're working with is a substring<br>
-      // of what we gave to MC.  This lets us use the original tokens.<br>
-      assert(!std::less<const char*>()(Str.begin(), AsmString.begin()) &&<br>
-             !std::less<const char*>()(AsmString.end(), Str.end()));<br>
-<br>
-      // Try to find a token whose offset matches the first token.<br>
-      unsigned FirstCharOffset = Str.begin() - AsmString.begin();<br>
-      const unsigned *FirstTokOffset<br>
-        = std::lower_bound(AsmTokOffsets.begin(), AsmTokOffsets.end(),<br>
-                           FirstCharOffset);<br>
-<br>
-      // For now, assert that the start of the string exactly<br>
-      // corresponds to the start of a token.<br>
-      assert(*FirstTokOffset == FirstCharOffset);<br>
-<br>
-      // Use all the original tokens for this line.  (We assume the<br>
-      // end of the line corresponds cleanly to a token break.)<br>
-      unsigned FirstTokIndex = FirstTokOffset - AsmTokOffsets.begin();<br>
-      FirstOrigToken = &AsmToks[FirstTokIndex];<br>
-      unsigned LastCharOffset = Str.end() - AsmString.begin();<br>
-      for (unsigned i = FirstTokIndex, e = AsmTokOffsets.size(); i != e; ++i) {<br>
-        if (AsmTokOffsets[i] >= LastCharOffset) break;<br>
-        TempToks.push_back(AsmToks[i]);<br>
-      }<br>
-    }<br>
-<br>
-    void handleDiagnostic(const llvm::SMDiagnostic &D) {<br>
-      // Compute an offset into the inline asm buffer.<br>
-      // FIXME: This isn't right if .macro is involved (but hopefully, no<br>
-      // real-world code does that).<br>
-      const llvm::SourceMgr &LSM = *D.getSourceMgr();<br>
-      const llvm::MemoryBuffer *LBuf =<br>
-        LSM.getMemoryBuffer(LSM.FindBufferContainingLoc(D.getLoc()));<br>
-      unsigned Offset = D.getLoc().getPointer() - LBuf->getBufferStart();<br>
-<br>
-      // Figure out which token that offset points into.<br>
-      const unsigned *TokOffsetPtr =<br>
-        std::lower_bound(AsmTokOffsets.begin(), AsmTokOffsets.end(), Offset);<br>
-      unsigned TokIndex = TokOffsetPtr - AsmTokOffsets.begin();<br>
-      unsigned TokOffset = *TokOffsetPtr;<br>
-<br>
-      // If we come up with an answer which seems sane, use it; otherwise,<br>
-      // just point at the __asm keyword.<br>
-      // FIXME: Assert the answer is sane once we handle .macro correctly.<br>
-      SourceLocation Loc = AsmLoc;<br>
-      if (TokIndex < AsmToks.size()) {<br>
-        const Token &Tok = AsmToks[TokIndex];<br>
-        Loc = Tok.getLocation();<br>
-        Loc = Loc.getLocWithOffset(Offset - TokOffset);<br>
-      }<br>
-      TheParser.Diag(Loc, diag::err_inline_ms_asm_parsing)<br>
-        << D.getMessage();<br>
-    }<br>
-  };<br>
-}<br>
-<br>
-/// Parse an identifier in an MS-style inline assembly block.<br>
-///<br>
-/// \param CastInfo - a void* so that we don't have to teach Parser.h<br>
-///   about the actual type.<br>
-ExprResult Parser::ParseMSAsmIdentifier(llvm::SmallVectorImpl<Token> &LineToks,<br>
-                                        unsigned &NumLineToksConsumed,<br>
-                                        void *CastInfo,<br>
-                                        bool IsUnevaluatedContext) {<br>
-  llvm::InlineAsmIdentifierInfo &Info =<br>
-    *(llvm::InlineAsmIdentifierInfo *) CastInfo;<br>
-<br>
-  // Push a fake token on the end so that we don't overrun the token<br>
-  // stream.  We use ';' because it expression-parsing should never<br>
-  // overrun it.<br>
-  const tok::TokenKind EndOfStream = tok::semi;<br>
-  Token EndOfStreamTok;<br>
-  EndOfStreamTok.startToken();<br>
-  EndOfStreamTok.setKind(EndOfStream);<br>
-  LineToks.push_back(EndOfStreamTok);<br>
-<br>
-  // Also copy the current token over.<br>
-  LineToks.push_back(Tok);<br>
-<br>
-  PP.EnterTokenStream(LineToks.begin(),<br>
-                      LineToks.size(),<br>
-                      /*disable macros*/ true,<br>
-                      /*owns tokens*/ false);<br>
-<br>
-  // Clear the current token and advance to the first token in LineToks.<br>
-  ConsumeAnyToken();<br>
-<br>
-  // Parse an optional scope-specifier if we're in C++.<br>
-  CXXScopeSpec SS;<br>
-  if (getLangOpts().CPlusPlus) {<br>
-    ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false);<br>
-  }<br>
-<br>
-  // Require an identifier here.<br>
-  SourceLocation TemplateKWLoc;<br>
-  UnqualifiedId Id;<br>
-  bool Invalid = ParseUnqualifiedId(SS,<br>
-                                    /*EnteringContext=*/false,<br>
-                                    /*AllowDestructorName=*/false,<br>
-                                    /*AllowConstructorName=*/false,<br>
-                                    /*ObjectType=*/ ParsedType(),<br>
-                                    TemplateKWLoc,<br>
-                                    Id);<br>
-<br>
-  // Figure out how many tokens we are into LineToks.<br>
-  unsigned LineIndex = 0;<br>
-  if (Tok.is(EndOfStream)) {<br>
-    LineIndex = LineToks.size() - 2;<br>
-  } else {<br>
-    while (LineToks[LineIndex].getLocation() != Tok.getLocation()) {<br>
-      LineIndex++;<br>
-      assert(LineIndex < LineToks.size() - 2); // we added two extra tokens<br>
-    }<br>
-  }<br>
-<br>
-  // If we've run into the poison token we inserted before, or there<br>
-  // was a parsing error, then claim the entire line.<br>
-  if (Invalid || Tok.is(EndOfStream)) {<br>
-    NumLineToksConsumed = LineToks.size() - 2;<br>
-  } else {<br>
-    // Otherwise, claim up to the start of the next token.<br>
-    NumLineToksConsumed = LineIndex;<br>
-  }<br>
-<br>
-  // Finally, restore the old parsing state by consuming all the tokens we<br>
-  // staged before, implicitly killing off the token-lexer we pushed.<br>
-  for (unsigned i = 0, e = LineToks.size() - LineIndex - 2; i != e; ++i) {<br>
-    ConsumeAnyToken();<br>
-  }<br>
-  assert(Tok.is(EndOfStream));<br>
-  ConsumeToken();<br>
-<br>
-  // Leave LineToks in its original state.<br>
-  LineToks.pop_back();<br>
-  LineToks.pop_back();<br>
-<br>
-  // Perform the lookup.<br>
-  return Actions.LookupInlineAsmIdentifier(SS, TemplateKWLoc, Id, Info,<br>
-                                           IsUnevaluatedContext);<br>
-}<br>
-<br>
-/// Turn a sequence of our tokens back into a string that we can hand<br>
-/// to the MC asm parser.<br>
-static bool buildMSAsmString(Preprocessor &PP,<br>
-                             SourceLocation AsmLoc,<br>
-                             ArrayRef<Token> AsmToks,<br>
-                             SmallVectorImpl<unsigned> &TokOffsets,<br>
-                             SmallString<512> &Asm) {<br>
-  assert (!AsmToks.empty() && "Didn't expect an empty AsmToks!");<br>
-<br>
-  // Is this the start of a new assembly statement?<br>
-  bool isNewStatement = true;<br>
-<br>
-  for (unsigned i = 0, e = AsmToks.size(); i < e; ++i) {<br>
-    const Token &Tok = AsmToks[i];<br>
-<br>
-    // Start each new statement with a newline and a tab.<br>
-    if (!isNewStatement &&<br>
-        (Tok.is(tok::kw_asm) || Tok.isAtStartOfLine())) {<br>
-      Asm += "\n\t";<br>
-      isNewStatement = true;<br>
-    }<br>
-<br>
-    // Preserve the existence of leading whitespace except at the<br>
-    // start of a statement.<br>
-    if (!isNewStatement && Tok.hasLeadingSpace())<br>
-      Asm += ' ';<br>
-<br>
-    // Remember the offset of this token.<br>
-    TokOffsets.push_back(Asm.size());<br>
-<br>
-    // Don't actually write '__asm' into the assembly stream.<br>
-    if (Tok.is(tok::kw_asm)) {<br>
-      // Complain about __asm at the end of the stream.<br>
-      if (i + 1 == e) {<br>
-        PP.Diag(AsmLoc, diag::err_asm_empty);<br>
-        return true;<br>
-      }<br>
-<br>
-      continue;<br>
-    }<br>
-<br>
-    // Append the spelling of the token.<br>
-    SmallString<32> SpellingBuffer;<br>
-    bool SpellingInvalid = false;<br>
-    Asm += PP.getSpelling(Tok, SpellingBuffer, &SpellingInvalid);<br>
-    assert(!SpellingInvalid && "spelling was invalid after correct parse?");<br>
-<br>
-    // We are no longer at the start of a statement.<br>
-    isNewStatement = false;<br>
-  }<br>
-<br>
-  // Ensure that the buffer is null-terminated.<br>
-  Asm.push_back('\0');<br>
-  Asm.pop_back();<br>
-<br>
-  assert(TokOffsets.size() == AsmToks.size());<br>
-  return false;<br>
-}<br>
-<br>
-/// ParseMicrosoftAsmStatement. When -fms-extensions/-fasm-blocks is enabled,<br>
-/// this routine is called to collect the tokens for an MS asm statement.<br>
-///<br>
-/// [MS]  ms-asm-statement:<br>
-///         ms-asm-block<br>
-///         ms-asm-block ms-asm-statement<br>
-///<br>
-/// [MS]  ms-asm-block:<br>
-///         '__asm' ms-asm-line '\n'<br>
-///         '__asm' '{' ms-asm-instruction-block[opt] '}' ';'[opt]<br>
-///<br>
-/// [MS]  ms-asm-instruction-block<br>
-///         ms-asm-line<br>
-///         ms-asm-line '\n' ms-asm-instruction-block<br>
-///<br>
-StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) {<br>
-  SourceManager &SrcMgr = PP.getSourceManager();<br>
-  SourceLocation EndLoc = AsmLoc;<br>
-  SmallVector<Token, 4> AsmToks;<br>
-<br>
-  bool InBraces = false;<br>
-  unsigned short savedBraceCount = 0;<br>
-  bool InAsmComment = false;<br>
-  FileID FID;<br>
-  unsigned LineNo = 0;<br>
-  unsigned NumTokensRead = 0;<br>
-  SourceLocation LBraceLoc;<br>
-<br>
-  if (Tok.is(tok::l_brace)) {<br>
-    // Braced inline asm: consume the opening brace.<br>
-    InBraces = true;<br>
-    savedBraceCount = BraceCount;<br>
-    EndLoc = LBraceLoc = ConsumeBrace();<br>
-    ++NumTokensRead;<br>
-  } else {<br>
-    // Single-line inline asm; compute which line it is on.<br>
-    std::pair<FileID, unsigned> ExpAsmLoc =<br>
-      SrcMgr.getDecomposedExpansionLoc(EndLoc);<br>
-    FID = ExpAsmLoc.first;<br>
-    LineNo = SrcMgr.getLineNumber(FID, ExpAsmLoc.second);<br>
-  }<br>
-<br>
-  SourceLocation TokLoc = Tok.getLocation();<br>
-  do {<br>
-    // If we hit EOF, we're done, period.<br>
-    if (isEofOrEom())<br>
-      break;<br>
-<br>
-    if (!InAsmComment && Tok.is(tok::semi)) {<br>
-      // A semicolon in an asm is the start of a comment.<br>
-      InAsmComment = true;<br>
-      if (InBraces) {<br>
-        // Compute which line the comment is on.<br>
-        std::pair<FileID, unsigned> ExpSemiLoc =<br>
-          SrcMgr.getDecomposedExpansionLoc(TokLoc);<br>
-        FID = ExpSemiLoc.first;<br>
-        LineNo = SrcMgr.getLineNumber(FID, ExpSemiLoc.second);<br>
-      }<br>
-    } else if (!InBraces || InAsmComment) {<br>
-      // If end-of-line is significant, check whether this token is on a<br>
-      // new line.<br>
-      std::pair<FileID, unsigned> ExpLoc =<br>
-        SrcMgr.getDecomposedExpansionLoc(TokLoc);<br>
-      if (ExpLoc.first != FID ||<br>
-          SrcMgr.getLineNumber(ExpLoc.first, ExpLoc.second) != LineNo) {<br>
-        // If this is a single-line __asm, we're done.<br>
-        if (!InBraces)<br>
-          break;<br>
-        // We're no longer in a comment.<br>
-        InAsmComment = false;<br>
-      } else if (!InAsmComment && Tok.is(tok::r_brace)) {<br>
-        // Single-line asm always ends when a closing brace is seen.<br>
-        // FIXME: This is compatible with Apple gcc's -fasm-blocks; what<br>
-        // does MSVC do here?<br>
-        break;<br>
-      }<br>
-    }<br>
-    if (!InAsmComment && InBraces && Tok.is(tok::r_brace) &&<br>
-        BraceCount == (savedBraceCount + 1)) {<br>
-      // Consume the closing brace, and finish<br>
-      EndLoc = ConsumeBrace();<br>
-      break;<br>
-    }<br>
-<br>
-    // Consume the next token; make sure we don't modify the brace count etc.<br>
-    // if we are in a comment.<br>
-    EndLoc = TokLoc;<br>
-    if (InAsmComment)<br>
-      PP.Lex(Tok);<br>
-    else {<br>
-      AsmToks.push_back(Tok);<br>
-      ConsumeAnyToken();<br>
-    }<br>
-    TokLoc = Tok.getLocation();<br>
-    ++NumTokensRead;<br>
-  } while (1);<br>
-<br>
-  if (InBraces && BraceCount != savedBraceCount) {<br>
-    // __asm without closing brace (this can happen at EOF).<br>
-    Diag(Tok, diag::err_expected) << tok::r_brace;<br>
-    Diag(LBraceLoc, diag::note_matching) << tok::l_brace;<br>
-    return StmtError();<br>
-  } else if (NumTokensRead == 0) {<br>
-    // Empty __asm.<br>
-    Diag(Tok, diag::err_expected) << tok::l_brace;<br>
-    return StmtError();<br>
-  }<br>
-<br>
-  // Okay, prepare to use MC to parse the assembly.<br>
-  SmallVector<StringRef, 4> ConstraintRefs;<br>
-  SmallVector<Expr*, 4> Exprs;<br>
-  SmallVector<StringRef, 4> ClobberRefs;<br>
-<br>
-  // We need an actual supported target.<br>
-  const llvm::Triple &TheTriple = Actions.Context.getTargetInfo().getTriple();<br>
-  llvm::Triple::ArchType ArchTy = TheTriple.getArch();<br>
-  const std::string &TT = TheTriple.getTriple();<br>
-  const llvm::Target *TheTarget = nullptr;<br>
-  bool UnsupportedArch = (ArchTy != llvm::Triple::x86 &&<br>
-                          ArchTy != llvm::Triple::x86_64);<br>
-  if (UnsupportedArch) {<br>
-    Diag(AsmLoc, diag::err_msasm_unsupported_arch) << TheTriple.getArchName();<br>
-  } else {<br>
-    std::string Error;<br>
-    TheTarget = llvm::TargetRegistry::lookupTarget(TT, Error);<br>
-    if (!TheTarget)<br>
-      Diag(AsmLoc, diag::err_msasm_unable_to_create_target) << Error;<br>
-  }<br>
-<br>
-  // If we don't support assembly, or the assembly is empty, we don't<br>
-  // need to instantiate the AsmParser, etc.<br>
-  if (!TheTarget || AsmToks.empty()) {<br>
-    return Actions.ActOnMSAsmStmt(AsmLoc, LBraceLoc, AsmToks, StringRef(),<br>
-                                  /*NumOutputs*/ 0, /*NumInputs*/ 0,<br>
-                                  ConstraintRefs, ClobberRefs, Exprs, EndLoc);<br>
-  }<br>
-<br>
-  // Expand the tokens into a string buffer.<br>
-  SmallString<512> AsmString;<br>
-  SmallVector<unsigned, 8> TokOffsets;<br>
-  if (buildMSAsmString(PP, AsmLoc, AsmToks, TokOffsets, AsmString))<br>
-    return StmtError();<br>
-<br>
-  std::unique_ptr<llvm::MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TT));<br>
-  std::unique_ptr<llvm::MCAsmInfo> MAI(TheTarget->createMCAsmInfo(*MRI, TT));<br>
-  // Get the instruction descriptor.<br>
-  std::unique_ptr<llvm::MCInstrInfo> MII(TheTarget->createMCInstrInfo());<br>
-  std::unique_ptr<llvm::MCObjectFileInfo> MOFI(new llvm::MCObjectFileInfo());<br>
-  std::unique_ptr<llvm::MCSubtargetInfo> STI(<br>
-      TheTarget->createMCSubtargetInfo(TT, "", ""));<br>
-<br>
-  llvm::SourceMgr TempSrcMgr;<br>
-  llvm::MCContext Ctx(MAI.get(), MRI.get(), MOFI.get(), &TempSrcMgr);<br>
-  llvm::MemoryBuffer *Buffer =<br>
-    llvm::MemoryBuffer::getMemBuffer(AsmString, "<MS inline asm>");<br>
-<br>
-  // Tell SrcMgr about this buffer, which is what the parser will pick up.<br>
-  TempSrcMgr.AddNewSourceBuffer(Buffer, llvm::SMLoc());<br>
-<br>
-  std::unique_ptr<llvm::MCStreamer> Str(createNullStreamer(Ctx));<br>
-  std::unique_ptr<llvm::MCAsmParser> Parser(<br>
-      createMCAsmParser(TempSrcMgr, Ctx, *Str.get(), *MAI));<br>
-<br>
-  // FIXME: init MCOptions from sanitizer flags here.<br>
-  llvm::MCTargetOptions MCOptions;<br>
-  std::unique_ptr<llvm::MCTargetAsmParser> TargetParser(<br>
-      TheTarget->createMCAsmParser(*STI, *Parser, *MII, MCOptions));<br>
-<br>
-  std::unique_ptr<llvm::MCInstPrinter> IP(<br>
-      TheTarget->createMCInstPrinter(1, *MAI, *MII, *MRI, *STI));<br>
-<br>
-  // Change to the Intel dialect.<br>
-  Parser->setAssemblerDialect(1);<br>
-  Parser->setTargetParser(*TargetParser.get());<br>
-  Parser->setParsingInlineAsm(true);<br>
-  TargetParser->setParsingInlineAsm(true);<br>
-<br>
-  ClangAsmParserCallback Callback(*this, AsmLoc, AsmString,<br>
-                                  AsmToks, TokOffsets);<br>
-  TargetParser->setSemaCallback(&Callback);<br>
-  TempSrcMgr.setDiagHandler(ClangAsmParserCallback::DiagHandlerCallback,<br>
-                            &Callback);<br>
-<br>
-  unsigned NumOutputs;<br>
-  unsigned NumInputs;<br>
-  std::string AsmStringIR;<br>
-  SmallVector<std::pair<void *, bool>, 4> OpExprs;<br>
-  SmallVector<std::string, 4> Constraints;<br>
-  SmallVector<std::string, 4> Clobbers;<br>
-  if (Parser->parseMSInlineAsm(AsmLoc.getPtrEncoding(), AsmStringIR,<br>
-                               NumOutputs, NumInputs, OpExprs, Constraints,<br>
-                               Clobbers, MII.get(), IP.get(), Callback))<br>
-    return StmtError();<br>
-<br>
-  // Filter out "fpsw".  Clang doesn't accept it, and it always lists flags and<br>
-  // fpsr as clobbers.<br>
-  auto End = std::remove(Clobbers.begin(), Clobbers.end(), "fpsw");<br>
-  Clobbers.erase(End, Clobbers.end());<br>
-<br>
-  // Build the vector of clobber StringRefs.<br>
-  unsigned NumClobbers = Clobbers.size();<br>
-  ClobberRefs.resize(NumClobbers);<br>
-  for (unsigned i = 0; i != NumClobbers; ++i)<br>
-    ClobberRefs[i] = StringRef(Clobbers[i]);<br>
-<br>
-  // Recast the void pointers and build the vector of constraint StringRefs.<br>
-  unsigned NumExprs = NumOutputs + NumInputs;<br>
-  ConstraintRefs.resize(NumExprs);<br>
-  Exprs.resize(NumExprs);<br>
-  for (unsigned i = 0, e = NumExprs; i != e; ++i) {<br>
-    Expr *OpExpr = static_cast<Expr *>(OpExprs[i].first);<br>
-    if (!OpExpr)<br>
-      return StmtError();<br>
-<br>
-    // Need address of variable.<br>
-    if (OpExprs[i].second)<br>
-      OpExpr = Actions.BuildUnaryOp(getCurScope(), AsmLoc, UO_AddrOf, OpExpr)<br>
-        .get();<br>
-<br>
-    ConstraintRefs[i] = StringRef(Constraints[i]);<br>
-    Exprs[i] = OpExpr;<br>
-  }<br>
-<br>
-  // FIXME: We should be passing source locations for better diagnostics.<br>
-  return Actions.ActOnMSAsmStmt(AsmLoc, LBraceLoc, AsmToks, AsmStringIR,<br>
-                                NumOutputs, NumInputs,<br>
-                                ConstraintRefs, ClobberRefs, Exprs, EndLoc);<br>
-}<br>
-<br>
-/// ParseAsmStatement - Parse a GNU extended asm statement.<br>
-///       asm-statement:<br>
-///         gnu-asm-statement<br>
-///         ms-asm-statement<br>
-///<br>
-/// [GNU] gnu-asm-statement:<br>
-///         'asm' type-qualifier[opt] '(' asm-argument ')' ';'<br>
-///<br>
-/// [GNU] asm-argument:<br>
-///         asm-string-literal<br>
-///         asm-string-literal ':' asm-operands[opt]<br>
-///         asm-string-literal ':' asm-operands[opt] ':' asm-operands[opt]<br>
-///         asm-string-literal ':' asm-operands[opt] ':' asm-operands[opt]<br>
-///                 ':' asm-clobbers<br>
-///<br>
-/// [GNU] asm-clobbers:<br>
-///         asm-string-literal<br>
-///         asm-clobbers ',' asm-string-literal<br>
-///<br>
-StmtResult Parser::ParseAsmStatement(bool &msAsm) {<br>
-  assert(Tok.is(tok::kw_asm) && "Not an asm stmt");<br>
-  SourceLocation AsmLoc = ConsumeToken();<br>
-<br>
-  if (getLangOpts().AsmBlocks && Tok.isNot(tok::l_paren) &&<br>
-      !isTypeQualifier()) {<br>
-    msAsm = true;<br>
-    return ParseMicrosoftAsmStatement(AsmLoc);<br>
-  }<br>
-  DeclSpec DS(AttrFactory);<br>
-  SourceLocation Loc = Tok.getLocation();<br>
-  ParseTypeQualifierListOpt(DS, true, false);<br>
-<br>
-  // GNU asms accept, but warn, about type-qualifiers other than volatile.<br>
-  if (DS.getTypeQualifiers() & DeclSpec::TQ_const)<br>
-    Diag(Loc, diag::w_asm_qualifier_ignored) << "const";<br>
-  if (DS.getTypeQualifiers() & DeclSpec::TQ_restrict)<br>
-    Diag(Loc, diag::w_asm_qualifier_ignored) << "restrict";<br>
-  // FIXME: Once GCC supports _Atomic, check whether it permits it here.<br>
-  if (DS.getTypeQualifiers() & DeclSpec::TQ_atomic)<br>
-    Diag(Loc, diag::w_asm_qualifier_ignored) << "_Atomic";<br>
-<br>
-  // Remember if this was a volatile asm.<br>
-  bool isVolatile = DS.getTypeQualifiers() & DeclSpec::TQ_volatile;<br>
-  if (Tok.isNot(tok::l_paren)) {<br>
-    Diag(Tok, diag::err_expected_lparen_after) << "asm";<br>
-    SkipUntil(tok::r_paren, StopAtSemi);<br>
-    return StmtError();<br>
-  }<br>
-  BalancedDelimiterTracker T(*this, tok::l_paren);<br>
-  T.consumeOpen();<br>
-<br>
-  ExprResult AsmString(ParseAsmStringLiteral());<br>
-  if (AsmString.isInvalid()) {<br>
-    // Consume up to and including the closing paren.<br>
-    T.skipToEnd();<br>
-    return StmtError();<br>
-  }<br>
-<br>
-  SmallVector<IdentifierInfo *, 4> Names;<br>
-  ExprVector Constraints;<br>
-  ExprVector Exprs;<br>
-  ExprVector Clobbers;<br>
-<br>
-  if (Tok.is(tok::r_paren)) {<br>
-    // We have a simple asm expression like 'asm("foo")'.<br>
-    T.consumeClose();<br>
-    return Actions.ActOnGCCAsmStmt(AsmLoc, /*isSimple*/ true, isVolatile,<br>
-                                   /*NumOutputs*/ 0, /*NumInputs*/ 0, nullptr,<br>
-                                   Constraints, Exprs, AsmString.get(),<br>
-                                   Clobbers, T.getCloseLocation());<br>
-  }<br>
-<br>
-  // Parse Outputs, if present.<br>
-  bool AteExtraColon = false;<br>
-  if (Tok.is(tok::colon) || Tok.is(tok::coloncolon)) {<br>
-    // In C++ mode, parse "::" like ": :".<br>
-    AteExtraColon = Tok.is(tok::coloncolon);<br>
-    ConsumeToken();<br>
-<br>
-    if (!AteExtraColon &&<br>
-        ParseAsmOperandsOpt(Names, Constraints, Exprs))<br>
-      return StmtError();<br>
-  }<br>
-<br>
-  unsigned NumOutputs = Names.size();<br>
-<br>
-  // Parse Inputs, if present.<br>
-  if (AteExtraColon ||<br>
-      Tok.is(tok::colon) || Tok.is(tok::coloncolon)) {<br>
-    // In C++ mode, parse "::" like ": :".<br>
-    if (AteExtraColon)<br>
-      AteExtraColon = false;<br>
-    else {<br>
-      AteExtraColon = Tok.is(tok::coloncolon);<br>
-      ConsumeToken();<br>
-    }<br>
-<br>
-    if (!AteExtraColon &&<br>
-        ParseAsmOperandsOpt(Names, Constraints, Exprs))<br>
-      return StmtError();<br>
-  }<br>
-<br>
-  assert(Names.size() == Constraints.size() &&<br>
-         Constraints.size() == Exprs.size() &&<br>
-         "Input operand size mismatch!");<br>
-<br>
-  unsigned NumInputs = Names.size() - NumOutputs;<br>
-<br>
-  // Parse the clobbers, if present.<br>
-  if (AteExtraColon || Tok.is(tok::colon)) {<br>
-    if (!AteExtraColon)<br>
-      ConsumeToken();<br>
-<br>
-    // Parse the asm-string list for clobbers if present.<br>
-    if (Tok.isNot(tok::r_paren)) {<br>
-      while (1) {<br>
-        ExprResult Clobber(ParseAsmStringLiteral());<br>
-<br>
-        if (Clobber.isInvalid())<br>
-          break;<br>
-<br>
-        Clobbers.push_back(Clobber.get());<br>
-<br>
-        if (!TryConsumeToken(tok::comma))<br>
-          break;<br>
-      }<br>
-    }<br>
-  }<br>
-<br>
-  T.consumeClose();<br>
-  return Actions.ActOnGCCAsmStmt(AsmLoc, false, isVolatile, NumOutputs,<br>
-                                 NumInputs, Names.data(), Constraints, Exprs,<br>
-                                 AsmString.get(), Clobbers,<br>
-                                 T.getCloseLocation());<br>
-}<br>
-<br>
-/// ParseAsmOperands - Parse the asm-operands production as used by<br>
-/// asm-statement, assuming the leading ':' token was eaten.<br>
-///<br>
-/// [GNU] asm-operands:<br>
-///         asm-operand<br>
-///         asm-operands ',' asm-operand<br>
-///<br>
-/// [GNU] asm-operand:<br>
-///         asm-string-literal '(' expression ')'<br>
-///         '[' identifier ']' asm-string-literal '(' expression ')'<br>
-///<br>
-//<br>
-// FIXME: Avoid unnecessary std::string trashing.<br>
-bool Parser::ParseAsmOperandsOpt(SmallVectorImpl<IdentifierInfo *> &Names,<br>
-                                 SmallVectorImpl<Expr *> &Constraints,<br>
-                                 SmallVectorImpl<Expr *> &Exprs) {<br>
-  // 'asm-operands' isn't present?<br>
-  if (!isTokenStringLiteral() && Tok.isNot(tok::l_square))<br>
-    return false;<br>
-<br>
-  while (1) {<br>
-    // Read the [id] if present.<br>
-    if (Tok.is(tok::l_square)) {<br>
-      BalancedDelimiterTracker T(*this, tok::l_square);<br>
-      T.consumeOpen();<br>
-<br>
-      if (Tok.isNot(tok::identifier)) {<br>
-        Diag(Tok, diag::err_expected) << tok::identifier;<br>
-        SkipUntil(tok::r_paren, StopAtSemi);<br>
-        return true;<br>
-      }<br>
-<br>
-      IdentifierInfo *II = Tok.getIdentifierInfo();<br>
-      ConsumeToken();<br>
-<br>
-      Names.push_back(II);<br>
-      T.consumeClose();<br>
-    } else<br>
-      Names.push_back(nullptr);<br>
-<br>
-    ExprResult Constraint(ParseAsmStringLiteral());<br>
-    if (Constraint.isInvalid()) {<br>
-        SkipUntil(tok::r_paren, StopAtSemi);<br>
-        return true;<br>
-    }<br>
-    Constraints.push_back(Constraint.get());<br>
-<br>
-    if (Tok.isNot(tok::l_paren)) {<br>
-      Diag(Tok, diag::err_expected_lparen_after) << "asm operand";<br>
-      SkipUntil(tok::r_paren, StopAtSemi);<br>
-      return true;<br>
-    }<br>
-<br>
-    // Read the parenthesized expression.<br>
-    BalancedDelimiterTracker T(*this, tok::l_paren);<br>
-    T.consumeOpen();<br>
-    ExprResult Res(ParseExpression());<br>
-    T.consumeClose();<br>
-    if (Res.isInvalid()) {<br>
-      SkipUntil(tok::r_paren, StopAtSemi);<br>
-      return true;<br>
-    }<br>
-    Exprs.push_back(Res.get());<br>
-    // Eat the comma and continue parsing if it exists.<br>
-    if (!TryConsumeToken(tok::comma))<br>
-      return false;<br>
-  }<br>
-}<br>
-<br>
 Decl *Parser::ParseFunctionStatementBody(Decl *Decl, ParseScope &BodyScope) {<br>
   assert(Tok.is(tok::l_brace));<br>
   SourceLocation LBraceLoc = Tok.getLocation();<br>
<br>
Added: cfe/trunk/lib/Parse/ParseStmtAsm.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseStmtAsm.cpp?rev=210420&view=auto" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseStmtAsm.cpp?rev=210420&view=auto</a><br>

==============================================================================<br>
--- cfe/trunk/lib/Parse/ParseStmtAsm.cpp (added)<br>
+++ cfe/trunk/lib/Parse/ParseStmtAsm.cpp Sun Jun  8 00:40:04 2014<br>
@@ -0,0 +1,732 @@<br>
+//===---- ParseStmtAsm.cpp - Assembly Statement Parser --------------------===//<br>
+//<br>
+//                     The LLVM Compiler Infrastructure<br>
+//<br>
+// This file is distributed under the University of Illinois Open Source<br>
+// License. See LICENSE.TXT for details.<br>
+//<br>
+//===----------------------------------------------------------------------===//<br>
+//<br>
+// This file implements parsing for GCC and Microsoft inline assembly.<br>
+//<br>
+//===----------------------------------------------------------------------===//<br>
+<br>
+#include "clang/Parse/Parser.h"<br>
+#include "RAIIObjectsForParser.h"<br>
+#include "clang/AST/ASTContext.h"<br>
+#include "clang/Basic/Diagnostic.h"<br>
+#include "clang/Basic/TargetInfo.h"<br>
+#include "llvm/ADT/SmallString.h"<br>
+#include "llvm/MC/MCAsmInfo.h"<br>
+#include "llvm/MC/MCContext.h"<br>
+#include "llvm/MC/MCInstPrinter.h"<br>
+#include "llvm/MC/MCInstrInfo.h"<br>
+#include "llvm/MC/MCObjectFileInfo.h"<br>
+#include "llvm/MC/MCParser/MCAsmParser.h"<br>
+#include "llvm/MC/MCRegisterInfo.h"<br>
+#include "llvm/MC/MCStreamer.h"<br>
+#include "llvm/MC/MCSubtargetInfo.h"<br>
+#include "llvm/MC/MCTargetAsmParser.h"<br>
+#include "llvm/MC/MCTargetOptions.h"<br>
+#include "llvm/Support/SourceMgr.h"<br>
+#include "llvm/Support/TargetRegistry.h"<br>
+#include "llvm/Support/TargetSelect.h"<br>
+using namespace clang;<br>
+<br>
+namespace {<br>
+class ClangAsmParserCallback : public llvm::MCAsmParserSemaCallback {<br>
+  Parser &TheParser;<br>
+  SourceLocation AsmLoc;<br>
+  StringRef AsmString;<br>
+<br>
+  /// The tokens we streamed into AsmString and handed off to MC.<br>
+  ArrayRef<Token> AsmToks;<br>
+<br>
+  /// The offset of each token in AsmToks within AsmString.<br>
+  ArrayRef<unsigned> AsmTokOffsets;<br>
+<br>
+public:<br>
+  ClangAsmParserCallback(Parser &P, SourceLocation Loc, StringRef AsmString,<br>
+                         ArrayRef<Token> Toks, ArrayRef<unsigned> Offsets)<br>
+      : TheParser(P), AsmLoc(Loc), AsmString(AsmString), AsmToks(Toks),<br>
+        AsmTokOffsets(Offsets) {<br>
+    assert(AsmToks.size() == AsmTokOffsets.size());<br>
+  }<br>
+<br>
+  void *LookupInlineAsmIdentifier(StringRef &LineBuf,<br>
+                                  llvm::InlineAsmIdentifierInfo &Info,<br>
+                                  bool IsUnevaluatedContext) override {<br>
+    // Collect the desired tokens.<br>
+    SmallVector<Token, 16> LineToks;<br>
+    const Token *FirstOrigToken = nullptr;<br>
+    findTokensForString(LineBuf, LineToks, FirstOrigToken);<br>
+<br>
+    unsigned NumConsumedToks;<br>
+    ExprResult Result = TheParser.ParseMSAsmIdentifier(<br>
+        LineToks, NumConsumedToks, &Info, IsUnevaluatedContext);<br>
+<br>
+    // If we consumed the entire line, tell MC that.<br>
+    // Also do this if we consumed nothing as a way of reporting failure.<br>
+    if (NumConsumedToks == 0 || NumConsumedToks == LineToks.size()) {<br>
+      // By not modifying LineBuf, we're implicitly consuming it all.<br>
+<br>
+      // Otherwise, consume up to the original tokens.<br>
+    } else {<br>
+      assert(FirstOrigToken && "not using original tokens?");<br>
+<br>
+      // Since we're using original tokens, apply that offset.<br>
+      assert(FirstOrigToken[NumConsumedToks].getLocation() ==<br>
+             LineToks[NumConsumedToks].getLocation());<br>
+      unsigned FirstIndex = FirstOrigToken - AsmToks.begin();<br>
+      unsigned LastIndex = FirstIndex + NumConsumedToks - 1;<br>
+<br>
+      // The total length we've consumed is the relative offset<br>
+      // of the last token we consumed plus its length.<br>
+      unsigned TotalOffset =<br>
+          (AsmTokOffsets[LastIndex] + AsmToks[LastIndex].getLength() -<br>
+           AsmTokOffsets[FirstIndex]);<br>
+      LineBuf = LineBuf.substr(0, TotalOffset);<br>
+    }<br>
+<br>
+    // Initialize the "decl" with the lookup result.<br>
+    Info.OpDecl = static_cast<void *>(Result.get());<br>
+    return Info.OpDecl;<br>
+  }<br>
+<br>
+  bool LookupInlineAsmField(StringRef Base, StringRef Member,<br>
+                            unsigned &Offset) override {<br>
+    return TheParser.getActions().LookupInlineAsmField(Base, Member, Offset,<br>
+                                                       AsmLoc);<br>
+  }<br>
+<br>
+  static void DiagHandlerCallback(const llvm::SMDiagnostic &D, void *Context) {<br>
+    ((ClangAsmParserCallback *)Context)->handleDiagnostic(D);<br>
+  }<br>
+<br>
+private:<br>
+  /// Collect the appropriate tokens for the given string.<br>
+  void findTokensForString(StringRef Str, SmallVectorImpl<Token> &TempToks,<br>
+                           const Token *&FirstOrigToken) const {<br>
+    // For now, assert that the string we're working with is a substring<br>
+    // of what we gave to MC.  This lets us use the original tokens.<br>
+    assert(!std::less<const char *>()(Str.begin(), AsmString.begin()) &&<br>
+           !std::less<const char *>()(AsmString.end(), Str.end()));<br>
+<br>
+    // Try to find a token whose offset matches the first token.<br>
+    unsigned FirstCharOffset = Str.begin() - AsmString.begin();<br>
+    const unsigned *FirstTokOffset = std::lower_bound(<br>
+        AsmTokOffsets.begin(), AsmTokOffsets.end(), FirstCharOffset);<br>
+<br>
+    // For now, assert that the start of the string exactly<br>
+    // corresponds to the start of a token.<br>
+    assert(*FirstTokOffset == FirstCharOffset);<br>
+<br>
+    // Use all the original tokens for this line.  (We assume the<br>
+    // end of the line corresponds cleanly to a token break.)<br>
+    unsigned FirstTokIndex = FirstTokOffset - AsmTokOffsets.begin();<br>
+    FirstOrigToken = &AsmToks[FirstTokIndex];<br>
+    unsigned LastCharOffset = Str.end() - AsmString.begin();<br>
+    for (unsigned i = FirstTokIndex, e = AsmTokOffsets.size(); i != e; ++i) {<br>
+      if (AsmTokOffsets[i] >= LastCharOffset)<br>
+        break;<br>
+      TempToks.push_back(AsmToks[i]);<br>
+    }<br>
+  }<br>
+<br>
+  void handleDiagnostic(const llvm::SMDiagnostic &D) {<br>
+    // Compute an offset into the inline asm buffer.<br>
+    // FIXME: This isn't right if .macro is involved (but hopefully, no<br>
+    // real-world code does that).<br>
+    const llvm::SourceMgr &LSM = *D.getSourceMgr();<br>
+    const llvm::MemoryBuffer *LBuf =<br>
+        LSM.getMemoryBuffer(LSM.FindBufferContainingLoc(D.getLoc()));<br>
+    unsigned Offset = D.getLoc().getPointer() - LBuf->getBufferStart();<br>
+<br>
+    // Figure out which token that offset points into.<br>
+    const unsigned *TokOffsetPtr =<br>
+        std::lower_bound(AsmTokOffsets.begin(), AsmTokOffsets.end(), Offset);<br>
+    unsigned TokIndex = TokOffsetPtr - AsmTokOffsets.begin();<br>
+    unsigned TokOffset = *TokOffsetPtr;<br>
+<br>
+    // If we come up with an answer which seems sane, use it; otherwise,<br>
+    // just point at the __asm keyword.<br>
+    // FIXME: Assert the answer is sane once we handle .macro correctly.<br>
+    SourceLocation Loc = AsmLoc;<br>
+    if (TokIndex < AsmToks.size()) {<br>
+      const Token &Tok = AsmToks[TokIndex];<br>
+      Loc = Tok.getLocation();<br>
+      Loc = Loc.getLocWithOffset(Offset - TokOffset);<br>
+    }<br>
+    TheParser.Diag(Loc, diag::err_inline_ms_asm_parsing) << D.getMessage();<br>
+  }<br>
+};<br>
+}<br>
+<br>
+/// Parse an identifier in an MS-style inline assembly block.<br>
+///<br>
+/// \param CastInfo - a void* so that we don't have to teach Parser.h<br>
+///   about the actual type.<br>
+ExprResult Parser::ParseMSAsmIdentifier(llvm::SmallVectorImpl<Token> &LineToks,<br>
+                                        unsigned &NumLineToksConsumed,<br>
+                                        void *CastInfo,<br>
+                                        bool IsUnevaluatedContext) {<br>
+  llvm::InlineAsmIdentifierInfo &Info =<br>
+      *(llvm::InlineAsmIdentifierInfo *)CastInfo;<br>
+<br>
+  // Push a fake token on the end so that we don't overrun the token<br>
+  // stream.  We use ';' because it expression-parsing should never<br>
+  // overrun it.<br>
+  const tok::TokenKind EndOfStream = tok::semi;<br>
+  Token EndOfStreamTok;<br>
+  EndOfStreamTok.startToken();<br>
+  EndOfStreamTok.setKind(EndOfStream);<br>
+  LineToks.push_back(EndOfStreamTok);<br>
+<br>
+  // Also copy the current token over.<br>
+  LineToks.push_back(Tok);<br>
+<br>
+  PP.EnterTokenStream(LineToks.begin(), LineToks.size(),<br>
+                      /*disable macros*/ true,<br>
+                      /*owns tokens*/ false);<br>
+<br>
+  // Clear the current token and advance to the first token in LineToks.<br>
+  ConsumeAnyToken();<br>
+<br>
+  // Parse an optional scope-specifier if we're in C++.<br>
+  CXXScopeSpec SS;<br>
+  if (getLangOpts().CPlusPlus) {<br>
+    ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false);<br>
+  }<br>
+<br>
+  // Require an identifier here.<br>
+  SourceLocation TemplateKWLoc;<br>
+  UnqualifiedId Id;<br>
+  bool Invalid =<br>
+      ParseUnqualifiedId(SS,<br>
+                         /*EnteringContext=*/false,<br>
+                         /*AllowDestructorName=*/false,<br>
+                         /*AllowConstructorName=*/false,<br>
+                         /*ObjectType=*/ParsedType(), TemplateKWLoc, Id);<br>
+<br>
+  // Figure out how many tokens we are into LineToks.<br>
+  unsigned LineIndex = 0;<br>
+  if (Tok.is(EndOfStream)) {<br>
+    LineIndex = LineToks.size() - 2;<br>
+  } else {<br>
+    while (LineToks[LineIndex].getLocation() != Tok.getLocation()) {<br>
+      LineIndex++;<br>
+      assert(LineIndex < LineToks.size() - 2); // we added two extra tokens<br>
+    }<br>
+  }<br>
+<br>
+  // If we've run into the poison token we inserted before, or there<br>
+  // was a parsing error, then claim the entire line.<br>
+  if (Invalid || Tok.is(EndOfStream)) {<br>
+    NumLineToksConsumed = LineToks.size() - 2;<br>
+  } else {<br>
+    // Otherwise, claim up to the start of the next token.<br>
+    NumLineToksConsumed = LineIndex;<br>
+  }<br>
+<br>
+  // Finally, restore the old parsing state by consuming all the tokens we<br>
+  // staged before, implicitly killing off the token-lexer we pushed.<br>
+  for (unsigned i = 0, e = LineToks.size() - LineIndex - 2; i != e; ++i) {<br>
+    ConsumeAnyToken();<br>
+  }<br>
+  assert(Tok.is(EndOfStream));<br>
+  ConsumeToken();<br>
+<br>
+  // Leave LineToks in its original state.<br>
+  LineToks.pop_back();<br>
+  LineToks.pop_back();<br>
+<br>
+  // Perform the lookup.<br>
+  return Actions.LookupInlineAsmIdentifier(SS, TemplateKWLoc, Id, Info,<br>
+                                           IsUnevaluatedContext);<br>
+}<br>
+<br>
+/// Turn a sequence of our tokens back into a string that we can hand<br>
+/// to the MC asm parser.<br>
+static bool buildMSAsmString(Preprocessor &PP, SourceLocation AsmLoc,<br>
+                             ArrayRef<Token> AsmToks,<br>
+                             SmallVectorImpl<unsigned> &TokOffsets,<br>
+                             SmallString<512> &Asm) {<br>
+  assert(!AsmToks.empty() && "Didn't expect an empty AsmToks!");<br>
+<br>
+  // Is this the start of a new assembly statement?<br>
+  bool isNewStatement = true;<br>
+<br>
+  for (unsigned i = 0, e = AsmToks.size(); i < e; ++i) {<br>
+    const Token &Tok = AsmToks[i];<br>
+<br>
+    // Start each new statement with a newline and a tab.<br>
+    if (!isNewStatement && (Tok.is(tok::kw_asm) || Tok.isAtStartOfLine())) {<br>
+      Asm += "\n\t";<br>
+      isNewStatement = true;<br>
+    }<br>
+<br>
+    // Preserve the existence of leading whitespace except at the<br>
+    // start of a statement.<br>
+    if (!isNewStatement && Tok.hasLeadingSpace())<br>
+      Asm += ' ';<br>
+<br>
+    // Remember the offset of this token.<br>
+    TokOffsets.push_back(Asm.size());<br>
+<br>
+    // Don't actually write '__asm' into the assembly stream.<br>
+    if (Tok.is(tok::kw_asm)) {<br>
+      // Complain about __asm at the end of the stream.<br>
+      if (i + 1 == e) {<br>
+        PP.Diag(AsmLoc, diag::err_asm_empty);<br>
+        return true;<br>
+      }<br>
+<br>
+      continue;<br>
+    }<br>
+<br>
+    // Append the spelling of the token.<br>
+    SmallString<32> SpellingBuffer;<br>
+    bool SpellingInvalid = false;<br>
+    Asm += PP.getSpelling(Tok, SpellingBuffer, &SpellingInvalid);<br>
+    assert(!SpellingInvalid && "spelling was invalid after correct parse?");<br>
+<br>
+    // We are no longer at the start of a statement.<br>
+    isNewStatement = false;<br>
+  }<br>
+<br>
+  // Ensure that the buffer is null-terminated.<br>
+  Asm.push_back('\0');<br>
+  Asm.pop_back();<br>
+<br>
+  assert(TokOffsets.size() == AsmToks.size());<br>
+  return false;<br>
+}<br>
+<br>
+/// ParseMicrosoftAsmStatement. When -fms-extensions/-fasm-blocks is enabled,<br>
+/// this routine is called to collect the tokens for an MS asm statement.<br>
+///<br>
+/// [MS]  ms-asm-statement:<br>
+///         ms-asm-block<br>
+///         ms-asm-block ms-asm-statement<br>
+///<br>
+/// [MS]  ms-asm-block:<br>
+///         '__asm' ms-asm-line '\n'<br>
+///         '__asm' '{' ms-asm-instruction-block[opt] '}' ';'[opt]<br>
+///<br>
+/// [MS]  ms-asm-instruction-block<br>
+///         ms-asm-line<br>
+///         ms-asm-line '\n' ms-asm-instruction-block<br>
+///<br>
+StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) {<br>
+  SourceManager &SrcMgr = PP.getSourceManager();<br>
+  SourceLocation EndLoc = AsmLoc;<br>
+  SmallVector<Token, 4> AsmToks;<br>
+<br>
+  bool InBraces = false;<br>
+  unsigned short savedBraceCount = 0;<br>
+  bool InAsmComment = false;<br>
+  FileID FID;<br>
+  unsigned LineNo = 0;<br>
+  unsigned NumTokensRead = 0;<br>
+  SourceLocation LBraceLoc;<br>
+<br>
+  if (Tok.is(tok::l_brace)) {<br>
+    // Braced inline asm: consume the opening brace.<br>
+    InBraces = true;<br>
+    savedBraceCount = BraceCount;<br>
+    EndLoc = LBraceLoc = ConsumeBrace();<br>
+    ++NumTokensRead;<br>
+  } else {<br>
+    // Single-line inline asm; compute which line it is on.<br>
+    std::pair<FileID, unsigned> ExpAsmLoc =<br>
+        SrcMgr.getDecomposedExpansionLoc(EndLoc);<br>
+    FID = ExpAsmLoc.first;<br>
+    LineNo = SrcMgr.getLineNumber(FID, ExpAsmLoc.second);<br>
+  }<br>
+<br>
+  SourceLocation TokLoc = Tok.getLocation();<br>
+  do {<br>
+    // If we hit EOF, we're done, period.<br>
+    if (isEofOrEom())<br>
+      break;<br>
+<br>
+    if (!InAsmComment && Tok.is(tok::semi)) {<br>
+      // A semicolon in an asm is the start of a comment.<br>
+      InAsmComment = true;<br>
+      if (InBraces) {<br>
+        // Compute which line the comment is on.<br>
+        std::pair<FileID, unsigned> ExpSemiLoc =<br>
+            SrcMgr.getDecomposedExpansionLoc(TokLoc);<br>
+        FID = ExpSemiLoc.first;<br>
+        LineNo = SrcMgr.getLineNumber(FID, ExpSemiLoc.second);<br>
+      }<br>
+    } else if (!InBraces || InAsmComment) {<br>
+      // If end-of-line is significant, check whether this token is on a<br>
+      // new line.<br>
+      std::pair<FileID, unsigned> ExpLoc =<br>
+          SrcMgr.getDecomposedExpansionLoc(TokLoc);<br>
+      if (ExpLoc.first != FID ||<br>
+          SrcMgr.getLineNumber(ExpLoc.first, ExpLoc.second) != LineNo) {<br>
+        // If this is a single-line __asm, we're done.<br>
+        if (!InBraces)<br>
+          break;<br>
+        // We're no longer in a comment.<br>
+        InAsmComment = false;<br>
+      } else if (!InAsmComment && Tok.is(tok::r_brace)) {<br>
+        // Single-line asm always ends when a closing brace is seen.<br>
+        // FIXME: This is compatible with Apple gcc's -fasm-blocks; what<br>
+        // does MSVC do here?<br>
+        break;<br>
+      }<br>
+    }<br>
+    if (!InAsmComment && InBraces && Tok.is(tok::r_brace) &&<br>
+        BraceCount == (savedBraceCount + 1)) {<br>
+      // Consume the closing brace, and finish<br>
+      EndLoc = ConsumeBrace();<br>
+      break;<br>
+    }<br>
+<br>
+    // Consume the next token; make sure we don't modify the brace count etc.<br>
+    // if we are in a comment.<br>
+    EndLoc = TokLoc;<br>
+    if (InAsmComment)<br>
+      PP.Lex(Tok);<br>
+    else {<br>
+      AsmToks.push_back(Tok);<br>
+      ConsumeAnyToken();<br>
+    }<br>
+    TokLoc = Tok.getLocation();<br>
+    ++NumTokensRead;<br>
+  } while (1);<br>
+<br>
+  if (InBraces && BraceCount != savedBraceCount) {<br>
+    // __asm without closing brace (this can happen at EOF).<br>
+    Diag(Tok, diag::err_expected) << tok::r_brace;<br>
+    Diag(LBraceLoc, diag::note_matching) << tok::l_brace;<br>
+    return StmtError();<br>
+  } else if (NumTokensRead == 0) {<br>
+    // Empty __asm.<br>
+    Diag(Tok, diag::err_expected) << tok::l_brace;<br>
+    return StmtError();<br>
+  }<br>
+<br>
+  // Okay, prepare to use MC to parse the assembly.<br>
+  SmallVector<StringRef, 4> ConstraintRefs;<br>
+  SmallVector<Expr *, 4> Exprs;<br>
+  SmallVector<StringRef, 4> ClobberRefs;<br>
+<br>
+  // We need an actual supported target.<br>
+  const llvm::Triple &TheTriple = Actions.Context.getTargetInfo().getTriple();<br>
+  llvm::Triple::ArchType ArchTy = TheTriple.getArch();<br>
+  const std::string &TT = TheTriple.getTriple();<br>
+  const llvm::Target *TheTarget = nullptr;<br>
+  bool UnsupportedArch =<br>
+      (ArchTy != llvm::Triple::x86 && ArchTy != llvm::Triple::x86_64);<br>
+  if (UnsupportedArch) {<br>
+    Diag(AsmLoc, diag::err_msasm_unsupported_arch) << TheTriple.getArchName();<br>
+  } else {<br>
+    std::string Error;<br>
+    TheTarget = llvm::TargetRegistry::lookupTarget(TT, Error);<br>
+    if (!TheTarget)<br>
+      Diag(AsmLoc, diag::err_msasm_unable_to_create_target) << Error;<br>
+  }<br>
+<br>
+  // If we don't support assembly, or the assembly is empty, we don't<br>
+  // need to instantiate the AsmParser, etc.<br>
+  if (!TheTarget || AsmToks.empty()) {<br>
+    return Actions.ActOnMSAsmStmt(AsmLoc, LBraceLoc, AsmToks, StringRef(),<br>
+                                  /*NumOutputs*/ 0, /*NumInputs*/ 0,<br>
+                                  ConstraintRefs, ClobberRefs, Exprs, EndLoc);<br>
+  }<br>
+<br>
+  // Expand the tokens into a string buffer.<br>
+  SmallString<512> AsmString;<br>
+  SmallVector<unsigned, 8> TokOffsets;<br>
+  if (buildMSAsmString(PP, AsmLoc, AsmToks, TokOffsets, AsmString))<br>
+    return StmtError();<br>
+<br>
+  std::unique_ptr<llvm::MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TT));<br>
+  std::unique_ptr<llvm::MCAsmInfo> MAI(TheTarget->createMCAsmInfo(*MRI, TT));<br>
+  // Get the instruction descriptor.<br>
+  std::unique_ptr<llvm::MCInstrInfo> MII(TheTarget->createMCInstrInfo());<br>
+  std::unique_ptr<llvm::MCObjectFileInfo> MOFI(new llvm::MCObjectFileInfo());<br>
+  std::unique_ptr<llvm::MCSubtargetInfo> STI(<br>
+      TheTarget->createMCSubtargetInfo(TT, "", ""));<br>
+<br>
+  llvm::SourceMgr TempSrcMgr;<br>
+  llvm::MCContext Ctx(MAI.get(), MRI.get(), MOFI.get(), &TempSrcMgr);<br>
+  llvm::MemoryBuffer *Buffer =<br>
+      llvm::MemoryBuffer::getMemBuffer(AsmString, "<MS inline asm>");<br>
+<br>
+  // Tell SrcMgr about this buffer, which is what the parser will pick up.<br>
+  TempSrcMgr.AddNewSourceBuffer(Buffer, llvm::SMLoc());<br>
+<br>
+  std::unique_ptr<llvm::MCStreamer> Str(createNullStreamer(Ctx));<br>
+  std::unique_ptr<llvm::MCAsmParser> Parser(<br>
+      createMCAsmParser(TempSrcMgr, Ctx, *Str.get(), *MAI));<br>
+<br>
+  // FIXME: init MCOptions from sanitizer flags here.<br>
+  llvm::MCTargetOptions MCOptions;<br>
+  std::unique_ptr<llvm::MCTargetAsmParser> TargetParser(<br>
+      TheTarget->createMCAsmParser(*STI, *Parser, *MII, MCOptions));<br>
+<br>
+  std::unique_ptr<llvm::MCInstPrinter> IP(<br>
+      TheTarget->createMCInstPrinter(1, *MAI, *MII, *MRI, *STI));<br>
+<br>
+  // Change to the Intel dialect.<br>
+  Parser->setAssemblerDialect(1);<br>
+  Parser->setTargetParser(*TargetParser.get());<br>
+  Parser->setParsingInlineAsm(true);<br>
+  TargetParser->setParsingInlineAsm(true);<br>
+<br>
+  ClangAsmParserCallback Callback(*this, AsmLoc, AsmString, AsmToks,<br>
+                                  TokOffsets);<br>
+  TargetParser->setSemaCallback(&Callback);<br>
+  TempSrcMgr.setDiagHandler(ClangAsmParserCallback::DiagHandlerCallback,<br>
+                            &Callback);<br>
+<br>
+  unsigned NumOutputs;<br>
+  unsigned NumInputs;<br>
+  std::string AsmStringIR;<br>
+  SmallVector<std::pair<void *, bool>, 4> OpExprs;<br>
+  SmallVector<std::string, 4> Constraints;<br>
+  SmallVector<std::string, 4> Clobbers;<br>
+  if (Parser->parseMSInlineAsm(AsmLoc.getPtrEncoding(), AsmStringIR, NumOutputs,<br>
+                               NumInputs, OpExprs, Constraints, Clobbers,<br>
+                               MII.get(), IP.get(), Callback))<br>
+    return StmtError();<br>
+<br>
+  // Filter out "fpsw".  Clang doesn't accept it, and it always lists flags and<br>
+  // fpsr as clobbers.<br>
+  auto End = std::remove(Clobbers.begin(), Clobbers.end(), "fpsw");<br>
+  Clobbers.erase(End, Clobbers.end());<br>
+<br>
+  // Build the vector of clobber StringRefs.<br>
+  unsigned NumClobbers = Clobbers.size();<br>
+  ClobberRefs.resize(NumClobbers);<br>
+  for (unsigned i = 0; i != NumClobbers; ++i)<br>
+    ClobberRefs[i] = StringRef(Clobbers[i]);<br>
+<br>
+  // Recast the void pointers and build the vector of constraint StringRefs.<br>
+  unsigned NumExprs = NumOutputs + NumInputs;<br>
+  ConstraintRefs.resize(NumExprs);<br>
+  Exprs.resize(NumExprs);<br>
+  for (unsigned i = 0, e = NumExprs; i != e; ++i) {<br>
+    Expr *OpExpr = static_cast<Expr *>(OpExprs[i].first);<br>
+    if (!OpExpr)<br>
+      return StmtError();<br>
+<br>
+    // Need address of variable.<br>
+    if (OpExprs[i].second)<br>
+      OpExpr =<br>
+          Actions.BuildUnaryOp(getCurScope(), AsmLoc, UO_AddrOf, OpExpr).get();<br>
+<br>
+    ConstraintRefs[i] = StringRef(Constraints[i]);<br>
+    Exprs[i] = OpExpr;<br>
+  }<br>
+<br>
+  // FIXME: We should be passing source locations for better diagnostics.<br>
+  return Actions.ActOnMSAsmStmt(AsmLoc, LBraceLoc, AsmToks, AsmStringIR,<br>
+                                NumOutputs, NumInputs, ConstraintRefs,<br>
+                                ClobberRefs, Exprs, EndLoc);<br>
+}<br>
+<br>
+/// ParseAsmStatement - Parse a GNU extended asm statement.<br>
+///       asm-statement:<br>
+///         gnu-asm-statement<br>
+///         ms-asm-statement<br>
+///<br>
+/// [GNU] gnu-asm-statement:<br>
+///         'asm' type-qualifier[opt] '(' asm-argument ')' ';'<br>
+///<br>
+/// [GNU] asm-argument:<br>
+///         asm-string-literal<br>
+///         asm-string-literal ':' asm-operands[opt]<br>
+///         asm-string-literal ':' asm-operands[opt] ':' asm-operands[opt]<br>
+///         asm-string-literal ':' asm-operands[opt] ':' asm-operands[opt]<br>
+///                 ':' asm-clobbers<br>
+///<br>
+/// [GNU] asm-clobbers:<br>
+///         asm-string-literal<br>
+///         asm-clobbers ',' asm-string-literal<br>
+///<br>
+StmtResult Parser::ParseAsmStatement(bool &msAsm) {<br>
+  assert(Tok.is(tok::kw_asm) && "Not an asm stmt");<br>
+  SourceLocation AsmLoc = ConsumeToken();<br>
+<br>
+  if (getLangOpts().AsmBlocks && Tok.isNot(tok::l_paren) &&<br>
+      !isTypeQualifier()) {<br>
+    msAsm = true;<br>
+    return ParseMicrosoftAsmStatement(AsmLoc);<br>
+  }<br>
+  DeclSpec DS(AttrFactory);<br>
+  SourceLocation Loc = Tok.getLocation();<br>
+  ParseTypeQualifierListOpt(DS, true, false);<br>
+<br>
+  // GNU asms accept, but warn, about type-qualifiers other than volatile.<br>
+  if (DS.getTypeQualifiers() & DeclSpec::TQ_const)<br>
+    Diag(Loc, diag::w_asm_qualifier_ignored) << "const";<br>
+  if (DS.getTypeQualifiers() & DeclSpec::TQ_restrict)<br>
+    Diag(Loc, diag::w_asm_qualifier_ignored) << "restrict";<br>
+  // FIXME: Once GCC supports _Atomic, check whether it permits it here.<br>
+  if (DS.getTypeQualifiers() & DeclSpec::TQ_atomic)<br>
+    Diag(Loc, diag::w_asm_qualifier_ignored) << "_Atomic";<br>
+<br>
+  // Remember if this was a volatile asm.<br>
+  bool isVolatile = DS.getTypeQualifiers() & DeclSpec::TQ_volatile;<br>
+  if (Tok.isNot(tok::l_paren)) {<br>
+    Diag(Tok, diag::err_expected_lparen_after) << "asm";<br>
+    SkipUntil(tok::r_paren, StopAtSemi);<br>
+    return StmtError();<br>
+  }<br>
+  BalancedDelimiterTracker T(*this, tok::l_paren);<br>
+  T.consumeOpen();<br>
+<br>
+  ExprResult AsmString(ParseAsmStringLiteral());<br>
+  if (AsmString.isInvalid()) {<br>
+    // Consume up to and including the closing paren.<br>
+    T.skipToEnd();<br>
+    return StmtError();<br>
+  }<br>
+<br>
+  SmallVector<IdentifierInfo *, 4> Names;<br>
+  ExprVector Constraints;<br>
+  ExprVector Exprs;<br>
+  ExprVector Clobbers;<br>
+<br>
+  if (Tok.is(tok::r_paren)) {<br>
+    // We have a simple asm expression like 'asm("foo")'.<br>
+    T.consumeClose();<br>
+    return Actions.ActOnGCCAsmStmt(AsmLoc, /*isSimple*/ true, isVolatile,<br>
+                                   /*NumOutputs*/ 0, /*NumInputs*/ 0, nullptr,<br>
+                                   Constraints, Exprs, AsmString.get(),<br>
+                                   Clobbers, T.getCloseLocation());<br>
+  }<br>
+<br>
+  // Parse Outputs, if present.<br>
+  bool AteExtraColon = false;<br>
+  if (Tok.is(tok::colon) || Tok.is(tok::coloncolon)) {<br>
+    // In C++ mode, parse "::" like ": :".<br>
+    AteExtraColon = Tok.is(tok::coloncolon);<br>
+    ConsumeToken();<br>
+<br>
+    if (!AteExtraColon && ParseAsmOperandsOpt(Names, Constraints, Exprs))<br>
+      return StmtError();<br>
+  }<br>
+<br>
+  unsigned NumOutputs = Names.size();<br>
+<br>
+  // Parse Inputs, if present.<br>
+  if (AteExtraColon || Tok.is(tok::colon) || Tok.is(tok::coloncolon)) {<br>
+    // In C++ mode, parse "::" like ": :".<br>
+    if (AteExtraColon)<br>
+      AteExtraColon = false;<br>
+    else {<br>
+      AteExtraColon = Tok.is(tok::coloncolon);<br>
+      ConsumeToken();<br>
+    }<br>
+<br>
+    if (!AteExtraColon && ParseAsmOperandsOpt(Names, Constraints, Exprs))<br>
+      return StmtError();<br>
+  }<br>
+<br>
+  assert(Names.size() == Constraints.size() &&<br>
+         Constraints.size() == Exprs.size() && "Input operand size mismatch!");<br>
+<br>
+  unsigned NumInputs = Names.size() - NumOutputs;<br>
+<br>
+  // Parse the clobbers, if present.<br>
+  if (AteExtraColon || Tok.is(tok::colon)) {<br>
+    if (!AteExtraColon)<br>
+      ConsumeToken();<br>
+<br>
+    // Parse the asm-string list for clobbers if present.<br>
+    if (Tok.isNot(tok::r_paren)) {<br>
+      while (1) {<br>
+        ExprResult Clobber(ParseAsmStringLiteral());<br>
+<br>
+        if (Clobber.isInvalid())<br>
+          break;<br>
+<br>
+        Clobbers.push_back(Clobber.get());<br>
+<br>
+        if (!TryConsumeToken(tok::comma))<br>
+          break;<br>
+      }<br>
+    }<br>
+  }<br>
+<br>
+  T.consumeClose();<br>
+  return Actions.ActOnGCCAsmStmt(<br>
+      AsmLoc, false, isVolatile, NumOutputs, NumInputs, Names.data(),<br>
+      Constraints, Exprs, AsmString.get(), Clobbers, T.getCloseLocation());<br>
+}<br>
+<br>
+/// ParseAsmOperands - Parse the asm-operands production as used by<br>
+/// asm-statement, assuming the leading ':' token was eaten.<br>
+///<br>
+/// [GNU] asm-operands:<br>
+///         asm-operand<br>
+///         asm-operands ',' asm-operand<br>
+///<br>
+/// [GNU] asm-operand:<br>
+///         asm-string-literal '(' expression ')'<br>
+///         '[' identifier ']' asm-string-literal '(' expression ')'<br>
+///<br>
+//<br>
+// FIXME: Avoid unnecessary std::string trashing.<br>
+bool Parser::ParseAsmOperandsOpt(SmallVectorImpl<IdentifierInfo *> &Names,<br>
+                                 SmallVectorImpl<Expr *> &Constraints,<br>
+                                 SmallVectorImpl<Expr *> &Exprs) {<br>
+  // 'asm-operands' isn't present?<br>
+  if (!isTokenStringLiteral() && Tok.isNot(tok::l_square))<br>
+    return false;<br>
+<br>
+  while (1) {<br>
+    // Read the [id] if present.<br>
+    if (Tok.is(tok::l_square)) {<br>
+      BalancedDelimiterTracker T(*this, tok::l_square);<br>
+      T.consumeOpen();<br>
+<br>
+      if (Tok.isNot(tok::identifier)) {<br>
+        Diag(Tok, diag::err_expected) << tok::identifier;<br>
+        SkipUntil(tok::r_paren, StopAtSemi);<br>
+        return true;<br>
+      }<br>
+<br>
+      IdentifierInfo *II = Tok.getIdentifierInfo();<br>
+      ConsumeToken();<br>
+<br>
+      Names.push_back(II);<br>
+      T.consumeClose();<br>
+    } else<br>
+      Names.push_back(nullptr);<br>
+<br>
+    ExprResult Constraint(ParseAsmStringLiteral());<br>
+    if (Constraint.isInvalid()) {<br>
+      SkipUntil(tok::r_paren, StopAtSemi);<br>
+      return true;<br>
+    }<br>
+    Constraints.push_back(Constraint.get());<br>
+<br>
+    if (Tok.isNot(tok::l_paren)) {<br>
+      Diag(Tok, diag::err_expected_lparen_after) << "asm operand";<br>
+      SkipUntil(tok::r_paren, StopAtSemi);<br>
+      return true;<br>
+    }<br>
+<br>
+    // Read the parenthesized expression.<br>
+    BalancedDelimiterTracker T(*this, tok::l_paren);<br>
+    T.consumeOpen();<br>
+    ExprResult Res(ParseExpression());<br>
+    T.consumeClose();<br>
+    if (Res.isInvalid()) {<br>
+      SkipUntil(tok::r_paren, StopAtSemi);<br>
+      return true;<br>
+    }<br>
+    Exprs.push_back(Res.get());<br>
+    // Eat the comma and continue parsing if it exists.<br>
+    if (!TryConsumeToken(tok::comma))<br>
+      return false;<br>
+  }<br>
+}<br>
<br>
<br>
_______________________________________________<br>
cfe-commits mailing list<br>
<a href="mailto:cfe-commits@cs.uiuc.edu">cfe-commits@cs.uiuc.edu</a><br>
<a href="http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits" target="_blank">http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits</a><br>
</blockquote></div><br></div>