Hi rsmith, majnemer, rnk,
This patch implements the microsoft segment pragmas. As posted it works up to
testing but it needs a little polish and some lit tests. Particularly I'm
pretty sure that the way I assign the code_seg attribute in
CheckFunctionDeclaration is wrong. Another thing to note about this patch is
that it introduces a unified pragma lexer for microsoft pragmas. This lexer
basically just snarfs up some tokens, adds a marker token and passes them all
onto the parser, which actually parses the tokens. The idea is that all past
and future ms pragmas would migrate to this pattern.
http://llvm-reviews.chandlerc.com/D3065
Files:
include/clang/Basic/Attr.td
include/clang/Basic/DiagnosticParseKinds.td
include/clang/Basic/TokenKinds.def
include/clang/Parse/Parser.h
include/clang/Sema/Sema.h
lib/CodeGen/CodeGenModule.cpp
lib/Parse/ParseDeclCXX.cpp
lib/Parse/ParsePragma.cpp
lib/Parse/ParseStmt.cpp
lib/Parse/Parser.cpp
lib/Sema/Sema.cpp
lib/Sema/SemaAttr.cpp
lib/Sema/SemaDecl.cpp
Index: include/clang/Basic/Attr.td
===================================================================
--- include/clang/Basic/Attr.td
+++ include/clang/Basic/Attr.td
@@ -1739,6 +1739,24 @@
let Documentation = [MSInheritanceDocs];
}
+def MSSegment : Attr {
+ // This attribute has no spellings as it is only ever created implicitly.
+ let Spellings = [];
+ let Args = [StringArgument<"SegName">, UnsignedArgument<"kind">];
+
+ let AdditionalMembers = [{
+ enum Kind {
+ DataSeg,
+ CodeSeg,
+ BSSSeg,
+ ConstSeg
+ };
+
+ Kind getSegKind() const { return Kind(kind); }
+ }];
+ let Documentation = [Undocumented];
+}
+
def MSVtorDisp : InheritableAttr {
// This attribute has no spellings as it is only ever created implicitly.
let Spellings = [];
Index: include/clang/Basic/DiagnosticParseKinds.td
===================================================================
--- include/clang/Basic/DiagnosticParseKinds.td
+++ include/clang/Basic/DiagnosticParseKinds.td
@@ -770,6 +770,8 @@
"missing ')' after '#pragma %0' - ignoring">, InGroup<IgnoredPragmas>;
def warn_pragma_expected_identifier : Warning<
"expected identifier in '#pragma %0' - ignored">, InGroup<IgnoredPragmas>;
+def warn_pragma_expected_string : Warning<
+ "expected string literal in '#pragma %0' - ignored">, InGroup<IgnoredPragmas>;
def warn_pragma_expected_integer : Warning<
"expected integer between %0 and %1 inclusive in '#pragma %2' - ignored">,
InGroup<IgnoredPragmas>;
Index: include/clang/Basic/TokenKinds.def
===================================================================
--- include/clang/Basic/TokenKinds.def
+++ include/clang/Basic/TokenKinds.def
@@ -683,6 +683,11 @@
// handles them.
ANNOTATION(pragma_ms_vtordisp)
+// Annotation for all microsoft #pragmas...
+// The lexer produces these so that they only take effect when the parser
+// handles them.
+ANNOTATION(pragma_ms_pragma)
+
// Annotation for #pragma OPENCL EXTENSION...
// The lexer produces these so that they only take effect when the parser
// handles them.
Index: include/clang/Parse/Parser.h
===================================================================
--- include/clang/Parse/Parser.h
+++ include/clang/Parse/Parser.h
@@ -154,6 +154,10 @@
OwningPtr<PragmaHandler> MSDetectMismatchHandler;
OwningPtr<PragmaHandler> MSPointersToMembers;
OwningPtr<PragmaHandler> MSVtorDisp;
+ OwningPtr<PragmaHandler> MSDataSeg;
+ OwningPtr<PragmaHandler> MSBSSSeg;
+ OwningPtr<PragmaHandler> MSConstSeg;
+ OwningPtr<PragmaHandler> MSCodeSeg;
OwningPtr<CommentHandler> CommentSemaHandler;
@@ -468,6 +472,8 @@
void HandlePragmaMSVtorDisp();
+ void HandlePragmaMSPragma();
+
/// \brief Handle the annotation token produced for
/// #pragma align...
void HandlePragmaAlign();
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -273,6 +273,13 @@
PVDK_Reset ///< #pragma vtordisp()
};
+ enum PragmaMsStackAction {
+ PSK_Push, // #pragma (push, ...)
+ PSK_Pop, // #pragma (pop, ...)
+ PSK_Reset, // #pragma ()
+ PSK_Set // #pragma (...)
+ };
+
/// \brief Whether to insert vtordisps prior to virtual bases in the Microsoft
/// C++ ABI. Possible values are 0, 1, and 2, which mean:
///
@@ -288,6 +295,24 @@
/// \brief Source location for newly created implicit MSInheritanceAttrs
SourceLocation ImplicitMSInheritanceAttrLoc;
+ struct MSSegmentStack {
+ void Act(SourceLocation PragmaLoc,
+ PragmaMsStackAction Action,
+ llvm::StringRef ActionTarget,
+ StringLiteral *Value);
+ explicit MSSegmentStack()
+ : Current(0) {}
+ typedef std::pair<llvm::StringRef,
+ std::pair<StringLiteral *, SourceLocation>> Slot;
+ SmallVector<Slot, 2> Stack;
+ StringLiteral *Current;
+ SourceLocation SourceLoc;
+ };
+ MSSegmentStack DataSegStack;
+ MSSegmentStack BSSSegStack;
+ MSSegmentStack ConstSegStack;
+ MSSegmentStack CodeSegStack;
+
/// VisContext - Manages the stack for \#pragma GCC visibility.
void *VisContext; // Really a "PragmaVisStack*"
@@ -6994,6 +7019,30 @@
void ActOnPragmaMSVtorDisp(PragmaVtorDispKind Kind, SourceLocation PragmaLoc,
MSVtorDispAttr::Mode Value);
+ /// \brief Called on well formed \#pragma data_seg().
+ void ActOnPragmaMSDataSeg(SourceLocation PragmaLoc,
+ PragmaMsStackAction Action,
+ llvm::StringRef ActionTarget,
+ StringLiteral *SegmentName);
+
+ /// \brief Called on well formed \#pragma bss_seg().
+ void ActOnPragmaMSBSSSeg(SourceLocation PragmaLoc,
+ PragmaMsStackAction Action,
+ llvm::StringRef ActionTarget,
+ StringLiteral *SegmentName);
+
+ /// \brief Called on well formed \#pragma const_seg().
+ void ActOnPragmaMSConstSeg(SourceLocation PragmaLoc,
+ PragmaMsStackAction Action,
+ llvm::StringRef ActionTarget,
+ StringLiteral *SegmentName);
+
+ /// \brief Called on well formed \#pragma code_seg().
+ void ActOnPragmaMSCodeSeg(SourceLocation PragmaLoc,
+ PragmaMsStackAction Action,
+ llvm::StringRef ActionTarget,
+ StringLiteral *SegmentName);
+
/// ActOnPragmaDetectMismatch - Call on well-formed \#pragma detect_mismatch
void ActOnPragmaDetectMismatch(StringRef Name, StringRef Value);
Index: lib/CodeGen/CodeGenModule.cpp
===================================================================
--- lib/CodeGen/CodeGenModule.cpp
+++ lib/CodeGen/CodeGenModule.cpp
@@ -704,6 +704,9 @@
if (const SectionAttr *SA = D->getAttr<SectionAttr>())
GV->setSection(SA->getName());
+ if (D->hasAttr<MSSegmentAttr>())
+ GV->setSection(D->getAttr<MSSegmentAttr>()->getSegName());
+
// Alias cannot have attributes. Filter them here.
if (!isa<llvm::GlobalAlias>(GV))
getTargetCodeGenInfo().SetTargetAttributes(D, GV, *this);
Index: lib/Parse/ParseDeclCXX.cpp
===================================================================
--- lib/Parse/ParseDeclCXX.cpp
+++ lib/Parse/ParseDeclCXX.cpp
@@ -2615,6 +2615,11 @@
continue;
}
+ if (Tok.is(tok::annot_pragma_ms_pragma)) {
+ HandlePragmaMSPragma();
+ continue;
+ }
+
// If we see a namespace here, a close brace was missing somewhere.
if (Tok.is(tok::kw_namespace)) {
DiagnoseUnexpectedNamespace(cast<NamedDecl>(TagDecl));
Index: lib/Parse/ParsePragma.cpp
===================================================================
--- lib/Parse/ParsePragma.cpp
+++ lib/Parse/ParsePragma.cpp
@@ -124,6 +124,12 @@
Token &FirstToken);
};
+struct PragmaMSPragma : public PragmaHandler {
+ explicit PragmaMSPragma(const char *name) : PragmaHandler(name) {}
+ virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+ Token &FirstToken);
+};
+
} // end namespace
void Parser::initializePragmaHandlers() {
@@ -175,6 +181,14 @@
PP.AddPragmaHandler(MSPointersToMembers.get());
MSVtorDisp.reset(new PragmaMSVtorDisp());
PP.AddPragmaHandler(MSVtorDisp.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());
}
}
@@ -214,6 +228,14 @@
MSPointersToMembers.reset();
PP.RemovePragmaHandler(MSVtorDisp.get());
MSVtorDisp.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("STDC", FPContractHandler.get());
@@ -400,6 +422,85 @@
Actions.ActOnPragmaMSVtorDisp(Kind, PragmaLoc, Mode);
}
+void Parser::HandlePragmaMSPragma() {
+ assert(Tok.is(tok::annot_pragma_ms_pragma));
+ SourceLocation PragmaLoc = ConsumeToken(); // The annotation token.
+ // Grab the identifier following #pragma
+ 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.
+ enum PragmaMSKind { DataSeg, BSSSeg, ConstSeg, CodeSeg } Kind =
+ llvm::StringSwitch<PragmaMSKind>(PragmaName)
+ .Case("data_seg", DataSeg)
+ .Case("bss_seg", BSSSeg)
+ .Case("const_seg", ConstSeg)
+ .Case("code_seg", CodeSeg);
+ if (Tok.isNot(tok::l_paren)) {
+ PP.Diag(PragmaLoc, diag::warn_pragma_expected_lparen) << PragmaName;
+ return;
+ }
+ PP.Lex(Tok); // (
+ Sema::PragmaMsStackAction Action = Sema::PSK_Set;
+ llvm::StringRef IName;
+ if (Tok.isAnyIdentifier()) {
+ IName = Tok.getIdentifierInfo()->getName();
+ if (IName == "push")
+ Action = Sema::PSK_Push;
+ else if (IName == "pop")
+ Action = Sema::PSK_Pop;
+ else {
+ PP.Diag(PragmaLoc, diag::warn_pragma_invalid_action) << PragmaName;
+ return;
+ }
+ if (Action != Sema::PSK_Set) {
+ IName = llvm::StringRef();
+ PP.Lex(Tok); // push | pop
+ if (Tok.is(tok::comma)) {
+ PP.Lex(Tok); // ,
+ if (Tok.isAnyIdentifier()) {
+ IName = Tok.getIdentifierInfo()->getName();
+ PP.Lex(Tok); // identifier
+ if (Tok.is(tok::comma))
+ PP.Lex(Tok);
+ else if (Tok.isNot(tok::r_paren)) {
+ PP.Diag(PragmaLoc, diag::warn_pragma_expected_punc) << PragmaName;
+ return;
+ }
+ }
+ } else if (Tok.isNot(tok::r_paren)) {
+ PP.Diag(PragmaLoc, diag::warn_pragma_expected_punc) << PragmaName;
+ return;
+ }
+ }
+ } else if (Tok.is(tok::r_paren))
+ Action = Sema::PSK_Reset;
+ // Grab the string literal for our section name.
+ StringLiteral *SegmentName = nullptr;
+ if (Tok.isNot(tok::r_paren)) {
+ ExprResult SegmentNameExpr = ParseStringLiteralExpression();
+ if (SegmentNameExpr.isInvalid()) {
+ PP.Diag(PragmaLoc, diag::warn_pragma_expected_string) << PragmaName;
+ return;
+ }
+ SegmentName = cast<StringLiteral>(SegmentNameExpr.get());
+ }
+ if (Tok.isNot(tok::r_paren)) {
+ PP.Diag(PragmaLoc, diag::warn_pragma_expected_rparen) << PragmaName;
+ return;
+ }
+ PP.Lex(Tok); // ')'
+ if (Kind == DataSeg)
+ Actions.ActOnPragmaMSDataSeg(PragmaLoc, Action, IName, SegmentName);
+ else if (Kind == BSSSeg)
+ Actions.ActOnPragmaMSBSSSeg(PragmaLoc, Action, IName, SegmentName);
+ else if (Kind == ConstSeg)
+ Actions.ActOnPragmaMSConstSeg(PragmaLoc, Action, IName, SegmentName);
+ else if (Kind == CodeSeg)
+ Actions.ActOnPragmaMSCodeSeg(PragmaLoc, Action, IName, SegmentName);
+}
+
// #pragma GCC visibility comes in two variants:
// 'push' '(' [visibility] ')'
// 'pop'
@@ -1204,6 +1305,24 @@
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 AnnotTok;
+ AnnotTok.startToken();
+ AnnotTok.setKind(tok::annot_pragma_ms_pragma);
+ AnnotTok.setLocation(Tok.getLocation());
+ SmallVector<Token, 8> TokenVector;
+ TokenVector.push_back(AnnotTok);
+ for (; Tok.isNot(tok::eod); PP.Lex(Tok))
+ TokenVector.push_back(Tok);
+ Token *TokenArray = new Token[TokenVector.size()];
+ memcpy(TokenArray, TokenVector.data(), sizeof(Token)* TokenVector.size());
+ PP.EnterTokenStream(TokenArray, TokenVector.size(), true, true);
+}
+
/// \brief Handle the Microsoft \#pragma detect_mismatch extension.
///
/// The syntax is:
Index: lib/Parse/ParseStmt.cpp
===================================================================
--- lib/Parse/ParseStmt.cpp
+++ lib/Parse/ParseStmt.cpp
@@ -350,6 +350,10 @@
HandlePragmaMSPointersToMembers();
return StmtEmpty();
+ case tok::annot_pragma_ms_pragma:
+ ProhibitAttributes(Attrs);
+ HandlePragmaMSPragma();
+ return StmtEmpty();
}
// If we reached this code, the statement must end in a semicolon.
@@ -828,6 +832,9 @@
case tok::annot_pragma_ms_pointers_to_members:
HandlePragmaMSPointersToMembers();
break;
+ case tok::annot_pragma_ms_pragma:
+ HandlePragmaMSPragma();
+ break;
default:
checkForPragmas = false;
break;
Index: lib/Parse/Parser.cpp
===================================================================
--- lib/Parse/Parser.cpp
+++ lib/Parse/Parser.cpp
@@ -631,6 +631,9 @@
case tok::annot_pragma_ms_vtordisp:
HandlePragmaMSVtorDisp();
return DeclGroupPtrTy();
+ case tok::annot_pragma_ms_pragma:
+ HandlePragmaMSPragma();
+ return DeclGroupPtrTy();
case tok::semi:
// Either a C++11 empty-declaration or attribute-declaration.
SingleDecl = Actions.ActOnEmptyDeclaration(getCurScope(),
Index: lib/Sema/Sema.cpp
===================================================================
--- lib/Sema/Sema.cpp
+++ lib/Sema/Sema.cpp
@@ -79,6 +79,7 @@
MSPointerToMemberRepresentationMethod(
LangOpts.getMSPointerToMemberRepresentationMethod()),
VtorDispModeStack(1, MSVtorDispAttr::Mode(LangOpts.VtorDispMode)),
+ DataSegStack(), CodeSegStack(), ConstSegStack(),
VisContext(0),
IsBuildingRecoveryCallExpr(false),
ExprNeedsCleanups(false), LateTemplateParser(0), OpaqueParser(0),
Index: lib/Sema/SemaAttr.cpp
===================================================================
--- lib/Sema/SemaAttr.cpp
+++ lib/Sema/SemaAttr.cpp
@@ -325,6 +325,100 @@
}
}
+template<typename Type> Type
+PopToName(std::vector<llvm::StringRef, Type>& Stack, llvm::StringRef Key) {
+ if (!ActionTarget.empty()) {
+ auto I = std::find_if(DataSegStack.rbegin(), DataSegStack.rend(),
+ [&](const std::pair<llvm::StringRef, StringLiteral *> &x) {
+ return x.first == ActionTarget;
+ });
+ CurrentDataSegment = I->second;
+ if (I != DataSegStack.rend())
+ DataSegStack.erase(std::prev(I.base()), DataSegStack.end());
+ }
+ else if (!DataSegStack.empty()) {
+ CurrentDataSegment = DataSegStack.back().second;
+ DataSegStack.pop_back();
+ }
+}
+
+void Sema::MSSegmentStack::Act(SourceLocation PragmaLoc,
+ PragmaMsStackAction Action,
+ llvm::StringRef ActionTarget,
+ StringLiteral *SectionName) {
+ switch (Action) {
+ case PSK_Push:
+ Stack.push_back(
+ std::make_pair(ActionTarget, std::make_pair(Current, SourceLoc)));
+ break;
+ case PSK_Pop:
+ if (!ActionTarget.empty()) {
+ // If we've got a label, try to find it and jump there.
+ auto I = std::find_if(Stack.rbegin(), Stack.rend(),
+ [&](const Slot &x) {
+ return x.first == ActionTarget;
+ });
+ // If we found the label so pop from there.
+ if (I != Stack.rend()) {
+ Current = I->second.first;
+ SourceLoc = I->second.second;
+ Stack.erase(std::prev(I.base()), Stack.end());
+ }
+ } else if (!Stack.empty()) {
+ // We don't have a label, just pop the last entry.
+ Current = Stack.back().second.first;
+ SourceLoc = Stack.back().second.second;
+ Stack.pop_back();
+ }
+ break;
+ case PSK_Reset:
+ assert(!SectionName);
+ Stack.clear();
+ Current = nullptr;
+ return;
+ case PSK_Set:
+ assert(SectionName);
+ break;
+ }
+ // Setting section "" has no effect
+ if (SectionName && SectionName->getLength()) {
+ Current = SectionName;
+ SourceLoc = PragmaLoc;
+ }
+}
+
+/// \brief Called on well formed \#pragma data_seg().
+void Sema::ActOnPragmaMSDataSeg(SourceLocation PragmaLoc,
+ PragmaMsStackAction Action,
+ llvm::StringRef ActionTarget,
+ StringLiteral *SegmentName) {
+ DataSegStack.Act(PragmaLoc, Action, ActionTarget, SegmentName);
+}
+
+/// \brief Called on well formed \#pragma bss_seg().
+void Sema::ActOnPragmaMSBSSSeg(SourceLocation PragmaLoc,
+ PragmaMsStackAction Action,
+ llvm::StringRef ActionTarget,
+ StringLiteral *SegmentName) {
+ BSSSegStack.Act(PragmaLoc, Action, ActionTarget, SegmentName);
+}
+
+/// \brief Called on well formed \#pragma bss_seg().
+void Sema::ActOnPragmaMSConstSeg(SourceLocation PragmaLoc,
+ PragmaMsStackAction Action,
+ llvm::StringRef ActionTarget,
+ StringLiteral *SegmentName) {
+ ConstSegStack.Act(PragmaLoc, Action, ActionTarget, SegmentName);
+}
+
+/// \brief Called on well formed \#pragma code_seg().
+void Sema::ActOnPragmaMSCodeSeg(SourceLocation PragmaLoc,
+ PragmaMsStackAction Action,
+ llvm::StringRef ActionTarget,
+ StringLiteral *SegmentName) {
+ CodeSegStack.Act(PragmaLoc, Action, ActionTarget, SegmentName);
+}
+
void Sema::ActOnPragmaUnused(const Token &IdTok, Scope *curScope,
SourceLocation PragmaLoc) {
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -7495,6 +7495,11 @@
}
}
+ if (/*NewFD->isFunctionDefinition() &&*/ CodeSegStack.Current)
+ NewFD->addAttr(MSSegmentAttr::CreateImplicit(
+ Context, CodeSegStack.Current->getString(),
+ MSSegmentAttr::CodeSeg, CodeSegStack.SourceLoc));
+
if (Redeclaration) {
// NewFD and OldDecl represent declarations that need to be
// merged.
@@ -8817,6 +8822,23 @@
Diag(var->getLocation(), diag::note_use_thread_local);
}
+ if (var->isThisDeclarationADefinition() && ActiveTemplateInstantiations.empty()) {
+ if (var->getType().isConstQualified()) {
+ if (ConstSegStack.Current)
+ var->addAttr(MSSegmentAttr::CreateImplicit(
+ Context, ConstSegStack.Current->getString(),
+ MSSegmentAttr::ConstSeg, ConstSegStack.SourceLoc));
+ } else if (!var->getInit()) {
+ if (BSSSegStack.Current)
+ var->addAttr(MSSegmentAttr::CreateImplicit(
+ Context, BSSSegStack.Current->getString(),
+ MSSegmentAttr::BSSSeg, BSSSegStack.SourceLoc));
+ } else if (DataSegStack.Current)
+ var->addAttr(MSSegmentAttr::CreateImplicit(
+ Context, DataSegStack.Current->getString(),
+ MSSegmentAttr::DataSeg, DataSegStack.SourceLoc));
+ }
+
// All the following checks are C++ only.
if (!getLangOpts().CPlusPlus) return;
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits