aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn McCall <rjmccall@apple.com>2013-05-03 00:10:13 +0000
committerJohn McCall <rjmccall@apple.com>2013-05-03 00:10:13 +0000
commitaeeacf725c9e0ddd64ea9764bd008e5b6873ce51 (patch)
tree370063ad5a0cf0312992d978ed703abc92c53403
parentc70fac3c52092013b08163187f034b73c94bf3d0 (diff)
Move parsing of identifiers in MS-style inline assembly into
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
-rw-r--r--include/clang/AST/Stmt.h91
-rw-r--r--include/clang/Basic/DiagnosticParseKinds.td7
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td5
-rw-r--r--include/clang/Parse/Parser.h5
-rw-r--r--include/clang/Sema/Sema.h30
-rw-r--r--include/clang/Serialization/ASTReader.h3
-rw-r--r--include/clang/Serialization/ASTWriter.h4
-rw-r--r--lib/AST/Stmt.cpp41
-rw-r--r--lib/AST/StmtPrinter.cpp2
-rw-r--r--lib/CodeGen/CGStmt.cpp12
-rw-r--r--lib/Parse/ParseStmt.cpp397
-rw-r--r--lib/Sema/SemaDeclCXX.cpp3
-rw-r--r--lib/Sema/SemaExpr.cpp10
-rw-r--r--lib/Sema/SemaExprCXX.cpp2
-rw-r--r--lib/Sema/SemaExprMember.cpp51
-rw-r--r--lib/Sema/SemaLambda.cpp1
-rw-r--r--lib/Sema/SemaStmt.cpp1
-rw-r--r--lib/Sema/SemaStmtAsm.cpp332
-rw-r--r--lib/Sema/TreeTransform.h36
-rw-r--r--lib/Serialization/ASTReader.cpp23
-rw-r--r--lib/Serialization/ASTReaderStmt.cpp74
-rw-r--r--lib/Serialization/ASTWriter.cpp26
-rw-r--r--lib/Serialization/ASTWriterStmt.cpp38
-rw-r--r--test/CodeGen/ms-inline-asm.cpp77
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,
+