llvm-project/clang/lib/Parse/ParsePragma.cpp
Tyler Nowicki cab7ca3e2a Add a state variable to the loop hint attribute.
This patch is necessary to support constant expressions which replaces the integer value in the loop hint attribute with an expression. The integer value was also storing the pragma’s state for options like vectorize(enable/disable) and the pragma unroll and nounroll directive. The state variable is introduced to hold the state of those options/pragmas. This moves the validation of the state (keywords) from SemaStmtAttr handler to the loop hint annotation token handler.

Reviewed by Aaron Ballman

llvm-svn: 214333
2014-07-30 20:54:33 +00:00

2005 lines
67 KiB
C++

//===--- ParsePragma.cpp - Language specific pragma parsing ---------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the language specific #pragma handlers.
//
//===----------------------------------------------------------------------===//
#include "RAIIObjectsForParser.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Parse/Parser.h"
#include "clang/Sema/LoopHint.h"
#include "clang/Sema/Scope.h"
#include "llvm/ADT/StringSwitch.h"
using namespace clang;
namespace {
struct PragmaAlignHandler : public PragmaHandler {
explicit PragmaAlignHandler() : PragmaHandler("align") {}
void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
Token &FirstToken) override;
};
struct PragmaGCCVisibilityHandler : public PragmaHandler {
explicit PragmaGCCVisibilityHandler() : PragmaHandler("visibility") {}
void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
Token &FirstToken) override;
};
struct PragmaOptionsHandler : public PragmaHandler {
explicit PragmaOptionsHandler() : PragmaHandler("options") {}
void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
Token &FirstToken) override;
};
struct PragmaPackHandler : public PragmaHandler {
explicit PragmaPackHandler() : PragmaHandler("pack") {}
void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
Token &FirstToken) override;
};
struct PragmaMSStructHandler : public PragmaHandler {
explicit PragmaMSStructHandler() : PragmaHandler("ms_struct") {}
void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
Token &FirstToken) override;
};
struct PragmaUnusedHandler : public PragmaHandler {
PragmaUnusedHandler() : PragmaHandler("unused") {}
void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
Token &FirstToken) override;
};
struct PragmaWeakHandler : public PragmaHandler {
explicit PragmaWeakHandler() : PragmaHandler("weak") {}
void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
Token &FirstToken) override;
};
struct PragmaRedefineExtnameHandler : public PragmaHandler {
explicit PragmaRedefineExtnameHandler() : PragmaHandler("redefine_extname") {}
void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
Token &FirstToken) override;
};
struct PragmaOpenCLExtensionHandler : public PragmaHandler {
PragmaOpenCLExtensionHandler() : PragmaHandler("EXTENSION") {}
void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
Token &FirstToken) override;
};
struct PragmaFPContractHandler : public PragmaHandler {
PragmaFPContractHandler() : PragmaHandler("FP_CONTRACT") {}
void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
Token &FirstToken) override;
};
struct PragmaNoOpenMPHandler : public PragmaHandler {
PragmaNoOpenMPHandler() : PragmaHandler("omp") { }
void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
Token &FirstToken) override;
};
struct PragmaOpenMPHandler : public PragmaHandler {
PragmaOpenMPHandler() : PragmaHandler("omp") { }
void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
Token &FirstToken) override;
};
/// PragmaCommentHandler - "\#pragma comment ...".
struct PragmaCommentHandler : public PragmaHandler {
PragmaCommentHandler(Sema &Actions)
: PragmaHandler("comment"), Actions(Actions) {}
void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
Token &FirstToken) override;
private:
Sema &Actions;
};
struct PragmaDetectMismatchHandler : public PragmaHandler {
PragmaDetectMismatchHandler(Sema &Actions)
: PragmaHandler("detect_mismatch"), Actions(Actions) {}
void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
Token &FirstToken) override;
private:
Sema &Actions;
};
struct PragmaMSPointersToMembers : public PragmaHandler {
explicit PragmaMSPointersToMembers() : PragmaHandler("pointers_to_members") {}
void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
Token &FirstToken) override;
};
struct PragmaMSVtorDisp : public PragmaHandler {
explicit PragmaMSVtorDisp() : PragmaHandler("vtordisp") {}
void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
Token &FirstToken) override;
};
struct PragmaMSPragma : public PragmaHandler {
explicit PragmaMSPragma(const char *name) : PragmaHandler(name) {}
void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
Token &FirstToken) override;
};
/// PragmaOptimizeHandler - "\#pragma clang optimize on/off".
struct PragmaOptimizeHandler : public PragmaHandler {
PragmaOptimizeHandler(Sema &S)
: PragmaHandler("optimize"), Actions(S) {}
void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
Token &FirstToken) override;
private:
Sema &Actions;
};
struct PragmaLoopHintHandler : public PragmaHandler {
PragmaLoopHintHandler() : PragmaHandler("loop") {}
void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
Token &FirstToken) override;
};
struct PragmaUnrollHintHandler : public PragmaHandler {
PragmaUnrollHintHandler(const char *name) : PragmaHandler(name) {}
void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
Token &FirstToken) override;
};
} // end namespace
void Parser::initializePragmaHandlers() {
AlignHandler.reset(new PragmaAlignHandler());
PP.AddPragmaHandler(AlignHandler.get());
GCCVisibilityHandler.reset(new PragmaGCCVisibilityHandler());
PP.AddPragmaHandler("GCC", GCCVisibilityHandler.get());
OptionsHandler.reset(new PragmaOptionsHandler());
PP.AddPragmaHandler(OptionsHandler.get());
PackHandler.reset(new PragmaPackHandler());
PP.AddPragmaHandler(PackHandler.get());
MSStructHandler.reset(new PragmaMSStructHandler());
PP.AddPragmaHandler(MSStructHandler.get());
UnusedHandler.reset(new PragmaUnusedHandler());
PP.AddPragmaHandler(UnusedHandler.get());
WeakHandler.reset(new PragmaWeakHandler());
PP.AddPragmaHandler(WeakHandler.get());
RedefineExtnameHandler.reset(new PragmaRedefineExtnameHandler());
PP.AddPragmaHandler(RedefineExtnameHandler.get());
FPContractHandler.reset(new PragmaFPContractHandler());
PP.AddPragmaHandler("STDC", FPContractHandler.get());
if (getLangOpts().OpenCL) {
OpenCLExtensionHandler.reset(new PragmaOpenCLExtensionHandler());
PP.AddPragmaHandler("OPENCL", OpenCLExtensionHandler.get());
PP.AddPragmaHandler("OPENCL", FPContractHandler.get());
}
if (getLangOpts().OpenMP)
OpenMPHandler.reset(new PragmaOpenMPHandler());
else
OpenMPHandler.reset(new PragmaNoOpenMPHandler());
PP.AddPragmaHandler(OpenMPHandler.get());
if (getLangOpts().MicrosoftExt) {
MSCommentHandler.reset(new PragmaCommentHandler(Actions));
PP.AddPragmaHandler(MSCommentHandler.get());
MSDetectMismatchHandler.reset(new PragmaDetectMismatchHandler(Actions));
PP.AddPragmaHandler(MSDetectMismatchHandler.get());
MSPointersToMembers.reset(new PragmaMSPointersToMembers());
PP.AddPragmaHandler(MSPointersToMembers.get());
MSVtorDisp.reset(new PragmaMSVtorDisp());
PP.AddPragmaHandler(MSVtorDisp.get());
MSInitSeg.reset(new PragmaMSPragma("init_seg"));
PP.AddPragmaHandler(MSInitSeg.get());
MSDataSeg.reset(new PragmaMSPragma("data_seg"));
PP.AddPragmaHandler(MSDataSeg.get());
MSBSSSeg.reset(new PragmaMSPragma("bss_seg"));
PP.AddPragmaHandler(MSBSSSeg.get());
MSConstSeg.reset(new PragmaMSPragma("const_seg"));
PP.AddPragmaHandler(MSConstSeg.get());
MSCodeSeg.reset(new PragmaMSPragma("code_seg"));
PP.AddPragmaHandler(MSCodeSeg.get());
MSSection.reset(new PragmaMSPragma("section"));
PP.AddPragmaHandler(MSSection.get());
}
OptimizeHandler.reset(new PragmaOptimizeHandler(Actions));
PP.AddPragmaHandler("clang", OptimizeHandler.get());
LoopHintHandler.reset(new PragmaLoopHintHandler());
PP.AddPragmaHandler("clang", LoopHintHandler.get());
UnrollHintHandler.reset(new PragmaUnrollHintHandler("unroll"));
PP.AddPragmaHandler(UnrollHintHandler.get());
NoUnrollHintHandler.reset(new PragmaUnrollHintHandler("nounroll"));
PP.AddPragmaHandler(NoUnrollHintHandler.get());
}
void Parser::resetPragmaHandlers() {
// Remove the pragma handlers we installed.
PP.RemovePragmaHandler(AlignHandler.get());
AlignHandler.reset();
PP.RemovePragmaHandler("GCC", GCCVisibilityHandler.get());
GCCVisibilityHandler.reset();
PP.RemovePragmaHandler(OptionsHandler.get());
OptionsHandler.reset();
PP.RemovePragmaHandler(PackHandler.get());
PackHandler.reset();
PP.RemovePragmaHandler(MSStructHandler.get());
MSStructHandler.reset();
PP.RemovePragmaHandler(UnusedHandler.get());
UnusedHandler.reset();
PP.RemovePragmaHandler(WeakHandler.get());
WeakHandler.reset();
PP.RemovePragmaHandler(RedefineExtnameHandler.get());
RedefineExtnameHandler.reset();
if (getLangOpts().OpenCL) {
PP.RemovePragmaHandler("OPENCL", OpenCLExtensionHandler.get());
OpenCLExtensionHandler.reset();
PP.RemovePragmaHandler("OPENCL", FPContractHandler.get());
}
PP.RemovePragmaHandler(OpenMPHandler.get());
OpenMPHandler.reset();
if (getLangOpts().MicrosoftExt) {
PP.RemovePragmaHandler(MSCommentHandler.get());
MSCommentHandler.reset();
PP.RemovePragmaHandler(MSDetectMismatchHandler.get());
MSDetectMismatchHandler.reset();
PP.RemovePragmaHandler(MSPointersToMembers.get());
MSPointersToMembers.reset();
PP.RemovePragmaHandler(MSVtorDisp.get());
MSVtorDisp.reset();
PP.RemovePragmaHandler(MSInitSeg.get());
MSInitSeg.reset();
PP.RemovePragmaHandler(MSDataSeg.get());
MSDataSeg.reset();
PP.RemovePragmaHandler(MSBSSSeg.get());
MSBSSSeg.reset();
PP.RemovePragmaHandler(MSConstSeg.get());
MSConstSeg.reset();
PP.RemovePragmaHandler(MSCodeSeg.get());
MSCodeSeg.reset();
PP.RemovePragmaHandler(MSSection.get());
MSSection.reset();
}
PP.RemovePragmaHandler("STDC", FPContractHandler.get());
FPContractHandler.reset();
PP.RemovePragmaHandler("clang", OptimizeHandler.get());
OptimizeHandler.reset();
PP.RemovePragmaHandler("clang", LoopHintHandler.get());
LoopHintHandler.reset();
PP.RemovePragmaHandler(UnrollHintHandler.get());
UnrollHintHandler.reset();
PP.RemovePragmaHandler(NoUnrollHintHandler.get());
NoUnrollHintHandler.reset();
}
/// \brief Handle the annotation token produced for #pragma unused(...)
///
/// Each annot_pragma_unused is followed by the argument token so e.g.
/// "#pragma unused(x,y)" becomes:
/// annot_pragma_unused 'x' annot_pragma_unused 'y'
void Parser::HandlePragmaUnused() {
assert(Tok.is(tok::annot_pragma_unused));
SourceLocation UnusedLoc = ConsumeToken();
Actions.ActOnPragmaUnused(Tok, getCurScope(), UnusedLoc);
ConsumeToken(); // The argument token.
}
void Parser::HandlePragmaVisibility() {
assert(Tok.is(tok::annot_pragma_vis));
const IdentifierInfo *VisType =
static_cast<IdentifierInfo *>(Tok.getAnnotationValue());
SourceLocation VisLoc = ConsumeToken();
Actions.ActOnPragmaVisibility(VisType, VisLoc);
}
struct PragmaPackInfo {
Sema::PragmaPackKind Kind;
IdentifierInfo *Name;
Token Alignment;
SourceLocation LParenLoc;
SourceLocation RParenLoc;
};
void Parser::HandlePragmaPack() {
assert(Tok.is(tok::annot_pragma_pack));
PragmaPackInfo *Info =
static_cast<PragmaPackInfo *>(Tok.getAnnotationValue());
SourceLocation PragmaLoc = ConsumeToken();
ExprResult Alignment;
if (Info->Alignment.is(tok::numeric_constant)) {
Alignment = Actions.ActOnNumericConstant(Info->Alignment);
if (Alignment.isInvalid())
return;
}
Actions.ActOnPragmaPack(Info->Kind, Info->Name, Alignment.get(), PragmaLoc,
Info->LParenLoc, Info->RParenLoc);
}
void Parser::HandlePragmaMSStruct() {
assert(Tok.is(tok::annot_pragma_msstruct));
Sema::PragmaMSStructKind Kind =
static_cast<Sema::PragmaMSStructKind>(
reinterpret_cast<uintptr_t>(Tok.getAnnotationValue()));
Actions.ActOnPragmaMSStruct(Kind);
ConsumeToken(); // The annotation token.
}
void Parser::HandlePragmaAlign() {
assert(Tok.is(tok::annot_pragma_align));
Sema::PragmaOptionsAlignKind Kind =
static_cast<Sema::PragmaOptionsAlignKind>(
reinterpret_cast<uintptr_t>(Tok.getAnnotationValue()));
SourceLocation PragmaLoc = ConsumeToken();
Actions.ActOnPragmaOptionsAlign(Kind, PragmaLoc);
}
void Parser::HandlePragmaWeak() {
assert(Tok.is(tok::annot_pragma_weak));
SourceLocation PragmaLoc = ConsumeToken();
Actions.ActOnPragmaWeakID(Tok.getIdentifierInfo(), PragmaLoc,
Tok.getLocation());
ConsumeToken(); // The weak name.
}
void Parser::HandlePragmaWeakAlias() {
assert(Tok.is(tok::annot_pragma_weakalias));
SourceLocation PragmaLoc = ConsumeToken();
IdentifierInfo *WeakName = Tok.getIdentifierInfo();
SourceLocation WeakNameLoc = Tok.getLocation();
ConsumeToken();
IdentifierInfo *AliasName = Tok.getIdentifierInfo();
SourceLocation AliasNameLoc = Tok.getLocation();
ConsumeToken();
Actions.ActOnPragmaWeakAlias(WeakName, AliasName, PragmaLoc,
WeakNameLoc, AliasNameLoc);
}
void Parser::HandlePragmaRedefineExtname() {
assert(Tok.is(tok::annot_pragma_redefine_extname));
SourceLocation RedefLoc = ConsumeToken();
IdentifierInfo *RedefName = Tok.getIdentifierInfo();
SourceLocation RedefNameLoc = Tok.getLocation();
ConsumeToken();
IdentifierInfo *AliasName = Tok.getIdentifierInfo();
SourceLocation AliasNameLoc = Tok.getLocation();
ConsumeToken();
Actions.ActOnPragmaRedefineExtname(RedefName, AliasName, RedefLoc,
RedefNameLoc, AliasNameLoc);
}
void Parser::HandlePragmaFPContract() {
assert(Tok.is(tok::annot_pragma_fp_contract));
tok::OnOffSwitch OOS =
static_cast<tok::OnOffSwitch>(
reinterpret_cast<uintptr_t>(Tok.getAnnotationValue()));
Actions.ActOnPragmaFPContract(OOS);
ConsumeToken(); // The annotation token.
}
StmtResult Parser::HandlePragmaCaptured()
{
assert(Tok.is(tok::annot_pragma_captured));
ConsumeToken();
if (Tok.isNot(tok::l_brace)) {
PP.Diag(Tok, diag::err_expected) << tok::l_brace;
return StmtError();
}
SourceLocation Loc = Tok.getLocation();
ParseScope CapturedRegionScope(this, Scope::FnScope | Scope::DeclScope);
Actions.ActOnCapturedRegionStart(Loc, getCurScope(), CR_Default,
/*NumParams=*/1);
StmtResult R = ParseCompoundStatement();
CapturedRegionScope.Exit();
if (R.isInvalid()) {
Actions.ActOnCapturedRegionError();
return StmtError();
}
return Actions.ActOnCapturedRegionEnd(R.get());
}
namespace {
typedef llvm::PointerIntPair<IdentifierInfo *, 1, bool> OpenCLExtData;
}
void Parser::HandlePragmaOpenCLExtension() {
assert(Tok.is(tok::annot_pragma_opencl_extension));
OpenCLExtData data =
OpenCLExtData::getFromOpaqueValue(Tok.getAnnotationValue());
unsigned state = data.getInt();
IdentifierInfo *ename = data.getPointer();
SourceLocation NameLoc = Tok.getLocation();
ConsumeToken(); // The annotation token.
OpenCLOptions &f = Actions.getOpenCLOptions();
// OpenCL 1.1 9.1: "The all variant sets the behavior for all extensions,
// overriding all previously issued extension directives, but only if the
// behavior is set to disable."
if (state == 0 && ename->isStr("all")) {
#define OPENCLEXT(nm) f.nm = 0;
#include "clang/Basic/OpenCLExtensions.def"
}
#define OPENCLEXT(nm) else if (ename->isStr(#nm)) { f.nm = state; }
#include "clang/Basic/OpenCLExtensions.def"
else {
PP.Diag(NameLoc, diag::warn_pragma_unknown_extension) << ename;
return;
}
}
void Parser::HandlePragmaMSPointersToMembers() {
assert(Tok.is(tok::annot_pragma_ms_pointers_to_members));
LangOptions::PragmaMSPointersToMembersKind RepresentationMethod =
static_cast<LangOptions::PragmaMSPointersToMembersKind>(
reinterpret_cast<uintptr_t>(Tok.getAnnotationValue()));
SourceLocation PragmaLoc = ConsumeToken(); // The annotation token.
Actions.ActOnPragmaMSPointersToMembers(RepresentationMethod, PragmaLoc);
}
void Parser::HandlePragmaMSVtorDisp() {
assert(Tok.is(tok::annot_pragma_ms_vtordisp));
uintptr_t Value = reinterpret_cast<uintptr_t>(Tok.getAnnotationValue());
Sema::PragmaVtorDispKind Kind =
static_cast<Sema::PragmaVtorDispKind>((Value >> 16) & 0xFFFF);
MSVtorDispAttr::Mode Mode = MSVtorDispAttr::Mode(Value & 0xFFFF);
SourceLocation PragmaLoc = ConsumeToken(); // The annotation token.
Actions.ActOnPragmaMSVtorDisp(Kind, PragmaLoc, Mode);
}
void Parser::HandlePragmaMSPragma() {
assert(Tok.is(tok::annot_pragma_ms_pragma));
// Grab the tokens out of the annotation and enter them into the stream.
auto TheTokens = (std::pair<Token*, size_t> *)Tok.getAnnotationValue();
PP.EnterTokenStream(TheTokens->first, TheTokens->second, true, true);
SourceLocation PragmaLocation = ConsumeToken(); // The annotation token.
assert(Tok.isAnyIdentifier());
StringRef PragmaName = Tok.getIdentifierInfo()->getName();
PP.Lex(Tok); // pragma kind
// Figure out which #pragma we're dealing with. The switch has no default
// because lex shouldn't emit the annotation token for unrecognized pragmas.
typedef bool (Parser::*PragmaHandler)(StringRef, SourceLocation);
PragmaHandler Handler = llvm::StringSwitch<PragmaHandler>(PragmaName)
.Case("data_seg", &Parser::HandlePragmaMSSegment)
.Case("bss_seg", &Parser::HandlePragmaMSSegment)
.Case("const_seg", &Parser::HandlePragmaMSSegment)
.Case("code_seg", &Parser::HandlePragmaMSSegment)
.Case("section", &Parser::HandlePragmaMSSection)
.Case("init_seg", &Parser::HandlePragmaMSInitSeg);
if (!(this->*Handler)(PragmaName, PragmaLocation)) {
// Pragma handling failed, and has been diagnosed. Slurp up the tokens
// until eof (really end of line) to prevent follow-on errors.
while (Tok.isNot(tok::eof))
PP.Lex(Tok);
PP.Lex(Tok);
}
}
bool Parser::HandlePragmaMSSection(StringRef PragmaName,
SourceLocation PragmaLocation) {
if (Tok.isNot(tok::l_paren)) {
PP.Diag(PragmaLocation, diag::warn_pragma_expected_lparen) << PragmaName;
return false;
}
PP.Lex(Tok); // (
// Parsing code for pragma section
if (Tok.isNot(tok::string_literal)) {
PP.Diag(PragmaLocation, diag::warn_pragma_expected_section_name)
<< PragmaName;
return false;
}
ExprResult StringResult = ParseStringLiteralExpression();
if (StringResult.isInvalid())
return false; // Already diagnosed.
StringLiteral *SegmentName = cast<StringLiteral>(StringResult.get());
if (SegmentName->getCharByteWidth() != 1) {
PP.Diag(PragmaLocation, diag::warn_pragma_expected_non_wide_string)
<< PragmaName;
return false;
}
int SectionFlags = 0;
while (Tok.is(tok::comma)) {
PP.Lex(Tok); // ,
if (!Tok.isAnyIdentifier()) {
PP.Diag(PragmaLocation, diag::warn_pragma_expected_action_or_r_paren)
<< PragmaName;
return false;
}
Sema::PragmaSectionFlag Flag =
llvm::StringSwitch<Sema::PragmaSectionFlag>(
Tok.getIdentifierInfo()->getName())
.Case("read", Sema::PSF_Read)
.Case("write", Sema::PSF_Write)
.Case("execute", Sema::PSF_Execute)
.Case("shared", Sema::PSF_Invalid)
.Case("nopage", Sema::PSF_Invalid)
.Case("nocache", Sema::PSF_Invalid)
.Case("discard", Sema::PSF_Invalid)
.Case("remove", Sema::PSF_Invalid)
.Default(Sema::PSF_None);
if (Flag == Sema::PSF_None || Flag == Sema::PSF_Invalid) {
PP.Diag(PragmaLocation, Flag == Sema::PSF_None
? diag::warn_pragma_invalid_specific_action
: diag::warn_pragma_unsupported_action)
<< PragmaName << Tok.getIdentifierInfo()->getName();
return false;
}
SectionFlags |= Flag;
PP.Lex(Tok); // Identifier
}
if (Tok.isNot(tok::r_paren)) {
PP.Diag(PragmaLocation, diag::warn_pragma_expected_rparen) << PragmaName;
return false;
}
PP.Lex(Tok); // )
if (Tok.isNot(tok::eof)) {
PP.Diag(PragmaLocation, diag::warn_pragma_extra_tokens_at_eol)
<< PragmaName;
return false;
}
PP.Lex(Tok); // eof
Actions.ActOnPragmaMSSection(PragmaLocation, SectionFlags, SegmentName);
return true;
}
bool Parser::HandlePragmaMSSegment(StringRef PragmaName,
SourceLocation PragmaLocation) {
if (Tok.isNot(tok::l_paren)) {
PP.Diag(PragmaLocation, diag::warn_pragma_expected_lparen) << PragmaName;
return false;
}
PP.Lex(Tok); // (
Sema::PragmaMsStackAction Action = Sema::PSK_Reset;
StringRef SlotLabel;
if (Tok.isAnyIdentifier()) {
StringRef PushPop = Tok.getIdentifierInfo()->getName();
if (PushPop == "push")
Action = Sema::PSK_Push;
else if (PushPop == "pop")
Action = Sema::PSK_Pop;
else {
PP.Diag(PragmaLocation,
diag::warn_pragma_expected_section_push_pop_or_name)
<< PragmaName;
return false;
}
if (Action != Sema::PSK_Reset) {
PP.Lex(Tok); // push | pop
if (Tok.is(tok::comma)) {
PP.Lex(Tok); // ,
// If we've got a comma, we either need a label or a string.
if (Tok.isAnyIdentifier()) {
SlotLabel = Tok.getIdentifierInfo()->getName();
PP.Lex(Tok); // identifier
if (Tok.is(tok::comma))
PP.Lex(Tok);
else if (Tok.isNot(tok::r_paren)) {
PP.Diag(PragmaLocation, diag::warn_pragma_expected_punc)
<< PragmaName;
return false;
}
}
} else if (Tok.isNot(tok::r_paren)) {
PP.Diag(PragmaLocation, diag::warn_pragma_expected_punc) << PragmaName;
return false;
}
}
}
// Grab the string literal for our section name.
StringLiteral *SegmentName = nullptr;
if (Tok.isNot(tok::r_paren)) {
if (Tok.isNot(tok::string_literal)) {
unsigned DiagID = Action != Sema::PSK_Reset ? !SlotLabel.empty() ?
diag::warn_pragma_expected_section_name :
diag::warn_pragma_expected_section_label_or_name :
diag::warn_pragma_expected_section_push_pop_or_name;
PP.Diag(PragmaLocation, DiagID) << PragmaName;
return false;
}
ExprResult StringResult = ParseStringLiteralExpression();
if (StringResult.isInvalid())
return false; // Already diagnosed.
SegmentName = cast<StringLiteral>(StringResult.get());
if (SegmentName->getCharByteWidth() != 1) {
PP.Diag(PragmaLocation, diag::warn_pragma_expected_non_wide_string)
<< PragmaName;
return false;
}
// Setting section "" has no effect
if (SegmentName->getLength())
Action = (Sema::PragmaMsStackAction)(Action | Sema::PSK_Set);
}
if (Tok.isNot(tok::r_paren)) {
PP.Diag(PragmaLocation, diag::warn_pragma_expected_rparen) << PragmaName;
return false;
}
PP.Lex(Tok); // )
if (Tok.isNot(tok::eof)) {
PP.Diag(PragmaLocation, diag::warn_pragma_extra_tokens_at_eol)
<< PragmaName;
return false;
}
PP.Lex(Tok); // eof
Actions.ActOnPragmaMSSeg(PragmaLocation, Action, SlotLabel,
SegmentName, PragmaName);
return true;
}
// #pragma init_seg({ compiler | lib | user | "section-name" [, func-name]} )
bool Parser::HandlePragmaMSInitSeg(StringRef PragmaName,
SourceLocation PragmaLocation) {
if (ExpectAndConsume(tok::l_paren, diag::warn_pragma_expected_lparen,
PragmaName))
return false;
// Parse either the known section names or the string section name.
StringLiteral *SegmentName = nullptr;
if (Tok.isAnyIdentifier()) {
auto *II = Tok.getIdentifierInfo();
StringRef Section = llvm::StringSwitch<StringRef>(II->getName())
.Case("compiler", "\".CRT$XCC\"")
.Case("lib", "\".CRT$XCL\"")
.Case("user", "\".CRT$XCU\"")
.Default("");
if (!Section.empty()) {
// Pretend the user wrote the appropriate string literal here.
Token Toks[1];
Toks[0].startToken();
Toks[0].setKind(tok::string_literal);
Toks[0].setLocation(Tok.getLocation());
Toks[0].setLiteralData(Section.data());
Toks[0].setLength(Section.size());
SegmentName =
cast<StringLiteral>(Actions.ActOnStringLiteral(Toks, nullptr).get());
PP.Lex(Tok);
}
} else if (Tok.is(tok::string_literal)) {
ExprResult StringResult = ParseStringLiteralExpression();
if (StringResult.isInvalid())
return false;
SegmentName = cast<StringLiteral>(StringResult.get());
if (SegmentName->getCharByteWidth() != 1) {
PP.Diag(PragmaLocation, diag::warn_pragma_expected_non_wide_string)
<< PragmaName;
return false;
}
// FIXME: Add support for the '[, func-name]' part of the pragma.
}
if (!SegmentName) {
PP.Diag(PragmaLocation, diag::warn_pragma_expected_init_seg) << PragmaName;
return false;
}
if (ExpectAndConsume(tok::r_paren, diag::warn_pragma_expected_rparen,
PragmaName) ||
ExpectAndConsume(tok::eof, diag::warn_pragma_extra_tokens_at_eol,
PragmaName))
return false;
Actions.ActOnPragmaMSInitSeg(PragmaLocation, SegmentName);
return true;
}
struct PragmaLoopHintInfo {
Token PragmaName;
Token Option;
Token Value;
bool HasValue;
};
bool Parser::HandlePragmaLoopHint(LoopHint &Hint) {
assert(Tok.is(tok::annot_pragma_loop_hint));
PragmaLoopHintInfo *Info =
static_cast<PragmaLoopHintInfo *>(Tok.getAnnotationValue());
ConsumeToken(); // The annotation token.
IdentifierInfo *PragmaNameInfo = Info->PragmaName.getIdentifierInfo();
Hint.PragmaNameLoc = IdentifierLoc::create(
Actions.Context, Info->PragmaName.getLocation(), PragmaNameInfo);
IdentifierInfo *OptionInfo = Info->Option.getIdentifierInfo();
Hint.OptionLoc = IdentifierLoc::create(
Actions.Context, Info->Option.getLocation(), OptionInfo);
// Return a valid hint if pragma unroll or nounroll were specified
// without an argument.
bool PragmaUnroll = PragmaNameInfo->getName() == "unroll";
bool PragmaNoUnroll = PragmaNameInfo->getName() == "nounroll";
if (!Info->HasValue && (PragmaUnroll || PragmaNoUnroll)) {
Hint.Range = Info->PragmaName.getLocation();
return true;
}
// If no option is specified the argument is assumed to be numeric.
bool StateOption = false;
if (OptionInfo)
StateOption = llvm::StringSwitch<bool>(OptionInfo->getName())
.Case("vectorize", true)
.Case("interleave", true)
.Case("unroll", true)
.Default(false);
// Validate the argument.
if (StateOption) {
bool OptionUnroll = OptionInfo->isStr("unroll");
SourceLocation StateLoc = Info->Value.getLocation();
IdentifierInfo *StateInfo = Info->Value.getIdentifierInfo();
if (!StateInfo || ((OptionUnroll ? !StateInfo->isStr("full")
: !StateInfo->isStr("enable")) &&
!StateInfo->isStr("disable"))) {
Diag(StateLoc, diag::err_pragma_invalid_keyword)
<< /*MissingArgument=*/false << /*FullKeyword=*/OptionUnroll;
return false;
}
Hint.StateLoc = IdentifierLoc::create(Actions.Context, StateLoc, StateInfo);
} else {
// FIXME: We should allow non-type template parameters for the loop hint
// value. See bug report #19610
if (Info->Value.is(tok::numeric_constant))
Hint.ValueExpr = Actions.ActOnNumericConstant(Info->Value).get();
else {
Diag(Info->Value.getLocation(), diag::err_pragma_loop_numeric_value);
return false;
}
}
Hint.Range =
SourceRange(Info->PragmaName.getLocation(), Info->Value.getLocation());
return true;
}
// #pragma GCC visibility comes in two variants:
// 'push' '(' [visibility] ')'
// 'pop'
void PragmaGCCVisibilityHandler::HandlePragma(Preprocessor &PP,
PragmaIntroducerKind Introducer,
Token &VisTok) {
SourceLocation VisLoc = VisTok.getLocation();
Token Tok;
PP.LexUnexpandedToken(Tok);
const IdentifierInfo *PushPop = Tok.getIdentifierInfo();
const IdentifierInfo *VisType;
if (PushPop && PushPop->isStr("pop")) {
VisType = nullptr;
} else if (PushPop && PushPop->isStr("push")) {
PP.LexUnexpandedToken(Tok);
if (Tok.isNot(tok::l_paren)) {
PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_lparen)
<< "visibility";
return;
}
PP.LexUnexpandedToken(Tok);
VisType = Tok.getIdentifierInfo();
if (!VisType) {
PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier)
<< "visibility";
return;
}
PP.LexUnexpandedToken(Tok);
if (Tok.isNot(tok::r_paren)) {
PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_rparen)
<< "visibility";
return;
}
} else {
PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier)
<< "visibility";
return;
}
PP.LexUnexpandedToken(Tok);
if (Tok.isNot(tok::eod)) {
PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)
<< "visibility";
return;
}
Token *Toks = new Token[1];
Toks[0].startToken();
Toks[0].setKind(tok::annot_pragma_vis);
Toks[0].setLocation(VisLoc);
Toks[0].setAnnotationValue(
const_cast<void*>(static_cast<const void*>(VisType)));
PP.EnterTokenStream(Toks, 1, /*DisableMacroExpansion=*/true,
/*OwnsTokens=*/true);
}
// #pragma pack(...) comes in the following delicious flavors:
// pack '(' [integer] ')'
// pack '(' 'show' ')'
// pack '(' ('push' | 'pop') [',' identifier] [, integer] ')'
void PragmaPackHandler::HandlePragma(Preprocessor &PP,
PragmaIntroducerKind Introducer,
Token &PackTok) {
SourceLocation PackLoc = PackTok.getLocation();
Token Tok;
PP.Lex(Tok);
if (Tok.isNot(tok::l_paren)) {
PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_lparen) << "pack";
return;
}
Sema::PragmaPackKind Kind = Sema::PPK_Default;
IdentifierInfo *Name = nullptr;
Token Alignment;
Alignment.startToken();
SourceLocation LParenLoc = Tok.getLocation();
PP.Lex(Tok);
if (Tok.is(tok::numeric_constant)) {
Alignment = Tok;
PP.Lex(Tok);
// In MSVC/gcc, #pragma pack(4) sets the alignment without affecting
// the push/pop stack.
// In Apple gcc, #pragma pack(4) is equivalent to #pragma pack(push, 4)
if (PP.getLangOpts().ApplePragmaPack)
Kind = Sema::PPK_Push;
} else if (Tok.is(tok::identifier)) {
const IdentifierInfo *II = Tok.getIdentifierInfo();
if (II->isStr("show")) {
Kind = Sema::PPK_Show;
PP.Lex(Tok);
} else {
if (II->isStr("push")) {
Kind = Sema::PPK_Push;
} else if (II->isStr("pop")) {
Kind = Sema::PPK_Pop;
} else {
PP.Diag(Tok.getLocation(), diag::warn_pragma_invalid_action) << "pack";
return;
}
PP.Lex(Tok);
if (Tok.is(tok::comma)) {
PP.Lex(Tok);
if (Tok.is(tok::numeric_constant)) {
Alignment = Tok;
PP.Lex(Tok);
} else if (Tok.is(tok::identifier)) {
Name = Tok.getIdentifierInfo();
PP.Lex(Tok);
if (Tok.is(tok::comma)) {
PP.Lex(Tok);
if (Tok.isNot(tok::numeric_constant)) {
PP.Diag(Tok.getLocation(), diag::warn_pragma_pack_malformed);
return;
}
Alignment = Tok;
PP.Lex(Tok);
}
} else {
PP.Diag(Tok.getLocation(), diag::warn_pragma_pack_malformed);
return;
}
}
}
} else if (PP.getLangOpts().ApplePragmaPack) {
// In MSVC/gcc, #pragma pack() resets the alignment without affecting
// the push/pop stack.
// In Apple gcc #pragma pack() is equivalent to #pragma pack(pop).
Kind = Sema::PPK_Pop;
}
if (Tok.isNot(tok::r_paren)) {
PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_rparen) << "pack";
return;
}
SourceLocation RParenLoc = Tok.getLocation();
PP.Lex(Tok);
if (Tok.isNot(tok::eod)) {
PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) << "pack";
return;
}
PragmaPackInfo *Info =
(PragmaPackInfo*) PP.getPreprocessorAllocator().Allocate(
sizeof(PragmaPackInfo), llvm::alignOf<PragmaPackInfo>());
new (Info) PragmaPackInfo();
Info->Kind = Kind;
Info->Name = Name;
Info->Alignment = Alignment;
Info->LParenLoc = LParenLoc;
Info->RParenLoc = RParenLoc;
Token *Toks =
(Token*) PP.getPreprocessorAllocator().Allocate(
sizeof(Token) * 1, llvm::alignOf<Token>());
new (Toks) Token();
Toks[0].startToken();
Toks[0].setKind(tok::annot_pragma_pack);
Toks[0].setLocation(PackLoc);
Toks[0].setAnnotationValue(static_cast<void*>(Info));
PP.EnterTokenStream(Toks, 1, /*DisableMacroExpansion=*/true,
/*OwnsTokens=*/false);
}
// #pragma ms_struct on
// #pragma ms_struct off
void PragmaMSStructHandler::HandlePragma(Preprocessor &PP,
PragmaIntroducerKind Introducer,
Token &MSStructTok) {
Sema::PragmaMSStructKind Kind = Sema::PMSST_OFF;
Token Tok;
PP.Lex(Tok);
if (Tok.isNot(tok::identifier)) {
PP.Diag(Tok.getLocation(), diag::warn_pragma_ms_struct);
return;
}
const IdentifierInfo *II = Tok.getIdentifierInfo();
if (II->isStr("on")) {
Kind = Sema::PMSST_ON;
PP.Lex(Tok);
}
else if (II->isStr("off") || II->isStr("reset"))
PP.Lex(Tok);
else {
PP.Diag(Tok.getLocation(), diag::warn_pragma_ms_struct);
return;
}
if (Tok.isNot(tok::eod)) {
PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)
<< "ms_struct";
return;
}
Token *Toks =
(Token*) PP.getPreprocessorAllocator().Allocate(
sizeof(Token) * 1, llvm::alignOf<Token>());
new (Toks) Token();
Toks[0].startToken();
Toks[0].setKind(tok::annot_pragma_msstruct);
Toks[0].setLocation(MSStructTok.getLocation());
Toks[0].setAnnotationValue(reinterpret_cast<void*>(
static_cast<uintptr_t>(Kind)));
PP.EnterTokenStream(Toks, 1, /*DisableMacroExpansion=*/true,
/*OwnsTokens=*/false);
}
// #pragma 'align' '=' {'native','natural','mac68k','power','reset'}
// #pragma 'options 'align' '=' {'native','natural','mac68k','power','reset'}
static void ParseAlignPragma(Preprocessor &PP, Token &FirstTok,
bool IsOptions) {
Token Tok;
if (IsOptions) {
PP.Lex(Tok);
if (Tok.isNot(tok::identifier) ||
!Tok.getIdentifierInfo()->isStr("align")) {
PP.Diag(Tok.getLocation(), diag::warn_pragma_options_expected_align);
return;
}
}
PP.Lex(Tok);
if (Tok.isNot(tok::equal)) {
PP.Diag(Tok.getLocation(), diag::warn_pragma_align_expected_equal)
<< IsOptions;
return;
}
PP.Lex(Tok);
if (Tok.isNot(tok::identifier)) {
PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier)
<< (IsOptions ? "options" : "align");
return;
}
Sema::PragmaOptionsAlignKind Kind = Sema::POAK_Natural;
const IdentifierInfo *II = Tok.getIdentifierInfo();
if (II->isStr("native"))
Kind = Sema::POAK_Native;
else if (II->isStr("natural"))
Kind = Sema::POAK_Natural;
else if (II->isStr("packed"))
Kind = Sema::POAK_Packed;
else if (II->isStr("power"))
Kind = Sema::POAK_Power;
else if (II->isStr("mac68k"))
Kind = Sema::POAK_Mac68k;
else if (II->isStr("reset"))
Kind = Sema::POAK_Reset;
else {
PP.Diag(Tok.getLocation(), diag::warn_pragma_align_invalid_option)
<< IsOptions;
return;
}
PP.Lex(Tok);
if (Tok.isNot(tok::eod)) {
PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)
<< (IsOptions ? "options" : "align");
return;
}
Token *Toks =
(Token*) PP.getPreprocessorAllocator().Allocate(
sizeof(Token) * 1, llvm::alignOf<Token>());
new (Toks) Token();
Toks[0].startToken();
Toks[0].setKind(tok::annot_pragma_align);
Toks[0].setLocation(FirstTok.getLocation());
Toks[0].setAnnotationValue(reinterpret_cast<void*>(
static_cast<uintptr_t>(Kind)));
PP.EnterTokenStream(Toks, 1, /*DisableMacroExpansion=*/true,
/*OwnsTokens=*/false);
}
void PragmaAlignHandler::HandlePragma(Preprocessor &PP,
PragmaIntroducerKind Introducer,
Token &AlignTok) {
ParseAlignPragma(PP, AlignTok, /*IsOptions=*/false);
}
void PragmaOptionsHandler::HandlePragma(Preprocessor &PP,
PragmaIntroducerKind Introducer,
Token &OptionsTok) {
ParseAlignPragma(PP, OptionsTok, /*IsOptions=*/true);
}
// #pragma unused(identifier)
void PragmaUnusedHandler::HandlePragma(Preprocessor &PP,
PragmaIntroducerKind Introducer,
Token &UnusedTok) {
// FIXME: Should we be expanding macros here? My guess is no.
SourceLocation UnusedLoc = UnusedTok.getLocation();
// Lex the left '('.
Token Tok;
PP.Lex(Tok);
if (Tok.isNot(tok::l_paren)) {
PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_lparen) << "unused";
return;
}
// Lex the declaration reference(s).
SmallVector<Token, 5> Identifiers;
SourceLocation RParenLoc;
bool LexID = true;
while (true) {
PP.Lex(Tok);
if (LexID) {
if (Tok.is(tok::identifier)) {
Identifiers.push_back(Tok);
LexID = false;
continue;
}
// Illegal token!
PP.Diag(Tok.getLocation(), diag::warn_pragma_unused_expected_var);
return;
}
// We are execting a ')' or a ','.
if (Tok.is(tok::comma)) {
LexID = true;
continue;
}
if (Tok.is(tok::r_paren)) {
RParenLoc = Tok.getLocation();
break;
}
// Illegal token!
PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_punc) << "unused";
return;
}
PP.Lex(Tok);
if (Tok.isNot(tok::eod)) {
PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) <<
"unused";
return;
}
// Verify that we have a location for the right parenthesis.
assert(RParenLoc.isValid() && "Valid '#pragma unused' must have ')'");
assert(!Identifiers.empty() && "Valid '#pragma unused' must have arguments");
// For each identifier token, insert into the token stream a
// annot_pragma_unused token followed by the identifier token.
// This allows us to cache a "#pragma unused" that occurs inside an inline
// C++ member function.
Token *Toks =
(Token*) PP.getPreprocessorAllocator().Allocate(
sizeof(Token) * 2 * Identifiers.size(), llvm::alignOf<Token>());
for (unsigned i=0; i != Identifiers.size(); i++) {
Token &pragmaUnusedTok = Toks[2*i], &idTok = Toks[2*i+1];
pragmaUnusedTok.startToken();
pragmaUnusedTok.setKind(tok::annot_pragma_unused);
pragmaUnusedTok.setLocation(UnusedLoc);
idTok = Identifiers[i];
}
PP.EnterTokenStream(Toks, 2*Identifiers.size(),
/*DisableMacroExpansion=*/true, /*OwnsTokens=*/false);
}
// #pragma weak identifier
// #pragma weak identifier '=' identifier
void PragmaWeakHandler::HandlePragma(Preprocessor &PP,
PragmaIntroducerKind Introducer,
Token &WeakTok) {
SourceLocation WeakLoc = WeakTok.getLocation();
Token Tok;
PP.Lex(Tok);
if (Tok.isNot(tok::identifier)) {
PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier) << "weak";
return;
}
Token WeakName = Tok;
bool HasAlias = false;
Token AliasName;
PP.Lex(Tok);
if (Tok.is(tok::equal)) {
HasAlias = true;
PP.Lex(Tok);
if (Tok.isNot(tok::identifier)) {
PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier)
<< "weak";
return;
}
AliasName = Tok;
PP.Lex(Tok);
}
if (Tok.isNot(tok::eod)) {
PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) << "weak";
return;
}
if (HasAlias) {
Token *Toks =
(Token*) PP.getPreprocessorAllocator().Allocate(
sizeof(Token) * 3, llvm::alignOf<Token>());
Token &pragmaUnusedTok = Toks[0];
pragmaUnusedTok.startToken();
pragmaUnusedTok.setKind(tok::annot_pragma_weakalias);
pragmaUnusedTok.setLocation(WeakLoc);
Toks[1] = WeakName;
Toks[2] = AliasName;
PP.EnterTokenStream(Toks, 3,
/*DisableMacroExpansion=*/true, /*OwnsTokens=*/false);
} else {
Token *Toks =
(Token*) PP.getPreprocessorAllocator().Allocate(
sizeof(Token) * 2, llvm::alignOf<Token>());
Token &pragmaUnusedTok = Toks[0];
pragmaUnusedTok.startToken();
pragmaUnusedTok.setKind(tok::annot_pragma_weak);
pragmaUnusedTok.setLocation(WeakLoc);
Toks[1] = WeakName;
PP.EnterTokenStream(Toks, 2,
/*DisableMacroExpansion=*/true, /*OwnsTokens=*/false);
}
}
// #pragma redefine_extname identifier identifier
void PragmaRedefineExtnameHandler::HandlePragma(Preprocessor &PP,
PragmaIntroducerKind Introducer,
Token &RedefToken) {
SourceLocation RedefLoc = RedefToken.getLocation();
Token Tok;
PP.Lex(Tok);
if (Tok.isNot(tok::identifier)) {
PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier) <<
"redefine_extname";
return;
}
Token RedefName = Tok;
PP.Lex(Tok);
if (Tok.isNot(tok::identifier)) {
PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier)
<< "redefine_extname";
return;
}
Token AliasName = Tok;
PP.Lex(Tok);
if (Tok.isNot(tok::eod)) {
PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) <<
"redefine_extname";
return;
}
Token *Toks =
(Token*) PP.getPreprocessorAllocator().Allocate(
sizeof(Token) * 3, llvm::alignOf<Token>());
Token &pragmaRedefTok = Toks[0];
pragmaRedefTok.startToken();
pragmaRedefTok.setKind(tok::annot_pragma_redefine_extname);
pragmaRedefTok.setLocation(RedefLoc);
Toks[1] = RedefName;
Toks[2] = AliasName;
PP.EnterTokenStream(Toks, 3,
/*DisableMacroExpansion=*/true, /*OwnsTokens=*/false);
}
void
PragmaFPContractHandler::HandlePragma(Preprocessor &PP,
PragmaIntroducerKind Introducer,
Token &Tok) {
tok::OnOffSwitch OOS;
if (PP.LexOnOffSwitch(OOS))
return;
Token *Toks =
(Token*) PP.getPreprocessorAllocator().Allocate(
sizeof(Token) * 1, llvm::alignOf<Token>());
new (Toks) Token();
Toks[0].startToken();
Toks[0].setKind(tok::annot_pragma_fp_contract);
Toks[0].setLocation(Tok.getLocation());
Toks[0].setAnnotationValue(reinterpret_cast<void*>(
static_cast<uintptr_t>(OOS)));
PP.EnterTokenStream(Toks, 1, /*DisableMacroExpansion=*/true,
/*OwnsTokens=*/false);
}
void
PragmaOpenCLExtensionHandler::HandlePragma(Preprocessor &PP,
PragmaIntroducerKind Introducer,
Token &Tok) {
PP.LexUnexpandedToken(Tok);
if (Tok.isNot(tok::identifier)) {
PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier) <<
"OPENCL";
return;
}
IdentifierInfo *ename = Tok.getIdentifierInfo();
SourceLocation NameLoc = Tok.getLocation();
PP.Lex(Tok);
if (Tok.isNot(tok::colon)) {
PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_colon) << ename;
return;
}
PP.Lex(Tok);
if (Tok.isNot(tok::identifier)) {
PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_enable_disable);
return;
}
IdentifierInfo *op = Tok.getIdentifierInfo();
unsigned state;
if (op->isStr("enable")) {
state = 1;
} else if (op->isStr("disable")) {
state = 0;
} else {
PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_enable_disable);
return;
}
SourceLocation StateLoc = Tok.getLocation();
PP.Lex(Tok);
if (Tok.isNot(tok::eod)) {
PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) <<
"OPENCL EXTENSION";
return;
}
OpenCLExtData data(ename, state);
Token *Toks =
(Token*) PP.getPreprocessorAllocator().Allocate(
sizeof(Token) * 1, llvm::alignOf<Token>());
new (Toks) Token();
Toks[0].startToken();
Toks[0].setKind(tok::annot_pragma_opencl_extension);
Toks[0].setLocation(NameLoc);
Toks[0].setAnnotationValue(data.getOpaqueValue());
PP.EnterTokenStream(Toks, 1, /*DisableMacroExpansion=*/true,
/*OwnsTokens=*/false);
if (PP.getPPCallbacks())
PP.getPPCallbacks()->PragmaOpenCLExtension(NameLoc, ename,
StateLoc, state);
}
/// \brief Handle '#pragma omp ...' when OpenMP is disabled.
///
void
PragmaNoOpenMPHandler::HandlePragma(Preprocessor &PP,
PragmaIntroducerKind Introducer,
Token &FirstTok) {
if (!PP.getDiagnostics().isIgnored(diag::warn_pragma_omp_ignored,
FirstTok.getLocation())) {
PP.Diag(FirstTok, diag::warn_pragma_omp_ignored);
PP.getDiagnostics().setSeverity(diag::warn_pragma_omp_ignored,
diag::Severity::Ignored, SourceLocation());
}
PP.DiscardUntilEndOfDirective();
}
/// \brief Handle '#pragma omp ...' when OpenMP is enabled.
///
void
PragmaOpenMPHandler::HandlePragma(Preprocessor &PP,
PragmaIntroducerKind Introducer,
Token &FirstTok) {
SmallVector<Token, 16> Pragma;
Token Tok;
Tok.startToken();
Tok.setKind(tok::annot_pragma_openmp);
Tok.setLocation(FirstTok.getLocation());
while (Tok.isNot(tok::eod)) {
Pragma.push_back(Tok);
PP.Lex(Tok);
}
SourceLocation EodLoc = Tok.getLocation();
Tok.startToken();
Tok.setKind(tok::annot_pragma_openmp_end);
Tok.setLocation(EodLoc);
Pragma.push_back(Tok);
Token *Toks = new Token[Pragma.size()];
std::copy(Pragma.begin(), Pragma.end(), Toks);
PP.EnterTokenStream(Toks, Pragma.size(),
/*DisableMacroExpansion=*/true, /*OwnsTokens=*/true);
}
/// \brief Handle '#pragma pointers_to_members'
// The grammar for this pragma is as follows:
//
// <inheritance model> ::= ('single' | 'multiple' | 'virtual') '_inheritance'
//
// #pragma pointers_to_members '(' 'best_case' ')'
// #pragma pointers_to_members '(' 'full_generality' [',' inheritance-model] ')'
// #pragma pointers_to_members '(' inheritance-model ')'
void PragmaMSPointersToMembers::HandlePragma(Preprocessor &PP,
PragmaIntroducerKind Introducer,
Token &Tok) {
SourceLocation PointersToMembersLoc = Tok.getLocation();
PP.Lex(Tok);
if (Tok.isNot(tok::l_paren)) {
PP.Diag(PointersToMembersLoc, diag::warn_pragma_expected_lparen)
<< "pointers_to_members";
return;
}
PP.Lex(Tok);
const IdentifierInfo *Arg = Tok.getIdentifierInfo();
if (!Arg) {
PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier)
<< "pointers_to_members";
return;
}
PP.Lex(Tok);
LangOptions::PragmaMSPointersToMembersKind RepresentationMethod;
if (Arg->isStr("best_case")) {
RepresentationMethod = LangOptions::PPTMK_BestCase;
} else {
if (Arg->isStr("full_generality")) {
if (Tok.is(tok::comma)) {
PP.Lex(Tok);
Arg = Tok.getIdentifierInfo();
if (!Arg) {
PP.Diag(Tok.getLocation(),
diag::err_pragma_pointers_to_members_unknown_kind)
<< Tok.getKind() << /*OnlyInheritanceModels*/ 0;
return;
}
PP.Lex(Tok);
} else if (Tok.is(tok::r_paren)) {
// #pragma pointers_to_members(full_generality) implicitly specifies
// virtual_inheritance.
Arg = nullptr;
RepresentationMethod = LangOptions::PPTMK_FullGeneralityVirtualInheritance;
} else {
PP.Diag(Tok.getLocation(), diag::err_expected_punc)
<< "full_generality";
return;
}
}
if (Arg) {
if (Arg->isStr("single_inheritance")) {
RepresentationMethod =
LangOptions::PPTMK_FullGeneralitySingleInheritance;
} else if (Arg->isStr("multiple_inheritance")) {
RepresentationMethod =
LangOptions::PPTMK_FullGeneralityMultipleInheritance;
} else if (Arg->isStr("virtual_inheritance")) {
RepresentationMethod =
LangOptions::PPTMK_FullGeneralityVirtualInheritance;
} else {
PP.Diag(Tok.getLocation(),
diag::err_pragma_pointers_to_members_unknown_kind)
<< Arg << /*HasPointerDeclaration*/ 1;
return;
}
}
}
if (Tok.isNot(tok::r_paren)) {
PP.Diag(Tok.getLocation(), diag::err_expected_rparen_after)
<< (Arg ? Arg->getName() : "full_generality");
return;
}
PP.Lex(Tok);
if (Tok.isNot(tok::eod)) {
PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)
<< "pointers_to_members";
return;
}
Token AnnotTok;
AnnotTok.startToken();
AnnotTok.setKind(tok::annot_pragma_ms_pointers_to_members);
AnnotTok.setLocation(PointersToMembersLoc);
AnnotTok.setAnnotationValue(
reinterpret_cast<void *>(static_cast<uintptr_t>(RepresentationMethod)));
PP.EnterToken(AnnotTok);
}
/// \brief Handle '#pragma vtordisp'
// The grammar for this pragma is as follows:
//
// <vtordisp-mode> ::= ('off' | 'on' | '0' | '1' | '2' )
//
// #pragma vtordisp '(' ['push' ','] vtordisp-mode ')'
// #pragma vtordisp '(' 'pop' ')'
// #pragma vtordisp '(' ')'
void PragmaMSVtorDisp::HandlePragma(Preprocessor &PP,
PragmaIntroducerKind Introducer,
Token &Tok) {
SourceLocation VtorDispLoc = Tok.getLocation();
PP.Lex(Tok);
if (Tok.isNot(tok::l_paren)) {
PP.Diag(VtorDispLoc, diag::warn_pragma_expected_lparen) << "vtordisp";
return;
}
PP.Lex(Tok);
Sema::PragmaVtorDispKind Kind = Sema::PVDK_Set;
const IdentifierInfo *II = Tok.getIdentifierInfo();
if (II) {
if (II->isStr("push")) {
// #pragma vtordisp(push, mode)
PP.Lex(Tok);
if (Tok.isNot(tok::comma)) {
PP.Diag(VtorDispLoc, diag::warn_pragma_expected_punc) << "vtordisp";
return;
}
PP.Lex(Tok);
Kind = Sema::PVDK_Push;
// not push, could be on/off
} else if (II->isStr("pop")) {
// #pragma vtordisp(pop)
PP.Lex(Tok);
Kind = Sema::PVDK_Pop;
}
// not push or pop, could be on/off
} else {
if (Tok.is(tok::r_paren)) {
// #pragma vtordisp()
Kind = Sema::PVDK_Reset;
}
}
uint64_t Value = 0;
if (Kind == Sema::PVDK_Push || Kind == Sema::PVDK_Set) {
const IdentifierInfo *II = Tok.getIdentifierInfo();
if (II && II->isStr("off")) {
PP.Lex(Tok);
Value = 0;
} else if (II && II->isStr("on")) {
PP.Lex(Tok);
Value = 1;
} else if (Tok.is(tok::numeric_constant) &&
PP.parseSimpleIntegerLiteral(Tok, Value)) {
if (Value > 2) {
PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_integer)
<< 0 << 2 << "vtordisp";
return;
}
} else {
PP.Diag(Tok.getLocation(), diag::warn_pragma_invalid_action)
<< "vtordisp";
return;
}
}
// Finish the pragma: ')' $
if (Tok.isNot(tok::r_paren)) {
PP.Diag(VtorDispLoc, diag::warn_pragma_expected_rparen) << "vtordisp";
return;
}
PP.Lex(Tok);
if (Tok.isNot(tok::eod)) {
PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)
<< "vtordisp";
return;
}
// Enter the annotation.
Token AnnotTok;
AnnotTok.startToken();
AnnotTok.setKind(tok::annot_pragma_ms_vtordisp);
AnnotTok.setLocation(VtorDispLoc);
AnnotTok.setAnnotationValue(reinterpret_cast<void *>(
static_cast<uintptr_t>((Kind << 16) | (Value & 0xFFFF))));
PP.EnterToken(AnnotTok);
}
/// \brief Handle all MS pragmas. Simply forwards the tokens after inserting
/// an annotation token.
void PragmaMSPragma::HandlePragma(Preprocessor &PP,
PragmaIntroducerKind Introducer,
Token &Tok) {
Token EoF, AnnotTok;
EoF.startToken();
EoF.setKind(tok::eof);
AnnotTok.startToken();
AnnotTok.setKind(tok::annot_pragma_ms_pragma);
AnnotTok.setLocation(Tok.getLocation());
SmallVector<Token, 8> TokenVector;
// Suck up all of the tokens before the eod.
for (; Tok.isNot(tok::eod); PP.Lex(Tok))
TokenVector.push_back(Tok);
// Add a sentinal EoF token to the end of the list.
TokenVector.push_back(EoF);
// We must allocate this array with new because EnterTokenStream is going to
// delete it later.
Token *TokenArray = new Token[TokenVector.size()];
std::copy(TokenVector.begin(), TokenVector.end(), TokenArray);
auto Value = new (PP.getPreprocessorAllocator())
std::pair<Token*, size_t>(std::make_pair(TokenArray, TokenVector.size()));
AnnotTok.setAnnotationValue(Value);
PP.EnterToken(AnnotTok);
}
/// \brief Handle the Microsoft \#pragma detect_mismatch extension.
///
/// The syntax is:
/// \code
/// #pragma detect_mismatch("name", "value")
/// \endcode
/// Where 'name' and 'value' are quoted strings. The values are embedded in
/// the object file and passed along to the linker. If the linker detects a
/// mismatch in the object file's values for the given name, a LNK2038 error
/// is emitted. See MSDN for more details.
void PragmaDetectMismatchHandler::HandlePragma(Preprocessor &PP,
PragmaIntroducerKind Introducer,
Token &Tok) {
SourceLocation CommentLoc = Tok.getLocation();
PP.Lex(Tok);
if (Tok.isNot(tok::l_paren)) {
PP.Diag(CommentLoc, diag::err_expected) << tok::l_paren;
return;
}
// Read the name to embed, which must be a string literal.
std::string NameString;
if (!PP.LexStringLiteral(Tok, NameString,
"pragma detect_mismatch",
/*MacroExpansion=*/true))
return;
// Read the comma followed by a second string literal.
std::string ValueString;
if (Tok.isNot(tok::comma)) {
PP.Diag(Tok.getLocation(), diag::err_pragma_detect_mismatch_malformed);
return;
}
if (!PP.LexStringLiteral(Tok, ValueString, "pragma detect_mismatch",
/*MacroExpansion=*/true))
return;
if (Tok.isNot(tok::r_paren)) {
PP.Diag(Tok.getLocation(), diag::err_expected) << tok::r_paren;
return;
}
PP.Lex(Tok); // Eat the r_paren.
if (Tok.isNot(tok::eod)) {
PP.Diag(Tok.getLocation(), diag::err_pragma_detect_mismatch_malformed);
return;
}
// If the pragma is lexically sound, notify any interested PPCallbacks.
if (PP.getPPCallbacks())
PP.getPPCallbacks()->PragmaDetectMismatch(CommentLoc, NameString,
ValueString);
Actions.ActOnPragmaDetectMismatch(NameString, ValueString);
}
/// \brief Handle the microsoft \#pragma comment extension.
///
/// The syntax is:
/// \code
/// #pragma comment(linker, "foo")
/// \endcode
/// 'linker' is one of five identifiers: compiler, exestr, lib, linker, user.
/// "foo" is a string, which is fully macro expanded, and permits string
/// concatenation, embedded escape characters etc. See MSDN for more details.
void PragmaCommentHandler::HandlePragma(Preprocessor &PP,
PragmaIntroducerKind Introducer,
Token &Tok) {
SourceLocation CommentLoc = Tok.getLocation();
PP.Lex(Tok);
if (Tok.isNot(tok::l_paren)) {
PP.Diag(CommentLoc, diag::err_pragma_comment_malformed);
return;
}
// Read the identifier.
PP.Lex(Tok);
if (Tok.isNot(tok::identifier)) {
PP.Diag(CommentLoc, diag::err_pragma_comment_malformed);
return;
}
// Verify that this is one of the 5 whitelisted options.
IdentifierInfo *II = Tok.getIdentifierInfo();
Sema::PragmaMSCommentKind Kind =
llvm::StringSwitch<Sema::PragmaMSCommentKind>(II->getName())
.Case("linker", Sema::PCK_Linker)
.Case("lib", Sema::PCK_Lib)
.Case("compiler", Sema::PCK_Compiler)
.Case("exestr", Sema::PCK_ExeStr)
.Case("user", Sema::PCK_User)
.Default(Sema::PCK_Unknown);
if (Kind == Sema::PCK_Unknown) {
PP.Diag(Tok.getLocation(), diag::err_pragma_comment_unknown_kind);
return;
}
// Read the optional string if present.
PP.Lex(Tok);
std::string ArgumentString;
if (Tok.is(tok::comma) && !PP.LexStringLiteral(Tok, ArgumentString,
"pragma comment",
/*MacroExpansion=*/true))
return;
// FIXME: warn that 'exestr' is deprecated.
// FIXME: If the kind is "compiler" warn if the string is present (it is
// ignored).
// The MSDN docs say that "lib" and "linker" require a string and have a short
// whitelist of linker options they support, but in practice MSVC doesn't
// issue a diagnostic. Therefore neither does clang.
if (Tok.isNot(tok::r_paren)) {
PP.Diag(Tok.getLocation(), diag::err_pragma_comment_malformed);
return;
}
PP.Lex(Tok); // eat the r_paren.
if (Tok.isNot(tok::eod)) {
PP.Diag(Tok.getLocation(), diag::err_pragma_comment_malformed);
return;
}
// If the pragma is lexically sound, notify any interested PPCallbacks.
if (PP.getPPCallbacks())
PP.getPPCallbacks()->PragmaComment(CommentLoc, II, ArgumentString);
Actions.ActOnPragmaMSComment(Kind, ArgumentString);
}
// #pragma clang optimize off
// #pragma clang optimize on
void PragmaOptimizeHandler::HandlePragma(Preprocessor &PP,
PragmaIntroducerKind Introducer,
Token &FirstToken) {
Token Tok;
PP.Lex(Tok);
if (Tok.is(tok::eod)) {
PP.Diag(Tok.getLocation(), diag::err_pragma_missing_argument)
<< "clang optimize" << /*Expected=*/true << "'on' or 'off'";
return;
}
if (Tok.isNot(tok::identifier)) {
PP.Diag(Tok.getLocation(), diag::err_pragma_optimize_invalid_argument)
<< PP.getSpelling(Tok);
return;
}
const IdentifierInfo *II = Tok.getIdentifierInfo();
// The only accepted values are 'on' or 'off'.
bool IsOn = false;
if (II->isStr("on")) {
IsOn = true;
} else if (!II->isStr("off")) {
PP.Diag(Tok.getLocation(), diag::err_pragma_optimize_invalid_argument)
<< PP.getSpelling(Tok);
return;
}
PP.Lex(Tok);
if (Tok.isNot(tok::eod)) {
PP.Diag(Tok.getLocation(), diag::err_pragma_optimize_extra_argument)
<< PP.getSpelling(Tok);
return;
}
Actions.ActOnPragmaOptimize(IsOn, FirstToken.getLocation());
}
/// \brief Parses loop or unroll pragma hint value and fills in Info.
static bool ParseLoopHintValue(Preprocessor &PP, Token &Tok, Token PragmaName,
Token Option, bool ValueInParens,
PragmaLoopHintInfo &Info) {
if (ValueInParens) {
if (Tok.is(tok::r_paren)) {
// Nothing between the parentheses.
std::string PragmaString;
if (PragmaName.getIdentifierInfo()->getName() == "loop") {
PragmaString = "clang loop ";
PragmaString += Option.getIdentifierInfo()->getName();
} else {
assert(PragmaName.getIdentifierInfo()->getName() == "unroll" &&
"Unexpected pragma name");
PragmaString = "unroll";
}
// Don't try to emit what the pragma is expecting with the diagnostic
// because the logic is non-trivial and we give expected values in sema
// diagnostics if an invalid argument is given. Here, just note that the
// pragma is missing an argument.
PP.Diag(Tok.getLocation(), diag::err_pragma_missing_argument)
<< PragmaString << /*Expected=*/false;
return true;
}
}
// FIXME: Value should be stored and parsed as a constant expression.
Token Value = Tok;
PP.Lex(Tok);
if (ValueInParens) {
// Read ')'
if (Tok.isNot(tok::r_paren)) {
PP.Diag(Tok.getLocation(), diag::err_expected) << tok::r_paren;
return true;
}
PP.Lex(Tok);
}
Info.PragmaName = PragmaName;
Info.Option = Option;
Info.Value = Value;
Info.HasValue = true;
return false;
}
/// \brief Handle the \#pragma clang loop directive.
/// #pragma clang 'loop' loop-hints
///
/// loop-hints:
/// loop-hint loop-hints[opt]
///
/// loop-hint:
/// 'vectorize' '(' loop-hint-keyword ')'
/// 'interleave' '(' loop-hint-keyword ')'
/// 'unroll' '(' unroll-hint-keyword ')'
/// 'vectorize_width' '(' loop-hint-value ')'
/// 'interleave_count' '(' loop-hint-value ')'
/// 'unroll_count' '(' loop-hint-value ')'
///
/// loop-hint-keyword:
/// 'enable'
/// 'disable'
///
/// unroll-hint-keyword:
/// 'full'
/// 'disable'
///
/// loop-hint-value:
/// constant-expression
///
/// Specifying vectorize(enable) or vectorize_width(_value_) instructs llvm to
/// try vectorizing the instructions of the loop it precedes. Specifying
/// interleave(enable) or interleave_count(_value_) instructs llvm to try
/// interleaving multiple iterations of the loop it precedes. The width of the
/// vector instructions is specified by vectorize_width() and the number of
/// interleaved loop iterations is specified by interleave_count(). Specifying a
/// value of 1 effectively disables vectorization/interleaving, even if it is
/// possible and profitable, and 0 is invalid. The loop vectorizer currently
/// only works on inner loops.
///
/// The unroll and unroll_count directives control the concatenation
/// unroller. Specifying unroll(full) instructs llvm to try to
/// unroll the loop completely, and unroll(disable) disables unrolling
/// for the loop. Specifying unroll_count(_value_) instructs llvm to
/// try to unroll the loop the number of times indicated by the value.
void PragmaLoopHintHandler::HandlePragma(Preprocessor &PP,
PragmaIntroducerKind Introducer,
Token &Tok) {
// Incoming token is "loop" from "#pragma clang loop".
Token PragmaName = Tok;
SmallVector<Token, 1> TokenList;
// Lex the optimization option and verify it is an identifier.
PP.Lex(Tok);
if (Tok.isNot(tok::identifier)) {
PP.Diag(Tok.getLocation(), diag::err_pragma_loop_invalid_option)
<< /*MissingOption=*/true << "";
return;
}
while (Tok.is(tok::identifier)) {
Token Option = Tok;
IdentifierInfo *OptionInfo = Tok.getIdentifierInfo();
bool OptionValid = llvm::StringSwitch<bool>(OptionInfo->getName())
.Case("vectorize", true)
.Case("interleave", true)
.Case("unroll", true)
.Case("vectorize_width", true)
.Case("interleave_count", true)
.Case("unroll_count", true)
.Default(false);
if (!OptionValid) {
PP.Diag(Tok.getLocation(), diag::err_pragma_loop_invalid_option)
<< /*MissingOption=*/false << OptionInfo;
return;
}
PP.Lex(Tok);
// Read '('
if (Tok.isNot(tok::l_paren)) {
PP.Diag(Tok.getLocation(), diag::err_expected) << tok::l_paren;
return;
}
PP.Lex(Tok);
auto *Info = new (PP.getPreprocessorAllocator()) PragmaLoopHintInfo;
if (ParseLoopHintValue(PP, Tok, PragmaName, Option, /*ValueInParens=*/true,
*Info))
return;
// Generate the loop hint token.
Token LoopHintTok;
LoopHintTok.startToken();
LoopHintTok.setKind(tok::annot_pragma_loop_hint);
LoopHintTok.setLocation(PragmaName.getLocation());
LoopHintTok.setAnnotationValue(static_cast<void *>(Info));
TokenList.push_back(LoopHintTok);
}
if (Tok.isNot(tok::eod)) {
PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)
<< "clang loop";
return;
}
Token *TokenArray = new Token[TokenList.size()];
std::copy(TokenList.begin(), TokenList.end(), TokenArray);
PP.EnterTokenStream(TokenArray, TokenList.size(),
/*DisableMacroExpansion=*/false,
/*OwnsTokens=*/true);
}
/// \brief Handle the loop unroll optimization pragmas.
/// #pragma unroll
/// #pragma unroll unroll-hint-value
/// #pragma unroll '(' unroll-hint-value ')'
/// #pragma nounroll
///
/// unroll-hint-value:
/// constant-expression
///
/// Loop unrolling hints can be specified with '#pragma unroll' or
/// '#pragma nounroll'. '#pragma unroll' can take a numeric argument optionally
/// contained in parentheses. With no argument the directive instructs llvm to
/// try to unroll the loop completely. A positive integer argument can be
/// specified to indicate the number of times the loop should be unrolled. To
/// maximize compatibility with other compilers the unroll count argument can be
/// specified with or without parentheses. Specifying, '#pragma nounroll'
/// disables unrolling of the loop.
void PragmaUnrollHintHandler::HandlePragma(Preprocessor &PP,
PragmaIntroducerKind Introducer,
Token &Tok) {
// Incoming token is "unroll" for "#pragma unroll", or "nounroll" for
// "#pragma nounroll".
Token PragmaName = Tok;
PP.Lex(Tok);
auto *Info = new (PP.getPreprocessorAllocator()) PragmaLoopHintInfo;
if (Tok.is(tok::eod)) {
// nounroll or unroll pragma without an argument.
Info->PragmaName = PragmaName;
Info->HasValue = false;
} else if (PragmaName.getIdentifierInfo()->getName() == "nounroll") {
PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)
<< "nounroll";
return;
} else {
// Unroll pragma with an argument: "#pragma unroll N" or
// "#pragma unroll(N)".
// Read '(' if it exists.
bool ValueInParens = Tok.is(tok::l_paren);
if (ValueInParens)
PP.Lex(Tok);
if (ParseLoopHintValue(PP, Tok, PragmaName, Token(), ValueInParens, *Info))
return;
// In CUDA, the argument to '#pragma unroll' should not be contained in
// parentheses.
if (PP.getLangOpts().CUDA && ValueInParens)
PP.Diag(Info->Value.getLocation(),
diag::warn_pragma_unroll_cuda_value_in_parens);
if (Tok.isNot(tok::eod)) {
PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)
<< "unroll";
return;
}
}
// Generate the hint token.
Token *TokenArray = new Token[1];
TokenArray[0].startToken();
TokenArray[0].setKind(tok::annot_pragma_loop_hint);
TokenArray[0].setLocation(PragmaName.getLocation());
TokenArray[0].setAnnotationValue(static_cast<void *>(Info));
PP.EnterTokenStream(TokenArray, 1, /*DisableMacroExpansion=*/false,
/*OwnsTokens=*/true);
}