This revision was automatically updated to reflect the committed changes.
Closed by commit rC332470: Add support for 
__declspec(code_seg("segname")) (authored by erichkeane, committed by 
).
Herald added a subscriber: cfe-commits.

Changed prior to commit:
  https://reviews.llvm.org/D43352?vs=147075&id=147081#toc

Repository:
  rC Clang

https://reviews.llvm.org/D43352

Files:
  include/clang/Basic/Attr.td
  include/clang/Basic/AttrDocs.td
  include/clang/Basic/DiagnosticSemaKinds.td
  include/clang/Sema/Sema.h
  lib/Sema/SemaDecl.cpp
  lib/Sema/SemaDeclAttr.cpp
  lib/Sema/SemaDeclCXX.cpp
  lib/Sema/SemaLambda.cpp

Index: lib/Sema/SemaDeclCXX.cpp
===================================================================
--- lib/Sema/SemaDeclCXX.cpp
+++ lib/Sema/SemaDeclCXX.cpp
@@ -2231,6 +2231,20 @@
   CXXRecordDecl *CXXBaseDecl = cast<CXXRecordDecl>(BaseDecl);
   assert(CXXBaseDecl && "Base type is not a C++ type");
 
+  // Microsoft docs say:
+  // "If a base-class has a code_seg attribute, derived classes must have the
+  // same attribute."
+   const auto *BaseSA = CXXBaseDecl->getAttr<SectionAttr>();
+   const auto *DerivedSA = Class->getAttr<SectionAttr>();
+   if (BaseSA || DerivedSA) {
+     if (!BaseSA || !DerivedSA || BaseSA->getName() != DerivedSA->getName()) {
+       Diag(Class->getLocation(), diag::err_mismatched_code_seg_base);
+       Diag(CXXBaseDecl->getLocation(), diag::note_base_class_specified_here)
+         << CXXBaseDecl;
+       return nullptr;
+     }
+   }
+
   // A class which contains a flexible array member is not suitable for use as a
   // base class:
   //   - If the layout determines that a base comes before another base,
@@ -5576,6 +5590,16 @@
   }
 }
 
+void Sema::checkClassLevelSectionAttribute(CXXRecordDecl *Class) {
+  // Mark any compiler-generated routines with the implicit Section attribute.
+  for (auto *Method : Class->methods()) {
+    if (Method->isUserProvided())
+      continue;
+    if (Attr *A = getImplicitSectionAttrForFunction(Method))
+      Method->addAttr(A);
+  }
+}
+
 /// Check class-level dllimport/dllexport attribute.
 void Sema::checkClassLevelDLLAttribute(CXXRecordDecl *Class) {
   Attr *ClassAttr = getDLLAttr(Class);
@@ -6079,6 +6103,7 @@
   }
 
   checkClassLevelDLLAttribute(Record);
+  checkClassLevelSectionAttribute(Record);
 
   bool ClangABICompat4 =
       Context.getLangOpts().getClangABICompat() <= LangOptions::ClangABI::Ver4;
@@ -14531,6 +14556,16 @@
              diag::note_overridden_marked_noescape);
       }
   }
+  // Virtual overrides must have the same code_seg.
+  const auto *OldSA = Old->getAttr<SectionAttr>();
+  const auto *NewSA = New->getAttr<SectionAttr>();
+  if (OldSA || NewSA) {
+    if (!OldSA || !NewSA || NewSA->getName() != OldSA->getName()) {
+      Diag(New->getLocation(), diag::err_mismatched_code_seg_override);
+      Diag(Old->getLocation(), diag::note_previous_declaration);
+      return true;
+    }
+  }
 
   CallingConv NewCC = NewFT->getCallConv(), OldCC = OldFT->getCallConv();
 
Index: lib/Sema/SemaLambda.cpp
===================================================================
--- lib/Sema/SemaLambda.cpp
+++ lib/Sema/SemaLambda.cpp
@@ -910,6 +910,10 @@
   AddRangeBasedOptnone(Method);
   
   // Attributes on the lambda apply to the method.  
+  if (Attr *A = getImplicitSectionAttrForFunction(Method))
+    Method->addAttr(A);
+  
+  // Attributes on the lambda apply to the method.
   ProcessDeclAttributes(CurScope, Method, ParamInfo);
 
   // CUDA lambdas get implicit attributes based on the scope in which they're
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -2667,9 +2667,14 @@
         Diag(New->getLocation(), diag::warn_attribute_section_on_redeclaration);
         Diag(Old->getLocation(), diag::note_previous_declaration);
       }
+    } else if (isa<CXXMethodDecl>(New)) {
+      const auto *NewSA = New->getAttr<SectionAttr>();
+      if (!NewSA->isImplicit()) {
+        Diag(New->getLocation(), diag::warn_mismatched_section);
+        Diag(Old->getLocation(), diag::note_previous_declaration);
+      }
     }
   }
-
   if (!Old->hasAttrs())
     return;
 
@@ -8716,18 +8721,18 @@
                                                  PragmaClangTextSection.PragmaLocation));
   }
 
