]> granicus.if.org Git - clang/commitdiff
Etch out the code path for MS-style inline assembly.
authorChad Rosier <mcrosier@apple.com>
Mon, 11 Jun 2012 20:47:18 +0000 (20:47 +0000)
committerChad Rosier <mcrosier@apple.com>
Mon, 11 Jun 2012 20:47:18 +0000 (20:47 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@158325 91177308-0d34-0410-b5e6-96231b3b80d8

21 files changed:
include/clang-c/Index.h
include/clang/AST/RecursiveASTVisitor.h
include/clang/AST/Stmt.h
include/clang/Basic/StmtNodes.td
include/clang/Sema/Sema.h
include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
lib/AST/Stmt.cpp
lib/AST/StmtPrinter.cpp
lib/AST/StmtProfile.cpp
lib/CodeGen/CGStmt.cpp
lib/CodeGen/CodeGenFunction.h
lib/Parse/ParseStmt.cpp
lib/Sema/AnalysisBasedWarnings.cpp
lib/Sema/SemaStmt.cpp
lib/Sema/TreeTransform.h
lib/Serialization/ASTReaderStmt.cpp
lib/Serialization/ASTWriterStmt.cpp
lib/StaticAnalyzer/Core/ExprEngine.cpp
tools/libclang/CIndex.cpp
tools/libclang/CXCursor.cpp
tools/libclang/RecursiveASTVisitor.h

index 8fffc39e541cb621604532131654613db4541cf5..94cfd685dc00498a4a59ef179c6d8e87e7055f40 100644 (file)
@@ -1996,6 +1996,10 @@ enum CXCursorKind {
    */
   CXCursor_SEHFinallyStmt                = 228,
 
+  /** \brief A MS inline assembly statement extension.
+   */
+  CXCursor_MSAsmStmt                     = 229,
+
   /** \brief The null satement ";": C99 6.8.3p3.
    *
    * This cursor kind is used to describe the null statement.
index b1db07af17d383dc91675bc7241d812dee49f076..de042cafb6d112830ef0882bebe27a3a848e63d4 100644 (file)
@@ -1826,6 +1826,11 @@ DEF_TRAVERSE_STMT(AsmStmt, {
     // children() iterates over inputExpr and outputExpr.
   })
 
+DEF_TRAVERSE_STMT(MSAsmStmt, { 
+    // FIXME: MS Asm doesn't currently parse Constraints, Clobbers, etc.  Once
+    // added this needs to be implemented.
+  })
+
 DEF_TRAVERSE_STMT(CXXCatchStmt, {
     TRY_TO(TraverseDecl(S->getExceptionDecl()));
     // children() iterates over the handler block.
index 1b0f576e271de2b639bfe62388702dd675025f7c..904d56ed9a8794d060fa39f10ecf7acbecca8bfd 100644 (file)
@@ -1606,6 +1606,52 @@ public:
   }
 };
 
+/// MSAsmStmt - This represents a MS inline-assembly statement extension.
+///
+class MSAsmStmt : public Stmt {
+  SourceLocation AsmLoc, EndLoc;
+  std::string AsmStr;
+
+  bool IsSimple;
+  bool IsVolatile;
+
+  Stmt **Exprs;
+
+public:
+  MSAsmStmt(ASTContext &C, SourceLocation asmloc, std::string &asmstr,
+            SourceLocation endloc);
+
+  SourceLocation getAsmLoc() const { return AsmLoc; }
+  void setAsmLoc(SourceLocation L) { AsmLoc = L; }
+  SourceLocation getEndLoc() const { return EndLoc; }
+  void setEndLoc(SourceLocation L) { EndLoc = L; }
+
+  bool isVolatile() const { return IsVolatile; }
+  void setVolatile(bool V) { IsVolatile = V; }
+  bool isSimple() const { return IsSimple; }
+  void setSimple(bool V) { IsSimple = V; }
+
+  //===--- Asm String Analysis ---===//
+
+  const std::string *getAsmString() const { return &AsmStr; }
+  std::string *getAsmString() { return &AsmStr; }
+  void setAsmString(StringRef &E) { AsmStr = E.str(); }
+
+  //===--- Other ---===//
+
+  SourceRange getSourceRange() const LLVM_READONLY {
+    return SourceRange(AsmLoc, EndLoc);
+  }
+  static bool classof(const Stmt *T) {
+    return T->getStmtClass() == MSAsmStmtClass;
+  }
+  static bool classof(const MSAsmStmt *) { return true; }
+
+  child_range children() {
+    return child_range(&Exprs[0], &Exprs[0]);
+  }
+};
+
 class SEHExceptStmt : public Stmt {
   SourceLocation  Loc;
   Stmt           *Children[2];
index 5abc50683c9c50a363a3ca326594704785c2e880..47738af2907f57c5a1aa724d5dd59665594cde12 100644 (file)
@@ -31,6 +31,9 @@ def DefaultStmt : DStmt<SwitchCase>;
 // GNU Extensions
 def AsmStmt : Stmt;
 
+// MS Extensions
+def MSAsmStmt : Stmt;
+
 // Obj-C statements
 def ObjCAtTryStmt : Stmt;
 def ObjCAtCatchStmt : Stmt;
index 43fbade8c190baca02ee20ec60a569d5cb80152d..7ab9ec60be3faff5da3549be6b129a6642d16fa1 100644 (file)
@@ -2530,6 +2530,9 @@ public:
                           SourceLocation RParenLoc,
                           bool MSAsm = false);
 
+  StmtResult ActOnMSAsmStmt(SourceLocation AsmLoc,
+                            std::string &AsmString,
+                            SourceLocation EndLoc);
 
   VarDecl *BuildObjCExceptionDecl(TypeSourceInfo *TInfo, QualType ExceptionType,
                                   SourceLocation StartLoc,
index 14087c926d8f128b5e485fb6ee686d882ff391b2..b101ebc62b383bb53f29375ba109462931103f8f 100644 (file)
@@ -285,6 +285,10 @@ public:
 
   /// VisitAsmStmt - Transfer function logic for inline asm.
   void VisitAsmStmt(const AsmStmt *A, ExplodedNode *Pred, ExplodedNodeSet &Dst);
+
+  /// VisitMSAsmStmt - Transfer function logic for MS inline asm.
+  void VisitMSAsmStmt(const MSAsmStmt *A, ExplodedNode *Pred,
+                      ExplodedNodeSet &Dst);
   
   /// VisitBlockExpr - Transfer function logic for BlockExprs.
   void VisitBlockExpr(const BlockExpr *BE, ExplodedNode *Pred, 
index e4d9f0a1ef425fd6595c1854754bd3ef1cfea65a..97eb4d579e499c1006036bbd923614f084c13c7b 100644 (file)
@@ -550,6 +550,12 @@ AsmStmt::AsmStmt(ASTContext &C, SourceLocation asmloc, bool issimple,
   std::copy(clobbers, clobbers + NumClobbers, Clobbers);
 }
 
+MSAsmStmt::MSAsmStmt(ASTContext &C, SourceLocation asmloc, std::string &asmstr,
+                     SourceLocation endloc)
+  : Stmt(MSAsmStmtClass), AsmLoc(asmloc), EndLoc(endloc), AsmStr(asmstr),
+    IsSimple(true), IsVolatile(true) {
+}
+
 ObjCForCollectionStmt::ObjCForCollectionStmt(Stmt *Elem, Expr *Collect,
                                              Stmt *Body,  SourceLocation FCL,
                                              SourceLocation RPL)
index 2bd4d769e795afc2cdf795f6a091c4c37693323c..30548aea60daeeee0f950e0191c2baeb8d6bc907 100644 (file)
@@ -429,6 +429,11 @@ void StmtPrinter::VisitAsmStmt(AsmStmt *Node) {
   OS << ");\n";
 }
 
+void StmtPrinter::VisitMSAsmStmt(MSAsmStmt *Node) {
+  // FIXME: Implement MS style inline asm statement printer.
+  Indent() << "asm ()";
+}
+
 void StmtPrinter::VisitObjCAtTryStmt(ObjCAtTryStmt *Node) {
   Indent() << "@try";
   if (CompoundStmt *TS = dyn_cast<CompoundStmt>(Node->getTryBody())) {
index 72b979d4c2f7952e57f97495b01fe5d1fb7ca2c4..2168b64d5b231e0b7ff0f57a201ca5dfcab7a2f9 100644 (file)
@@ -178,6 +178,11 @@ void StmtProfiler::VisitAsmStmt(const AsmStmt *S) {
     VisitStringLiteral(S->getClobber(I));
 }
 
+void StmtProfiler::VisitMSAsmStmt(const MSAsmStmt *S) {
+  // FIXME: Implement MS style inline asm statement profiler.
+  VisitStmt(S);
+}
+
 void StmtProfiler::VisitCXXCatchStmt(const CXXCatchStmt *S) {
   VisitStmt(S);
   VisitType(S->getCaughtType());
index 86046b70a544b73e766e2d3fe50ea99593986fcb..2f06a8ed28320e640b28cbba39e9ee8b5a8588ae 100644 (file)
@@ -133,6 +133,7 @@ void CodeGenFunction::EmitStmt(const Stmt *S) {
 
   case Stmt::SwitchStmtClass:   EmitSwitchStmt(cast<SwitchStmt>(*S));     break;
   case Stmt::AsmStmtClass:      EmitAsmStmt(cast<AsmStmt>(*S));           break;
+  case Stmt::MSAsmStmtClass:    EmitMSAsmStmt(cast<MSAsmStmt>(*S));       break;
 
   case Stmt::ObjCAtTryStmtClass:
     EmitObjCAtTryStmt(cast<ObjCAtTryStmt>(*S));
@@ -1681,3 +1682,43 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
     EmitStoreThroughLValue(RValue::get(Tmp), ResultRegDests[i]);
   }
 }
+
+void CodeGenFunction::EmitMSAsmStmt(const MSAsmStmt &S) {
+  // Analyze the asm string to decompose it into its pieces.  We know that Sema
+  // has already done this, so it is guaranteed to be successful.
+
+  // Get all the output and input constraints together.
+
+  std::vector<llvm::Value*> Args;
+  std::vector<llvm::Type *> ArgTypes;
+  std::string Constraints;
+
+  // Keep track of inout constraints.
+  
+  // Append the "input" part of inout constraints last.
+
+  // Clobbers
+
+  // Add machine specific clobbers
+  std::string MachineClobbers = Target.getClobbers();
+  if (!MachineClobbers.empty()) {
+    if (!Constraints.empty())
+      Constraints += ',';
+    Constraints += MachineClobbers;
+  }
+
+  llvm::Type *ResultType = VoidTy;
+
+  llvm::FunctionType *FTy =
+    llvm::FunctionType::get(ResultType, ArgTypes, false);
+
+  llvm::InlineAsm *IA =
+    llvm::InlineAsm::get(FTy, *S.getAsmString(), Constraints, true);
+  llvm::CallInst *Result = Builder.CreateCall(IA, Args);
+  Result->addAttribute(~0, llvm::Attribute::NoUnwind);
+
+  // Slap the source location of the inline asm into a !srcloc metadata on the
+  // call.
+
+  // Extract all of the register value results from the asm.
+}
index de7e89e3911b0bfb9e759f1773ba1233ad49c5f2..a6d77e31c7fe54f0b7f794aa065bb762bd14e5f0 100644 (file)
@@ -1970,6 +1970,7 @@ public:
   void EmitCaseStmt(const CaseStmt &S);
   void EmitCaseStmtRange(const CaseStmt &S);
   void EmitAsmStmt(const AsmStmt &S);
+  void EmitMSAsmStmt(const MSAsmStmt &S);
 
   void EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S);
   void EmitObjCAtTryStmt(const ObjCAtTryStmt &S);
index 6652beaff49b4aa037ba18fbafc238babd3b0ed3..9f49ab59ce8172a9cf4a1fc8879325b23fa7aab3 100644 (file)
@@ -20,6 +20,7 @@
 #include "clang/Basic/Diagnostic.h"
 #include "clang/Basic/PrettyStackTrace.h"
 #include "clang/Basic/SourceManager.h"
+#include "llvm/ADT/SmallString.h"
 using namespace clang;
 
 //===----------------------------------------------------------------------===//
@@ -1627,9 +1628,24 @@ StmtResult Parser::ParseReturnStatement() {
 
 /// ParseMicrosoftAsmStatement. When -fms-extensions/-fasm-blocks is enabled,
 /// this routine is called to collect the tokens for an MS asm statement.
+///
+/// [MS]  ms-asm-statement:
+///         ms-asm-block
+///         ms-asm-block ms-asm-statement
+///
+/// [MS]  ms-asm-block:
+///         '__asm' ms-asm-line '\n'
+///         '__asm' '{' ms-asm-instruction-block[opt] '}' ';'[opt]
+///
+/// [MS]  ms-asm-instruction-block
+///         ms-asm-line
+///         ms-asm-line '\n' ms-asm-instruction-block
+///
 StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) {
   SourceManager &SrcMgr = PP.getSourceManager();
   SourceLocation EndLoc = AsmLoc;
+  SmallVector<Token, 4> AsmToks;
+  SmallVector<unsigned, 4> LineEnds;
   do {
     bool InBraces = false;
     unsigned short savedBraceCount = 0;
@@ -1658,9 +1674,6 @@ StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) {
       // If we hit EOF, we're done, period.
       if (Tok.is(tok::eof))
         break;
-      // When we consume the closing brace, we're done.
-      if (InBraces && BraceCount == savedBraceCount)
-        break;
 
       if (!InAsmComment && Tok.is(tok::semi)) {
         // A semicolon in an asm is the start of a comment.
@@ -1690,8 +1703,15 @@ StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) {
           // does MSVC do here?
           break;
         }
+      } else if (InBraces && Tok.is(tok::r_brace) &&
+                 BraceCount == savedBraceCount + 1) {
+        // Consume the closing brace, and finish
+        EndLoc = ConsumeBrace();
+        break;
       }
 
+      AsmToks.push_back(Tok);
+
       // Consume the next token; make sure we don't modify the brace count etc.
       // if we are in a comment.
       EndLoc = TokLoc;
@@ -1703,6 +1723,8 @@ StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) {
       ++NumTokensRead;
     } while (1);
 
+    LineEnds.push_back(AsmToks.size());
+
     if (InBraces && BraceCount != savedBraceCount) {
       // __asm without closing brace (this can happen at EOF).
       Diag(Tok, diag::err_expected_rbrace);
@@ -1719,24 +1741,33 @@ StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) {
       break;
     EndLoc = ConsumeToken();
   } while (1);
-  // FIXME: Need to actually grab the data and pass it on to Sema.  Ideally,
-  // what Sema wants is a string of the entire inline asm, with one instruction
-  // per line and all the __asm keywords stripped out, and a way of mapping
-  // from any character of that string to its location in the original source
-  // code. I'm not entirely sure how to go about that, though.
-  Token t;
-  t.setKind(tok::string_literal);
-  t.setLiteralData("\"/*FIXME: not done*/\"");
-  t.clearFlag(Token::NeedsCleaning);
-  t.setLength(21);
-  ExprResult AsmString(Actions.ActOnStringLiteral(&t, 1));
-  ExprVector Constraints(Actions);
-  ExprVector Exprs(Actions);
-  ExprVector Clobbers(Actions);
-  return Actions.ActOnAsmStmt(AsmLoc, true, true, 0, 0, 0,
-                              move_arg(Constraints), move_arg(Exprs),
-                              AsmString.take(), move_arg(Clobbers),
-                              EndLoc, true);
+
+  // Collect the tokens into a string
+  SmallString<512> Asm;
+  SmallString<512> TokenBuf;
+  TokenBuf.resize(512);
+  unsigned AsmLineNum = 0;
+  for (unsigned i = 0, e = AsmToks.size(); i < e; i++) {
+    const char *ThisTokBuf = &TokenBuf[0];
+    bool StringInvalid = false;
+    unsigned ThisTokLen = 
+      Lexer::getSpelling(AsmToks[i], ThisTokBuf, PP.getSourceManager(),
+                         PP.getLangOpts(), &StringInvalid);
+    if (i && (!AsmLineNum || i != LineEnds[AsmLineNum-1]))
+      Asm += ' '; // FIXME: Too much whitespace around punctuation
+    Asm += StringRef(ThisTokBuf, ThisTokLen);
+    if (i + 1 == LineEnds[AsmLineNum] && i + 1 != AsmToks.size()) {
+      Asm += '\n';
+      ++AsmLineNum;
+    }
+  }
+
+  // FIXME: We should be passing the tokens and source locations, rather than
+  // (or possibly in addition to the) AsmString.  Sema is going to interact with
+  // MC to determine Constraints, Clobbers, etc., which would be simplest to
+  // do with the tokens.
+  std::string AsmString = Asm.data();
+  return Actions.ActOnMSAsmStmt(AsmLoc, AsmString, EndLoc);
 }
 
 /// ParseAsmStatement - Parse a GNU extended asm statement.
