]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/clang/lib/Parse/ParseStmtAsm.cpp
MFV r276759: libpcap 1.6.2.
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / clang / lib / Parse / ParseStmtAsm.cpp
1 //===---- ParseStmtAsm.cpp - Assembly Statement Parser --------------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file implements parsing for GCC and Microsoft inline assembly. 
11 //
12 //===----------------------------------------------------------------------===//
13
14 #include "clang/Parse/Parser.h"
15 #include "RAIIObjectsForParser.h"
16 #include "clang/AST/ASTContext.h"
17 #include "clang/Basic/Diagnostic.h"
18 #include "clang/Basic/TargetInfo.h"
19 #include "llvm/ADT/SmallString.h"
20 #include "llvm/MC/MCAsmInfo.h"
21 #include "llvm/MC/MCContext.h"
22 #include "llvm/MC/MCInstPrinter.h"
23 #include "llvm/MC/MCInstrInfo.h"
24 #include "llvm/MC/MCObjectFileInfo.h"
25 #include "llvm/MC/MCParser/MCAsmParser.h"
26 #include "llvm/MC/MCRegisterInfo.h"
27 #include "llvm/MC/MCStreamer.h"
28 #include "llvm/MC/MCSubtargetInfo.h"
29 #include "llvm/MC/MCTargetAsmParser.h"
30 #include "llvm/MC/MCTargetOptions.h"
31 #include "llvm/Support/SourceMgr.h"
32 #include "llvm/Support/TargetRegistry.h"
33 #include "llvm/Support/TargetSelect.h"
34 using namespace clang;
35
36 namespace {
37 class ClangAsmParserCallback : public llvm::MCAsmParserSemaCallback {
38   Parser &TheParser;
39   SourceLocation AsmLoc;
40   StringRef AsmString;
41
42   /// The tokens we streamed into AsmString and handed off to MC.
43   ArrayRef<Token> AsmToks;
44
45   /// The offset of each token in AsmToks within AsmString.
46   ArrayRef<unsigned> AsmTokOffsets;
47
48 public:
49   ClangAsmParserCallback(Parser &P, SourceLocation Loc, StringRef AsmString,
50                          ArrayRef<Token> Toks, ArrayRef<unsigned> Offsets)
51       : TheParser(P), AsmLoc(Loc), AsmString(AsmString), AsmToks(Toks),
52         AsmTokOffsets(Offsets) {
53     assert(AsmToks.size() == AsmTokOffsets.size());
54   }
55
56   void *LookupInlineAsmIdentifier(StringRef &LineBuf,
57                                   llvm::InlineAsmIdentifierInfo &Info,
58                                   bool IsUnevaluatedContext) override {
59     // Collect the desired tokens.
60     SmallVector<Token, 16> LineToks;
61     const Token *FirstOrigToken = nullptr;
62     findTokensForString(LineBuf, LineToks, FirstOrigToken);
63
64     unsigned NumConsumedToks;
65     ExprResult Result = TheParser.ParseMSAsmIdentifier(
66         LineToks, NumConsumedToks, &Info, IsUnevaluatedContext);
67
68     // If we consumed the entire line, tell MC that.
69     // Also do this if we consumed nothing as a way of reporting failure.
70     if (NumConsumedToks == 0 || NumConsumedToks == LineToks.size()) {
71       // By not modifying LineBuf, we're implicitly consuming it all.
72
73       // Otherwise, consume up to the original tokens.
74     } else {
75       assert(FirstOrigToken && "not using original tokens?");
76
77       // Since we're using original tokens, apply that offset.
78       assert(FirstOrigToken[NumConsumedToks].getLocation() ==
79              LineToks[NumConsumedToks].getLocation());
80       unsigned FirstIndex = FirstOrigToken - AsmToks.begin();
81       unsigned LastIndex = FirstIndex + NumConsumedToks - 1;
82
83       // The total length we've consumed is the relative offset
84       // of the last token we consumed plus its length.
85       unsigned TotalOffset =
86           (AsmTokOffsets[LastIndex] + AsmToks[LastIndex].getLength() -
87            AsmTokOffsets[FirstIndex]);
88       LineBuf = LineBuf.substr(0, TotalOffset);
89     }
90
91     // Initialize the "decl" with the lookup result.
92     Info.OpDecl = static_cast<void *>(Result.get());
93     return Info.OpDecl;
94   }
95
96   bool LookupInlineAsmField(StringRef Base, StringRef Member,
97                             unsigned &Offset) override {
98     return TheParser.getActions().LookupInlineAsmField(Base, Member, Offset,
99                                                        AsmLoc);
100   }
101
102   static void DiagHandlerCallback(const llvm::SMDiagnostic &D, void *Context) {
103     ((ClangAsmParserCallback *)Context)->handleDiagnostic(D);
104   }
105
106 private:
107   /// Collect the appropriate tokens for the given string.
108   void findTokensForString(StringRef Str, SmallVectorImpl<Token> &TempToks,
109                            const Token *&FirstOrigToken) const {
110     // For now, assert that the string we're working with is a substring
111     // of what we gave to MC.  This lets us use the original tokens.
112     assert(!std::less<const char *>()(Str.begin(), AsmString.begin()) &&
113            !std::less<const char *>()(AsmString.end(), Str.end()));
114
115     // Try to find a token whose offset matches the first token.
116     unsigned FirstCharOffset = Str.begin() - AsmString.begin();
117     const unsigned *FirstTokOffset = std::lower_bound(
118         AsmTokOffsets.begin(), AsmTokOffsets.end(), FirstCharOffset);
119
120     // For now, assert that the start of the string exactly
121     // corresponds to the start of a token.
122     assert(*FirstTokOffset == FirstCharOffset);
123
124     // Use all the original tokens for this line.  (We assume the
125     // end of the line corresponds cleanly to a token break.)
126     unsigned FirstTokIndex = FirstTokOffset - AsmTokOffsets.begin();
127     FirstOrigToken = &AsmToks[FirstTokIndex];
128     unsigned LastCharOffset = Str.end() - AsmString.begin();
129     for (unsigned i = FirstTokIndex, e = AsmTokOffsets.size(); i != e; ++i) {
130       if (AsmTokOffsets[i] >= LastCharOffset)
131         break;
132       TempToks.push_back(AsmToks[i]);
133     }
134   }
135
136   void handleDiagnostic(const llvm::SMDiagnostic &D) {
137     // Compute an offset into the inline asm buffer.
138     // FIXME: This isn't right if .macro is involved (but hopefully, no
139     // real-world code does that).
140     const llvm::SourceMgr &LSM = *D.getSourceMgr();
141     const llvm::MemoryBuffer *LBuf =
142         LSM.getMemoryBuffer(LSM.FindBufferContainingLoc(D.getLoc()));
143     unsigned Offset = D.getLoc().getPointer() - LBuf->getBufferStart();
144
145     // Figure out which token that offset points into.
146     const unsigned *TokOffsetPtr =
147         std::lower_bound(AsmTokOffsets.begin(), AsmTokOffsets.end(), Offset);
148     unsigned TokIndex = TokOffsetPtr - AsmTokOffsets.begin();
149     unsigned TokOffset = *TokOffsetPtr;
150
151     // If we come up with an answer which seems sane, use it; otherwise,
152     // just point at the __asm keyword.
153     // FIXME: Assert the answer is sane once we handle .macro correctly.
154     SourceLocation Loc = AsmLoc;
155     if (TokIndex < AsmToks.size()) {
156       const Token &Tok = AsmToks[TokIndex];
157       Loc = Tok.getLocation();
158       Loc = Loc.getLocWithOffset(Offset - TokOffset);
159     }
160     TheParser.Diag(Loc, diag::err_inline_ms_asm_parsing) << D.getMessage();
161   }
162 };
163 }
164
165 /// Parse an identifier in an MS-style inline assembly block.
166 ///
167 /// \param CastInfo - a void* so that we don't have to teach Parser.h
168 ///   about the actual type.
169 ExprResult Parser::ParseMSAsmIdentifier(llvm::SmallVectorImpl<Token> &LineToks,
170                                         unsigned &NumLineToksConsumed,
171                                         void *CastInfo,
172                                         bool IsUnevaluatedContext) {
173   llvm::InlineAsmIdentifierInfo &Info =
174       *(llvm::InlineAsmIdentifierInfo *)CastInfo;
175
176   // Push a fake token on the end so that we don't overrun the token
177   // stream.  We use ';' because it expression-parsing should never
178   // overrun it.
179   const tok::TokenKind EndOfStream = tok::semi;
180   Token EndOfStreamTok;
181   EndOfStreamTok.startToken();
182   EndOfStreamTok.setKind(EndOfStream);
183   LineToks.push_back(EndOfStreamTok);
184
185   // Also copy the current token over.
186   LineToks.push_back(Tok);
187
188   PP.EnterTokenStream(LineToks.begin(), LineToks.size(),
189                       /*disable macros*/ true,
190                       /*owns tokens*/ false);
191
192   // Clear the current token and advance to the first token in LineToks.
193   ConsumeAnyToken();
194
195   // Parse an optional scope-specifier if we're in C++.
196   CXXScopeSpec SS;
197   if (getLangOpts().CPlusPlus) {
198     ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false);
199   }
200
201   // Require an identifier here.
202   SourceLocation TemplateKWLoc;
203   UnqualifiedId Id;
204   bool Invalid =
205       ParseUnqualifiedId(SS,
206                          /*EnteringContext=*/false,
207                          /*AllowDestructorName=*/false,
208                          /*AllowConstructorName=*/false,
209                          /*ObjectType=*/ParsedType(), TemplateKWLoc, Id);
210
211   // Figure out how many tokens we are into LineToks.
212   unsigned LineIndex = 0;
213   if (Tok.is(EndOfStream)) {
214     LineIndex = LineToks.size() - 2;
215   } else {
216     while (LineToks[LineIndex].getLocation() != Tok.getLocation()) {
217       LineIndex++;
218       assert(LineIndex < LineToks.size() - 2); // we added two extra tokens
219     }
220   }
221
222   // If we've run into the poison token we inserted before, or there
223   // was a parsing error, then claim the entire line.
224   if (Invalid || Tok.is(EndOfStream)) {
225     NumLineToksConsumed = LineToks.size() - 2;
226   } else {
227     // Otherwise, claim up to the start of the next token.
228     NumLineToksConsumed = LineIndex;
229   }
230
231   // Finally, restore the old parsing state by consuming all the tokens we
232   // staged before, implicitly killing off the token-lexer we pushed.
233   for (unsigned i = 0, e = LineToks.size() - LineIndex - 2; i != e; ++i) {
234     ConsumeAnyToken();
235   }
236   assert(Tok.is(EndOfStream));
237   ConsumeToken();
238
239   // Leave LineToks in its original state.
240   LineToks.pop_back();
241   LineToks.pop_back();
242
243   // Perform the lookup.
244   return Actions.LookupInlineAsmIdentifier(SS, TemplateKWLoc, Id, Info,
245                                            IsUnevaluatedContext);
246 }
247
248 /// Turn a sequence of our tokens back into a string that we can hand
249 /// to the MC asm parser.
250 static bool buildMSAsmString(Preprocessor &PP, SourceLocation AsmLoc,
251                              ArrayRef<Token> AsmToks,
252                              SmallVectorImpl<unsigned> &TokOffsets,
253                              SmallString<512> &Asm) {
254   assert(!AsmToks.empty() && "Didn't expect an empty AsmToks!");
255
256   // Is this the start of a new assembly statement?
257   bool isNewStatement = true;
258
259   for (unsigned i = 0, e = AsmToks.size(); i < e; ++i) {
260     const Token &Tok = AsmToks[i];
261
262     // Start each new statement with a newline and a tab.
263     if (!isNewStatement && (Tok.is(tok::kw_asm) || Tok.isAtStartOfLine())) {
264       Asm += "\n\t";
265       isNewStatement = true;
266     }
267
268     // Preserve the existence of leading whitespace except at the
269     // start of a statement.
270     if (!isNewStatement && Tok.hasLeadingSpace())
271       Asm += ' ';
272
273     // Remember the offset of this token.
274     TokOffsets.push_back(Asm.size());
275
276     // Don't actually write '__asm' into the assembly stream.
277     if (Tok.is(tok::kw_asm)) {
278       // Complain about __asm at the end of the stream.
279       if (i + 1 == e) {
280         PP.Diag(AsmLoc, diag::err_asm_empty);
281         return true;
282       }
283
284       continue;
285     }
286
287     // Append the spelling of the token.
288     SmallString<32> SpellingBuffer;
289     bool SpellingInvalid = false;
290     Asm += PP.getSpelling(Tok, SpellingBuffer, &SpellingInvalid);
291     assert(!SpellingInvalid && "spelling was invalid after correct parse?");
292
293     // We are no longer at the start of a statement.
294     isNewStatement = false;
295   }
296
297   // Ensure that the buffer is null-terminated.
298   Asm.push_back('\0');
299   Asm.pop_back();
300
301   assert(TokOffsets.size() == AsmToks.size());
302   return false;
303 }
304
305 /// ParseMicrosoftAsmStatement. When -fms-extensions/-fasm-blocks is enabled,
306 /// this routine is called to collect the tokens for an MS asm statement.
307 ///
308 /// [MS]  ms-asm-statement:
309 ///         ms-asm-block
310 ///         ms-asm-block ms-asm-statement
311 ///
312 /// [MS]  ms-asm-block:
313 ///         '__asm' ms-asm-line '\n'
314 ///         '__asm' '{' ms-asm-instruction-block[opt] '}' ';'[opt]
315 ///
316 /// [MS]  ms-asm-instruction-block
317 ///         ms-asm-line
318 ///         ms-asm-line '\n' ms-asm-instruction-block
319 ///
320 StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) {
321   SourceManager &SrcMgr = PP.getSourceManager();
322   SourceLocation EndLoc = AsmLoc;
323   SmallVector<Token, 4> AsmToks;
324
325   unsigned BraceNesting = 0;
326   unsigned short savedBraceCount = BraceCount;
327   bool InAsmComment = false;
328   FileID FID;
329   unsigned LineNo = 0;
330   unsigned NumTokensRead = 0;
331   SmallVector<SourceLocation, 4> LBraceLocs;
332   bool SkippedStartOfLine = false;
333
334   if (Tok.is(tok::l_brace)) {
335     // Braced inline asm: consume the opening brace.
336     BraceNesting = 1;
337     EndLoc = ConsumeBrace();
338     LBraceLocs.push_back(EndLoc);
339     ++NumTokensRead;
340   } else {
341     // Single-line inline asm; compute which line it is on.
342     std::pair<FileID, unsigned> ExpAsmLoc =
343         SrcMgr.getDecomposedExpansionLoc(EndLoc);
344     FID = ExpAsmLoc.first;
345     LineNo = SrcMgr.getLineNumber(FID, ExpAsmLoc.second);
346     LBraceLocs.push_back(SourceLocation());
347   }
348
349   SourceLocation TokLoc = Tok.getLocation();
350   do {
351     // If we hit EOF, we're done, period.
352     if (isEofOrEom())
353       break;
354
355     if (!InAsmComment && Tok.is(tok::l_brace)) {
356       // Consume the opening brace.
357       SkippedStartOfLine = Tok.isAtStartOfLine();
358       EndLoc = ConsumeBrace();
359       BraceNesting++;
360       LBraceLocs.push_back(EndLoc);
361       TokLoc = Tok.getLocation();
362       ++NumTokensRead;
363       continue;
364     } else if (!InAsmComment && Tok.is(tok::semi)) {
365       // A semicolon in an asm is the start of a comment.
366       InAsmComment = true;
367       if (BraceNesting) {
368         // Compute which line the comment is on.
369         std::pair<FileID, unsigned> ExpSemiLoc =
370             SrcMgr.getDecomposedExpansionLoc(TokLoc);
371         FID = ExpSemiLoc.first;
372         LineNo = SrcMgr.getLineNumber(FID, ExpSemiLoc.second);
373       }
374     } else if (!BraceNesting || InAsmComment) {
375       // If end-of-line is significant, check whether this token is on a
376       // new line.
377       std::pair<FileID, unsigned> ExpLoc =
378           SrcMgr.getDecomposedExpansionLoc(TokLoc);
379       if (ExpLoc.first != FID ||
380           SrcMgr.getLineNumber(ExpLoc.first, ExpLoc.second) != LineNo) {
381         // If this is a single-line __asm, we're done.
382         if (!BraceNesting)
383           break;
384         // We're no longer in a comment.
385         InAsmComment = false;
386       } else if (!InAsmComment && Tok.is(tok::r_brace)) {
387         // Single-line asm always ends when a closing brace is seen.
388         // FIXME: This is compatible with Apple gcc's -fasm-blocks; what
389         // does MSVC do here?
390         break;
391       }
392     }
393     if (!InAsmComment && BraceNesting && Tok.is(tok::r_brace) &&
394         BraceCount == (savedBraceCount + BraceNesting)) {
395       // Consume the closing brace.
396       SkippedStartOfLine = Tok.isAtStartOfLine();
397       EndLoc = ConsumeBrace();
398       BraceNesting--;
399       // Finish if all of the opened braces in the inline asm section were
400       // consumed.
401       if (BraceNesting == 0)
402         break;
403       else {
404         LBraceLocs.pop_back();
405         TokLoc = Tok.getLocation();
406         ++NumTokensRead;
407         continue;
408       }
409     }
410
411     // Consume the next token; make sure we don't modify the brace count etc.
412     // if we are in a comment.
413     EndLoc = TokLoc;
414     if (InAsmComment)
415       PP.Lex(Tok);
416     else {
417       // Set the token as the start of line if we skipped the original start
418       // of line token in case it was a nested brace.
419       if (SkippedStartOfLine)
420         Tok.setFlag(Token::StartOfLine);
421       AsmToks.push_back(Tok);
422       ConsumeAnyToken();
423     }
424     TokLoc = Tok.getLocation();
425     ++NumTokensRead;
426     SkippedStartOfLine = false;
427   } while (1);
428
429   if (BraceNesting && BraceCount != savedBraceCount) {
430     // __asm without closing brace (this can happen at EOF).
431     for (unsigned i = 0; i < BraceNesting; ++i) {
432       Diag(Tok, diag::err_expected) << tok::r_brace;
433       Diag(LBraceLocs.back(), diag::note_matching) << tok::l_brace;
434       LBraceLocs.pop_back();
435     }
436     return StmtError();
437   } else if (NumTokensRead == 0) {
438     // Empty __asm.
439     Diag(Tok, diag::err_expected) << tok::l_brace;
440     return StmtError();
441   }
442
443   // Okay, prepare to use MC to parse the assembly.
444   SmallVector<StringRef, 4> ConstraintRefs;
445   SmallVector<Expr *, 4> Exprs;
446   SmallVector<StringRef, 4> ClobberRefs;
447
448   // We need an actual supported target.
449   const llvm::Triple &TheTriple = Actions.Context.getTargetInfo().getTriple();
450   llvm::Triple::ArchType ArchTy = TheTriple.getArch();
451   const std::string &TT = TheTriple.getTriple();
452   const llvm::Target *TheTarget = nullptr;
453   bool UnsupportedArch =
454       (ArchTy != llvm::Triple::x86 && ArchTy != llvm::Triple::x86_64);
455   if (UnsupportedArch) {
456     Diag(AsmLoc, diag::err_msasm_unsupported_arch) << TheTriple.getArchName();
457   } else {
458     std::string Error;
459     TheTarget = llvm::TargetRegistry::lookupTarget(TT, Error);
460     if (!TheTarget)
461       Diag(AsmLoc, diag::err_msasm_unable_to_create_target) << Error;
462   }
463
464   assert(!LBraceLocs.empty() && "Should have at least one location here");
465
466   // If we don't support assembly, or the assembly is empty, we don't
467   // need to instantiate the AsmParser, etc.
468   if (!TheTarget || AsmToks.empty()) {
469     return Actions.ActOnMSAsmStmt(AsmLoc, LBraceLocs[0], AsmToks, StringRef(),
470                                   /*NumOutputs*/ 0, /*NumInputs*/ 0,
471                                   ConstraintRefs, ClobberRefs, Exprs, EndLoc);
472   }
473
474   // Expand the tokens into a string buffer.
475   SmallString<512> AsmString;
476   SmallVector<unsigned, 8> TokOffsets;
477   if (buildMSAsmString(PP, AsmLoc, AsmToks, TokOffsets, AsmString))
478     return StmtError();
479
480   std::unique_ptr<llvm::MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TT));
481   std::unique_ptr<llvm::MCAsmInfo> MAI(TheTarget->createMCAsmInfo(*MRI, TT));
482   // Get the instruction descriptor.
483   std::unique_ptr<llvm::MCInstrInfo> MII(TheTarget->createMCInstrInfo());
484   std::unique_ptr<llvm::MCObjectFileInfo> MOFI(new llvm::MCObjectFileInfo());
485   std::unique_ptr<llvm::MCSubtargetInfo> STI(
486       TheTarget->createMCSubtargetInfo(TT, "", ""));
487
488   llvm::SourceMgr TempSrcMgr;
489   llvm::MCContext Ctx(MAI.get(), MRI.get(), MOFI.get(), &TempSrcMgr);
490   llvm::MemoryBuffer *Buffer =
491       llvm::MemoryBuffer::getMemBuffer(AsmString, "<MS inline asm>");
492
493   // Tell SrcMgr about this buffer, which is what the parser will pick up.
494   TempSrcMgr.AddNewSourceBuffer(Buffer, llvm::SMLoc());
495
496   std::unique_ptr<llvm::MCStreamer> Str(createNullStreamer(Ctx));
497   std::unique_ptr<llvm::MCAsmParser> Parser(
498       createMCAsmParser(TempSrcMgr, Ctx, *Str.get(), *MAI));
499
500   // FIXME: init MCOptions from sanitizer flags here.
501   llvm::MCTargetOptions MCOptions;
502   std::unique_ptr<llvm::MCTargetAsmParser> TargetParser(
503       TheTarget->createMCAsmParser(*STI, *Parser, *MII, MCOptions));
504
505   std::unique_ptr<llvm::MCInstPrinter> IP(
506       TheTarget->createMCInstPrinter(1, *MAI, *MII, *MRI, *STI));
507
508   // Change to the Intel dialect.
509   Parser->setAssemblerDialect(1);
510   Parser->setTargetParser(*TargetParser.get());
511   Parser->setParsingInlineAsm(true);
512   TargetParser->setParsingInlineAsm(true);
513
514   ClangAsmParserCallback Callback(*this, AsmLoc, AsmString, AsmToks,
515                                   TokOffsets);
516   TargetParser->setSemaCallback(&Callback);
517   TempSrcMgr.setDiagHandler(ClangAsmParserCallback::DiagHandlerCallback,
518                             &Callback);
519
520   unsigned NumOutputs;
521   unsigned NumInputs;
522   std::string AsmStringIR;
523   SmallVector<std::pair<void *, bool>, 4> OpExprs;
524   SmallVector<std::string, 4> Constraints;
525   SmallVector<std::string, 4> Clobbers;
526   if (Parser->parseMSInlineAsm(AsmLoc.getPtrEncoding(), AsmStringIR, NumOutputs,
527                                NumInputs, OpExprs, Constraints, Clobbers,
528                                MII.get(), IP.get(), Callback))
529     return StmtError();
530
531   // Filter out "fpsw".  Clang doesn't accept it, and it always lists flags and
532   // fpsr as clobbers.
533   auto End = std::remove(Clobbers.begin(), Clobbers.end(), "fpsw");
534   Clobbers.erase(End, Clobbers.end());
535
536   // Build the vector of clobber StringRefs.
537   ClobberRefs.insert(ClobberRefs.end(), Clobbers.begin(), Clobbers.end());
538
539   // Recast the void pointers and build the vector of constraint StringRefs.
540   unsigned NumExprs = NumOutputs + NumInputs;
541   ConstraintRefs.resize(NumExprs);
542   Exprs.resize(NumExprs);
543   for (unsigned i = 0, e = NumExprs; i != e; ++i) {
544     Expr *OpExpr = static_cast<Expr *>(OpExprs[i].first);
545     if (!OpExpr)
546       return StmtError();
547
548     // Need address of variable.
549     if (OpExprs[i].second)
550       OpExpr =
551           Actions.BuildUnaryOp(getCurScope(), AsmLoc, UO_AddrOf, OpExpr).get();
552
553     ConstraintRefs[i] = StringRef(Constraints[i]);
554     Exprs[i] = OpExpr;
555   }
556
557   // FIXME: We should be passing source locations for better diagnostics.
558   return Actions.ActOnMSAsmStmt(AsmLoc, LBraceLocs[0], AsmToks, AsmStringIR,
559                                 NumOutputs, NumInputs, ConstraintRefs,
560                                 ClobberRefs, Exprs, EndLoc);
561 }
562
563 /// ParseAsmStatement - Parse a GNU extended asm statement.
564 ///       asm-statement:
565 ///         gnu-asm-statement
566 ///         ms-asm-statement
567 ///
568 /// [GNU] gnu-asm-statement:
569 ///         'asm' type-qualifier[opt] '(' asm-argument ')' ';'
570 ///
571 /// [GNU] asm-argument:
572 ///         asm-string-literal
573 ///         asm-string-literal ':' asm-operands[opt]
574 ///         asm-string-literal ':' asm-operands[opt] ':' asm-operands[opt]
575 ///         asm-string-literal ':' asm-operands[opt] ':' asm-operands[opt]
576 ///                 ':' asm-clobbers
577 ///
578 /// [GNU] asm-clobbers:
579 ///         asm-string-literal
580 ///         asm-clobbers ',' asm-string-literal
581 ///
582 StmtResult Parser::ParseAsmStatement(bool &msAsm) {
583   assert(Tok.is(tok::kw_asm) && "Not an asm stmt");
584   SourceLocation AsmLoc = ConsumeToken();
585
586   if (getLangOpts().AsmBlocks && Tok.isNot(tok::l_paren) &&
587       !isTypeQualifier()) {
588     msAsm = true;
589     return ParseMicrosoftAsmStatement(AsmLoc);
590   }
591   DeclSpec DS(AttrFactory);
592   SourceLocation Loc = Tok.getLocation();
593   ParseTypeQualifierListOpt(DS, true, false);
594
595   // GNU asms accept, but warn, about type-qualifiers other than volatile.
596   if (DS.getTypeQualifiers() & DeclSpec::TQ_const)
597     Diag(Loc, diag::w_asm_qualifier_ignored) << "const";
598   if (DS.getTypeQualifiers() & DeclSpec::TQ_restrict)
599     Diag(Loc, diag::w_asm_qualifier_ignored) << "restrict";
600   // FIXME: Once GCC supports _Atomic, check whether it permits it here.
601   if (DS.getTypeQualifiers() & DeclSpec::TQ_atomic)
602     Diag(Loc, diag::w_asm_qualifier_ignored) << "_Atomic";
603
604   // Remember if this was a volatile asm.
605   bool isVolatile = DS.getTypeQualifiers() & DeclSpec::TQ_volatile;
606   if (Tok.isNot(tok::l_paren)) {
607     Diag(Tok, diag::err_expected_lparen_after) << "asm";
608     SkipUntil(tok::r_paren, StopAtSemi);
609     return StmtError();
610   }
611   BalancedDelimiterTracker T(*this, tok::l_paren);
612   T.consumeOpen();
613
614   ExprResult AsmString(ParseAsmStringLiteral());
615   if (AsmString.isInvalid()) {
616     // Consume up to and including the closing paren.
617     T.skipToEnd();
618     return StmtError();
619   }
620
621   SmallVector<IdentifierInfo *, 4> Names;
622   ExprVector Constraints;
623   ExprVector Exprs;
624   ExprVector Clobbers;
625
626   if (Tok.is(tok::r_paren)) {
627     // We have a simple asm expression like 'asm("foo")'.
628     T.consumeClose();
629     return Actions.ActOnGCCAsmStmt(AsmLoc, /*isSimple*/ true, isVolatile,
630                                    /*NumOutputs*/ 0, /*NumInputs*/ 0, nullptr,
631                                    Constraints, Exprs, AsmString.get(),
632                                    Clobbers, T.getCloseLocation());
633   }
634
635   // Parse Outputs, if present.
636   bool AteExtraColon = false;
637   if (Tok.is(tok::colon) || Tok.is(tok::coloncolon)) {
638     // In C++ mode, parse "::" like ": :".
639     AteExtraColon = Tok.is(tok::coloncolon);
640     ConsumeToken();
641
642     if (!AteExtraColon && ParseAsmOperandsOpt(Names, Constraints, Exprs))
643       return StmtError();
644   }
645
646   unsigned NumOutputs = Names.size();
647
648   // Parse Inputs, if present.
649   if (AteExtraColon || Tok.is(tok::colon) || Tok.is(tok::coloncolon)) {
650     // In C++ mode, parse "::" like ": :".
651     if (AteExtraColon)
652       AteExtraColon = false;
653     else {
654       AteExtraColon = Tok.is(tok::coloncolon);
655       ConsumeToken();
656     }
657
658     if (!AteExtraColon && ParseAsmOperandsOpt(Names, Constraints, Exprs))
659       return StmtError();
660   }
661
662   assert(Names.size() == Constraints.size() &&
663          Constraints.size() == Exprs.size() && "Input operand size mismatch!");
664
665   unsigned NumInputs = Names.size() - NumOutputs;
666
667   // Parse the clobbers, if present.
668   if (AteExtraColon || Tok.is(tok::colon)) {
669     if (!AteExtraColon)
670       ConsumeToken();
671
672     // Parse the asm-string list for clobbers if present.
673     if (Tok.isNot(tok::r_paren)) {
674       while (1) {
675         ExprResult Clobber(ParseAsmStringLiteral());
676
677         if (Clobber.isInvalid())
678           break;
679
680         Clobbers.push_back(Clobber.get());
681
682         if (!TryConsumeToken(tok::comma))
683           break;
684       }
685     }
686   }
687
688   T.consumeClose();
689   return Actions.ActOnGCCAsmStmt(
690       AsmLoc, false, isVolatile, NumOutputs, NumInputs, Names.data(),
691       Constraints, Exprs, AsmString.get(), Clobbers, T.getCloseLocation());
692 }
693
694 /// ParseAsmOperands - Parse the asm-operands production as used by
695 /// asm-statement, assuming the leading ':' token was eaten.
696 ///
697 /// [GNU] asm-operands:
698 ///         asm-operand
699 ///         asm-operands ',' asm-operand
700 ///
701 /// [GNU] asm-operand:
702 ///         asm-string-literal '(' expression ')'
703 ///         '[' identifier ']' asm-string-literal '(' expression ')'
704 ///
705 //
706 // FIXME: Avoid unnecessary std::string trashing.
707 bool Parser::ParseAsmOperandsOpt(SmallVectorImpl<IdentifierInfo *> &Names,
708                                  SmallVectorImpl<Expr *> &Constraints,
709                                  SmallVectorImpl<Expr *> &Exprs) {
710   // 'asm-operands' isn't present?
711   if (!isTokenStringLiteral() && Tok.isNot(tok::l_square))
712     return false;
713
714   while (1) {
715     // Read the [id] if present.
716     if (Tok.is(tok::l_square)) {
717       BalancedDelimiterTracker T(*this, tok::l_square);
718       T.consumeOpen();
719
720       if (Tok.isNot(tok::identifier)) {
721         Diag(Tok, diag::err_expected) << tok::identifier;
722         SkipUntil(tok::r_paren, StopAtSemi);
723         return true;
724       }
725
726       IdentifierInfo *II = Tok.getIdentifierInfo();
727       ConsumeToken();
728
729       Names.push_back(II);
730       T.consumeClose();
731     } else
732       Names.push_back(nullptr);
733
734     ExprResult Constraint(ParseAsmStringLiteral());
735     if (Constraint.isInvalid()) {
736       SkipUntil(tok::r_paren, StopAtSemi);
737       return true;
738     }
739     Constraints.push_back(Constraint.get());
740
741     if (Tok.isNot(tok::l_paren)) {
742       Diag(Tok, diag::err_expected_lparen_after) << "asm operand";
743       SkipUntil(tok::r_paren, StopAtSemi);
744       return true;
745     }
746
747     // Read the parenthesized expression.
748     BalancedDelimiterTracker T(*this, tok::l_paren);
749     T.consumeOpen();
750     ExprResult Res(ParseExpression());
751     T.consumeClose();
752     if (Res.isInvalid()) {
753       SkipUntil(tok::r_paren, StopAtSemi);
754       return true;
755     }
756     Exprs.push_back(Res.get());
757     // Eat the comma and continue parsing if it exists.
758     if (!TryConsumeToken(tok::comma))
759       return false;
760   }
761 }