-  // Apply an implicit SectionAttr if #pragma code_seg is active.
-  if (CodeSegStack.CurrentValue && D.isFunctionDefinition() &&
-      !NewFD->hasAttr<SectionAttr>()) {
-    NewFD->addAttr(
-        SectionAttr::CreateImplicit(Context, SectionAttr::Declspec_allocate,
-                                    CodeSegStack.CurrentValue->getString(),
-                                    CodeSegStack.CurrentPragmaLocation));
-    if (UnifySection(CodeSegStack.CurrentValue->getString(),
-                     ASTContext::PSF_Implicit | ASTContext::PSF_Execute |
-                         ASTContext::PSF_Read,
-                     NewFD))
-      NewFD->dropAttr<SectionAttr>();
+  // Apply an implicit SectionAttr from class declspec or from
+  // #pragma code_seg if active.
+  if (!NewFD->hasAttr<SectionAttr>()) {
+    if (Attr *SAttr = getImplicitSectionAttrForFunction(NewFD,
+                                                        D.isFunctionDefinition())) {
+      NewFD->addAttr(SAttr);
+      if (UnifySection(cast<SectionAttr>(SAttr)->getName(),
+                       ASTContext::PSF_Implicit | ASTContext::PSF_Execute |
+                       ASTContext::PSF_Read,
+                       NewFD))
+        NewFD->dropAttr<SectionAttr>();
+    }
   }
 
   // Handle attributes.
@@ -9177,6 +9182,64 @@
   return NewFD;
 }
 
+/// Return a SectionAttr from a containing class.  The Microsoft docs say
+/// when __declspec(code_seg) "is applied to a class, all member functions of
+/// the class and nested classes -- this includes compiler-generated special
+/// member functions -- are put in the specified segment."
+/// The actual behavior is a little more complicated. The Microsoft compiler
+/// won't check outer classes if there is an active value from #pragma code_seg.
+/// The section is always applied from the direct parent but only from outer
+/// classes when the #pragma code_seg stack is empty. See:
+/// https://reviews.llvm.org/D22931, the Microsoft feedback page is no longer
+/// available since MS has removed the page.
+static Attr *getImplicitSectionAttrFromClass(Sema &S, const FunctionDecl *FD) {
+  const auto *Method = dyn_cast<CXXMethodDecl>(FD);
+  if (!Method)
+    return nullptr;
+  const CXXRecordDecl *Parent = Method->getParent();
+  if (const auto *SAttr = Parent->getAttr<SectionAttr>()) {
+    Attr *NewAttr = SAttr->clone(S.getASTContext());
+    NewAttr->setImplicit(true);
+    return NewAttr;
+  }
+
+  // The Microsoft compiler won't check outer classes for the section
+  // when the #pragma code_seg stack is active.
+  if (S.CodeSegStack.CurrentValue)
+    return nullptr;
+
+  while ((Parent = dyn_cast<CXXRecordDecl>(Parent->getParent()))) {
+    if (const auto *SAttr = Parent->getAttr<SectionAttr>()) {
+      Attr *NewAttr = SAttr->clone(S.getASTContext());
+      NewAttr->setImplicit(true);
+      return NewAttr;
+    }
+  }
+  return nullptr;
+}
+
+/// \brief Returns an implicit SectionAttr for a function.
+///
+/// \param FD Function being declared.
+/// \param IsDefinition Whether it is a definition or just a declarartion.
+/// \returns A SectionAttr to apply to the function or nullptr if no
+///          attribute should be added.
+///
+/// First tries to find a SectionAttr on a containing class (from
+/// a __declspec(code_seg)).  If not found on the class, and if the function is
+/// also a definition it will use the current #pragma code_seg value.
+Attr *Sema::getImplicitSectionAttrForFunction(const FunctionDecl *FD, bool IsDefinition) {
+  if (Attr *A = getImplicitSectionAttrFromClass(*this, FD))
+    return A;
+  if (IsDefinition && CodeSegStack.CurrentValue) {
+    return SectionAttr::CreateImplicit(getASTContext(),
+                                       SectionAttr::Declspec_allocate,
+                                       CodeSegStack.CurrentValue->getString(),
+                                       CodeSegStack.CurrentPragmaLocation);
+  }
+  return nullptr;
+}
+
 /// Checks if the new declaration declared in dependent context must be
 /// put in the same redeclaration chain as the specified declaration.
 ///
