]> granicus.if.org Git - clang/commitdiff
Move parsing of identifiers in MS-style inline assembly into
authorJohn McCall <rjmccall@apple.com>
Fri, 3 May 2013 00:10:13 +0000 (00:10 +0000)
committerJohn McCall <rjmccall@apple.com>
Fri, 3 May 2013 00:10:13 +0000 (00:10 +0000)
the actual parser and support arbitrary id-expressions.

We're actually basically set up to do arbitrary expressions here
if we wanted to.

Assembly operands permit things like A::x to be written regardless
of language mode, which forces us to embellish the evaluation
context logic somewhat.  The logic here under template instantiation
is incorrect;  we need to preserve the fact that an expression was
unevaluated.  Of course, template instantiation in general is fishy
here because we have no way of delaying semantic analysis in the
MC parser.  It's all just fishy.

I've also fixed the serialization of MS asm statements.

This commit depends on an LLVM commit.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@180976 91177308-0d34-0410-b5e6-96231b3b80d8

24 files changed:
include/clang/AST/Stmt.h
include/clang/Basic/DiagnosticParseKinds.td
include/clang/Basic/DiagnosticSemaKinds.td
include/clang/Parse/Parser.h
include/clang/Sema/Sema.h
include/clang/Serialization/ASTReader.h
include/clang/Serialization/ASTWriter.h
lib/AST/Stmt.cpp
lib/AST/StmtPrinter.cpp
lib/CodeGen/CGStmt.cpp
lib/Parse/ParseStmt.cpp
lib/Sema/SemaDeclCXX.cpp
lib/Sema/SemaExpr.cpp
lib/Sema/SemaExprCXX.cpp
lib/Sema/SemaExprMember.cpp
lib/Sema/SemaLambda.cpp
lib/Sema/SemaStmt.cpp
lib/Sema/SemaStmtAsm.cpp
lib/Sema/TreeTransform.h
lib/Serialization/ASTReader.cpp
lib/Serialization/ASTReaderStmt.cpp
lib/Serialization/ASTWriter.cpp
lib/Serialization/ASTWriterStmt.cpp
test/CodeGen/ms-inline-asm.cpp

index 1e5892fcf77d89d18490dcdcb858f5b0179eaa87..6e5fae4f3c2cbf2e6d9de32827afa1e43d7a9421 100644 (file)
@@ -1387,7 +1387,6 @@ protected:
   unsigned NumInputs;
   unsigned NumClobbers;
 
