]> granicus.if.org Git - clang/commitdiff
[MS-ABI] Add support for #pragma section and related pragmas
authorWarren Hunt <whunt@google.com>
Tue, 8 Apr 2014 22:30:47 +0000 (22:30 +0000)
committerWarren Hunt <whunt@google.com>
Tue, 8 Apr 2014 22:30:47 +0000 (22:30 +0000)
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

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@205810 91177308-0d34-0410-b5e6-96231b3b80d8

18 files changed:
include/clang/Basic/Attr.td
include/clang/Basic/AttrDocs.td
include/clang/Basic/DiagnosticParseKinds.td
include/clang/Basic/DiagnosticSemaKinds.td
include/clang/Basic/TokenKinds.def
include/clang/Parse/Parser.h
include/clang/Sema/Sema.h
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
lib/Sema/SemaObjCProperty.cpp
test/CodeGen/function-sections.c [new file with mode: 0644]
test/CodeGen/sections.c
test/Sema/pragma-section.c [new file with mode: 0644]

index 12a85174c94bf4c64ec026dc3909d22c5e57505c..6c08e49dac0d0cfae490a8ae6def0e7474768294 100644 (file)
@@ -1075,7 +1075,7 @@ def InitPriority : InheritableAttr {
 }
 
 def Section : InheritableAttr {
-  let Spellings = [GCC<"section">];
+  let Spellings = [GCC<"section">, Declspec<"allocate">];
   let Args = [StringArgument<"Name">];
   let Subjects = SubjectList<[Function, GlobalVar, 
                               ObjCMethod, ObjCProperty], ErrorDiag,
@@ -1697,6 +1697,7 @@ def MSInheritance : InheritableAttr {
                    Keyword<"__multiple_inheritance">,
                    Keyword<"__virtual_inheritance">,
                    Keyword<"__unspecified_inheritance">];
+  let Documentation = [SectionDocs];
   let AdditionalMembers = [{
   static bool hasVBPtrOffsetField(Spelling Inheritance) {
     return Inheritance == Keyword_unspecified_inheritance;
index 2f621758494d3b2361d53b82e316dc71ec77a95e..7e923af812f1f153c04c29c76a49c8401e142d24 100644 (file)
@@ -27,6 +27,14 @@ This page lists the attributes currently supported by Clang.
 }];
 }
 
+def SectionDocs : Documentation {
+  let Category = DocCatVariable;
+  let Content = [{
+The ``section`` attribute allows you to specify a specific section a
+global variable or function should be in after translation.
+  }];
+}
+
 def TLSModelDocs : Documentation {
   let Category = DocCatVariable;
   let Content = [{
index 40fab75f8a097ea298f9b385b503bfc405e5c232..3efac016adc921512ce3c21a480c164d41caa23a 100644 (file)
@@ -771,6 +771,15 @@ def warn_pragma_expected_rparen : Warning<
   "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_section_name : Warning<
+  "expected a string literal for the section name in '#pragma %0' - ignored">,
+  InGroup<IgnoredPragmas>;
+def warn_pragma_expected_section_push_pop_or_name : Warning<
+  "expected push, pop or a string literal for the section name in '#pragma %0' - ignored">,
+  InGroup<IgnoredPragmas>;
+def warn_pragma_expected_section_label_or_name : Warning<
+  "expected a stack label or a string literal for the section name 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>;
@@ -793,6 +802,15 @@ def warn_pragma_align_invalid_option : Warning<
   "invalid alignment option in '#pragma %select{align|options align}0' - ignored">,
   InGroup<IgnoredPragmas>;
 // - #pragma pack
+def warn_pragma_unsupported_action : Warning<
+  "known but unsupported action '%1' for '#pragma %0' - ignored">,
+  InGroup<IgnoredPragmas>;
+def warn_pragma_invalid_specific_action : Warning<
+  "unknown action '%1' for '#pragma %0' - ignored">,
+  InGroup<IgnoredPragmas>;
+def warn_pragma_expected_action_or_r_paren : Warning<
+  "expected action or ')' in '#pragma %0' - ignored">,
+  InGroup<IgnoredPragmas>;
 def warn_pragma_invalid_action : Warning<
   "unknown action for '#pragma %0' - ignored">,
   InGroup<IgnoredPragmas>;
index 1dd7f815be926acf6d1561ea9307689bb8976e4c..0eefcd70f0079ed458d53e103ead671a22832b12 100644 (file)
@@ -521,6 +521,7 @@ def warn_cxx_ms_struct :
   Warning<"ms_struct may not produce MSVC-compatible layouts for classes "
           "with base classes or virtual functions">,
   DefaultError, InGroup<IncompatibleMSStruct>;
+def err_section_conflict : Error<"%0 causes a section type conflict with %1">;
 
 def warn_pragma_unused_undeclared_var : Warning<
   "undeclared variable %0 used as an argument for '#pragma unused'">,
index 47e23ff04998d3021decc09bf22aaf6e7a060b6f..845a8b096f63fecc618977caa84eef7394ba4a60 100644 (file)
@@ -685,6 +685,11 @@ ANNOTATION(pragma_ms_pointers_to_members)
 // 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 db527f6e45368842101844002c52527e99263682..2d71a0403dcd4e84ca49e1aaa52965ef574b6956 100644 (file)
@@ -155,6 +155,11 @@ class Parser : public CodeCompletionHandler {
   std::unique_ptr<PragmaHandler> MSPointersToMembers;
   std::unique_ptr<PragmaHandler> MSVtorDisp;
   std::unique_ptr<PragmaHandler> MSInitSeg;
+  std::unique_ptr<PragmaHandler> MSDataSeg;
+  std::unique_ptr<PragmaHandler> MSBSSSeg;
+  std::unique_ptr<PragmaHandler> MSConstSeg;
+  std::unique_ptr<PragmaHandler> MSCodeSeg;
+  std::unique_ptr<PragmaHandler> MSSection;
 
   std::unique_ptr<CommentHandler> CommentSemaHandler;
 
@@ -476,6 +481,14 @@ private:
 
   void HandlePragmaMSVtorDisp();
 
+  void HandlePragmaMSPragma();
+  unsigned HandlePragmaMSSection(llvm::StringRef PragmaName,
+                                 SourceLocation PragmaLocation);
+  unsigned HandlePragmaMSSegment(llvm::StringRef PragmaName,
+                                 SourceLocation PragmaLocation);
+  unsigned HandlePragmaMSInitSeg(llvm::StringRef PragmaName,
+                                 SourceLocation PragmaLocation);
+
   /// \brief Handle the annotation token produced for
   /// #pragma align...
   void HandlePragmaAlign();
index ea9344d4838b0e1d97f92c007592f8f4c29fdd46..ce830893228f3e21bcdca706a58095ceb1ae145b 100644 (file)
@@ -274,6 +274,15 @@ public:
     PVDK_Reset          ///< #pragma vtordisp()
   };
 
+  enum PragmaMsStackAction {
+    PSK_Reset,    // #pragma ()
+    PSK_Set,      // #pragma ("name")
+    PSK_Push,     // #pragma (push[, id])
+    PSK_Push_Set, // #pragma (push[, id], "name")
+    PSK_Pop,      // #pragma (pop[, id])
+    PSK_Pop_Set,  // #pragma (pop[, id], "name")
+  };
+
   /// \brief Whether to insert vtordisps prior to virtual bases in the Microsoft
   /// C++ ABI.  Possible values are 0, 1, and 2, which mean:
   ///
@@ -289,6 +298,35 @@ public:
   /// \brief Source location for newly created implicit MSInheritanceAttrs
   SourceLocation ImplicitMSInheritanceAttrLoc;
 
+  template<typename ValueType>
+  struct PragmaStack {
+    struct Slot {
+      llvm::StringRef StackSlotLabel;
+      ValueType Value;
+      SourceLocation PragmaLocation;
+      Slot(llvm::StringRef StackSlotLabel,
+           ValueType Value,
+           SourceLocation PragmaLocation)
+        : StackSlotLabel(StackSlotLabel), Value(Value),
+          PragmaLocation(PragmaLocation) {}
+    };
+    void Act(SourceLocation PragmaLocation,
+             PragmaMsStackAction Action,
+             llvm::StringRef StackSlotLabel,
+             ValueType Value);
+    explicit PragmaStack(const ValueType &Value)
+      : CurrentValue(Value) {}
+    SmallVector<Slot, 2> Stack;
+    ValueType CurrentValue;
+    SourceLocation CurrentPragmaLocation;
+  };
+  // FIXME: We should serialize / deserialize these if they occur in a PCH (but
+  // we shouldn't do so if they're in a module).
+  PragmaStack<StringLiteral *> DataSegStack;
+  PragmaStack<StringLiteral *> BSSSegStack;
+  PragmaStack<StringLiteral *> ConstSegStack;
+  PragmaStack<StringLiteral *> CodeSegStack;
+
   /// VisContext - Manages the stack for \#pragma GCC visibility.
   void *VisContext; // Really a "PragmaVisStack*"
 
@@ -7031,6 +7069,54 @@ public:
   void ActOnPragmaMSVtorDisp(PragmaVtorDispKind Kind, SourceLocation PragmaLoc,
                              MSVtorDispAttr::Mode Value);
 
+  enum PragmaSectionKind {
+    PSK_DataSeg,
+    PSK_BSSSeg,
+    PSK_ConstSeg,
+    PSK_CodeSeg,
+  };
+
+  enum PragmaSectionFlag {
+    PSF_None = 0,
+    PSF_Read = 0x1,
+    PSF_Write = 0x2,
+    PSF_Execute = 0x4,
+    PSF_Implicit = 0x8,
+    PSF_Invalid = 0x80000000,
+  };
+
+  struct SectionInfo {
+    DeclaratorDecl *Decl;
+    SourceLocation PragmaSectionLocation;
+    int SectionFlags;
+    SectionInfo() = default;
+    SectionInfo(DeclaratorDecl *Decl,
+                SourceLocation PragmaSectionLocation,
+                int SectionFlags)
+      : Decl(Decl),
+        PragmaSectionLocation(PragmaSectionLocation),
+        SectionFlags(SectionFlags) {}
+  };
+
+  llvm::StringMap<SectionInfo> SectionInfos;
+  bool UnifySection(const StringRef &SectionName, 
+                    int SectionFlags,
+                    DeclaratorDecl *TheDecl);
+  bool UnifySection(const StringRef &SectionName,
+                    int SectionFlags,
+                    SourceLocation PragmaSectionLocation);
+
+  /// \brief Called on well formed \#pragma bss_seg/data_seg/const_seg/code_seg.
+  void ActOnPragmaMSSeg(SourceLocation PragmaLocation,
+                        PragmaMsStackAction Action,
+                        llvm::StringRef StackSlotLabel,
+                        StringLiteral *SegmentName,
+                        llvm::StringRef PragmaName);
+
+  /// \brief Called on well formed \#pragma section().
+  void ActOnPragmaMSSection(SourceLocation PragmaLocation,
+                            int SectionFlags, StringLiteral *SegmentName);
+
   /// ActOnPragmaDetectMismatch - Call on well-formed \#pragma detect_mismatch
   void ActOnPragmaDetectMismatch(StringRef Name, StringRef Value);
 
index cef748f2aae5df2554e5254ae80aee91dd9df540..a04b33c6270f37bc1cfd097c907056aca617eab7 100644 (file)
@@ -2648,6 +2648,11 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
         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 33c1f0b628fb47b23e65589a7a41ef61644e8209..4b687a8b2e27ced2d10f12e91ccf373a52bdb7a2 100644 (file)
@@ -11,6 +11,7 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "RAIIObjectsForParser.h"
 #include "clang/Lex/Preprocessor.h"
 #include "clang/Parse/ParseDiagnostic.h"
 #include "clang/Parse/Parser.h"
@@ -124,8 +125,8 @@ struct PragmaMSVtorDisp : public PragmaHandler {
                     Token &FirstToken) override;
 };
 
-struct PragmaMSInitSeg : public PragmaHandler {
-  explicit PragmaMSInitSeg() : PragmaHandler("init_seg") {}
+struct PragmaMSPragma : public PragmaHandler {
+  explicit PragmaMSPragma(const char *name) : PragmaHandler(name) {}
   void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
                     Token &FirstToken) override;
 };
@@ -181,8 +182,18 @@ void Parser::initializePragmaHandlers() {
     PP.AddPragmaHandler(MSPointersToMembers.get());
     MSVtorDisp.reset(new PragmaMSVtorDisp());
     PP.AddPragmaHandler(MSVtorDisp.get());
-    MSInitSeg.reset(new PragmaMSInitSeg());
+    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());
   }
 }
 
@@ -224,6 +235,16 @@ void Parser::resetPragmaHandlers() {
     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());
@@ -410,6 +431,145 @@ void Parser::HandlePragmaMSVtorDisp() {
   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'
@@ -1214,12 +1374,31 @@ void PragmaMSVtorDisp::HandlePragma(Preprocessor &PP,
   PP.EnterToken(AnnotTok);
 }
 
-void PragmaMSInitSeg::HandlePragma(Preprocessor &PP,
-                                   PragmaIntroducerKind Introducer,
-                                   Token &Tok) {
-  unsigned ID = PP.getDiagnostics().getCustomDiagID(
-      DiagnosticsEngine::Error, "'#pragma init_seg' not implemented");
-  PP.Diag(Tok.getLocation(), ID);
+/// \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.
index 7254eb3c11733cd08471fae34f3b2377e5db27ac..0fbb764fde9eb76564aa7ba218abb33dc88fe1d8 100644 (file)
@@ -350,6 +350,10 @@ Retry:
     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 @@ void Parser::ParseCompoundStatementLeadingPragmas() {
     case tok::annot_pragma_ms_pointers_to_members:
       HandlePragmaMSPointersToMembers();
       break;
+    case tok::annot_pragma_ms_pragma:
+      HandlePragmaMSPragma();
+      break;
     default:
       checkForPragmas = false;
       break;
index 9936a5a3abfe4fe1edc9a20d9b3b56a7973ebac0..9d3f251a55a6fc720e9bb1000bcf675a37a8f33c 100644 (file)
@@ -631,6 +631,9 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
   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 3612bb962c96edd9febe606d826d21c03372ad75..a0d64ac2afd551815c44250408262e4f5d7a3c81 100644 (file)
@@ -79,7 +79,8 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
     MSPointerToMemberRepresentationMethod(
         LangOpts.getMSPointerToMemberRepresentationMethod()),
     VtorDispModeStack(1, MSVtorDispAttr::Mode(LangOpts.VtorDispMode)),
-    VisContext(0),
+    DataSegStack(nullptr), BSSSegStack(nullptr), ConstSegStack(nullptr),
+    CodeSegStack(nullptr), VisContext(0),
     IsBuildingRecoveryCallExpr(false),
     ExprNeedsCleanups(false), LateTemplateParser(0), OpaqueParser(0),
     IdResolver(pp), StdInitializerList(0), CXXTypeInfoDecl(0), MSVCGuidDecl(0),
index 2e344ff930637b62d138263d27a13263b4a10ed2..f5905842fd0f4cb21400175cab91915cbf669718 100644 (file)
@@ -325,6 +325,112 @@ void Sema::ActOnPragmaMSVtorDisp(PragmaVtorDispKind Kind,
   }
 }
 
+template<typename ValueType>
+void Sema::PragmaStack<ValueType>::Act(SourceLocation PragmaLocation,
+                                       PragmaMsStackAction Action,
+                                       llvm::StringRef StackSlotLabel,
+                                       ValueType Value) {
+  if (Action == PSK_Reset) {
+    CurrentValue = nullptr;
+    return;
+  }
+  if (Action & PSK_Push)
+    Stack.push_back(Slot(StackSlotLabel, CurrentValue, CurrentPragmaLocation));
+  else if (Action & PSK_Pop) {
+    if (!StackSlotLabel.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.StackSlotLabel == StackSlotLabel; });
+      // If we found the label so pop from there.
+      if (I != Stack.rend()) {
+        CurrentValue = I->Value;
+        CurrentPragmaLocation = I->PragmaLocation;
+        Stack.erase(std::prev(I.base()), Stack.end());
+      }
+    } else if (!Stack.empty()) {
+      // We don't have a label, just pop the last entry.
+      CurrentValue = Stack.back().Value;
+      CurrentPragmaLocation = Stack.back().PragmaLocation;
+      Stack.pop_back();
+    }
+  }
+  if (Action & PSK_Set) {
+    CurrentValue = Value;
+    CurrentPragmaLocation = PragmaLocation;
+  }
+}
+
+bool Sema::UnifySection(const StringRef &SectionName,
+                        int SectionFlags,
+                        DeclaratorDecl *Decl) {
+  auto Section = SectionInfos.find(SectionName);
+  if (Section == SectionInfos.end()) {
+    SectionInfos[SectionName] =
+        SectionInfo(Decl, SourceLocation(), SectionFlags);
+    return false;
+  }
+  // A pre-declared section takes precedence w/o diagnostic.
+  if (Section->second.SectionFlags == SectionFlags ||
+      !(Section->second.SectionFlags & PSF_Implicit))
+    return false;
+  auto OtherDecl = Section->second.Decl;
+  Diag(Decl->getLocation(), diag::err_section_conflict)
+      << Decl << OtherDecl;
+  Diag(OtherDecl->getLocation(), diag::note_declared_at)
+      << OtherDecl->getName();
+  if (auto A = Decl->getAttr<SectionAttr>())
+    if (A->isImplicit())
+      Diag(A->getLocation(), diag::note_pragma_entered_here);
+  if (auto A = OtherDecl->getAttr<SectionAttr>())
+    if (A->isImplicit())
+      Diag(A->getLocation(), diag::note_pragma_entered_here);
+  return false;
+}
+
+bool Sema::UnifySection(const StringRef &SectionName,
+                        int SectionFlags,
+                        SourceLocation PragmaSectionLocation) {
+  auto Section = SectionInfos.find(SectionName);
+  if (Section != SectionInfos.end()) {
+    if (Section->second.SectionFlags == SectionFlags)
+      return false;
+    if (!(Section->second.SectionFlags & PSF_Implicit)) {
+      Diag(PragmaSectionLocation, diag::err_section_conflict)
+          << "this" << "a prior #pragma section";
+      Diag(Section->second.PragmaSectionLocation,
+           diag::note_pragma_entered_here);
+      return true;
+    }
+  }
+  SectionInfos[SectionName] =
+      SectionInfo(nullptr, PragmaSectionLocation, SectionFlags);
+  return false;
+}
+
+/// \brief Called on well formed \#pragma bss_seg().
+void Sema::ActOnPragmaMSSeg(SourceLocation PragmaLocation,
+                            PragmaMsStackAction Action,
+                            llvm::StringRef StackSlotLabel,
+                            StringLiteral *SegmentName,
+                            llvm::StringRef PragmaName) {
+  PragmaStack<StringLiteral *> *Stack =
+    llvm::StringSwitch<PragmaStack<StringLiteral *> *>(PragmaName)
+        .Case("data_seg", &DataSegStack)
+        .Case("bss_seg", &BSSSegStack)
+        .Case("const_seg", &ConstSegStack)
+        .Case("code_seg", &CodeSegStack);
+  if (Action & PSK_Pop && Stack->Stack.empty())
+    Diag(PragmaLocation, diag::warn_pragma_pop_failed) << PragmaName
+        << "stack empty";
+  Stack->Act(PragmaLocation, Action, StackSlotLabel, SegmentName);
+}
+
+/// \brief Called on well formed \#pragma bss_seg().
+void Sema::ActOnPragmaMSSection(SourceLocation PragmaLocation,
+                                int SectionFlags, StringLiteral *SegmentName) {
+  UnifySection(SegmentName->getString(), SectionFlags, PragmaLocation);
+}
+
 void Sema::ActOnPragmaUnused(const Token &IdTok, Scope *curScope,
                              SourceLocation PragmaLoc) {
 
index 6a013a713810ff2a8c8708d5f4187a7a94d789a6..cc461ef14120b2f0e4173a645e21be647ea130ab 100644 (file)
@@ -7059,6 +7059,17 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
     NewFD->setInvalidDecl();
   }
 
+  if (D.isFunctionDefinition() && CodeSegStack.CurrentValue &&
+      !NewFD->hasAttr<SectionAttr>()) {
+    NewFD->addAttr(
+        SectionAttr::CreateImplicit(Context, SectionAttr::Declspec_allocate,
+                                    CodeSegStack.CurrentValue->getString(),
+                                    CodeSegStack.CurrentPragmaLocation));
+    if (UnifySection(CodeSegStack.CurrentValue->getString(),
+                     PSF_Implicit | PSF_Execute | PSF_Read, NewFD))
+      NewFD->dropAttr<SectionAttr>();
+  }
+
   // Handle attributes.
   ProcessDeclAttributes(S, NewFD, D);
 
@@ -8929,6 +8940,29 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
       Diag(var->getLocation(), diag::note_use_thread_local);
   }
 
