18 #include "llvm/ADT/SmallString.h" 19 #include "llvm/ADT/StringExtras.h" 20 #include "llvm/MC/MCAsmInfo.h" 21 #include "llvm/MC/MCContext.h" 22 #include "llvm/MC/MCInstPrinter.h" 23 #include "llvm/MC/MCInstrInfo.h" 24 #include "llvm/MC/MCObjectFileInfo.h" 25 #include "llvm/MC/MCParser/MCAsmParser.h" 26 #include "llvm/MC/MCParser/MCTargetAsmParser.h" 27 #include "llvm/MC/MCRegisterInfo.h" 28 #include "llvm/MC/MCStreamer.h" 29 #include "llvm/MC/MCSubtargetInfo.h" 30 #include "llvm/MC/MCTargetOptions.h" 31 #include "llvm/Support/SourceMgr.h" 32 #include "llvm/Support/TargetRegistry.h" 33 #include "llvm/Support/TargetSelect.h" 34 using namespace clang;
37 class ClangAsmParserCallback :
public llvm::MCAsmParserSemaCallback {
51 : TheParser(P), AsmLoc(Loc), AsmString(AsmString), AsmToks(Toks),
52 AsmTokOffsets(Offsets) {
53 assert(AsmToks.size() == AsmTokOffsets.size());
56 void LookupInlineAsmIdentifier(StringRef &LineBuf,
57 llvm::InlineAsmIdentifierInfo &Info,
58 bool IsUnevaluatedContext)
override;
60 StringRef LookupInlineAsmLabel(StringRef
Identifier, llvm::SourceMgr &LSM,
64 bool LookupInlineAsmField(StringRef
Base, StringRef Member,
65 unsigned &
Offset)
override {
70 static void DiagHandlerCallback(
const llvm::SMDiagnostic &D,
void *Context) {
71 ((ClangAsmParserCallback *)Context)->handleDiagnostic(D);
77 const Token *&FirstOrigToken)
const;
82 void handleDiagnostic(
const llvm::SMDiagnostic &D);
86 void ClangAsmParserCallback::LookupInlineAsmIdentifier(
87 StringRef &LineBuf, llvm::InlineAsmIdentifierInfo &Info,
88 bool IsUnevaluatedContext) {
91 const Token *FirstOrigToken =
nullptr;
92 findTokensForString(LineBuf, LineToks, FirstOrigToken);
94 unsigned NumConsumedToks;
96 IsUnevaluatedContext);
100 if (NumConsumedToks == 0 || NumConsumedToks == LineToks.size()) {
105 assert(FirstOrigToken &&
"not using original tokens?");
108 assert(FirstOrigToken[NumConsumedToks].getLocation() ==
109 LineToks[NumConsumedToks].getLocation());
110 unsigned FirstIndex = FirstOrigToken - AsmToks.begin();
111 unsigned LastIndex = FirstIndex + NumConsumedToks - 1;
115 unsigned TotalOffset =
116 (AsmTokOffsets[LastIndex] + AsmToks[LastIndex].getLength() -
117 AsmTokOffsets[FirstIndex]);
118 LineBuf = LineBuf.substr(0, TotalOffset);
127 StringRef ClangAsmParserCallback::LookupInlineAsmLabel(StringRef
Identifier,
128 llvm::SourceMgr &LSM,
129 llvm::SMLoc Location,
137 void ClangAsmParserCallback::findTokensForString(
139 const Token *&FirstOrigToken)
const {
142 assert(!std::less<const char *>()(Str.begin(), AsmString.begin()) &&
143 !std::less<const char *>()(AsmString.end(), Str.end()));
146 unsigned FirstCharOffset = Str.begin() - AsmString.begin();
147 const unsigned *FirstTokOffset =
148 llvm::lower_bound(AsmTokOffsets, FirstCharOffset);
152 assert(*FirstTokOffset == FirstCharOffset);
156 unsigned FirstTokIndex = FirstTokOffset - AsmTokOffsets.begin();
157 FirstOrigToken = &AsmToks[FirstTokIndex];
158 unsigned LastCharOffset = Str.end() - AsmString.begin();
159 for (
unsigned i = FirstTokIndex, e = AsmTokOffsets.size();
i != e; ++
i) {
160 if (AsmTokOffsets[
i] >= LastCharOffset)
162 TempToks.push_back(AsmToks[
i]);
167 ClangAsmParserCallback::translateLocation(
const llvm::SourceMgr &LSM,
172 const llvm::MemoryBuffer *LBuf =
173 LSM.getMemoryBuffer(LSM.FindBufferContainingLoc(SMLoc));
174 unsigned Offset = SMLoc.getPointer() - LBuf->getBufferStart();
177 const unsigned *TokOffsetPtr = llvm::lower_bound(AsmTokOffsets, Offset);
178 unsigned TokIndex = TokOffsetPtr - AsmTokOffsets.begin();
179 unsigned TokOffset = *TokOffsetPtr;
185 if (TokIndex < AsmToks.size()) {
186 const Token &
Tok = AsmToks[TokIndex];
193 void ClangAsmParserCallback::handleDiagnostic(
const llvm::SMDiagnostic &D) {
194 const llvm::SourceMgr &LSM = *D.getSourceMgr();
196 TheParser.
Diag(Loc, diag::err_inline_ms_asm_parsing) << D.getMessage();
201 unsigned &NumLineToksConsumed,
202 bool IsUnevaluatedContext) {
207 Token EndOfStreamTok;
209 EndOfStreamTok.
setKind(EndOfStream);
210 LineToks.push_back(EndOfStreamTok);
213 LineToks.push_back(Tok);
215 PP.EnterTokenStream(LineToks,
true,
224 ParseOptionalCXXScopeSpecifier(SS,
nullptr,
false);
232 if (Tok.
is(tok::kw_this)) {
233 Result = ParseCXXThis();
236 Invalid = ParseUnqualifiedId(SS,
241 nullptr, &TemplateKWLoc, Id);
243 Result = Actions.LookupInlineAsmIdentifier(SS, TemplateKWLoc, Id,
244 IsUnevaluatedContext);
249 while (Result.
isUsable() && Tok.
is(tok::period)) {
250 Token IdTok = PP.LookAhead(0);
251 if (IdTok.
isNot(tok::identifier))
256 Result = Actions.LookupInlineAsmVarDeclField(Result.
get(), Id->
getName(),
261 unsigned LineIndex = 0;
262 if (Tok.
is(EndOfStream)) {
263 LineIndex = LineToks.size() - 2;
265 while (LineToks[LineIndex].getLocation() != Tok.
getLocation()) {
267 assert(LineIndex < LineToks.size() - 2);
273 if (Invalid || Tok.
is(EndOfStream)) {
274 NumLineToksConsumed = LineToks.size() - 2;
277 NumLineToksConsumed = LineIndex;
282 for (
unsigned i = 0, e = LineToks.size() - LineIndex - 2;
i != e; ++
i) {
285 assert(Tok.
is(EndOfStream));
301 assert(!AsmToks.empty() &&
"Didn't expect an empty AsmToks!");
304 bool isNewStatement =
true;
306 for (
unsigned i = 0, e = AsmToks.size();
i < e; ++
i) {
307 const Token &Tok = AsmToks[
i];
312 isNewStatement =
true;
321 TokOffsets.push_back(Asm.size());
324 if (Tok.
is(tok::kw_asm)) {
327 PP.
Diag(AsmLoc, diag::err_asm_empty);
336 bool SpellingInvalid =
false;
337 Asm += PP.
getSpelling(Tok, SpellingBuffer, &SpellingInvalid);
338 assert(!SpellingInvalid &&
"spelling was invalid after correct parse?");
341 isNewStatement =
false;
348 assert(TokOffsets.size() == AsmToks.size());
356 default:
return false;
359 case tok::kw_volatile:
360 case tok::kw_restrict:
361 case tok::kw___private:
362 case tok::kw___local:
363 case tok::kw___global:
364 case tok::kw___constant:
365 case tok::kw___generic:
366 case tok::kw___read_only:
367 case tok::kw___read_write:
368 case tok::kw___write_only:
375 return TokAfterAsm.
is(tok::l_paren) || TokAfterAsm.
is(tok::kw_goto) ||
399 bool SingleLineMode =
true;
400 unsigned BraceNesting = 0;
401 unsigned short savedBraceCount = BraceCount;
402 bool InAsmComment =
false;
405 unsigned NumTokensRead = 0;
407 bool SkippedStartOfLine =
false;
409 if (Tok.
is(tok::l_brace)) {
411 SingleLineMode =
false;
413 EndLoc = ConsumeBrace();
414 LBraceLocs.push_back(EndLoc);
418 std::pair<FileID, unsigned> ExpAsmLoc =
420 FID = ExpAsmLoc.first;
431 if (!InAsmComment && Tok.
is(tok::l_brace)) {
434 AsmToks.push_back(Tok);
435 EndLoc = ConsumeBrace();
437 LBraceLocs.push_back(EndLoc);
441 }
else if (!InAsmComment && Tok.
is(tok::semi)) {
444 if (!SingleLineMode) {
446 std::pair<FileID, unsigned> ExpSemiLoc =
448 FID = ExpSemiLoc.first;
451 }
else if (SingleLineMode || InAsmComment) {
454 std::pair<FileID, unsigned> ExpLoc =
456 if (ExpLoc.first != FID ||
457 SrcMgr.
getLineNumber(ExpLoc.first, ExpLoc.second) != LineNo) {
462 bool isAsm = Tok.
is(tok::kw_asm);
466 InAsmComment =
false;
470 if (PP.LookAhead(0).is(tok::l_brace))
474 }
else if (Tok.
is(tok::semi)) {
480 }
else if (!InAsmComment && Tok.
is(tok::r_brace)) {
488 if (!InAsmComment && BraceNesting && Tok.
is(tok::r_brace) &&
489 BraceCount == (savedBraceCount + BraceNesting)) {
493 if (SingleLineMode || BraceNesting > 1) {
495 AsmToks.push_back(Tok);
497 EndLoc = ConsumeBrace();
501 if (BraceNesting == 0 && !SingleLineMode)
504 LBraceLocs.pop_back();
519 if (SkippedStartOfLine)
521 AsmToks.push_back(Tok);
526 SkippedStartOfLine =
false;
529 if (BraceNesting && BraceCount != savedBraceCount) {
531 for (
unsigned i = 0;
i < BraceNesting; ++
i) {
532 Diag(Tok, diag::err_expected) << tok::r_brace;
533 Diag(LBraceLocs.back(), diag::note_matching) << tok::l_brace;
534 LBraceLocs.pop_back();
537 }
else if (NumTokensRead == 0) {
539 Diag(Tok, diag::err_expected) << tok::l_brace;
549 const llvm::Triple &TheTriple = Actions.Context.getTargetInfo().getTriple();
550 llvm::Triple::ArchType ArchTy = TheTriple.getArch();
551 const std::string &TT = TheTriple.getTriple();
553 bool UnsupportedArch =
554 (ArchTy != llvm::Triple::x86 && ArchTy != llvm::Triple::x86_64);
555 if (UnsupportedArch) {
556 Diag(AsmLoc, diag::err_msasm_unsupported_arch) << TheTriple.getArchName();
559 TheTarget = llvm::TargetRegistry::lookupTarget(TT, Error);
561 Diag(AsmLoc, diag::err_msasm_unable_to_create_target) <<
Error;
564 assert(!LBraceLocs.empty() &&
"Should have at least one location here");
568 if (!TheTarget || AsmToks.empty()) {
569 return Actions.ActOnMSAsmStmt(AsmLoc, LBraceLocs[0], AsmToks, StringRef(),
571 ConstraintRefs, ClobberRefs, Exprs, EndLoc);
580 const TargetOptions &TO = Actions.Context.getTargetInfo().getTargetOpts();
581 std::string FeaturesStr =
584 std::unique_ptr<llvm::MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TT));
585 std::unique_ptr<llvm::MCAsmInfo> MAI(TheTarget->createMCAsmInfo(*MRI, TT));
587 std::unique_ptr<llvm::MCInstrInfo> MII(TheTarget->createMCInstrInfo());
588 std::unique_ptr<llvm::MCObjectFileInfo> MOFI(
new llvm::MCObjectFileInfo());
589 std::unique_ptr<llvm::MCSubtargetInfo> STI(
590 TheTarget->createMCSubtargetInfo(TT, TO.
CPU, FeaturesStr));
592 llvm::SourceMgr TempSrcMgr;
593 llvm::MCContext Ctx(MAI.get(), MRI.get(), MOFI.get(), &TempSrcMgr);
594 MOFI->InitMCObjectFileInfo(TheTriple,
false, Ctx);
595 std::unique_ptr<llvm::MemoryBuffer> Buffer =
596 llvm::MemoryBuffer::getMemBuffer(AsmString,
"<MS inline asm>");
599 TempSrcMgr.AddNewSourceBuffer(std::move(Buffer), llvm::SMLoc());
601 std::unique_ptr<llvm::MCStreamer> Str(createNullStreamer(Ctx));
602 std::unique_ptr<llvm::MCAsmParser>
Parser(
603 createMCAsmParser(TempSrcMgr, Ctx, *Str.get(), *MAI));
606 llvm::MCTargetOptions MCOptions;
607 std::unique_ptr<llvm::MCTargetAsmParser> TargetParser(
608 TheTarget->createMCAsmParser(*STI, *Parser, *MII, MCOptions));
610 std::unique_ptr<llvm::MCInstPrinter> IP(
611 TheTarget->createMCInstPrinter(llvm::Triple(TT), 1, *MAI, *MII, *MRI));
614 Parser->setAssemblerDialect(1);
615 Parser->setTargetParser(*TargetParser.get());
616 Parser->setParsingInlineAsm(
true);
617 TargetParser->setParsingInlineAsm(
true);
619 ClangAsmParserCallback Callback(*
this, AsmLoc, AsmString, AsmToks,
621 TargetParser->setSemaCallback(&Callback);
622 TempSrcMgr.setDiagHandler(ClangAsmParserCallback::DiagHandlerCallback,
627 std::string AsmStringIR;
631 if (Parser->parseMSInlineAsm(AsmLoc.
getPtrEncoding(), AsmStringIR, NumOutputs,
632 NumInputs, OpExprs, Constraints, Clobbers,
633 MII.get(), IP.get(), Callback))
638 llvm::erase_if(Clobbers, [](
const std::string &
C) {
639 return C ==
"fpsr" || C ==
"mxcsr";
643 ClobberRefs.insert(ClobberRefs.end(), Clobbers.begin(), Clobbers.end());
646 unsigned NumExprs = NumOutputs + NumInputs;
647 ConstraintRefs.resize(NumExprs);
648 Exprs.resize(NumExprs);
649 for (
unsigned i = 0, e = NumExprs;
i != e; ++
i) {
650 Expr *OpExpr =
static_cast<Expr *
>(OpExprs[
i].first);
655 if (OpExprs[
i].second)
657 Actions.BuildUnaryOp(getCurScope(), AsmLoc, UO_AddrOf, OpExpr).get();
659 ConstraintRefs[
i] = StringRef(Constraints[
i]);
664 return Actions.ActOnMSAsmStmt(AsmLoc, LBraceLocs[0], AsmToks, AsmStringIR,
665 NumOutputs, NumInputs, ConstraintRefs,
666 ClobberRefs, Exprs, EndLoc);
688 StmtResult Parser::ParseAsmStatement(
bool &msAsm) {
689 assert(Tok.
is(tok::kw_asm) &&
"Not an asm stmt");
694 return ParseMicrosoftAsmStatement(AsmLoc);
699 ParseTypeQualifierListOpt(DS, AR_VendorAttributesParsed);
703 Diag(Loc, diag::warn_asm_qualifier_ignored) <<
"const";
705 Diag(Loc, diag::warn_asm_qualifier_ignored) <<
"restrict";
708 Diag(Loc, diag::warn_asm_qualifier_ignored) <<
"_Atomic";
713 bool isGotoAsm =
false;
715 if (Tok.
is(tok::kw_goto)) {
720 if (Tok.
isNot(tok::l_paren)) {
721 Diag(Tok, diag::err_expected_lparen_after) <<
"asm";
722 SkipUntil(tok::r_paren, StopAtSemi);
728 ExprResult AsmString(ParseAsmStringLiteral());
732 if (!(getLangOpts().GNUAsm || AsmString.
isInvalid())) {
733 const auto *SL = cast<StringLiteral>(AsmString.
get());
734 if (!SL->getString().trim().empty())
735 Diag(Loc, diag::err_gnu_inline_asm_disabled);
745 ExprVector Constraints;
749 if (Tok.
is(tok::r_paren)) {
752 return Actions.ActOnGCCAsmStmt(AsmLoc,
true, isVolatile,
754 Constraints, Exprs, AsmString.
get(),
760 bool AteExtraColon =
false;
761 if (Tok.
is(tok::colon) || Tok.
is(tok::coloncolon)) {
763 AteExtraColon = Tok.
is(tok::coloncolon);
766 if (!AteExtraColon && isGotoAsm && Tok.
isNot(tok::colon)) {
767 Diag(Tok, diag::err_asm_goto_cannot_have_output);
768 SkipUntil(tok::r_paren, StopAtSemi);
772 if (!AteExtraColon && ParseAsmOperandsOpt(Names, Constraints, Exprs))
776 unsigned NumOutputs = Names.size();
779 if (AteExtraColon || Tok.
is(tok::colon) || Tok.
is(tok::coloncolon)) {
782 AteExtraColon =
false;
784 AteExtraColon = Tok.
is(tok::coloncolon);
788 if (!AteExtraColon && ParseAsmOperandsOpt(Names, Constraints, Exprs))
792 assert(Names.size() == Constraints.size() &&
793 Constraints.size() == Exprs.size() &&
"Input operand size mismatch!");
795 unsigned NumInputs = Names.size() - NumOutputs;
798 if (AteExtraColon || Tok.
is(tok::colon) || Tok.
is(tok::coloncolon)) {
800 AteExtraColon =
false;
802 AteExtraColon = Tok.
is(tok::coloncolon);
806 if (!AteExtraColon && isTokenStringLiteral()) {
813 Clobbers.push_back(Clobber.
get());
815 if (!TryConsumeToken(tok::comma))
820 if (!isGotoAsm && (Tok.
isNot(tok::r_paren) || AteExtraColon)) {
821 Diag(Tok, diag::err_expected) << tok::r_paren;
822 SkipUntil(tok::r_paren, StopAtSemi);
827 unsigned NumLabels = 0;
828 if (AteExtraColon || Tok.
is(tok::colon)) {
833 if (Tok.
isNot(tok::identifier)) {
834 Diag(Tok, diag::err_expected) << tok::identifier;
835 SkipUntil(tok::r_paren, StopAtSemi);
842 SkipUntil(tok::r_paren, StopAtSemi);
847 Exprs.push_back(Res.
get());
850 if (!TryConsumeToken(tok::comma))
853 }
else if (isGotoAsm) {
854 Diag(Tok, diag::err_expected) << tok::colon;
855 SkipUntil(tok::r_paren, StopAtSemi);
859 return Actions.ActOnGCCAsmStmt(
860 AsmLoc,
false, isVolatile, NumOutputs, NumInputs, Names.data(),
861 Constraints, Exprs, AsmString.
get(), Clobbers, NumLabels,
882 if (!isTokenStringLiteral() && Tok.
isNot(tok::l_square))
887 if (Tok.
is(tok::l_square)) {
891 if (Tok.
isNot(tok::identifier)) {
892 Diag(Tok, diag::err_expected) << tok::identifier;
893 SkipUntil(tok::r_paren, StopAtSemi);
903 Names.push_back(
nullptr);
905 ExprResult Constraint(ParseAsmStringLiteral());
907 SkipUntil(tok::r_paren, StopAtSemi);
910 Constraints.push_back(Constraint.
get());
912 if (Tok.
isNot(tok::l_paren)) {
913 Diag(Tok, diag::err_expected_lparen_after) <<
"asm operand";
914 SkipUntil(tok::r_paren, StopAtSemi);
921 ExprResult Res = Actions.CorrectDelayedTyposInExpr(ParseExpression());
924 SkipUntil(tok::r_paren, StopAtSemi);
927 Exprs.push_back(Res.
get());
929 if (!TryConsumeToken(tok::comma))
Defines the clang::ASTContext interface.
static DiagnosticBuilder Diag(DiagnosticsEngine *Diags, const LangOptions &Features, FullSourceLoc TokLoc, const char *TokBegin, const char *TokRangeBegin, const char *TokRangeEnd, unsigned DiagID)
Produce a diagnostic highlighting some portion of a literal.
SourceLocation getLocWithOffset(int Offset) const
Return a source location with the specified offset from this SourceLocation.
void FillInlineAsmIdentifierInfo(Expr *Res, llvm::InlineAsmIdentifierInfo &Info)
bool is(tok::TokenKind K) const
is/isNot - Predicates to check if this token is a specific kind, as in "if (Tok.is(tok::l_brace)) {...
SourceLocation getCloseLocation() const
void setFlag(TokenFlags Flag)
Set the specified flag.
Parser - This implements a parser for the C family of languages.
ActionResult< Stmt * > StmtResult
Options for controlling the target.
tok::TokenKind getKind() const
static bool isGCCAsmStatement(const Token &TokAfterAsm)
One of these records is kept for each identifier that is lexed.
Token - This structure provides full information about a lexed token.
void setKind(tok::TokenKind K)
RAII class that helps handle the parsing of an open/close delimiter pair, such as braces { ...
LabelDecl * GetOrCreateMSAsmLabel(StringRef ExternalLabelName, SourceLocation Location, bool AlwaysCreate)
std::pair< FileID, unsigned > getDecomposedExpansionLoc(SourceLocation Loc) const
Decompose the specified location into a raw FileID + Offset pair.
Represents a C++ unqualified-id that has been parsed.
StringRef getSpelling(SourceLocation loc, SmallVectorImpl< char > &buffer, bool *invalid=nullptr) const
Return the 'spelling' of the token at the given location; does not go up to the spelling location or ...
Defines the Diagnostic-related interfaces.
Represents a C++ nested-name-specifier or a global scope specifier.
This represents one expression.
static bool buildMSAsmString(Preprocessor &PP, SourceLocation AsmLoc, ArrayRef< Token > AsmToks, SmallVectorImpl< unsigned > &TokOffsets, SmallString< 512 > &Asm)
Turn a sequence of our tokens back into a string that we can hand to the MC asm parser.
Sema & getActions() const
SourceLocation getLocation() const
Return a source location identifier for the specified offset in the current file. ...
The result type of a method or function.
std::string CPU
If given, the name of the target CPU to generate code for.
ActionResult - This structure is used while parsing/acting on expressions, stmts, etc...
Encodes a location in the source.
IdentifierInfo * getIdentifierInfo() const
Represents the declaration of a label.
ExprResult ParseMSAsmIdentifier(llvm::SmallVectorImpl< Token > &LineToks, unsigned &NumLineToksConsumed, bool IsUnevaluated)
Parse an identifier in an MS-style inline assembly block.
unsigned getLineNumber(FileID FID, unsigned FilePos, bool *Invalid=nullptr) const
Given a SourceLocation, return the spelling line number for the position indicated.
std::vector< std::string > Features
The list of target specific features to enable or disable – this should be a list of strings startin...
bool isAtStartOfLine() const
isAtStartOfLine - Return true if this token is at the start of a line.
TokenKind
Provides a simple uniform namespace for tokens from all C languages.
bool LookupInlineAsmField(StringRef Base, StringRef Member, unsigned &Offset, SourceLocation AsmLoc)
StringRef getName() const
Return the actual identifier string.
static bool isTypeQualifier(const Token &Tok)
isTypeQualifier - Return true if the current token could be the start of a type-qualifier-list.
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
bool isNot(tok::TokenKind K) const
Dataflow Directional Tag Classes.
StringRef getMSAsmLabel() const
unsigned getTypeQualifiers() const
getTypeQualifiers - Return a set of TQs.
DiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID)
Captures information about "declaration specifiers".
Defines the clang::TargetInfo interface.
void clearFlag(TokenFlags Flag)
Unset the specified flag.
bool hasLeadingSpace() const
Return true if this token has whitespace before it.
DiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID) const
Forwarding function for diagnostics.
This class handles loading and caching of source files into memory.
void startToken()
Reset all flags to cleared.
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
static OMPLinearClause * Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc, OpenMPLinearClauseKind Modifier, SourceLocation ModifierLoc, SourceLocation ColonLoc, SourceLocation EndLoc, ArrayRef< Expr *> VL, ArrayRef< Expr *> PL, ArrayRef< Expr *> IL, Expr *Step, Expr *CalcStep, Stmt *PreInit, Expr *PostUpdate)
Creates clause with a list of variables VL and a linear step Step.
void * getPtrEncoding() const
When a SourceLocation itself cannot be used, this returns an (opaque) pointer encoding for it...