-  IdentifierInfo **Names;
   Stmt **Exprs;
 
   AsmStmt(StmtClass SC, SourceLocation asmloc, bool issimple, bool isvolatile,
@@ -1395,10 +1394,12 @@ protected:
     Stmt (SC), AsmLoc(asmloc), IsSimple(issimple), IsVolatile(isvolatile),
     NumOutputs(numoutputs), NumInputs(numinputs), NumClobbers(numclobbers) { }
 
+  friend class ASTStmtReader;
+
 public:
   /// \brief Build an empty inline-assembly statement.
   explicit AsmStmt(StmtClass SC, EmptyShell Empty) :
-    Stmt(SC, Empty), Names(0), Exprs(0) { }
+    Stmt(SC, Empty), Exprs(0) { }
 
   SourceLocation getAsmLoc() const { return AsmLoc; }
   void setAsmLoc(SourceLocation L) { AsmLoc = L; }
@@ -1421,17 +1422,6 @@ public:
 
   unsigned getNumOutputs() const { return NumOutputs; }
 
-  IdentifierInfo *getOutputIdentifier(unsigned i) const {
-    return Names[i];
-  }
-
-  StringRef getOutputName(unsigned i) const {
-    if (IdentifierInfo *II = getOutputIdentifier(i))
-      return II->getName();
-
-    return StringRef();
-  }
-
   /// getOutputConstraint - Return the constraint string for the specified
   /// output operand.  All output constraints are known to be non-empty (either
   /// '=' or '+').
@@ -1454,17 +1444,6 @@ public:
 
   unsigned getNumInputs() const { return NumInputs; }
 
-  IdentifierInfo *getInputIdentifier(unsigned i) const {
-    return Names[i + NumOutputs];
-  }
-
-  StringRef getInputName(unsigned i) const {
-    if (IdentifierInfo *II = getInputIdentifier(i))
-      return II->getName();
-
-    return StringRef();
-  }
-
   /// getInputConstraint - Return the specified input constraint.  Unlike output
   /// constraints, these can be empty.
   StringRef getInputConstraint(unsigned i) const;
@@ -1535,6 +1514,9 @@ class GCCAsmStmt : public AsmStmt {
   // FIXME: If we wanted to, we could allocate all of these in one big array.
   StringLiteral **Constraints;
   StringLiteral **Clobbers;
+  IdentifierInfo **Names;
+
+  friend class ASTStmtReader;
 
 public:
   GCCAsmStmt(ASTContext &C, SourceLocation asmloc, bool issimple,
@@ -1545,7 +1527,7 @@ public:
 
   /// \brief Build an empty inline-assembly statement.
   explicit GCCAsmStmt(EmptyShell Empty) : AsmStmt(GCCAsmStmtClass, Empty),
-    Constraints(0), Clobbers(0) { }
+    Constraints(0), Clobbers(0), Names(0) { }
 
   SourceLocation getRParenLoc() const { return RParenLoc; }
   void setRParenLoc(SourceLocation L) { RParenLoc = L; }
@@ -1610,6 +1592,17 @@ public:
 
   //===--- Output operands ---===//
 
+  IdentifierInfo *getOutputIdentifier(unsigned i) const {
+    return Names[i];
+  }
+
+  StringRef getOutputName(unsigned i) const {
+    if (IdentifierInfo *II = getOutputIdentifier(i))
+      return II->getName();
+
+    return StringRef();
+  }
+
   StringRef getOutputConstraint(unsigned i) const;
 
   const StringLiteral *getOutputConstraintLiteral(unsigned i) const {
@@ -1627,6 +1620,17 @@ public:
 
   //===--- Input operands ---===//
 
+  IdentifierInfo *getInputIdentifier(unsigned i) const {
+    return Names[i + NumOutputs];
+  }
+
+  StringRef getInputName(unsigned i) const {
+    if (IdentifierInfo *II = getInputIdentifier(i))
+      return II->getName();
+
+    return StringRef();
+  }
+
   StringRef getInputConstraint(unsigned i) const;
 
   const StringLiteral *getInputConstraintLiteral(unsigned i) const {
@@ -1643,6 +1647,7 @@ public:
     return const_cast<GCCAsmStmt*>(this)->getInputExpr(i);
   }
 
+private:
   void setOutputsAndInputsAndClobbers(ASTContext &C,
                                       IdentifierInfo **Names,
                                       StringLiteral **Constraints,
@@ -1651,6 +1656,7 @@ public:
                                       unsigned NumInputs,
                                       StringLiteral **Clobbers,
                                       unsigned NumClobbers);
+public:
 
   //===--- Other ---===//
 
@@ -1677,7 +1683,7 @@ public:
 ///
 class MSAsmStmt : public AsmStmt {
   SourceLocation LBraceLoc, EndLoc;
-  std::string AsmStr;
+  StringRef AsmStr;
 
   unsigned NumAsmToks;
 
@@ -1685,11 +1691,13 @@ class MSAsmStmt : public AsmStmt {
   StringRef *Constraints;
   StringRef *Clobbers;
 
+  friend class ASTStmtReader;
+
 public:
   MSAsmStmt(ASTContext &C, SourceLocation asmloc, SourceLocation lbraceloc,
             bool issimple, bool isvolatile, ArrayRef<Token> asmtoks,
             unsigned numoutputs, unsigned numinputs,
-            ArrayRef<IdentifierInfo*> names, ArrayRef<StringRef> constraints,
+            ArrayRef<StringRef> constraints,
             ArrayRef<Expr*> exprs, StringRef asmstr,
             ArrayRef<StringRef> clobbers, SourceLocation endloc);
 
@@ -1708,10 +1716,7 @@ public:
   Token *getAsmToks() { return AsmToks; }
 
   //===--- Asm String Analysis ---===//
-
-  const std::string *getAsmString() const { return &AsmStr; }
-  std::string *getAsmString() { return &AsmStr; }
-  void setAsmString(StringRef &E) { AsmStr = E.str(); }
+  StringRef getAsmString() const { return AsmStr; }
 
   /// Assemble final IR asm string.
   std::string generateAsmString(ASTContext &C) const;
@@ -1719,6 +1724,7 @@ public:
   //===--- Output operands ---===//
 
   StringRef getOutputConstraint(unsigned i) const {
+    assert(i < NumOutputs);
     return Constraints[i];
   }
 
@@ -1731,6 +1737,7 @@ public:
   //===--- Input operands ---===//
 
   StringRef getInputConstraint(unsigned i) const {
+    assert(i < NumInputs);
     return Constraints[i + NumOutputs];
   }
 
@@ -1743,7 +1750,27 @@ public:
 
   //===--- Other ---===//
 
-  StringRef getClobber(unsigned i) const { return Clobbers[i]; }
+  ArrayRef<StringRef> getAllConstraints() const {
+    return ArrayRef<StringRef>(Constraints, NumInputs + NumOutputs);
+  }
+  ArrayRef<StringRef> getClobbers() const {
+    return ArrayRef<StringRef>(Clobbers, NumClobbers);
+  }
+  ArrayRef<Expr*> getAllExprs() const {
+    return ArrayRef<Expr*>(reinterpret_cast<Expr**>(Exprs),
+                           NumInputs + NumOutputs);
+  }
+
+  StringRef getClobber(unsigned i) const { return getClobbers()[i]; }
+
+private:
+  void initialize(ASTContext &C,
+                  StringRef AsmString,
+                  ArrayRef<Token> AsmToks,
+                  ArrayRef<StringRef> Constraints,
+                  ArrayRef<Expr*> Exprs,
+                  ArrayRef<StringRef> Clobbers);
+public:
 
   SourceLocation getLocStart() const LLVM_READONLY { return AsmLoc; }
   SourceLocation getLocEnd() const LLVM_READONLY { return EndLoc; }
index 08abef120af0ded6c9809305919b09bdc903d031..f50dceca578a724e5e88cf383c8b4e08fc5180e4 100644 (file)
@@ -18,6 +18,13 @@ def w_asm_qualifier_ignored : Warning<"ignored %0 qualifier on asm">,
 def warn_file_asm_volatile : Warning<
   "meaningless 'volatile' on asm outside function">, CatInlineAsm;
 
+let CategoryName = "Inline Assembly Issue" in {
+def err_asm_empty : Error<"__asm used with no assembly instructions">;
+def err_inline_ms_asm_parsing : Error<"%0">;
+def err_msasm_unsupported_arch : Error<
+  "Unsupported architecture '%0' for MS-style inline assembly">;
+}
+
 let CategoryName = "Parse Issue" in {
 
 def ext_empty_translation_unit : Extension<
index fb2ffe88728c00165a520bdf4aee1148c472d3f9..bfbbb91be9510ec586b71dceecc25eb9b275de48 100644 (file)
@@ -5408,16 +5408,13 @@ let CategoryName = "Inline Assembly Issue" in {
   def err_asm_tying_incompatible_types : Error<
     "unsupported inline asm: input with type "
     "%diff{$ matching output with type $|}0,1">;
+  def err_asm_incomplete_type : Error<"asm operand has incomplete type %0">;
   def err_asm_unknown_register_name : Error<"unknown register name '%0' in asm">;
-  def err_asm_empty : Error<"__asm used with no assembly instructions">;
   def err_asm_invalid_input_size : Error<
     "invalid input size for constraint '%0'">;
   def err_invalid_asm_cast_lvalue : Error<
     "invalid use of a cast in a inline asm context requiring an l-value: "
     "remove the cast or build with -fheinous-gnu-extensions">;
-  def err_inline_ms_asm_parsing : Error<"%0">;
-  def err_msasm_unsupported_arch : Error<
-    "Unsupported architecture '%0' for MS-style inline assembly">;
 
   def warn_asm_label_on_auto_decl : Warning<
     "ignored asm label '%0' on automatic variable">;
index 44c213c5ef413762d1191bca5bb014cd9bf9d03a..a33d01d27b650499ff5d7f8712d666fb3a5cb72f 100644 (file)
@@ -1221,6 +1221,11 @@ public:
   // Expr that doesn't include commas.
   ExprResult ParseAssignmentExpression(TypeCastState isTypeCast = NotTypeCast);
 
+  ExprResult ParseMSAsmIdentifier(llvm::SmallVectorImpl<Token> &LineToks,
+                                  unsigned &NumLineToksConsumed,
+                                  void *Info,
+                                  bool IsUnevaluated);
+
 private:
   ExprResult ParseExpressionWithLeadingAt(SourceLocation AtLoc);
 
index e5f2d448fd488fc9f7904a420cbe848bb7319e42..9aee774d1f2f652bae58c0650d7078c6fa051ca4 100644 (file)
@@ -600,6 +600,10 @@ public:
   /// have been declared.
   bool GlobalNewDeleteDeclared;
 
+  /// A flag to indicate that we're in a context that permits abstract
+  /// references to fields.  This is really a 
+  bool AllowAbstractFieldReference;
+
   /// \brief Describes how the expressions currently being parsed are
   /// evaluated at run-time, if at all.
   enum ExpressionEvaluationContext {
@@ -610,6 +614,11 @@ public:
     /// run time.
     Unevaluated,
 
+    /// \brief The current expression occurs within an unevaluated
+    /// operand that unconditionally permits abstract references to
+    /// fields, such as a SIZE operator in MS-style inline assembly.
+    UnevaluatedAbstract,
+
     /// \brief The current context is "potentially evaluated" in C++11 terms,
     /// but the expression is evaluated at compile-time (like the values of
     /// cases in a switch statment).
@@ -689,6 +698,10 @@ public:
         LambdaMangle = new LambdaMangleContext;
       return *LambdaMangle;
     }
+
+    bool isUnevaluated() const {
+      return Context == Unevaluated || Context == UnevaluatedAbstract;
+    }
   };
 
   /// A stack of expression evaluation contexts.
@@ -2801,12 +2814,21 @@ public:
                              Expr *AsmString, MultiExprArg Clobbers,
                              SourceLocation RParenLoc);
 
-  NamedDecl *LookupInlineAsmIdentifier(StringRef &LineBuf, SourceLocation Loc,
-                                       InlineAsmIdentifierInfo &Info);
+  ExprResult LookupInlineAsmIdentifier(CXXScopeSpec &SS,
+                                       SourceLocation TemplateKWLoc,
+                                       UnqualifiedId &Id,
+                                       InlineAsmIdentifierInfo &Info,
+                                       bool IsUnevaluatedContext);
   bool LookupInlineAsmField(StringRef Base, StringRef Member,
                             unsigned &Offset, SourceLocation AsmLoc);
   StmtResult ActOnMSAsmStmt(SourceLocation AsmLoc, SourceLocation LBraceLoc,
-                            ArrayRef<Token> AsmToks, SourceLocation EndLoc);
+                            ArrayRef<Token> AsmToks,
+                            StringRef AsmString,
+                            unsigned NumOutputs, unsigned NumInputs,
+                            ArrayRef<StringRef> Constraints,
+                            ArrayRef<StringRef> Clobbers,
+                            ArrayRef<Expr*> Exprs,
+                            SourceLocation EndLoc);
 
   VarDecl *BuildObjCExceptionDecl(TypeSourceInfo *TInfo, QualType ExceptionType,
                                   SourceLocation StartLoc,
@@ -5998,7 +6020,7 @@ public:
   bool isUnevaluatedContext() const {
     assert(!ExprEvalContexts.empty() &&
            "Must be in an expression evaluation context");
-    return ExprEvalContexts.back().Context == Sema::Unevaluated;
+    return ExprEvalContexts.back().isUnevaluated();
   }
 
   /// \brief RAII class used to determine whether SFINAE has
index 0aa649a84d17f5188ab56cd550eaf0e15edcd519..9c19eda1ff1ced6c10fddf34c246e93f99e7f8ca 100644 (file)
@@ -1802,6 +1802,9 @@ public:
   /// \brief Reads a sub-expression operand during statement reading.
   Expr *ReadSubExpr();
 
+  /// \brief Reads a token out of a record.
+  Token ReadToken(ModuleFile &M, const RecordData &Record, unsigned &Idx);
+
   /// \brief Reads the macro record located at the given offset.
   MacroInfo *ReadMacroRecord(ModuleFile &F, uint64_t Offset);
 
index 2938dc76de4992db31e34dcecdb7aa36767aeb99..8ac8fde88470c1a17e5e94f557fcd3fc9a8803fa 100644 (file)
@@ -63,6 +63,7 @@ class Sema;
 class SourceManager;
 class SwitchCase;
 class TargetInfo;
+class Token;
 class VersionTuple;
 class ASTUnresolvedSet;
 
@@ -498,6 +499,9 @@ public:
                 Module *WritingModule, StringRef isysroot,
                 bool hasErrors = false);
 
+  /// \brief Emit a token.
+  void AddToken(const Token &Tok, RecordDataImpl &Record);
+
   /// \brief Emit a source location.
   void AddSourceLocation(SourceLocation Loc, RecordDataImpl &Record);
 
index 2a7b170222067bffb6d05460cb709b9663f28482..888a148b961cdb5226ccf6b14ffa3f93a12b2727 100644 (file)
@@ -673,19 +673,38 @@ GCCAsmStmt::GCCAsmStmt(ASTContext &C, SourceLocation asmloc, bool issimple,
 MSAsmStmt::MSAsmStmt(ASTContext &C, SourceLocation asmloc,
                      SourceLocation lbraceloc, bool issimple, bool isvolatile,
                      ArrayRef<Token> asmtoks, unsigned numoutputs,
-                     unsigned numinputs, ArrayRef<IdentifierInfo*> names,
+                     unsigned numinputs,
                      ArrayRef<StringRef> constraints, ArrayRef<Expr*> exprs,
                      StringRef asmstr, ArrayRef<StringRef> clobbers,
                      SourceLocation endloc)
   : AsmStmt(MSAsmStmtClass, asmloc, issimple, isvolatile, numoutputs,
             numinputs, clobbers.size()), LBraceLoc(lbraceloc),
-            EndLoc(endloc), AsmStr(asmstr.str()), NumAsmToks(asmtoks.size()) {
+            EndLoc(endloc), NumAsmToks(asmtoks.size()) {
 
-  unsigned NumExprs = NumOutputs + NumInputs;
+  initialize(C, asmstr, asmtoks, constraints, exprs, clobbers);
+}
 
-  Names = new (C) IdentifierInfo*[NumExprs];
-  for (unsigned i = 0, e = NumExprs; i != e; ++i)
-    Names[i] = names[i];
+static StringRef copyIntoContext(ASTContext &C, StringRef str) {
+  size_t size = str.size();
+  char *buffer = new (C) char[size];
+  memcpy(buffer, str.data(), size);
+  return StringRef(buffer, size);
+}
+
+void MSAsmStmt::initialize(ASTContext &C,
+                           StringRef asmstr,
+                           ArrayRef<Token> asmtoks,
+                           ArrayRef<StringRef> constraints,
+                           ArrayRef<Expr*> exprs,
+                           ArrayRef<StringRef> clobbers) {
+  assert(NumAsmToks == asmtoks.size());
+  assert(NumClobbers == clobbers.size());
+
+  unsigned NumExprs = exprs.size();
+  assert(NumExprs == NumOutputs + NumInputs);
+  assert(NumExprs == constraints.size());
+
+  AsmStr = copyIntoContext(C, asmstr);
 
   Exprs = new (C) Stmt*[NumExprs];
   for (unsigned i = 0, e = NumExprs; i != e; ++i)
@@ -697,19 +716,13 @@ MSAsmStmt::MSAsmStmt(ASTContext &C, SourceLocation asmloc,
 
   Constraints = new (C) StringRef[NumExprs];
   for (unsigned i = 0, e = NumExprs; i != e; ++i) {
-    size_t size = constraints[i].size();
-    char *dest = new (C) char[size];
-    std::strncpy(dest, constraints[i].data(), size); 
-    Constraints[i] = StringRef(dest, size);
+    Constraints[i] = copyIntoContext(C, constraints[i]);
   }
 
   Clobbers = new (C) StringRef[NumClobbers];
   for (unsigned i = 0, e = NumClobbers; i != e; ++i) {
     // FIXME: Avoid the allocation/copy if at all possible.
-    size_t size = clobbers[i].size();
-    char *dest = new (C) char[size];
-    std::strncpy(dest, clobbers[i].data(), size); 
-    Clobbers[i] = StringRef(dest, size);
+    Clobbers[i] = copyIntoContext(C, clobbers[i]);
   }
 }
 
index a7177063ce0f8e34b2f8973221b3eddc42ca7b25..9203dc1584bb46b4e36ccf751fd0046f8e57e5a3 100644 (file)
@@ -445,7 +445,7 @@ void StmtPrinter::VisitMSAsmStmt(MSAsmStmt *Node) {
   Indent() << "__asm ";
   if (Node->hasBraces())
     OS << "{\n";
-  OS << *(Node->getAsmString()) << "\n";
+  OS << Node->getAsmString() << "\n";
   if (Node->hasBraces())
     Indent() << "}\n";
 }
index 28bbc46c689c4efac4316b57453a228b58be985f..73f66e0c8c7dea12c4e6b248d902cf090012434f 100644 (file)
@@ -1475,16 +1475,20 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
   SmallVector<TargetInfo::ConstraintInfo, 4> InputConstraintInfos;
 
   for (unsigned i = 0, e = S.getNumOutputs(); i != e; i++) {
-    TargetInfo::ConstraintInfo Info(S.getOutputConstraint(i),
-                                    S.getOutputName(i));
+    StringRef Name;
+    if (const GCCAsmStmt *GAS = dyn_cast<GCCAsmStmt>(&S))
+      Name = GAS->getOutputName(i);
+    TargetInfo::ConstraintInfo Info(S.getOutputConstraint(i), Name);
     bool IsValid = getTarget().validateOutputConstraint(Info); (void)IsValid;
     assert(IsValid && "Failed to parse output constraint"); 
     OutputConstraintInfos.push_back(Info);
   }
 
   for (unsigned i = 0, e = S.getNumInputs(); i != e; i++) {
-    TargetInfo::ConstraintInfo Info(S.getInputConstraint(i),
-                                    S.getInputName(i));
+    StringRef Name;
+    if (const GCCAsmStmt *GAS = dyn_cast<GCCAsmStmt>(&S))
+      Name = GAS->getInputName(i);
+    TargetInfo::ConstraintInfo Info(S.getInputConstraint(i), Name);
     bool IsValid =
       getTarget().validateInputConstraint(OutputConstraintInfos.data(),
                                           S.getNumOutputs(), Info);
index 5fa4f170265f1208f715bbae47500063e3cf518d..43b6965d314fcbd662f0355052508534b5c21595 100644 (file)
 
 #include "clang/Parse/Parser.h"
 #include "RAIIObjectsForParser.h"
+#include "clang/AST/ASTContext.h"
 #include "clang/Basic/Diagnostic.h"
 #include "clang/Basic/PrettyStackTrace.h"
 #include "clang/Basic/SourceManager.h"
+#include "clang/Basic/TargetInfo.h"
 #include "clang/Sema/DeclSpec.h"
 #include "clang/Sema/PrettyDeclStackTrace.h"
 #include "clang/Sema/Scope.h"
 #include "clang/Sema/TypoCorrection.h"
+#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCObjectFileInfo.h"
+#include "llvm/MC/MCParser/MCAsmParser.h"
+#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/MC/MCStreamer.h"
+#include "llvm/MC/MCSubtargetInfo.h"
+#include "llvm/MC/MCTargetAsmParser.h"
+#include "llvm/Support/SourceMgr.h"
+#include "llvm/Support/TargetRegistry.h"
+#include "llvm/Support/TargetSelect.h"
 #include "llvm/ADT/SmallString.h"
 using namespace clang;
 
@@ -1663,6 +1676,281 @@ StmtResult Parser::ParseReturnStatement() {
   return Actions.ActOnReturnStmt(ReturnLoc, R.take());
 }
 
+namespace {
+  class ClangAsmParserCallback : public llvm::MCAsmParserSemaCallback {
+    Parser &TheParser;
+    SourceLocation AsmLoc;
+    StringRef AsmString;
+
+    /// The tokens we streamed into AsmString and handed off to MC.
+    ArrayRef<Token> AsmToks;
+
+    /// The offset of each token in AsmToks within AsmString.
+    ArrayRef<unsigned> AsmTokOffsets;
+
+  public:
+    ClangAsmParserCallback(Parser &P, SourceLocation Loc,
+                           StringRef AsmString,
+                           ArrayRef<Token> Toks,
+                           ArrayRef<unsigned> Offsets)
+      : TheParser(P), AsmLoc(Loc), AsmString(AsmString),
+        AsmToks(Toks), AsmTokOffsets(Offsets) {
+      assert(AsmToks.size() == AsmTokOffsets.size());
+    }
+
+    void *LookupInlineAsmIdentifier(StringRef &LineBuf,
+                                    InlineAsmIdentifierInfo &Info,
+                                    bool IsUnevaluatedContext) {
+      // Collect the desired tokens.
+      SmallVector<Token, 16> LineToks;
+      const Token *FirstOrigToken = 0;
+      findTokensForString(LineBuf, LineToks, FirstOrigToken);
+
+      unsigned NumConsumedToks;
+      ExprResult Result =
+        TheParser.ParseMSAsmIdentifier(LineToks, NumConsumedToks, &Info,
+                                       IsUnevaluatedContext);
+
+      // If we consumed the entire line, tell MC that.
+      // Also do this if we consumed nothing as a way of reporting failure.
+      if (NumConsumedToks == 0 || NumConsumedToks == LineToks.size()) {
+        // By not modifying LineBuf, we're implicitly consuming it all.
+
+      // Otherwise, consume up to the original tokens.
+      } else {
+        assert(FirstOrigToken && "not using original tokens?");
+
+        // Since we're using original tokens, apply that offset.
+        assert(FirstOrigToken[NumConsumedToks].getLocation()
+                  == LineToks[NumConsumedToks].getLocation());
+        unsigned FirstIndex = FirstOrigToken - AsmToks.begin();
+        unsigned LastIndex = FirstIndex + NumConsumedToks - 1;
+
+        // The total length we've consumed is the relative offset
+        // of the last token we consumed plus its length.
+        unsigned TotalOffset = (AsmTokOffsets[LastIndex]
+                                + AsmToks[LastIndex].getLength()
+                                - AsmTokOffsets[FirstIndex]);
+        LineBuf = LineBuf.substr(0, TotalOffset);
+      }
+
+      // Initialize the "decl" with the lookup result.
+      Info.OpDecl = static_cast<void*>(Result.take());
+      return Info.OpDecl;
+    }
+
+    bool LookupInlineAsmField(StringRef Base, StringRef Member,
+                              unsigned &Offset) {
+      return TheParser.getActions().LookupInlineAsmField(Base, Member,
+                                                         Offset, AsmLoc);
+    }
+
+    static void DiagHandlerCallback(const llvm::SMDiagnostic &D,
+                                    void *Context) {
+      ((ClangAsmParserCallback*) Context)->handleDiagnostic(D);
+    }
+
+  private:
+    /// Collect the appropriate tokens for the given string.
+    void findTokensForString(StringRef Str, SmallVectorImpl<Token> &TempToks,
+                             const Token *&FirstOrigToken) const {
+      // For now, assert that the string we're working with is a substring
+      // of what we gave to MC.  This lets us use the original tokens.
+      assert(!std::less<const char*>()(Str.begin(), AsmString.begin()) &&
+             !std::less<const char*>()(AsmString.end(), Str.end()));
+
+      // Try to find a token whose offset matches the first token.
+      unsigned FirstCharOffset = Str.begin() - AsmString.begin();
+      const unsigned *FirstTokOffset
+        = std::lower_bound(AsmTokOffsets.begin(), AsmTokOffsets.end(),
+                           FirstCharOffset);
+
+      // For now, assert that the start of the string exactly
+      // corresponds to the start of a token.
+      assert(*FirstTokOffset == FirstCharOffset);
+
+      // Use all the original tokens for this line.  (We assume the
+      // end of the line corresponds cleanly to a token break.)
+      unsigned FirstTokIndex = FirstTokOffset - AsmTokOffsets.begin();
+      FirstOrigToken = &AsmToks[FirstTokIndex];
+      unsigned LastCharOffset = Str.end() - AsmString.begin();
+      for (unsigned i = FirstTokIndex, e = AsmTokOffsets.size(); i != e; ++i) {
+        if (AsmTokOffsets[i] >= LastCharOffset) break;
+        TempToks.push_back(AsmToks[i]);
+      }
+    }
+
+    void handleDiagnostic(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 *TokOffsetPtr =
+        std::lower_bound(AsmTokOffsets.begin(), AsmTokOffsets.end(), Offset);
+      unsigned TokIndex = TokOffsetPtr - AsmTokOffsets.begin();
+      unsigned TokOffset = *TokOffsetPtr;
+
+      // 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 - TokOffset);
+      }
+      TheParser.Diag(Loc, diag::err_inline_ms_asm_parsing)
+        << D.getMessage();
+    }
+  };
+}
+
+/// Parse an identifier in an MS-style inline assembly block.
+///
+/// \param CastInfo - a void* so that we don't have to teach Parser.h
+///   about the actual type.
+ExprResult Parser::ParseMSAsmIdentifier(llvm::SmallVectorImpl<Token> &LineToks,
+                                        unsigned &NumLineToksConsumed,
+                                        void *CastInfo,
+                                        bool IsUnevaluatedContext) {
+  llvm::InlineAsmIdentifierInfo &Info =
+    *(llvm::InlineAsmIdentifierInfo *) CastInfo;
+
+  // Push a fake token on the end so that we don't overrun the token
+  // stream.  We use ';' because it expression-parsing should never
+  // overrun it.
+  const tok::TokenKind EndOfStream = tok::semi;
+  Token EndOfStreamTok;
+  EndOfStreamTok.startToken();
+  EndOfStreamTok.setKind(EndOfStream);
+  LineToks.push_back(EndOfStreamTok);
+
+  // Also copy the current token over.
+  LineToks.push_back(Tok);
+
+  PP.EnterTokenStream(LineToks.begin(),
+                      LineToks.size(),
+                      /*disable macros*/ true,
+                      /*owns tokens*/ false);
+
+  // Clear the current token and advance to the first token in LineToks.
+  ConsumeAnyToken();
+
+  // Parse an optional scope-specifier if we're in C++.
+  CXXScopeSpec SS;
+  if (getLangOpts().CPlusPlus) {
+    ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false);
+  }
+
+  // Require an identifier here.
+  SourceLocation TemplateKWLoc;
+  UnqualifiedId Id;
+  bool Invalid = ParseUnqualifiedId(SS,
+                                    /*EnteringContext=*/false,
+                                    /*AllowDestructorName=*/false,
+                                    /*AllowConstructorName=*/false,
+                                    /*ObjectType=*/ ParsedType(),
+                                    TemplateKWLoc,
+                                    Id);
+
+  // If we've run into the poison token we inserted before, or there
+  // was a parsing error, then claim the entire line.
+  if (Invalid || Tok.is(EndOfStream)) {
+    NumLineToksConsumed = LineToks.size() - 2;
+
+    // Otherwise, claim up to the start of the next token.
+  } else {
+    // Figure out how many tokens we are into LineToks.
+    unsigned LineIndex = 0;
+    while (LineToks[LineIndex].getLocation() != Tok.getLocation()) {
+      LineIndex++;
+      assert(LineIndex < LineToks.size() - 2); // we added two extra tokens
+    }
+
+    NumLineToksConsumed = LineIndex;
+  }
+      
+  // Finally, restore the old parsing state by consuming all the
+  // tokens we staged before, implicitly killing off the
+  // token-lexer we pushed.
+  for (unsigned n = LineToks.size() - 2 - NumLineToksConsumed; n != 0; --n) {
+    ConsumeAnyToken();
+  }
+  ConsumeToken(EndOfStream);
+
+  // Leave LineToks in its original state.
+  LineToks.pop_back();
+  LineToks.pop_back();
+
+  // Perform the lookup.
+  return Actions.LookupInlineAsmIdentifier(SS, TemplateKWLoc, Id, Info,
+                                           IsUnevaluatedContext);
+}
+
+/// Turn a sequence of our tokens back into a string that we can hand
+/// to the MC asm parser.
+static bool buildMSAsmString(Preprocessor &PP,
+                             SourceLocation AsmLoc,
+                             ArrayRef<Token> AsmToks,
+                             SmallVectorImpl<unsigned> &TokOffsets,
+                             SmallString<512> &Asm) {
+  assert (!AsmToks.empty() && "Didn't expect an empty AsmToks!");
+
+  // Is this the start of a new assembly statement?
+  bool isNewStatement = true;
+
+  for (unsigned i = 0, e = AsmToks.size(); i < e; ++i) {
+    const Token &Tok = AsmToks[i];
+
+    // Start each new statement with a newline and a tab.
+    if (!isNewStatement &&
+        (Tok.is(tok::kw_asm) || Tok.isAtStartOfLine())) {
+      Asm += "\n\t";
+      isNewStatement = true;
+    }
+
+    // Preserve the existence of leading whitespace except at the
+    // start of a statement.
+    if (!isNewStatement && Tok.hasLeadingSpace())
+      Asm += ' ';
+
+    // Remember the offset of this token.
+    TokOffsets.push_back(Asm.size());
+
+    // Don't actually write '__asm' into the assembly stream.
+    if (Tok.is(tok::kw_asm)) {
+      // Complain about __asm at the end of the stream.
+      if (i + 1 == e) {
+        PP.Diag(AsmLoc, diag::err_asm_empty);
+        return true;
+      }
+
+      continue;
+    }
+
+    // Append the spelling of the token.
+    SmallString<32> SpellingBuffer;
+    bool SpellingInvalid = false;
+    Asm += PP.getSpelling(Tok, SpellingBuffer, &SpellingInvalid);
+    assert(!SpellingInvalid && "spelling was invalid after correct parse?");
+
+    // We are no longer at the start of a statement.
+    isNewStatement = false;
+  }
+
+  // Ensure that the buffer is null-terminated.
+  Asm.push_back('\0');
+  Asm.pop_back();
+
+  assert(TokOffsets.size() == AsmToks.size());
+  return false;
+}
+
 /// ParseMicrosoftAsmStatement. When -fms-extensions/-fasm-blocks is enabled,
 /// this routine is called to collect the tokens for an MS asm statement.
 ///
@@ -1771,9 +2059,114 @@ StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) {
     return StmtError();
   }
 
+  // Okay, prepare to use MC to parse the assembly.
+  SmallVector<StringRef, 4> ConstraintRefs;
+  SmallVector<Expr*, 4> Exprs;
+  SmallVector<StringRef, 4> ClobberRefs;
+
+  // We need an actual supported target.
+  llvm::Triple TheTriple = Actions.Context.getTargetInfo().getTriple();
+  llvm::Triple::ArchType ArchTy = TheTriple.getArch();
+  bool UnsupportedArch = (ArchTy != llvm::Triple::x86 &&
+                          ArchTy != llvm::Triple::x86_64);
+  if (UnsupportedArch)
+    Diag(AsmLoc, diag::err_msasm_unsupported_arch) << TheTriple.getArchName();
+    
+  // If we don't support assembly, or the assembly is empty, we don't
+  // need to instantiate the AsmParser, etc.
+  if (UnsupportedArch || AsmToks.empty()) {
+    return Actions.ActOnMSAsmStmt(AsmLoc, LBraceLoc, AsmToks, StringRef(),
+                                  /*NumOutputs*/ 0, /*NumInputs*/ 0,
+                                  ConstraintRefs, ClobberRefs, Exprs, EndLoc);
+  }
+
+  // Expand the tokens into a string buffer.
+  SmallString<512> AsmString;
+  SmallVector<unsigned, 8> TokOffsets;
+  if (buildMSAsmString(PP, AsmLoc, AsmToks, TokOffsets, AsmString))
+    return StmtError();
+
+  // Find the target and create the target specific parser.
+  std::string Error;
+  const std::string &TT = TheTriple.getTriple();
+  const llvm::Target *TheTarget = llvm::TargetRegistry::lookupTarget(TT, Error);
+
+  OwningPtr<llvm::MCAsmInfo> MAI(TheTarget->createMCAsmInfo(TT));
+  OwningPtr<llvm::MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TT));
+  OwningPtr<llvm::MCObjectFileInfo> MOFI(new llvm::MCObjectFileInfo());
+  OwningPtr<llvm::MCSubtargetInfo>
+    STI(TheTarget->createMCSubtargetInfo(TT, "", ""));
+
+  llvm::SourceMgr TempSrcMgr;
+  llvm::MCContext Ctx(*MAI, *MRI, MOFI.get(), &TempSrcMgr);
+  llvm::MemoryBuffer *Buffer =
+    llvm::MemoryBuffer::getMemBuffer(AsmString, "<MS inline asm>");
+
+  // Tell SrcMgr about this buffer, which is what the parser will pick up.
+  TempSrcMgr.AddNewSourceBuffer(Buffer, llvm::SMLoc());
+
+  OwningPtr<llvm::MCStreamer> Str(createNullStreamer(Ctx));
+  OwningPtr<llvm::MCAsmParser>
+    Parser(createMCAsmParser(TempSrcMgr, Ctx, *Str.get(), *MAI));
+  OwningPtr<llvm::MCTargetAsmParser>
+    TargetParser(TheTarget->createMCAsmParser(*STI, *Parser));
+
+  // Get the instruction descriptor.
+  const llvm::MCInstrInfo *MII = TheTarget->createMCInstrInfo(); 
+  llvm::MCInstPrinter *IP =
+    TheTarget->createMCInstPrinter(1, *MAI, *MII, *MRI, *STI);
+
+  // Change to the Intel dialect.
+  Parser->setAssemblerDialect(1);
+  Parser->setTargetParser(*TargetParser.get());
+  Parser->setParsingInlineAsm(true);
+  TargetParser->setParsingInlineAsm(true);
+
+  ClangAsmParserCallback Callback(*this, AsmLoc, AsmString,
+                                  AsmToks, TokOffsets);
+  TargetParser->setSemaCallback(&Callback);
+  TempSrcMgr.setDiagHandler(ClangAsmParserCallback::DiagHandlerCallback,
+                            &Callback);
+
+  unsigned NumOutputs;
+  unsigned NumInputs;
+  std::string AsmStringIR;
+  SmallVector<std::pair<void *, bool>, 4> OpExprs;
+  SmallVector<std::string, 4> Constraints;
+  SmallVector<std::string, 4> Clobbers;
+  if (Parser->parseMSInlineAsm(AsmLoc.getPtrEncoding(), AsmStringIR,
+                               NumOutputs, NumInputs, OpExprs, Constraints,
+                               Clobbers, MII, IP, Callback))
+    return StmtError();
+
+  // Build the vector of clobber StringRefs.
+  unsigned NumClobbers = Clobbers.size();
+  ClobberRefs.resize(NumClobbers);
+  for (unsigned i = 0; i != NumClobbers; ++i)
+    ClobberRefs[i] = StringRef(Clobbers[i]);
+
+  // Recast the void pointers and build the vector of constraint StringRefs.
+  unsigned NumExprs = NumOutputs + NumInputs;
+  ConstraintRefs.resize(NumExprs);
+  Exprs.resize(NumExprs);
+  for (unsigned i = 0, e = NumExprs; i != e; ++i) {
+    Expr *OpExpr = static_cast<Expr *>(OpExprs[i].first);
+    if (!OpExpr)
+      return StmtError();
+
+    // Need address of variable.
+    if (OpExprs[i].second)
+      OpExpr = Actions.BuildUnaryOp(getCurScope(), AsmLoc, UO_AddrOf, OpExpr)
+        .take();
+
+    ConstraintRefs[i] = StringRef(Constraints[i]);
+    Exprs[i] = OpExpr;
+  }
+
   // FIXME: We should be passing source locations for better diagnostics.
-  return Actions.ActOnMSAsmStmt(AsmLoc, LBraceLoc,
-                                llvm::makeArrayRef(AsmToks), EndLoc);
+  return Actions.ActOnMSAsmStmt(AsmLoc, LBraceLoc, AsmToks, AsmStringIR,
+                                NumOutputs, NumInputs,
+                                ConstraintRefs, ClobberRefs, Exprs, EndLoc);
 }
 
 /// ParseAsmStatement - Parse a GNU extended asm statement.
index 48860e027b820237695d8c60a52b9a27ea9338e7..1c943786f0b00b6c0d8e6f9c78d0955cc861cb81 100644 (file)
@@ -11718,8 +11718,7 @@ void Sema::MarkVTableUsed(SourceLocation Loc, CXXRecordDecl *Class,
   // Ignore any vtable uses in unevaluated operands or for classes that do
   // not have a vtable.
   if (!Class->isDynamicClass() || Class->isDependentContext() ||
-      CurContext->isDependentContext() ||
-      ExprEvalContexts.back().Context == Unevaluated)
+      CurContext->isDependentContext() || isUnevaluatedContext())
     return;
 
   // Try to insert this class into the map.
index 9f4f6d051c856ab3daf3b8772247322e4c8243a9..9a3c3b4289770eb1f23f69b677025922686af0e3 100644 (file)
@@ -10576,11 +10576,11 @@ namespace {
 }
 
 ExprResult Sema::TransformToPotentiallyEvaluated(Expr *E) {
-  assert(ExprEvalContexts.back().Context == Unevaluated &&
+  assert(isUnevaluatedContext() &&
          "Should only transform unevaluated expressions");
   ExprEvalContexts.back().Context =
       ExprEvalContexts[ExprEvalContexts.size()-2].Context;
-  if (ExprEvalContexts.back().Context == Unevaluated)
+  if (isUnevaluatedContext())
     return E;
   return TransformToPE(*this).TransformExpr(E);
 }
@@ -10612,7 +10612,7 @@ void Sema::PopExpressionEvaluationContext() {
   ExpressionEvaluationContextRecord& Rec = ExprEvalContexts.back();
 
   if (!Rec.Lambdas.empty()) {
-    if (Rec.Context == Unevaluated) {
+    if (Rec.isUnevaluated()) {
       // C++11 [expr.prim.lambda]p2:
       //   A lambda-expression shall not appear in an unevaluated operand
       //   (Clause 5).
@@ -10638,7 +10638,7 @@ void Sema::PopExpressionEvaluationContext() {
   // temporaries that we may have created as part of the evaluation of
   // the expression in that context: they aren't relevant because they
   // will never be constructed.
-  if (Rec.Context == Unevaluated || Rec.Context == ConstantEvaluated) {
+  if (Rec.isUnevaluated() || Rec.Context == ConstantEvaluated) {
     ExprCleanupObjects.erase(ExprCleanupObjects.begin() + Rec.NumCleanupObjects,
                              ExprCleanupObjects.end());
     ExprNeedsCleanups = Rec.ParentNeedsCleanups;
@@ -10677,6 +10677,7 @@ static bool IsPotentiallyEvaluatedContext(Sema &SemaRef) {
 
   switch (SemaRef.ExprEvalContexts.back().Context) {
     case Sema::Unevaluated:
+    case Sema::UnevaluatedAbstract:
       // We are in an expression that is not potentially evaluated; do nothing.
       // (Depending on how you read the standard, we actually do need to do
       // something here for null pointer constants, but the standard's
@@ -11761,6 +11762,7 @@ bool Sema::DiagRuntimeBehavior(SourceLocation Loc, const Stmt *Statement,
                                const PartialDiagnostic &PD) {
   switch (ExprEvalContexts.back().Context) {
   case Unevaluated:
+  case UnevaluatedAbstract:
     // The argument will never be evaluated, so don't complain.
     break;
 
index 56c418720a89a3b6610f704c1389440486ac3f37..85f6bfd9c339d23942e0676df23d0529a0d90e31 100644 (file)
@@ -742,7 +742,7 @@ static Expr *captureThis(ASTContext &Context, RecordDecl *RD,
 
 void Sema::CheckCXXThisCapture(SourceLocation Loc, bool Explicit) {
   // We don't need to capture this in an unevaluated context.
-  if (ExprEvalContexts.back().Context == Unevaluated && !Explicit)
+  if (isUnevaluatedContext() && !Explicit)
     return;
 
   // Otherwise, check that we can capture 'this'.
index c3642f56ce257ed4e646e0a7356d6db49cc90117..545ac2746d6d83ec2602c09915b731006ce38920 100644 (file)
@@ -60,6 +60,9 @@ enum IMAKind {
   /// The reference may be to an unresolved using declaration.
   IMA_Unresolved,
 
+  /// The reference is a contextually-permitted abstract member reference.
+  IMA_Abstract,
+
   /// The reference may be to an unresolved using declaration and the
   /// context is not an instance method.
   IMA_Unresolved_StaticContext,
@@ -120,19 +123,32 @@ static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef,
   // member reference.
   if (Classes.empty())
     return IMA_Static;
-
-  bool IsCXX11UnevaluatedField = false;
-  if (SemaRef.getLangOpts().CPlusPlus11 && isField) {
-    // C++11 [expr.prim.general]p12:
-    //   An id-expression that denotes a non-static data member or non-static
-    //   member function of a class can only be used:
-    //   (...)
-    //   - if that id-expression denotes a non-static data member and it
-    //     appears in an unevaluated operand.
-    const Sema::ExpressionEvaluationContextRecord& record
-      = SemaRef.ExprEvalContexts.back();
-    if (record.Context == Sema::Unevaluated)
-      IsCXX11UnevaluatedField = true;
+  
+  // C++11 [expr.prim.general]p12:
+  //   An id-expression that denotes a non-static data member or non-static
+  //   member function of a class can only be used:
+  //   (...)
+  //   - if that id-expression denotes a non-static data member and it
+  //     appears in an unevaluated operand.
+  //
+  // This rule is specific to C++11.  However, we also permit this form
+  // in unevaluated inline assembly operands, like the operand to a SIZE.
+  IMAKind AbstractInstanceResult = IMA_Static; // happens to be 'false'
+  assert(!AbstractInstanceResult);
+  switch (SemaRef.ExprEvalContexts.back().Context) {
+  case Sema::Unevaluated:
+    if (isField && SemaRef.getLangOpts().CPlusPlus11)
+      AbstractInstanceResult = IMA_Field_Uneval_Context;
+    break;
+
+  case Sema::UnevaluatedAbstract:
+    AbstractInstanceResult = IMA_Abstract;
+    break;
+
+  case Sema::ConstantEvaluated:
+  case Sema::PotentiallyEvaluated:
+  case Sema::PotentiallyEvaluatedIfUsed:
+    break;
   }
 
   // If the current context is not an instance method, it can't be
@@ -141,8 +157,8 @@ static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef,
     if (hasNonInstance)
       return IMA_Mixed_StaticContext;
 
-    return IsCXX11UnevaluatedField ? IMA_Field_Uneval_Context
-                                   : IMA_Error_StaticContext;
+    return AbstractInstanceResult ? AbstractInstanceResult
+                                  : IMA_Error_StaticContext;
   }
 
   CXXRecordDecl *contextClass;
@@ -172,8 +188,8 @@ static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef,
   // which case it's an error if any of those members are selected).
   if (isProvablyNotDerivedFrom(SemaRef, contextClass, Classes))
     return hasNonInstance ? IMA_Mixed_Unrelated :
-           IsCXX11UnevaluatedField ? IMA_Field_Uneval_Context :
-                                     IMA_Error_Unrelated;
+           AbstractInstanceResult ? AbstractInstanceResult :
+                                    IMA_Error_Unrelated;
 
   return (hasNonInstance ? IMA_Mixed : IMA_Instance);
 }
@@ -233,6 +249,7 @@ Sema::BuildPossibleImplicitMemberExpr(const CXXScopeSpec &SS,
       << R.getLookupNameInfo().getName();
     // Fall through.
   case IMA_Static:
+  case IMA_Abstract:
   case IMA_Mixed_StaticContext:
   case IMA_Unresolved_StaticContext:
     if (TemplateArgs || TemplateKWLoc.isValid())
index 77e6bfd086652d282133843a072fed48b55eec4a..d16bb6a052c499d580aa45cd45727a11cf446fc9 100644 (file)
@@ -950,6 +950,7 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
   if (!CurContext->isDependentContext()) {
     switch (ExprEvalContexts.back().Context) {
     case Unevaluated:
+    case UnevaluatedAbstract:
       // We don't actually diagnose this case immediately, because we
       // could be within a context where we might find out later that
       // the expression is potentially evaluated (e.g., for typeid).
index 673b84e8153d0a3837b88f420fb0199b2888324d..8dfc8b9290b3c3377ae5f1c938e0d4ba7ec705e5 100644 (file)
@@ -22,7 +22,6 @@
 #include "clang/AST/StmtCXX.h"
 #include "clang/AST/StmtObjC.h"
 #include "clang/AST/TypeLoc.h"
-#include "clang/Basic/TargetInfo.h"
 #include "clang/Lex/Preprocessor.h"
 #include "clang/Sema/Initialization.h"
 #include "clang/Sema/Lookup.h"
index 14ee67bfc32244f3fed29d5f68144ba4e758c684..fce95bebd1a9c57f00c289371e24deed460e0ea7 100644 (file)
 #include "clang/Sema/ScopeInfo.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/BitVector.h"
-#include "llvm/ADT/SmallString.h"
-#include "llvm/MC/MCAsmInfo.h"
-#include "llvm/MC/MCContext.h"
-#include "llvm/MC/MCObjectFileInfo.h"
-#include "llvm/MC/MCParser/MCAsmParser.h"
-#include "llvm/MC/MCRegisterInfo.h"
-#include "llvm/MC/MCStreamer.h"
-#include "llvm/MC/MCSubtargetInfo.h"
-#include "llvm/MC/MCTargetAsmParser.h"
-#include "llvm/Support/SourceMgr.h"
-#include "llvm/Support/TargetRegistry.h"
-#include "llvm/Support/TargetSelect.h"
 using namespace clang;
 using namespace sema;
 
@@ -381,180 +369,60 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
   return Owned(NS);
 }
 
-// getSpelling - Get the spelling of the AsmTok token.
-static StringRef getSpelling(Sema &SemaRef, Token AsmTok) {
-  StringRef Asm;
-  SmallString<512> TokenBuf;
-  TokenBuf.resize(512);
-  bool StringInvalid = false;
-  Asm = SemaRef.PP.getSpelling(AsmTok, TokenBuf, &StringInvalid);
-  assert (!StringInvalid && "Expected valid string!");
-  return Asm;
-}
+ExprResult Sema::LookupInlineAsmIdentifier(CXXScopeSpec &SS,
+                                           SourceLocation TemplateKWLoc,
+                                           UnqualifiedId &Id,
+                                           InlineAsmIdentifierInfo &Info,
+                                           bool IsUnevaluatedContext) {
+  Info.clear();
 
-// Build the inline assembly string.  Returns true on error.
-static bool buildMSAsmString(Sema &SemaRef,
-                             SourceLocation AsmLoc,
-                             ArrayRef<Token> AsmToks,
-                             SmallVectorImpl<unsigned> &TokOffsets,
-                             std::string &AsmString) {
-  assert (!AsmToks.empty() && "Didn't expect an empty AsmToks!");
-
-  SmallString<512> Asm;
-  for (unsigned i = 0, e = AsmToks.size(); i < e; ++i) {
-    bool isNewAsm = ((i == 0) ||
-                     AsmToks[i].isAtStartOfLine() ||
-                     AsmToks[i].is(tok::kw_asm));
-    if (isNewAsm) {
-      if (i != 0)
-        Asm += "\n\t";
-
-      if (AsmToks[i].is(tok::kw_asm)) {
-        i++; // Skip __asm
-        if (i == e) {
-          SemaRef.Diag(AsmLoc, diag::err_asm_empty);
-          return true;
-        }
+  if (IsUnevaluatedContext)
+    PushExpressionEvaluationContext(UnevaluatedAbstract,
+                                    ReuseLambdaContextDecl);
 
-      }
-    }
+  ExprResult Result = ActOnIdExpression(getCurScope(), SS, TemplateKWLoc, Id,
+                                        /*trailing lparen*/ false,
+                                        /*is & operand*/ false);
 
-    if (i && AsmToks[i].hasLeadingSpace() && !isNewAsm)
-      Asm += ' ';
+  if (IsUnevaluatedContext)
+    PopExpressionEvaluationContext();
 
-    StringRef Spelling = getSpelling(SemaRef, AsmToks[i]);
-    Asm += Spelling;
-    TokOffsets.push_back(Asm.size());
-  }
-  AsmString = Asm.str();
-  return false;
-}
+  if (!Result.isUsable()) return Result;
 
-namespace {
-
-class MCAsmParserSemaCallbackImpl : public llvm::MCAsmParserSemaCallback {
-  Sema &SemaRef;
-  SourceLocation AsmLoc;
-  ArrayRef<Token> AsmToks;
-  ArrayRef<unsigned> TokOffsets;
-
-public:
-  MCAsmParserSemaCallbackImpl(Sema &Ref, SourceLocation Loc,
-                              ArrayRef<Token> Toks,
-                              ArrayRef<unsigned> Offsets)
-    : SemaRef(Ref), AsmLoc(Loc), AsmToks(Toks), TokOffsets(Offsets) { }
-  ~MCAsmParserSemaCallbackImpl() {}
-
-  void *LookupInlineAsmIdentifier(StringRef &LineBuf,
-                                  InlineAsmIdentifierInfo &Info) {
-    SourceLocation Loc = SourceLocation::getFromPtrEncoding(LineBuf.data());
-    NamedDecl *OpDecl = SemaRef.LookupInlineAsmIdentifier(LineBuf, Loc, Info);
-    Info.OpDecl = static_cast<void *>(OpDecl);
-    return static_cast<void *>(OpDecl);
-  }
+  Result = CheckPlaceholderExpr(Result.take());
+  if (!Result.isUsable()) return Result;
 
-  bool LookupInlineAsmField(StringRef Base, StringRef Member,
-                            unsigned &Offset) {
-    return SemaRef.LookupInlineAsmField(Base, Member, Offset, AsmLoc);
-  }
+  QualType T = Result.get()->getType();
 
-  static void MSAsmDiagHandlerCallback(const llvm::SMDiagnostic &D,
-                                       void *Context) {
-    ((MCAsmParserSemaCallbackImpl*)Context)->MSAsmDiagHandler(D);
+  // For now, reject dependent types.
+  if (T->isDependentType()) {
+    Diag(Id.getLocStart(), diag::err_asm_incomplete_type) << T;
+    return ExprError();
   }
-  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();
-  }
-};
 
-}
-
-// FIXME: Temporary hack until the frontend parser is hooked up to parse 
-// variables.
-static bool isIdentifierChar(char c) {
-  return isalnum(c) || c == '_' || c == '$' || c == '.' || c == '@';
-}
-
-static void lexIdentifier(const char *&CurPtr) {
-  while (isIdentifierChar(*CurPtr))
-    ++CurPtr;
-}
-
-static StringRef parseIdentifier(StringRef Identifier) {
-  const char *StartPtr = Identifier.data(), *EndPtr, *CurPtr;
-  EndPtr = StartPtr + Identifier.size();
-  CurPtr = StartPtr;
-  while(CurPtr <= EndPtr) {
-    if (isIdentifierChar(*CurPtr))
-      lexIdentifier(CurPtr);
-    else if (CurPtr[0] == ':' && CurPtr[1] == ':')
-      CurPtr += 2;
-    else
-      break;
+  // Any sort of function type is fine.
+  if (T->isFunctionType()) {
+    return Result;
   }
-  return StringRef(StartPtr, CurPtr - StartPtr);
-}
 
-NamedDecl *Sema::LookupInlineAsmIdentifier(StringRef &LineBuf, SourceLocation Loc,
-                                           InlineAsmIdentifierInfo &Info) {
-  Info.clear();
-  // FIXME: Temporary hack until the frontend parser is hooked up to parse 
-  // variables.
-  LineBuf = parseIdentifier(LineBuf);
-  LookupResult Result(*this, &Context.Idents.get(LineBuf), Loc,
-                      Sema::LookupOrdinaryName);
-
-  if (!LookupName(Result, getCurScope())) {
-    // If we don't find anything, return null; the AsmParser will assume
-    // it is a label of some sort.
-    return 0;
+  // Otherwise, it needs to be a complete type.
+  if (RequireCompleteExprType(Result.get(), diag::err_asm_incomplete_type)) {
+    return ExprError();
   }
 
-  if (!Result.isSingleResult()) {
-    // FIXME: Diagnose result.
-    return 0;
+  // Compute the type size (and array length if applicable?).
+  Info.Type = Info.Size = Context.getTypeSizeInChars(T).getQuantity();
+  if (T->isArrayType()) {
+    const ArrayType *ATy = Context.getAsArrayType(T);
+    Info.Type = Context.getTypeSizeInChars(ATy->getElementType()).getQuantity();
+    Info.Length = Info.Size / Info.Type;
   }
 
-  NamedDecl *FoundDecl = Result.getFoundDecl();
-  if (isa<FunctionDecl>(FoundDecl))
-    return FoundDecl;
-  if (VarDecl *Var = dyn_cast<VarDecl>(FoundDecl)) {
-    QualType Ty = Var->getType();
-    Info.Type = Info.Size = Context.getTypeSizeInChars(Ty).getQuantity();
-    if (Ty->isArrayType()) {
-      const ArrayType *ATy = Context.getAsArrayType(Ty);
-      Info.Type = Context.getTypeSizeInChars(ATy->getElementType()).getQuantity();
-      Info.Length = Info.Size / Info.Type;
-    }
+  // We can work with the expression as long as it's not an r-value.
+  if (!Result.get()->isRValue())
     Info.IsVarDecl = true;
-    return FoundDecl;
-  }
 
-  // FIXME: Handle other kinds of results? (FieldDecl, etc.)
-  // FIXME: Diagnose if we find something we can't handle, like a typedef.
-  return 0;
+  return Result;
 }
 
 bool Sema::LookupInlineAsmField(StringRef Base, StringRef Member,
@@ -601,124 +469,18 @@ bool Sema::LookupInlineAsmField(StringRef Base, StringRef Member,
 }
 
 StmtResult Sema::ActOnMSAsmStmt(SourceLocation AsmLoc, SourceLocation LBraceLoc,
-                                ArrayRef<Token> AsmToks,SourceLocation EndLoc) {
-  SmallVector<IdentifierInfo*, 4> Names;
-  SmallVector<StringRef, 4> ConstraintRefs;
-  SmallVector<Expr*, 4> Exprs;
-  SmallVector<StringRef, 4> ClobberRefs;
-
-  llvm::Triple TheTriple = Context.getTargetInfo().getTriple();
-  llvm::Triple::ArchType ArchTy = TheTriple.getArch();
-  bool UnsupportedArch = ArchTy != llvm::Triple::x86 &&
-    ArchTy != llvm::Triple::x86_64;
-  if (UnsupportedArch)
-    Diag(AsmLoc, diag::err_msasm_unsupported_arch) << TheTriple.getArchName();
-    
-  // Empty asm statements don't need to instantiate the AsmParser, etc.
-  if (UnsupportedArch || AsmToks.empty()) {
-    StringRef EmptyAsmStr;
-    MSAsmStmt *NS =
-      new (Context) MSAsmStmt(Context, AsmLoc, LBraceLoc, /*IsSimple*/ true,
-                              /*IsVolatile*/ true, AsmToks, /*NumOutputs*/ 0,
-                              /*NumInputs*/ 0, Names, ConstraintRefs, Exprs,
-                              EmptyAsmStr, ClobberRefs, EndLoc);
-    return Owned(NS);
-  }
-
-  std::string AsmString;
-  SmallVector<unsigned, 8> TokOffsets;
-  if (buildMSAsmString(*this, AsmLoc, AsmToks, TokOffsets, AsmString))
-    return StmtError();
-
-  // Get the target specific parser.
-  std::string Error;
-  const std::string &TT = TheTriple.getTriple();
-  const llvm::Target *TheTarget(llvm::TargetRegistry::lookupTarget(TT, Error));
-
-  OwningPtr<llvm::MCAsmInfo> MAI(TheTarget->createMCAsmInfo(TT));
-  OwningPtr<llvm::MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TT));
-  OwningPtr<llvm::MCObjectFileInfo> MOFI(new llvm::MCObjectFileInfo());
-  OwningPtr<llvm::MCSubtargetInfo>
-    STI(TheTarget->createMCSubtargetInfo(TT, "", ""));
-
-  llvm::SourceMgr SrcMgr;
-  llvm::MCContext Ctx(*MAI, *MRI, MOFI.get(), &SrcMgr);
-  llvm::MemoryBuffer *Buffer =
-    llvm::MemoryBuffer::getMemBuffer(AsmString, "<MS inline asm>");
-
-  // Tell SrcMgr about this buffer, which is what the parser will pick up.
-  SrcMgr.AddNewSourceBuffer(Buffer, llvm::SMLoc());
-
-  OwningPtr<llvm::MCStreamer> Str(createNullStreamer(Ctx));
-  OwningPtr<llvm::MCAsmParser>
-    Parser(createMCAsmParser(SrcMgr, Ctx, *Str.get(), *MAI));
-  OwningPtr<llvm::MCTargetAsmParser>
-    TargetParser(TheTarget->createMCAsmParser(*STI, *Parser));
-
-  // Get the instruction descriptor.
-  const llvm::MCInstrInfo *MII = TheTarget->createMCInstrInfo(); 
-  llvm::MCInstPrinter *IP =
-    TheTarget->createMCInstPrinter(1, *MAI, *MII, *MRI, *STI);
-
-  // Change to the Intel dialect.
-  Parser->setAssemblerDialect(1);
-  Parser->setTargetParser(*TargetParser.get());
-  Parser->setParsingInlineAsm(true);
-  TargetParser->setParsingInlineAsm(true);
-
-  MCAsmParserSemaCallbackImpl MCAPSI(*this, AsmLoc, AsmToks, TokOffsets);
-  TargetParser->setSemaCallback(&MCAPSI);
-  SrcMgr.setDiagHandler(MCAsmParserSemaCallbackImpl::MSAsmDiagHandlerCallback,
-                        &MCAPSI);
-
-  unsigned NumOutputs;
-  unsigned NumInputs;
-  std::string AsmStringIR;
-  SmallVector<std::pair<void *, bool>, 4> OpDecls;
-  SmallVector<std::string, 4> Constraints;
-  SmallVector<std::string, 4> Clobbers;
-  if (Parser->parseMSInlineAsm(AsmLoc.getPtrEncoding(), AsmStringIR,
-                               NumOutputs, NumInputs, OpDecls, Constraints,
-                               Clobbers, MII, IP, MCAPSI))
-    return StmtError();
-
-  // Build the vector of clobber StringRefs.
-  unsigned NumClobbers = Clobbers.size();
-  ClobberRefs.resize(NumClobbers);
-  for (unsigned i = 0; i != NumClobbers; ++i)
-    ClobberRefs[i] = StringRef(Clobbers[i]);
-
-  // Recast the void pointers and build the vector of constraint StringRefs.
-  unsigned NumExprs = NumOutputs + NumInputs;
-  Names.resize(NumExprs);
-  ConstraintRefs.resize(NumExprs);
-  Exprs.resize(NumExprs);
-  for (unsigned i = 0, e = NumExprs; i != e; ++i) {
-    NamedDecl *OpDecl = static_cast<NamedDecl *>(OpDecls[i].first);
-    if (!OpDecl)
-      return StmtError();
-
-    DeclarationNameInfo NameInfo(OpDecl->getDeclName(), AsmLoc);
-    ExprResult OpExpr = BuildDeclarationNameExpr(CXXScopeSpec(), NameInfo,
-                                                 OpDecl);
-    if (OpExpr.isInvalid())
-      return StmtError();
-
-    // Need address of variable.
-    if (OpDecls[i].second)
-      OpExpr = BuildUnaryOp(getCurScope(), AsmLoc, clang::UO_AddrOf,
-                            OpExpr.take());
-
-    Names[i] = OpDecl->getIdentifier();
-    ConstraintRefs[i] = StringRef(Constraints[i]);
-    Exprs[i] = OpExpr.take();
-  }
-
-  bool IsSimple = NumExprs > 0;
+                                ArrayRef<Token> AsmToks,
+                                StringRef AsmString,
+                                unsigned NumOutputs, unsigned NumInputs,
+                                ArrayRef<StringRef> Constraints,
+                                ArrayRef<StringRef> Clobbers,
+                                ArrayRef<Expr*> Exprs,
+                                SourceLocation EndLoc) {
+  bool IsSimple = (NumOutputs != 0 || NumInputs != 0);
   MSAsmStmt *NS =
     new (Context) MSAsmStmt(Context, AsmLoc, LBraceLoc, IsSimple,
                             /*IsVolatile*/ true, AsmToks, NumOutputs, NumInputs,
-                            Names, ConstraintRefs, Exprs, AsmStringIR,
-                            ClobberRefs, EndLoc);
+                            Constraints, Exprs, AsmString,
+                            Clobbers, EndLoc);
   return Owned(NS);
 }
index fda154820a177b0ccf65084a4dd40ce2605bf822..99cb2829bfcc235f742846eb3e382864bff58f3d 100644 (file)
@@ -1190,8 +1190,16 @@ public:
   /// By default, performs semantic analysis to build the new statement.
   /// Subclasses may override this routine to provide different behavior.
   StmtResult RebuildMSAsmStmt(SourceLocation AsmLoc, SourceLocation LBraceLoc,
-                              ArrayRef<Token> AsmToks, SourceLocation EndLoc) {
-    return getSema().ActOnMSAsmStmt(AsmLoc, LBraceLoc, AsmToks, EndLoc);
+                              ArrayRef<Token> AsmToks,
+                              StringRef AsmString,
+                              unsigned NumOutputs, unsigned NumInputs,
+                              ArrayRef<StringRef> Constraints,
+                              ArrayRef<StringRef> Clobbers,
+                              ArrayRef<Expr*> Exprs,
+                              SourceLocation EndLoc) {
+    return getSema().ActOnMSAsmStmt(AsmLoc, LBraceLoc, AsmToks, AsmString,
+                                    NumOutputs, NumInputs,
+                                    Constraints, Clobbers, Exprs, EndLoc);
   }
 
   /// \brief Build a new Objective-C \@try statement.
@@ -5649,8 +5657,30 @@ TreeTransform<Derived>::TransformMSAsmStmt(MSAsmStmt *S) {
   ArrayRef<Token> AsmToks =
     llvm::makeArrayRef(S->getAsmToks(), S->getNumAsmToks());
 
+  bool HadError = false, HadChange = false;
+
+  ArrayRef<Expr*> SrcExprs = S->getAllExprs();
+  SmallVector<Expr*, 8> TransformedExprs;
+  TransformedExprs.reserve(SrcExprs.size());
+  for (unsigned i = 0, e = SrcExprs.size(); i != e; ++i) {
+    ExprResult Result = getDerived().TransformExpr(SrcExprs[i]);
+    if (!Result.isUsable()) {
+      HadError = true;
+    } else {
+      HadChange |= (Result.get() != SrcExprs[i]);
+      TransformedExprs.push_back(Result.take());
+    }
+  }
+
+  if (HadError) return StmtError();
+  if (!HadChange && !getDerived().AlwaysRebuild())
+    return Owned(S);
+
   return getDerived().RebuildMSAsmStmt(S->getAsmLoc(), S->getLBraceLoc(),
-                                       AsmToks, S->getEndLoc());
+                                       AsmToks, S->getAsmString(),
+                                       S->getNumOutputs(), S->getNumInputs(),
+                                       S->getAllConstraints(), S->getClobbers(),
+                                       TransformedExprs, S->getEndLoc());
 }
 
 template<typename Derived>
index a5fd2e324f2919b5529c901507265f9b769d70d2..a766bd2af4b222e7201e0e148807d01bb0f98cce 100644 (file)
@@ -1103,6 +1103,19 @@ bool ASTReader::ReadBlockAbbrevs(BitstreamCursor &Cursor, unsigned BlockID) {
   }
 }
 
+Token ASTReader::ReadToken(ModuleFile &F, const RecordData &Record,
+                           unsigned &Idx) {
+  Token Tok;
+  Tok.startToken();
+  Tok.setLocation(ReadSourceLocation(F, Record, Idx));
+  Tok.setLength(Record[Idx++]);
+  if (IdentifierInfo *II = getLocalIdentifier(F, Record[Idx++]))
+    Tok.setIdentifierInfo(II);
+  Tok.setKind((tok::TokenKind)Record[Idx++]);
+  Tok.setFlag((Token::TokenFlags)Record[Idx++]);
+  return Tok;
+}
+
 MacroInfo *ASTReader::ReadMacroRecord(ModuleFile &F, uint64_t Offset) {
   BitstreamCursor &Stream = F.MacroCursor;
 
@@ -1203,14 +1216,8 @@ MacroInfo *ASTReader::ReadMacroRecord(ModuleFile &F, uint64_t Offset) {
       // erroneous, just pretend we didn't see this.
       if (Macro == 0) break;
 
-      Token Tok;
-      Tok.startToken();
-      Tok.setLocation(ReadSourceLocation(F, Record[0]));
-      Tok.setLength(Record[1]);
-      if (IdentifierInfo *II = getLocalIdentifier(F, Record[2]))
-        Tok.setIdentifierInfo(II);
-      Tok.setKind((tok::TokenKind)Record[3]);
-      Tok.setFlag((Token::TokenFlags)Record[4]);
+      unsigned Idx = 0;
+      Token Tok = ReadToken(F, Record, Idx);
       Macro->AddTokenToBody(Tok);
       break;
     }
index c7748b7f6bae8e0da9a27e7d5f4a564fe31ed9ea..fd60ec4fd5eb6538b450b8a9048dd7664a85fb08 100644 (file)
@@ -17,6 +17,7 @@
 #include "clang/AST/DeclCXX.h"
 #include "clang/AST/DeclTemplate.h"
 #include "clang/AST/StmtVisitor.h"
+#include "clang/Lex/Token.h"
 #include "llvm/ADT/SmallString.h"
 using namespace clang;
 using namespace clang::serialization;
@@ -32,14 +33,22 @@ namespace clang {
     const ASTReader::RecordData &Record;
     unsigned &Idx;
 
+    Token ReadToken(const RecordData &R, unsigned &I) {
+      return Reader.ReadToken(F, R, I);
+    }
+
     SourceLocation ReadSourceLocation(const RecordData &R, unsigned &I) {
       return Reader.ReadSourceLocation(F, R, I);
     }
-    
+
     SourceRange ReadSourceRange(const RecordData &R, unsigned &I) {
       return Reader.ReadSourceRange(F, R, I);
     }
-    
+
+    std::string ReadString(const RecordData &R, unsigned &I) {
+      return Reader.ReadString(R, I);
+    }
+        
     TypeSourceInfo *GetTypeSourceInfo(const RecordData &R, unsigned &I) {
       return Reader.GetTypeSourceInfo(F, R, I);
     }
@@ -286,18 +295,25 @@ void ASTStmtReader::VisitDeclStmt(DeclStmt *S) {
   }
 }
 
-void ASTStmtReader::VisitGCCAsmStmt(GCCAsmStmt *S) {
+void ASTStmtReader::VisitAsmStmt(AsmStmt *S) {
   VisitStmt(S);
-  unsigned NumOutputs = Record[Idx++];
-  unsigned NumInputs = Record[Idx++];
-  unsigned NumClobbers = Record[Idx++];
+  S->NumOutputs = Record[Idx++];
+  S->NumInputs = Record[Idx++];
+  S->NumClobbers = Record[Idx++];
   S->setAsmLoc(ReadSourceLocation(Record, Idx));
-  S->setRParenLoc(ReadSourceLocation(Record, Idx));
   S->setVolatile(Record[Idx++]);
   S->setSimple(Record[Idx++]);
+}
 
+void ASTStmtReader::VisitGCCAsmStmt(GCCAsmStmt *S) {
+  VisitAsmStmt(S);
+  S->setRParenLoc(ReadSourceLocation(Record, Idx));
   S->setAsmString(cast_or_null<StringLiteral>(Reader.ReadSubStmt()));
 
+  unsigned NumOutputs = S->getNumOutputs();
+  unsigned NumInputs = S->getNumInputs();
+  unsigned NumClobbers = S->getNumClobbers();
+
   // Outputs and inputs
   SmallVector<IdentifierInfo *, 16> Names;
   SmallVector<StringLiteral*, 16> Constraints;
@@ -320,8 +336,48 @@ void ASTStmtReader::VisitGCCAsmStmt(GCCAsmStmt *S) {
 }
 
 void ASTStmtReader::VisitMSAsmStmt(MSAsmStmt *S) {
-  // FIXME: Statement reader not yet implemented for MS style inline asm.
-  VisitStmt(S);
+  VisitAsmStmt(S);
+  S->LBraceLoc = ReadSourceLocation(Record, Idx);
+  S->EndLoc = ReadSourceLocation(Record, Idx);
+  S->NumAsmToks = Record[Idx++];
+  std::string AsmStr = ReadString(Record, Idx);
+
+  // Read the tokens.
+  SmallVector<Token, 16> AsmToks;
+  AsmToks.reserve(S->NumAsmToks);
+  for (unsigned i = 0, e = S->NumAsmToks; i != e; ++i) {
+    AsmToks.push_back(ReadToken(Record, Idx));
+  }
+
+  // The calls to reserve() for the FooData vectors are mandatory to
+  // prevent dead StringRefs in the Foo vectors.
+
+  // Read the clobbers.
+  SmallVector<std::string, 16> ClobbersData;
+  SmallVector<StringRef, 16> Clobbers;
+  ClobbersData.reserve(S->NumClobbers);
+  Clobbers.reserve(S->NumClobbers);
+  for (unsigned i = 0, e = S->NumClobbers; i != e; ++i) {
+    ClobbersData.push_back(ReadString(Record, Idx));
+    Clobbers.push_back(ClobbersData.back());
+  }
+
+  // Read the operands.
+  unsigned NumOperands = S->NumOutputs + S->NumInputs;
+  SmallVector<Expr*, 16> Exprs;
+  SmallVector<std::string, 16> ConstraintsData;
+  SmallVector<StringRef, 16> Constraints;
+  Exprs.reserve(NumOperands);
+  ConstraintsData.reserve(NumOperands);
+  Constraints.reserve(NumOperands);
+  for (unsigned i = 0; i != NumOperands; ++i) {
+    Exprs.push_back(cast<Expr>(Reader.ReadSubStmt()));
+    ConstraintsData.push_back(ReadString(Record, Idx));
+    Constraints.push_back(ConstraintsData.back());
+  }
+
+  S->initialize(Reader.getContext(), AsmStr, AsmToks,
+                Constraints, Exprs, Clobbers);
 }
 
 void ASTStmtReader::VisitCapturedStmt(CapturedStmt *S) {
index 2d691b11aaa444d5b6293531b1d73ca2fe64ba55..b8ada04e5d8aac2f53316c89685e6b5d6900d3b6 100644 (file)
@@ -2012,18 +2012,7 @@ void ASTWriter::WritePreprocessor(const Preprocessor &PP, bool IsModule) {
       // tokens in it because they are created by the parser, and thus can't
       // be in a macro definition.
       const Token &Tok = MI->getReplacementToken(TokNo);
-
-      Record.push_back(Tok.getLocation().getRawEncoding());
-      Record.push_back(Tok.getLength());
-
-      // FIXME: When reading literal tokens, reconstruct the literal pointer
-      // if it is needed.
-      AddIdentifierRef(Tok.getIdentifierInfo(), Record);
-      // FIXME: Should translate token kind to a stable encoding.
-      Record.push_back(Tok.getKind());
-      // FIXME: Should translate token flags to a stable encoding.
-      Record.push_back(Tok.getFlags());
-
+      AddToken(Tok, Record);
       Stream.EmitRecord(PP_TOKEN, Record);
       Record.clear();
     }
@@ -3661,6 +3650,19 @@ void ASTWriter::WriteAttributes(ArrayRef<const Attr*> Attrs,
   }
 }
 
+void ASTWriter::AddToken(const Token &Tok, RecordDataImpl &Record) {
+  AddSourceLocation(Tok.getLocation(), Record);
+  Record.push_back(Tok.getLength());
+
+  // FIXME: When reading literal tokens, reconstruct the literal pointer
+  // if it is needed.
+  AddIdentifierRef(Tok.getIdentifierInfo(), Record);
+  // FIXME: Should translate token kind to a stable encoding.
+  Record.push_back(Tok.getKind());
+  // FIXME: Should translate token flags to a stable encoding.
+  Record.push_back(Tok.getFlags());
+}
+
 void ASTWriter::AddString(StringRef Str, RecordDataImpl &Record) {
   Record.push_back(Str.size());
   Record.insert(Record.end(), Str.begin(), Str.end());
index 5c8e2133843d5767447749f28e71dd6c5b03b23a..832bbf69906f588d6d324611e5f2b40c79fdc8c0 100644 (file)
@@ -17,6 +17,7 @@
 #include "clang/AST/DeclObjC.h"
 #include "clang/AST/DeclTemplate.h"
 #include "clang/AST/StmtVisitor.h"
+#include "clang/Lex/Token.h"
 #include "llvm/Bitcode/BitstreamWriter.h"
 using namespace clang;
 
@@ -216,15 +217,19 @@ void ASTStmtWriter::VisitDeclStmt(DeclStmt *S) {
   Code = serialization::STMT_DECL;
 }
 
-void ASTStmtWriter::VisitGCCAsmStmt(GCCAsmStmt *S) {
+void ASTStmtWriter::VisitAsmStmt(AsmStmt *S) {
   VisitStmt(S);
   Record.push_back(S->getNumOutputs());
   Record.push_back(S->getNumInputs());
   Record.push_back(S->getNumClobbers());
   Writer.AddSourceLocation(S->getAsmLoc(), Record);
-  Writer.AddSourceLocation(S->getRParenLoc(), Record);
   Record.push_back(S->isVolatile());
   Record.push_back(S->isSimple());
+}
+
+void ASTStmtWriter::VisitGCCAsmStmt(GCCAsmStmt *S) {
+  VisitAsmStmt(S);
+  Writer.AddSourceLocation(S->getRParenLoc(), Record);
   Writer.AddStmt(S->getAsmString());
 
   // Outputs
@@ -249,8 +254,33 @@ void ASTStmtWriter::VisitGCCAsmStmt(GCCAsmStmt *S) {
 }
 
 void ASTStmtWriter::VisitMSAsmStmt(MSAsmStmt *S) {
-  // FIXME: Statement writer not yet implemented for MS style inline asm.
-  VisitStmt(S);
+  VisitAsmStmt(S);
+  Writer.AddSourceLocation(S->getLBraceLoc(), Record);
+  Writer.AddSourceLocation(S->getEndLoc(), Record);
+  Record.push_back(S->getNumAsmToks());
+  Writer.AddString(S->getAsmString(), Record);
+
+  // Tokens
+  for (unsigned I = 0, N = S->getNumAsmToks(); I != N; ++I) {
+    Writer.AddToken(S->getAsmToks()[I], Record);
+  }
+
+  // Clobbers
+  for (unsigned I = 0, N = S->getNumClobbers(); I != N; ++I) {
+    Writer.AddString(S->getClobber(I), Record);
+  }
+
+  // Outputs
+  for (unsigned I = 0, N = S->getNumOutputs(); I != N; ++I) {      
+    Writer.AddStmt(S->getOutputExpr(I));
+    Writer.AddString(S->getOutputConstraint(I), Record);
+  }
+
+  // Inputs
+  for (unsigned I = 0, N = S->getNumInputs(); I != N; ++I) {
+    Writer.AddStmt(S->getInputExpr(I));
+    Writer.AddString(S->getInputConstraint(I), Record);
+  }
 
   Code = serialization::STMT_MSASM;
 }
index 99071aa81caaac95c2e77718594001756520f7b8..8f824f9947b62850d561ba3f5b7f2b7d66ec6281 100644 (file)
@@ -1,6 +1,8 @@
 // REQUIRES: x86-64-registered-target
 // RUN: %clang_cc1 -x c++ %s -triple i386-apple-darwin10 -O0 -fasm-blocks -emit-llvm -o - | FileCheck %s
 
+// rdar://13645930
+
 struct Foo {
   static int *ptr;
   static int a, b;
@@ -14,17 +16,17 @@ struct Foo {
 void t1() {
   Foo::ptr = (int *)0xDEADBEEF;
   Foo::Bar::ptr = (int *)0xDEADBEEF;
-  __asm mov eax, Foo::ptr
-  __asm mov eax, Foo::Bar::ptr
-  __asm mov eax, [Foo::ptr]
-  __asm mov eax, dword ptr [Foo::ptr]
-  __asm mov eax, dword ptr [Foo::ptr]
+  __asm mov eax, Foo ::ptr
+  __asm mov eax, Foo :: Bar :: ptr
+  __asm mov eax, [Foo:: ptr]
+  __asm mov eax, dword ptr [Foo :: ptr]
+  __asm mov eax, dword ptr [Foo :: ptr]
 // CHECK: @_Z2t1v
-// CHECK: call void asm sideeffect inteldialect "mov eax, Foo::ptr", "~{eax},~{dirflag},~{fpsr},~{flags}"()
-// CHECK: call void asm sideeffect inteldialect "mov eax, Foo::Bar::ptr", "~{eax},~{dirflag},~{fpsr},~{flags}"()
-// CHECK: call void asm sideeffect inteldialect "mov eax, Foo::ptr", "~{eax},~{dirflag},~{fpsr},~{flags}"()
-// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr Foo::ptr", "~{eax},~{dirflag},~{fpsr},~{flags}"()
-// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr Foo::ptr", "~{eax},~{dirflag},~{fpsr},~{flags}"()
+// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32** @_ZN3Foo3ptrE)
+// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32** @_ZN3Foo3Bar3ptrE)
+// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32** @_ZN3Foo3ptrE)
+// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32** @_ZN3Foo3ptrE)
+// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32** @_ZN3Foo3ptrE)
 }
 
 int gvar = 10;
@@ -33,26 +35,71 @@ void t2() {
   __asm mov eax, offset Foo::ptr
   __asm mov eax, offset Foo::Bar::ptr
 // CHECK: t2
-// CHECK: call void asm sideeffect inteldialect "mov eax, Foo::ptr", "~{eax},~{dirflag},~{fpsr},~{flags}"()
-// CHECK: call void asm sideeffect inteldialect "mov eax, Foo::Bar::ptr", "~{eax},~{dirflag},~{fpsr},~{flags}"()
+// CHECK: call void asm sideeffect inteldialect "mov eax, $0", "r,~{eax},~{dirflag},~{fpsr},~{flags}"(i32** @_ZN3Foo3ptrE)
+// CHECK: call void asm sideeffect inteldialect "mov eax, $0", "r,~{eax},~{dirflag},~{fpsr},~{flags}"(i32** @_ZN3Foo3Bar3ptrE)
 }
 
+// CHECK: define void @_Z2t3v()
 void t3() {
   __asm mov eax, LENGTH Foo::ptr
+// CHECK: call void asm sideeffect inteldialect "mov eax, $$1", "~{eax},~{dirflag},~{fpsr},~{flags}"()
   __asm mov eax, LENGTH Foo::Bar::ptr
+// CHECK: call void asm sideeffect inteldialect "mov eax, $$1", "~{eax},~{dirflag},~{fpsr},~{flags}"()
   __asm mov eax, LENGTH Foo::arr
+// CHECK: call void asm sideeffect inteldialect "mov eax, $$4", "~{eax},~{dirflag},~{fpsr},~{flags}"()
   __asm mov eax, LENGTH Foo::Bar::arr
+// CHECK: call void asm sideeffect inteldialect "mov eax, $$2", "~{eax},~{dirflag},~{fpsr},~{flags}"()
 
   __asm mov eax, TYPE Foo::ptr
+// CHECK: call void asm sideeffect inteldialect "mov eax, $$4", "~{eax},~{dirflag},~{fpsr},~{flags}"()
   __asm mov eax, TYPE Foo::Bar::ptr
+// CHECK: call void asm sideeffect inteldialect "mov eax, $$4", "~{eax},~{dirflag},~{fpsr},~{flags}"()
   __asm mov eax, TYPE Foo::arr
+// CHECK: call void asm sideeffect inteldialect "mov eax, $$4", "~{eax},~{dirflag},~{fpsr},~{flags}"()
   __asm mov eax, TYPE Foo::Bar::arr
+// CHECK: call void asm sideeffect inteldialect "mov eax, $$1", "~{eax},~{dirflag},~{fpsr},~{flags}"()
 
   __asm mov eax, SIZE Foo::ptr
+// CHECK: call void asm sideeffect inteldialect "mov eax, $$4", "~{eax},~{dirflag},~{fpsr},~{flags}"()
   __asm mov eax, SIZE Foo::Bar::ptr
+// CHECK: call void asm sideeffect inteldialect "mov eax, $$4", "~{eax},~{dirflag},~{fpsr},~{flags}"()
   __asm mov eax, SIZE Foo::arr
+// CHECK: call void asm sideeffect inteldialect "mov eax, $$16", "~{eax},~{dirflag},~{fpsr},~{flags}"()
   __asm mov eax, SIZE Foo::Bar::arr
-// CHECK: t3
-// FIXME: These tests just make sure we can parse things properly.
-// Additional work needs to be done in Sema to perform the lookup.
+// CHECK: call void asm sideeffect inteldialect "mov eax, $$2", "~{eax},~{dirflag},~{fpsr},~{flags}"()
+
+}
+
+struct T4 {
+  int x;
+  static int y;
+  void test();
+};
+
+// CHECK: define void @_ZN2T44testEv(
+void T4::test() {
+// CHECK: [[T0:%.*]] = alloca [[T4:%.*]]*,
+// CHECK: [[THIS:%.*]] = load [[T4]]** [[T0]]
+// CHECK: [[X:%.*]] = getelementptr inbounds [[T4]]* [[THIS]], i32 0, i32 0
+  __asm mov eax, x;
+// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* [[X]])
+  __asm mov y, eax;
+// CHECK: call void asm sideeffect inteldialect "mov dword ptr $0, eax", "=*m,~{dirflag},~{fpsr},~{flags}"(i32* @_ZN2T41yE)
+}
+
+template <class T> struct T5 {
+  template <class U> static T create(U);
+  void run();
+};
+// CHECK: define void @_Z5test5v()
+void test5() {
+  // CHECK: [[X:%.*]] = alloca i32
+  // CHECK: [[Y:%.*]] = alloca i32
+  int x, y;
+  __asm push y
+  // CHECK: call void asm sideeffect inteldialect "push dword ptr $0", "=*m,~{dirflag},~{fpsr},~{flags}"(i32* [[Y]])
+  __asm call T5<int>::create<float>
+  // CHECK: call void asm sideeffect inteldialect "call $0", "r,~{dirflag},~{fpsr},~{flags}"(i32 (float)* @_ZN2T5IiE6createIfEEiT_)
+  __asm mov x, eax
+  // CHECK: call void asm sideeffect inteldialect "mov dword ptr $0, eax", "=*m,~{dirflag},~{fpsr},~{flags}"(i32* [[X]])
 }