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
diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp
index 2a7b170..888a148 100644
--- a/lib/AST/Stmt.cpp
+++ b/lib/AST/Stmt.cpp
@@ -673,19 +673,38 @@
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 @@
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 a717706..9203dc1 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -445,7 +445,7 @@
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 28bbc46..73f66e0 100644
--- a/lib/CodeGen/CGStmt.cpp
+++ b/lib/CodeGen/CGStmt.cpp
@@ -1475,16 +1475,20 @@
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 5fa4f17..43b6965 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 @@
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 @@
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.
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 48860e0..1c94378 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -11718,8 +11718,7 @@
// 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.
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 9f4f6d0..9a3c3b4 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -10576,11 +10576,11 @@
}
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 @@
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 @@
// 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 @@
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 @@
const PartialDiagnostic &PD) {
switch (ExprEvalContexts.back().Context) {
case Unevaluated:
+ case UnevaluatedAbstract:
// The argument will never be evaluated, so don't complain.
break;
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 56c4187..85f6bfd 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -742,7 +742,7 @@
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'.
diff --git a/lib/Sema/SemaExprMember.cpp b/lib/Sema/SemaExprMember.cpp
index c3642f5..545ac27 100644
--- a/lib/Sema/SemaExprMember.cpp
+++ b/lib/Sema/SemaExprMember.cpp
@@ -60,6 +60,9 @@
/// 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 @@
// member reference.
if (Classes.empty())
return IMA_Static;
+
+ // 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;
- 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;
+ 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 @@
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 @@
// 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 @@
<< R.getLookupNameInfo().getName();
// Fall through.
case IMA_Static:
+ case IMA_Abstract:
case IMA_Mixed_StaticContext:
case IMA_Unresolved_StaticContext:
if (TemplateArgs || TemplateKWLoc.isValid())
diff --git a/lib/Sema/SemaLambda.cpp b/lib/Sema/SemaLambda.cpp
index 77e6bfd..d16bb6a 100644
--- a/lib/Sema/SemaLambda.cpp
+++ b/lib/Sema/SemaLambda.cpp
@@ -950,6 +950,7 @@
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).
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index 673b84e..8dfc8b9 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -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"
diff --git a/lib/Sema/SemaStmtAsm.cpp b/lib/Sema/SemaStmtAsm.cpp
index 14ee67b..fce95be 100644
--- a/lib/Sema/SemaStmtAsm.cpp
+++ b/lib/Sema/SemaStmtAsm.cpp
@@ -22,18 +22,6 @@
#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 @@
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;
-}
-
-// 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 (i && AsmToks[i].hasLeadingSpace() && !isNewAsm)
- Asm += ' ';
-
- StringRef Spelling = getSpelling(SemaRef, AsmToks[i]);
- Asm += Spelling;
- TokOffsets.push_back(Asm.size());
- }
- AsmString = Asm.str();
- return false;
-}
-
-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);
- }
-
- bool LookupInlineAsmField(StringRef Base, StringRef Member,
- unsigned &Offset) {
- return SemaRef.LookupInlineAsmField(Base, Member, Offset, AsmLoc);
- }
-
- static void MSAsmDiagHandlerCallback(const llvm::SMDiagnostic &D,
- void *Context) {
- ((MCAsmParserSemaCallbackImpl*)Context)->MSAsmDiagHandler(D);
- }
- void MSAsmDiagHandler(const llvm::SMDiagnostic &D) {
- // Compute an offset into the inline asm buffer.
- // FIXME: This isn't right if .macro is involved (but hopefully, no
- // real-world code does that).
- const llvm::SourceMgr &LSM = *D.getSourceMgr();
- const llvm::MemoryBuffer *LBuf =
- LSM.getMemoryBuffer(LSM.FindBufferContainingLoc(D.getLoc()));
- unsigned Offset = D.getLoc().getPointer() - LBuf->getBufferStart();
-
- // Figure out which token that offset points into.
- const unsigned *OffsetPtr =
- std::lower_bound(TokOffsets.begin(), TokOffsets.end(), Offset);
- unsigned TokIndex = OffsetPtr - TokOffsets.begin();
-
- // If we come up with an answer which seems sane, use it; otherwise,
- // just point at the __asm keyword.
- // FIXME: Assert the answer is sane once we handle .macro correctly.
- SourceLocation Loc = AsmLoc;
- if (TokIndex < AsmToks.size()) {
- const Token *Tok = &AsmToks[TokIndex];
- Loc = Tok->getLocation();
- Loc = Loc.getLocWithOffset(Offset - (*OffsetPtr - Tok->getLength()));
- }
- SemaRef.Diag(Loc, diag::err_inline_ms_asm_parsing) << D.getMessage();
- }
-};
-
-}
-
-// 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;
- }
- return StringRef(StartPtr, CurPtr - StartPtr);
-}
-
-NamedDecl *Sema::LookupInlineAsmIdentifier(StringRef &LineBuf, SourceLocation Loc,
- InlineAsmIdentifierInfo &Info) {
+ExprResult Sema::LookupInlineAsmIdentifier(CXXScopeSpec &SS,
+ SourceLocation TemplateKWLoc,
+ UnqualifiedId &Id,
+ InlineAsmIdentifierInfo &Info,
+ bool IsUnevaluatedContext) {
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;
+ if (IsUnevaluatedContext)
+ PushExpressionEvaluationContext(UnevaluatedAbstract,
+ ReuseLambdaContextDecl);
+
+ ExprResult Result = ActOnIdExpression(getCurScope(), SS, TemplateKWLoc, Id,
+ /*trailing lparen*/ false,
+ /*is & operand*/ false);
+
+ if (IsUnevaluatedContext)
+ PopExpressionEvaluationContext();
+
+ if (!Result.isUsable()) return Result;
+
+ Result = CheckPlaceholderExpr(Result.take());
+ if (!Result.isUsable()) return Result;
+
+ QualType T = Result.get()->getType();
+
+ // For now, reject dependent types.
+ if (T->isDependentType()) {
+ Diag(Id.getLocStart(), diag::err_asm_incomplete_type) << T;
+ return ExprError();
}
- if (!Result.isSingleResult()) {
- // FIXME: Diagnose result.
- return 0;
+ // Any sort of function type is fine.
+ if (T->isFunctionType()) {
+ return Result;
}
- 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;
- }
+ // Otherwise, it needs to be a complete type.
+ if (RequireCompleteExprType(Result.get(), diag::err_asm_incomplete_type)) {
+ return ExprError();
+ }
+
+ // 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;
+ }
+
+ // 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 @@
}
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);
}
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index fda1548..99cb282 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -1190,8 +1190,16 @@
/// 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 @@
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>
diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp
index a5fd2e3..a766bd2 100644
--- a/lib/Serialization/ASTReader.cpp
+++ b/lib/Serialization/ASTReader.cpp
@@ -1103,6 +1103,19 @@
}
}
+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 @@
// 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;
}
diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp
index c7748b7..fd60ec4 100644
--- a/lib/Serialization/ASTReaderStmt.cpp
+++ b/lib/Serialization/ASTReaderStmt.cpp
@@ -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 @@
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::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::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) {
diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp
index 2d691b1..b8ada04 100644
--- a/lib/Serialization/ASTWriter.cpp
+++ b/lib/Serialization/ASTWriter.cpp
@@ -2012,18 +2012,7 @@
// 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::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());
diff --git a/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp
index 5c8e213..832bbf6 100644
--- a/lib/Serialization/ASTWriterStmt.cpp
+++ b/lib/Serialization/ASTWriterStmt.cpp
@@ -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 @@
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::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;
}