@@ -1758,18 +1789,6 @@ StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) {
 ///         asm-string-literal
 ///         asm-clobbers ',' asm-string-literal
 ///
-/// [MS]  ms-asm-statement:
-///         ms-asm-block
-///         ms-asm-block ms-asm-statement
-///
-/// [MS]  ms-asm-block:
-///         '__asm' ms-asm-line '\n'
-///         '__asm' '{' ms-asm-instruction-block[opt] '}' ';'[opt]
-///
-/// [MS]  ms-asm-instruction-block
-///         ms-asm-line
-///         ms-asm-line '\n' ms-asm-instruction-block
-///
 StmtResult Parser::ParseAsmStatement(bool &msAsm) {
   assert(Tok.is(tok::kw_asm) && "Not an asm stmt");
   SourceLocation AsmLoc = ConsumeToken();
index cea8a765c805a07f17ce76cf15c044761f5203f1..7eba772743914d3143428d80fb17ed5dfaa8b7c5 100644 (file)
@@ -189,6 +189,12 @@ static ControlFlowKind CheckFallThrough(AnalysisDeclContext &AC) {
         continue;
       }
     }
+    if (isa<MSAsmStmt>(S)) {
+      // TODO: Verify this is correct.
+      HasFakeEdge = true;
+      HasLiveReturn = true;
+      continue;
+    }
     if (isa<CXXTryStmt>(S)) {
       HasAbnormalEdge = true;
       continue;
index 0e393149663d40b6e55e755e54ed97c44d17cdad..fb828909c3d5d1b818a578e3519947de2235f17b 100644 (file)
@@ -2670,6 +2670,15 @@ StmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, bool IsSimple,
   return Owned(NS);
 }
 
+StmtResult Sema::ActOnMSAsmStmt(SourceLocation AsmLoc,
+                                std::string &AsmString,
+                                SourceLocation EndLoc) {
+  MSAsmStmt *NS =
+    new (Context) MSAsmStmt(Context, AsmLoc, AsmString, EndLoc);
+
+  return Owned(NS);
+}
+
 StmtResult
 Sema::ActOnObjCAtCatchStmt(SourceLocation AtLoc,
                            SourceLocation RParen, Decl *Parm,
index 01b82aa3d75de64d484f7ddd7beec9aed117cd3e..08c7d7d11a14ecdcec6ee42cf3ea26ef26d4f210 100644 (file)
@@ -1179,6 +1179,16 @@ public:
                                   RParenLoc, MSAsm);
   }
 