Index: lib/Sema/SemaDeclAttr.cpp
===================================================================
--- lib/Sema/SemaDeclAttr.cpp
+++ lib/Sema/SemaDeclAttr.cpp
@@ -2853,6 +2853,13 @@
 SectionAttr *Sema::mergeSectionAttr(Decl *D, SourceRange Range,
                                     StringRef Name,
                                     unsigned AttrSpellingListIndex) {
+  // Explicit or partial specializations do not inherit
+  // the code_seg attribute from the primary template.
+  if (const auto *FD = dyn_cast<FunctionDecl>(D)){
+    if (FD->isFunctionTemplateSpecialization())
+      return nullptr;
+  }
+
   if (SectionAttr *ExistingAttr = D->getAttr<SectionAttr>()) {
     if (ExistingAttr->getName() == Name)
       return nullptr;
@@ -2942,6 +2949,27 @@
   D->addAttr(NewAttr);
 }
 
+static void handleCodeSegAttr(Sema &S, Decl *D, const AttributeList &AL) {
+  StringRef Str;
+  SourceLocation LiteralLoc;
+  if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &LiteralLoc))
+    return;
+  if (!S.checkSectionName(LiteralLoc, Str))
+    return;
+  if (const auto *ExistingAttr = D->getAttr<SectionAttr>()) {
+    if (!ExistingAttr->isImplicit()) {
+      S.Diag(AL.getLoc(), 
+             ExistingAttr->getName() == Str 
+             ? diag::warn_duplicate_codeseg_attribute
+             : diag::err_conflicting_codeseg_attribute);	    
+      return;
+    }
+    D->dropAttr<SectionAttr>();
+  }
+  D->addAttr(::new (S.Context) SectionAttr(
+      AL.getRange(), S.Context, Str, AL.getAttributeSpellingListIndex()));
+}
+
 static void handleCleanupAttr(Sema &S, Decl *D, const AttributeList &AL) {
   Expr *E = AL.getArgAsExpr(0);
   SourceLocation Loc = E->getExprLoc();
@@ -6297,6 +6325,9 @@
   case AttributeList::AT_Uuid:
     handleUuidAttr(S, D, AL);
     break;
+  case AttributeList::AT_CodeSeg:
+    handleCodeSegAttr(S, D, AL);
+    break;
   case AttributeList::AT_MSInheritance:
     handleMSInheritanceAttr(S, D, AL);
     break;
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -1934,6 +1934,7 @@
   bool shouldLinkDependentDeclWithPrevious(Decl *D, Decl *OldDecl);
   void CheckMain(FunctionDecl *FD, const DeclSpec &D);
   void CheckMSVCRTEntryPoint(FunctionDecl *FD);
+  Attr *getImplicitSectionAttrForFunction(const FunctionDecl *FD, bool IsDefinition = true);
   Decl *ActOnParamDeclarator(Scope *S, Declarator &D);
   ParmVarDecl *BuildParmVarDeclForTypedef(DeclContext *DC,
                                           SourceLocation Loc,
@@ -5836,6 +5837,7 @@
   /// ensure that referenceDLLExportedClassMethods is called some point later
   /// when all outer classes of Class are complete.
   void checkClassLevelDLLAttribute(CXXRecordDecl *Class);
+  void checkClassLevelSectionAttribute(CXXRecordDecl *Class);
 
   void referenceDLLExportedClassMethods();
 
Index: include/clang/Basic/AttrDocs.td
===================================================================
--- include/clang/Basic/AttrDocs.td
+++ include/clang/Basic/AttrDocs.td
@@ -306,6 +306,18 @@
   }];
 }
 
+def CodeSegDocs : Documentation {
+  let Category = DocCatFunction;
+  let Content = [{
+The ``__declspec(code_seg)`` attribute enables the placement of code into separate
+named segments that can be paged or locked in memory individually. This attribute
+is used to control the placement of instantiated templates and compiler-generated
+code. See the documentation for `__declspec(code_seg)`_ on MSDN.
+
+.. _`__declspec(code_seg)`: http://msdn.microsoft.com/en-us/library/dn636922.aspx
+  }];
+}
+
 def AllocAlignDocs : Documentation {
   let Category = DocCatFunction;
   let Content = [{
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -2668,6 +2668,14 @@
 def warn_attribute_section_on_redeclaration : Warning<
   "section attribute is specified on redeclared variable">, InGroup<Section>;
 
+def err_mismatched_code_seg_base : Error<
+  "derived class must specify the same code segment as its base classes">;
+def err_mismatched_code_seg_override : Error<
+  "overriding virtual function must specify the same code segment as its overridden function">;
+def err_conflicting_codeseg_attribute : Error<
+  "conflicting code segment specifiers">;
+def warn_duplicate_codeseg_attribute : Warning<
+  "duplicate code segment specifiers">, InGroup<Section>;
 def err_anonymous_property: Error<
   "anonymous property is not supported">;
 def err_property_is_variably_modified : Error<
Index: include/clang/Basic/Attr.td
===================================================================
--- include/clang/Basic/Attr.td
+++ include/clang/Basic/Attr.td
@@ -1769,6 +1769,13 @@
   let Documentation = [SectionDocs];
 }
 
+def CodeSeg : InheritableAttr {
+  let Spellings = [Declspec<"code_seg">];
+  let Args = [StringArgument<"Name">];
+  let Subjects = SubjectList<[Function, CXXRecord], ErrorDiag>;
+  let Documentation = [CodeSegDocs];
+}
+
 def PragmaClangBSSSection : InheritableAttr {
   // This attribute has no spellings as it is only ever created implicitly.
   let Spellings = [];
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D43352: Add support fo... Erich Keane via Phabricator via cfe-commits

Reply via email to