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 = []; 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
; +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
; def err_anonymous_property: Error< "anonymous property is not supported">; def err_property_is_variably_modified : Error< 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: 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(New)) { + const auto *NewSA = New->getAttr(); + 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()) { - 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(); + // Apply an implicit SectionAttr from class declspec or from + // #pragma code_seg if active. + if (!NewFD->hasAttr()) { + if (Attr *SAttr = getImplicitSectionAttrForFunction(NewFD, + D.isFunctionDefinition())) { + NewFD->addAttr(SAttr); + if (UnifySection(cast(SAttr)->getName(), + ASTContext::PSF_Implicit | ASTContext::PSF_Execute | + ASTContext::PSF_Read, + NewFD)) + NewFD->dropAttr(); + } } // 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(FD); + if (!Method) + return nullptr; + const CXXRecordDecl *Parent = Method->getParent(); + if (const auto *SAttr = Parent->getAttr()) { + 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(Parent->getParent()))) { + if (const auto *SAttr = Parent->getAttr()) { + 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(D)){ + if (FD->isFunctionTemplateSpecialization()) + return nullptr; + } + if (SectionAttr *ExistingAttr = D->getAttr()) { 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()) { + if (!ExistingAttr->isImplicit()) { + S.Diag(AL.getLoc(), + ExistingAttr->getName() == Str + ? diag::warn_duplicate_codeseg_attribute + : diag::err_conflicting_codeseg_attribute); + return; + } + D->dropAttr(); + } + 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: lib/Sema/SemaDeclCXX.cpp =================================================================== --- lib/Sema/SemaDeclCXX.cpp +++ lib/Sema/SemaDeclCXX.cpp @@ -2231,6 +2231,20 @@ CXXRecordDecl *CXXBaseDecl = cast(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(); + const auto *DerivedSA = Class->getAttr(); + 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(); + const auto *NewSA = New->getAttr(); + 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