+  if (var->isThisDeclarationADefinition() &&
+      ActiveTemplateInstantiations.empty()) {
+    PragmaStack<StringLiteral *> *Stack = nullptr;
+    int SectionFlags = PSF_Implicit | PSF_Read;
+    if (var->getType().isConstQualified())
+      Stack = &ConstSegStack;
+    else if (!var->getInit()) {
+      Stack = &BSSSegStack;
+      SectionFlags |= PSF_Write;
+    } else {
+      Stack = &DataSegStack;
+      SectionFlags |= PSF_Write;
+    }
+    if (!var->hasAttr<SectionAttr>() && Stack->CurrentValue)
+      var->addAttr(
+          SectionAttr::CreateImplicit(Context, SectionAttr::Declspec_allocate,
+                                      Stack->CurrentValue->getString(),
+                                      Stack->CurrentPragmaLocation));
+    if (const SectionAttr *SA = var->getAttr<SectionAttr>())
+      if (UnifySection(SA->getName(), SectionFlags, var))
+        var->dropAttr<SectionAttr>();
+  }
+
   // All the following checks are C++ only.
   if (!getLangOpts().CPlusPlus) return;
 
index 3f37efa7c172cc8d76964ad095288077f95c451f..75dc5cfd901fef78c273c2962c08b7171d3c1f67 100644 (file)
@@ -1969,8 +1969,9 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property,
         ObjCReturnsInnerPointerAttr::CreateImplicit(Context, Loc));
     
     if (const SectionAttr *SA = property->getAttr<SectionAttr>())
