<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>