[ms-inline-asm] Add handling for errors coming out of the backend.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@166463 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaStmtAsm.cpp b/lib/Sema/SemaStmtAsm.cpp
index 616dcfc..f33b87c 100644
--- a/lib/Sema/SemaStmtAsm.cpp
+++ b/lib/Sema/SemaStmtAsm.cpp
@@ -328,6 +328,7 @@
 static bool buildMSAsmString(Sema &SemaRef,
                              SourceLocation AsmLoc,
                              ArrayRef<Token> AsmToks,
+                             llvm::SmallVectorImpl<unsigned> &TokOffsets,
                              std::string &AsmString) {
   assert (!AsmToks.empty() && "Didn't expect an empty AsmToks!");
 
@@ -355,6 +356,7 @@
 
     StringRef Spelling = getSpelling(SemaRef, AsmToks[i]);
     Asm += Spelling;
+    TokOffsets.push_back(Asm.size());
   }
   AsmString = Asm.str();
   return false;
@@ -363,17 +365,53 @@
 namespace {
 
 class MCAsmParserSemaCallbackImpl : public llvm::MCAsmParserSemaCallback {
-  Sema *SemaRef;
+  Sema &SemaRef;
+  SourceLocation AsmLoc;
+  ArrayRef<Token> AsmToks;
+  ArrayRef<unsigned> TokOffsets;
 
 public:
-  MCAsmParserSemaCallbackImpl(class Sema *Ref) { SemaRef = Ref; }
+  MCAsmParserSemaCallbackImpl(Sema &Ref, SourceLocation Loc,
+                              ArrayRef<Token> Toks,
+                              ArrayRef<unsigned> Offsets)
+    : SemaRef(Ref), AsmLoc(Loc), AsmToks(Toks), TokOffsets(Offsets) { }
   ~MCAsmParserSemaCallbackImpl() {}
 
   void *LookupInlineAsmIdentifier(StringRef Name, void *SrcLoc, unsigned &Size){
     SourceLocation Loc = SourceLocation::getFromPtrEncoding(SrcLoc);
-    NamedDecl *OpDecl = SemaRef->LookupInlineAsmIdentifier(Name, Loc, Size);
+    NamedDecl *OpDecl = SemaRef.LookupInlineAsmIdentifier(Name, Loc, Size);
     return static_cast<void *>(OpDecl);
   }
+
+  static void MSAsmDiagHandlerCallback(const llvm::SMDiagnostic &D,
+                                       void *Context) {
+    ((MCAsmParserSemaCallbackImpl*)Context)->MSAsmDiagHandler(D);
+  }
+  void MSAsmDiagHandler(const llvm::SMDiagnostic &D) {
+    // Compute an offset into the inline asm buffer.
+    // FIXME: This isn't right if .macro is involved (but hopefully, no
+    // real-world code does that).
+    const llvm::SourceMgr &LSM = *D.getSourceMgr();
+    const llvm::MemoryBuffer *LBuf =
+    LSM.getMemoryBuffer(LSM.FindBufferContainingLoc(D.getLoc()));
+    unsigned Offset = D.getLoc().getPointer()  - LBuf->getBufferStart();
+
+    // Figure out which token that offset points into.
+    const unsigned *OffsetPtr =
+        std::lower_bound(TokOffsets.begin(), TokOffsets.end(), Offset);
+    unsigned TokIndex = OffsetPtr - TokOffsets.begin();
+
+    // If we come up with an answer which seems sane, use it; otherwise,
+    // just point at the __asm keyword.
+    // FIXME: Assert the answer is sane once we handle .macro correctly.
+    SourceLocation Loc = AsmLoc;
+    if (TokIndex < AsmToks.size()) {
+      const Token *Tok = &AsmToks[TokIndex];
+      Loc = Tok->getLocation();
+      Loc = Loc.getLocWithOffset(Offset - (*OffsetPtr - Tok->getLength()));
+    }
+    SemaRef.Diag(Loc, diag::err_inline_ms_asm_parsing) << D.getMessage();
+  }
 };
 
 }
@@ -427,7 +465,8 @@
   }
 
   std::string AsmString;
-  if (buildMSAsmString(*this, AsmLoc, AsmToks, AsmString))
+  llvm::SmallVector<unsigned, 8> TokOffsets;
+  if (buildMSAsmString(*this, AsmLoc, AsmToks, TokOffsets, AsmString))
     return StmtError();
 
   // Get the target specific parser.
@@ -466,8 +505,10 @@
   Parser->setParsingInlineAsm(true);
   TargetParser->setParsingInlineAsm(true);
 
-  MCAsmParserSemaCallbackImpl MCAPSI(this);
+  MCAsmParserSemaCallbackImpl MCAPSI(*this, AsmLoc, AsmToks, TokOffsets);
   TargetParser->setSemaCallback(&MCAPSI);
+  SrcMgr.setDiagHandler(MCAsmParserSemaCallbackImpl::MSAsmDiagHandlerCallback,
+                        &MCAPSI);
 
   unsigned NumOutputs;
   unsigned NumInputs;