+  /// \brief Build a new MS style inline asm statement.
+  ///
+  /// By default, performs semantic analysis to build the new statement.
+  /// Subclasses may override this routine to provide different behavior.
+  StmtResult RebuildMSAsmStmt(SourceLocation AsmLoc,
+                              std::string &AsmString,
+                              SourceLocation EndLoc) {
+    return getSema().ActOnMSAsmStmt(AsmLoc, AsmString, EndLoc);
+  }
+
   /// \brief Build a new Objective-C @try statement.
   ///
   /// By default, performs semantic analysis to build the new statement.
@@ -5602,6 +5612,14 @@ TreeTransform<Derived>::TransformAsmStmt(AsmStmt *S) {
                                      S->isMSAsm());
 }
 
+template<typename Derived>
+StmtResult
+TreeTransform<Derived>::TransformMSAsmStmt(MSAsmStmt *S) {
+  // No need to transform the asm string literal.
+  return getDerived().RebuildMSAsmStmt(S->getAsmLoc(),
+                                       *S->getAsmString(),
+                                       S->getEndLoc());
+}
 
 template<typename Derived>
 StmtResult
index 965b4d1facd0e4a4a25846d19975bcd8e2c3bd5d..9823be19427be88d039a5b884ce23e363c3179e7 100644 (file)
@@ -317,6 +317,11 @@ void ASTStmtReader::VisitAsmStmt(AsmStmt *S) {
                                     Clobbers.data(), NumClobbers);
 }
 
