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

Reply via email to