diff options
-rw-r--r-- | include/clang/AST/Stmt.h | 91 | ||||
-rw-r--r-- | include/clang/Basic/DiagnosticParseKinds.td | 7 | ||||
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.td | 5 | ||||
-rw-r--r-- | include/clang/Parse/Parser.h | 5 | ||||
-rw-r--r-- | include/clang/Sema/Sema.h | 30 | ||||
-rw-r--r-- | include/clang/Serialization/ASTReader.h | 3 | ||||
-rw-r--r-- | include/clang/Serialization/ASTWriter.h | 4 | ||||
-rw-r--r-- | lib/AST/Stmt.cpp | 41 | ||||
-rw-r--r-- | lib/AST/StmtPrinter.cpp | 2 | ||||
-rw-r--r-- | lib/CodeGen/CGStmt.cpp | 12 | ||||
-rw-r--r-- | lib/Parse/ParseStmt.cpp | 397 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 3 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 10 | ||||
-rw-r--r-- | lib/Sema/SemaExprCXX.cpp | 2 | ||||
-rw-r--r-- | lib/Sema/SemaExprMember.cpp | 51 | ||||
-rw-r--r-- | lib/Sema/SemaLambda.cpp | 1 | ||||
-rw-r--r-- | lib/Sema/SemaStmt.cpp | 1 | ||||
-rw-r--r-- | lib/Sema/SemaStmtAsm.cpp | 332 | ||||
-rw-r--r-- | lib/Sema/TreeTransform.h | 36 | ||||
-rw-r--r-- | lib/Serialization/ASTReader.cpp | 23 | ||||
-rw-r--r-- | lib/Serialization/ASTReaderStmt.cpp | 74 | ||||
-rw-r--r-- | lib/Serialization/ASTWriter.cpp | 26 | ||||
-rw-r--r-- | lib/Serialization/ASTWriterStmt.cpp | 38 | ||||
-rw-r--r-- | test/CodeGen/ms-inline-asm.cpp | 77 |
24 files changed, 849 insertions, 422 deletions
diff --git a/include/clang/AST/Stmt.h b/include/clang/AST/Stmt.h index 1e5892fcf7..6e5fae4f3c 100644 --- a/include/clang/AST/Stmt.h +++ b/include/clang/AST/Stmt.h @@ -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; } diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td index 08abef120a..f50dceca57 100644 --- a/include/clang/Basic/DiagnosticParseKinds.td +++ b/include/clang/Basic/DiagnosticParseKinds.td @@ -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< diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index fb2ffe8872..bfbbb91be9 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -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">; diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index 44c213c5ef..a33d01d27b 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -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); diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index e5f2d448fd..9aee774d1f 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -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 diff --git a/include/clang/Serialization/ASTReader.h b/include/clang/Serialization/ASTReader.h index 0aa649a84d..9c19eda1ff 100644 --- a/include/clang/Serialization/ASTReader.h +++ b/include/clang/Serialization/ASTReader.h @@ -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); diff --git a/include/clang/Serialization/ASTWriter.h b/include/clang/Serialization/ASTWriter.h index 2938dc76de..8ac8fde884 100644 --- a/include/clang/Serialization/ASTWriter.h +++ b/include/clang/Serialization/ASTWriter.h @@ -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); diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp index 2a7b170222..888a148b96 100644 --- a/lib/AST/Stmt.cpp +++ b/lib/AST/Stmt.cpp @@ -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]); } } diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index a7177063ce..9203dc1584 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/lib/AST/StmtPrinter.cpp @@ -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"; } diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp index 28bbc46c68..73f66e0c8c 100644 --- a/lib/CodeGen/CGStmt.cpp +++ b/lib/CodeGen/CGStmt.cpp @@ -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); diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index 5fa4f17026..43b6965d31 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -14,13 +14,26 @@ #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; + } |