-      GetterMethod->addAttr(SectionAttr::CreateImplicit(Context, SA->getName(),
-                                                        Loc));
+      GetterMethod->addAttr(
+          SectionAttr::CreateImplicit(Context, SectionAttr::GNU_section,
+                                      SA->getName(), Loc));
 
     if (getLangOpts().ObjCAutoRefCount)
       CheckARCMethodDecl(GetterMethod);
@@ -2022,8 +2023,9 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property,
       if (lexicalDC)
         SetterMethod->setLexicalDeclContext(lexicalDC);
       if (const SectionAttr *SA = property->getAttr<SectionAttr>())
-        SetterMethod->addAttr(SectionAttr::CreateImplicit(Context,
-                                                          SA->getName(), Loc));
+        SetterMethod->addAttr(
+            SectionAttr::CreateImplicit(Context, SectionAttr::GNU_section,
+                                        SA->getName(), Loc));
       // It's possible for the user to have set a very odd custom
       // setter selector that causes it to have a method family.
       if (getLangOpts().ObjCAutoRefCount)
diff --git a/test/CodeGen/function-sections.c b/test/CodeGen/function-sections.c
new file mode 100644 (file)
index 0000000..7994acf
--- /dev/null
@@ -0,0 +1,28 @@
+// REQUIRES: x86-registered-target
+
+// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -S -o - < %s | FileCheck %s --check-prefix=PLAIN
+// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -S -ffunction-sections -fno-function-sections -o - < %s | FileCheck %s --check-prefix=PLAIN
+
+// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -S -ffunction-sections -o - < %s | FileCheck %s --check-prefix=FUNC_SECT
+// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -S -fno-function-sections -ffunction-sections -o - < %s | FileCheck %s --check-prefix=FUNC_SECT
+
+// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -S -fdata-sections -o - < %s | FileCheck %s --check-prefix=DATA_SECT
+// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -S -fno-data-sections -fdata-sections -o - < %s | FileCheck %s --check-prefix=DATA_SECT
+
+const int hello = 123;
+void world() {}
+
+// PLAIN-NOT: section
+// PLAIN: world:
+// PLAIN: section .rodata,
+// PLAIN: hello:
+
+// FUNC_SECT: section .text.world,
+// FUNC_SECT: world:
+// FUNC_SECT: section .rodata,
+// FUNC_SECT: hello:
+
+// DATA_SECT-NOT: section
+// DATA_SECT: world:
+// DATA_SECT: .section .rodata.hello,
+// DATA_SECT: hello:
index 7994acf4dcac13a37b5dd9ec0061854de447f9f4..6e44e77f5b17781063730854095f087be6d96dc3 100644 (file)
@@ -1,28 +1,51 @@
-// REQUIRES: x86-registered-target
+// RUN: %clang_cc1 -emit-llvm -fms-extensions -xc++ -o - < %s | FileCheck %s
 
-// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -S -o - < %s | FileCheck %s --check-prefix=PLAIN
-// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -S -ffunction-sections -fno-function-sections -o - < %s | FileCheck %s --check-prefix=PLAIN
+#ifdef __cplusplus
+extern "C" {
+#endif
+#pragma const_seg(".my_const")
+#pragma bss_seg(".my_bss")
+int D = 1;
+#pragma data_seg(".data")
+int a = 1;
+#pragma data_seg(push, label, ".data2")
+extern const int b;
+const int b = 1;
+const char* s = "my string!";
+#pragma data_seg(push, ".my_seg")
+int c = 1;
+#pragma data_seg(pop, label)
+int d = 1;
+int e;
+#pragma bss_seg(".c")
+int f;
+void g(void){}
+#pragma code_seg(".my_code")
+void h(void){}
+#pragma bss_seg()
+int i;
+#pragma bss_seg(".bss1")
+#pragma bss_seg(push, test, ".bss2")
+#pragma bss_seg()
+#pragma bss_seg()
+int TEST1;
+#pragma bss_seg(pop)
+int TEST2;
+#ifdef __cplusplus
+}
+#endif
 
-// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -S -ffunction-sections -o - < %s | FileCheck %s --check-prefix=FUNC_SECT
-// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -S -fno-function-sections -ffunction-sections -o - < %s | FileCheck %s --check-prefix=FUNC_SECT
-
-// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -S -fdata-sections -o - < %s | FileCheck %s --check-prefix=DATA_SECT
-// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -S -fno-data-sections -fdata-sections -o - < %s | FileCheck %s --check-prefix=DATA_SECT
-
-const int hello = 123;
-void world() {}
-
-// PLAIN-NOT: section
-// PLAIN: world:
-// PLAIN: section .rodata,
-// PLAIN: hello:
-
-// FUNC_SECT: section .text.world,
-// FUNC_SECT: world:
-// FUNC_SECT: section .rodata,
-// FUNC_SECT: hello:
-
-// DATA_SECT-NOT: section
-// DATA_SECT: world:
-// DATA_SECT: .section .rodata.hello,
-// DATA_SECT: hello:
+//CHECK: @D = global i32 1
+//CHECK: @a = global i32 1, section ".data"
+//CHECK: @b = constant i32 1, section ".my_const"
+//CHECK: @[[MYSTR:.*]] = linkonce_odr unnamed_addr constant [11 x i8] c"my string!\00"
+//CHECK: @s = global i8* getelementptr inbounds ([11 x i8]* @[[MYSTR]], i32 0, i32 0), section ".data2"
+//CHECK: @c = global i32 1, section ".my_seg"
+//CHECK: @d = global i32 1, section ".data"
+//CHECK: @e = global i32 0, section ".my_bss"
+//CHECK: @f = global i32 0, section ".c"
+//CHECK: @i = global i32 0
+//CHECK: @TEST1 = global i32 0
+//CHECK: @TEST2 = global i32 0, section ".bss1"
+//CHECK: define void @g()
+//CHECK: define void @h() {{.*}} section ".my_code"
diff --git a/test/Sema/pragma-section.c b/test/Sema/pragma-section.c
new file mode 100644 (file)
index 0000000..3b6147b
--- /dev/null
@@ -0,0 +1,42 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -fms-extensions %s
+
+#pragma const_seg(".my_const") // expected-note 2 {{#pragma entered here}}
+extern const int a;
+const int a = 1; // expected-note 2 {{declared here}}
+#pragma data_seg(".my_const") // expected-note {{#pragma entered here}}
+int b = 1; // expected-error {{'b' causes a section type conflict with 'a'}}
+#pragma data_seg()
+int c = 1;
+__declspec(allocate(".my_const")) int d = 1; // expected-error {{'d' causes a section type conflict with 'a'}}
+
+#pragma section(".my_seg", execute) // expected-note 2 {{#pragma entered her}}
+__declspec(allocate(".my_seg")) int int_my_seg;
+#pragma code_seg(".my_seg")
+void fn_my_seg(void){}
+
+__declspec(allocate(".bad_seg")) int int_bad_seg = 1; // expected-note {{declared here}}
+#pragma code_seg(".bad_seg") // expected-note {{#pragma entered here}}
+void fn_bad_seg(void){} // expected-error {{'fn_bad_seg' causes a section type conflict with 'int_bad_seg'}}
+
+#pragma bss_seg // expected-warning {{missing '(' after '#pragma bss_seg' - ignoring}}
+#pragma bss_seg(L".my_seg") // expected-warning {{expected push, pop or a string literal for the section name in '#pragma bss_seg' - ignored}}
+#pragma bss_seg(1) // expected-warning {{expected push, pop or a string literal for the section name in '#pragma bss_seg' - ignored}}
+#pragma bss_seg(push)
+#pragma bss_seg(push, ".my_seg")
+#pragma bss_seg(push, 1) // expected-warning {{expected a stack label or a string literal for the section name in '#pragma bss_seg'}}
+#pragma bss_seg ".my_seg" // expected-warning {{missing '(' after '#pragma bss_seg' - ignoring}}
+#pragma bss_seg(push, my_label, 1) // expected-warning {{expected a string literal for the section name in '#pragma bss_seg' - ignored}}
+#pragma bss_seg(".my_seg", 1) // expected-warning {{missing ')' after '#pragma bss_seg' - ignoring}}
+#pragma bss_seg(".my_seg" // expected-warning {{missing ')' after '#pragma bss_seg' - ignoring}}
+
+#pragma section // expected-warning {{missing '(' after '#pragma section' - ignoring}}
+#pragma section( // expected-warning {{expected a string literal for the section name in '#pragma section' - ignored}}
+#pragma section(L".my_seg") // expected-warning {{expected a string literal for the section name in '#pragma section' - ignored}}
+#pragma section(".my_seg" // expected-warning {{missing ')' after '#pragma section' - ignoring}}
+#pragma section(".my_seg" 1  // expected-warning {{missing ')' after '#pragma section' - ignoring}}
+#pragma section(".my_seg",  // expected-warning {{expected action or ')' in '#pragma section' - ignored}}
+#pragma section(".my_seg", read) // expected-error {{this causes a section type conflict with a prior #pragma section}}
+#pragma section(".my_seg", bogus) // expected-warning {{unknown action 'bogus' for '#pragma section' - ignored}}
+#pragma section(".my_seg", nopage) // expected-warning {{known but unsupported action 'nopage' for '#pragma section' - ignored}}
+#pragma section(".my_seg", read, write) // expected-error {{this causes a section type conflict with a prior #pragma section}}
+#pragma section(".my_seg", read, write, 1) //  expected-warning {{expected action or ')' in '#pragma section' - ignored}}