+void ASTStmtReader::VisitMSAsmStmt(MSAsmStmt *S) {
+  // FIXME: Statement reader not yet implemented for MS style inline asm.
+  VisitStmt(S);
+}
+
 void ASTStmtReader::VisitExpr(Expr *E) {
   VisitStmt(E);
   E->setType(Reader.readType(F, Record, Idx));
index 9921d6ec47fd9c355a78a4dcb88ecc943946a770..1d2efe48e4487fbae18e1f2eab15691005866ca0 100644 (file)
@@ -249,6 +249,11 @@ void ASTStmtWriter::VisitAsmStmt(AsmStmt *S) {
   Code = serialization::STMT_ASM;
 }
 
+void ASTStmtWriter::VisitMSAsmStmt(MSAsmStmt *S) {
+  // FIXME: Statement writer not yet implemented for MS style inline asm.
+  VisitStmt(S);
+}
+
 void ASTStmtWriter::VisitExpr(Expr *E) {
   VisitStmt(E);
   Writer.AddTypeRef(E->getType(), Record);
index 6531265807cbfb592ac5b4e156ba6090b3161c73..a95f565b6c9d20c0e16fc5c38b3079dd8fca44c2 100644 (file)
@@ -670,6 +670,12 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
       Bldr.addNodes(Dst);
       break;
 
+    case Stmt::MSAsmStmtClass:
+      Bldr.takeNodes(Pred);
+      VisitMSAsmStmt(cast<MSAsmStmt>(S), Pred, Dst);
+      Bldr.addNodes(Dst);
+      break;
+
     case Stmt::BlockExprClass:
       Bldr.takeNodes(Pred);
       VisitBlockExpr(cast<BlockExpr>(S), Pred, Dst);
@@ -1813,6 +1819,12 @@ void ExprEngine::VisitAsmStmt(const AsmStmt *A, ExplodedNode *Pred,
   Bldr.generateNode(A, Pred, state);
 }
 
+void ExprEngine::VisitMSAsmStmt(const MSAsmStmt *A, ExplodedNode *Pred,
+                                ExplodedNodeSet &Dst) {
+  StmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext);
+  Bldr.generateNode(A, Pred, Pred->getState());
+}
+
 //===----------------------------------------------------------------------===//
 // Visualization.
 //===----------------------------------------------------------------------===//
index 9a17b35cd10bd147cfca9dd3728af3caedc6beb3..7fb944ddd3ab20e983a2f9fb7655542077a6b3fd 100644 (file)
@@ -3506,6 +3506,8 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) {
       return createCXString("ReturnStmt");
   case CXCursor_AsmStmt:
       return createCXString("AsmStmt");
+  case CXCursor_MSAsmStmt:
+      return createCXString("MSAsmStmt");
   case CXCursor_ObjCAtTryStmt:
       return createCXString("ObjCAtTryStmt");
   case CXCursor_ObjCAtCatchStmt:
index c344b41cecc1d459be85aaddf37ee869a2f774bd..08c4de367af1101f66c52bbb55e239a0bb90000a 100644 (file)
@@ -148,6 +148,10 @@ CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent, CXTranslationUnit TU,
   case Stmt::AsmStmtClass:
     K = CXCursor_AsmStmt;
     break;
+
+  case Stmt::MSAsmStmtClass:
+    K = CXCursor_MSAsmStmt;
+    break;
   
   case Stmt::ObjCAtTryStmtClass:
     K = CXCursor_ObjCAtTryStmt;
index bf43956a1a3464d98baa2abe0206553413116210..7131025ee1e0fab39dca7137fd9a892cfa0e3562 100644 (file)
@@ -1767,6 +1767,11 @@ DEF_TRAVERSE_STMT(AsmStmt, {
     // children() iterates over inputExpr and outputExpr.
   })
 
+DEF_TRAVERSE_STMT(MSAsmStmt, {
+    // FIXME: MS Asm doesn't currently parse Constraints, Clobbers, etc.  Once
+    // added this needs to be implemented.
+  })
+
 DEF_TRAVERSE_STMT(CXXCatchStmt, {
     TRY_TO(TraverseDecl(S->getExceptionDecl()));
     // children() iterates over the handler block.