This patch adds support for the msvc pragmas section, bss_seg, code_seg, const_seg and data_seg as well as support for __declspec(allocate()). Additionally it corrects semantics and adds diagnostics for __attribute__((section())) and the interaction between the attribute and the msvc pragmas and declspec. In general conflicts should now be well diganosed within and among these features. In supporting the pragmas new machinery for uniform lexing for msvc pragmas was introduced. The new machinery always lexes the entire pragma and stores it on an annotation token. The parser is responsible for parsing the pragma when the handling the annotation token. There is a known outstanding bug in this implementation in C mode. Because these attributes and pragmas apply _only_ to definitions, we process them at the time we detect a definition. Due to tentative definitions in C, we end up processing the definition late. This means that in C mode, everything that ends up in a BSS section will end up in the _last_ BSS section rather than the one that was live at the time of tentative definition, even if that turns out to be the point of actual definition. This issue is not known to impact anything as of yet because we are not aware of a clear use or use case for #pragma bss_seg but should be fixed at some point. Differential Revision=http://reviews.llvm.org/D3065#inline-16241 llvm-svn: 205810
1534 lines
50 KiB
C++
1534 lines
50 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/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;
|
|
};
|
|
|
|
} // 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());
|
|
}
|
|
}
|
|
|
|
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();
|
|
}
|
|
|
|
/// \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());
|
|
llvm::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 unsigned (Parser::*PragmaHandler)(llvm::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 (auto DiagID = (this->*Handler)(PragmaName, PragmaLocation)) {
|
|
PP.Diag(PragmaLocation, DiagID) << PragmaName;
|
|
while (Tok.isNot(tok::eof))
|
|
PP.Lex(Tok);
|
|
PP.Lex(Tok);
|
|
}
|
|
}
|
|
|
|
unsigned Parser::HandlePragmaMSSection(llvm::StringRef PragmaName,
|
|
SourceLocation PragmaLocation) {
|
|
if (Tok.isNot(tok::l_paren))
|
|
return diag::warn_pragma_expected_lparen;
|
|
PP.Lex(Tok); // (
|
|
// Parsing code for pragma section
|
|
if (Tok.isNot(tok::string_literal))
|
|
return diag::warn_pragma_expected_section_name;
|
|
StringLiteral *SegmentName =
|
|
cast<StringLiteral>(ParseStringLiteralExpression().get());
|
|
int SectionFlags = 0;
|
|
while (Tok.is(tok::comma)) {
|
|
PP.Lex(Tok); // ,
|
|
if (!Tok.isAnyIdentifier())
|
|
return diag::warn_pragma_expected_action_or_r_paren;
|
|
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();
|
|
while (Tok.isNot(tok::eof))
|
|
PP.Lex(Tok);
|
|
PP.Lex(Tok);
|
|
return 0;
|
|
}
|
|
SectionFlags |= Flag;
|
|
PP.Lex(Tok); // Identifier
|
|
}
|
|
if (Tok.isNot(tok::r_paren))
|
|
return diag::warn_pragma_expected_rparen;
|
|
PP.Lex(Tok); // )
|
|
if (Tok.isNot(tok::eof))
|
|
return diag::warn_pragma_extra_tokens_at_eol;
|
|
PP.Lex(Tok); // eof
|
|
Actions.ActOnPragmaMSSection(PragmaLocation, SectionFlags, SegmentName);
|
|
return 0;
|
|
}
|
|
|
|
unsigned Parser::HandlePragmaMSSegment(llvm::StringRef PragmaName,
|
|
SourceLocation PragmaLocation) {
|
|
if (Tok.isNot(tok::l_paren))
|
|
return diag::warn_pragma_expected_lparen;
|
|
PP.Lex(Tok); // (
|
|
Sema::PragmaMsStackAction Action = Sema::PSK_Reset;
|
|
llvm::StringRef SlotLabel;
|
|
if (Tok.isAnyIdentifier()) {
|
|
llvm::StringRef PushPop = Tok.getIdentifierInfo()->getName();
|
|
if (PushPop == "push")
|
|
Action = Sema::PSK_Push;
|
|
else if (PushPop == "pop")
|
|
Action = Sema::PSK_Pop;
|
|
else
|
|
return diag::warn_pragma_expected_section_push_pop_or_name;
|
|
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))
|
|
return diag::warn_pragma_expected_punc;
|
|
}
|
|
} else if (Tok.isNot(tok::r_paren))
|
|
return diag::warn_pragma_expected_punc;
|
|
}
|
|
}
|
|
// Grab the string literal for our section name.
|
|
StringLiteral *SegmentName = nullptr;
|
|
if (Tok.isNot(tok::r_paren)) {
|
|
if (Tok.isNot(tok::string_literal))
|
|
return 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;
|
|
SegmentName = cast<StringLiteral>(ParseStringLiteralExpression().get());
|
|
// Setting section "" has no effect
|
|
if (SegmentName->getLength())
|
|
Action = (Sema::PragmaMsStackAction)(Action | Sema::PSK_Set);
|
|
}
|
|
if (Tok.isNot(tok::r_paren))
|
|
return diag::warn_pragma_expected_rparen;
|
|
PP.Lex(Tok); // )
|
|
if (Tok.isNot(tok::eof))
|
|
return diag::warn_pragma_extra_tokens_at_eol;
|
|
PP.Lex(Tok); // eof
|
|
Actions.ActOnPragmaMSSeg(PragmaLocation, Action, SlotLabel,
|
|
SegmentName, PragmaName);
|
|
return 0;
|
|
}
|
|
|
|
unsigned Parser::HandlePragmaMSInitSeg(llvm::StringRef PragmaName,
|
|
SourceLocation PragmaLocation) {
|
|
return PP.getDiagnostics().getCustomDiagID(
|
|
DiagnosticsEngine::Error, "'#pragma %0' not implemented.");
|
|
}
|
|
|
|
// #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 = 0;
|
|
} 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 = 0;
|
|
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().getDiagnosticLevel(diag::warn_pragma_omp_ignored,
|
|
FirstTok.getLocation()) !=
|
|
DiagnosticsEngine::Ignored) {
|
|
PP.Diag(FirstTok, diag::warn_pragma_omp_ignored);
|
|
PP.getDiagnostics().setDiagnosticMapping(diag::warn_pragma_omp_ignored,
|
|
diag::MAP_IGNORE,
|
|
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 = 0;
|
|
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);
|
|
}
|