Skip to content

Commit 64144eb

Browse files
author
Erich Keane
committed
Add support for __declspec(code_seg("segname"))
Add support for __declspec(code_seg("segname")) This patch is built on the existing support for #pragma code_seg. The code_seg declspec is allowed on functions and classes. The attribute enables the placement of code into separate named segments, including compiler-generated members and template instantiations. For more information, please see the following: https://msdn.microsoft.com/en-us/library/dn636922.aspx A new CodeSeg attribute is used instead of adding a new spelling to the existing Section attribute since they don’t apply to the same Subjects. Section attributes are also added for the code_seg declspec since they are used for #pragma code_seg. No CodeSeg attributes are added to the AST. The patch is written to match with the Microsoft compiler’s behavior even where that behavior is a little complicated (see https://reviews.llvm.org/D22931, the Microsoft feedback page is no longer available since MS has removed the page). That code is in getImplicitSectionAttrFromClass routine. Diagnostics messages are added to match with the Microsoft compiler for code-seg attribute mismatches on base and derived classes and virtual overrides. Differential Revision: https://reviews.llvm.org/D43352 llvm-svn: 332470
1 parent 091069c commit 64144eb

File tree

8 files changed

+175
-13
lines changed

8 files changed

+175
-13
lines changed

clang/include/clang/Basic/Attr.td

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1769,6 +1769,13 @@ def Section : InheritableAttr {
17691769
let Documentation = [SectionDocs];
17701770
}
17711771

1772+
def CodeSeg : InheritableAttr {
1773+
let Spellings = [Declspec<"code_seg">];
1774+
let Args = [StringArgument<"Name">];
1775+
let Subjects = SubjectList<[Function, CXXRecord], ErrorDiag>;
1776+
let Documentation = [CodeSegDocs];
1777+
}
1778+
17721779
def PragmaClangBSSSection : InheritableAttr {
17731780
// This attribute has no spellings as it is only ever created implicitly.
17741781
let Spellings = [];

clang/include/clang/Basic/AttrDocs.td

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,18 @@ An example of how to use ``alloc_size``
306306
}];
307307
}
308308

309+
def CodeSegDocs : Documentation {
310+
let Category = DocCatFunction;
311+
let Content = [{
312+
The ``__declspec(code_seg)`` attribute enables the placement of code into separate
313+
named segments that can be paged or locked in memory individually. This attribute
314+
is used to control the placement of instantiated templates and compiler-generated
315+
code. See the documentation for `__declspec(code_seg)`_ on MSDN.
316+
317+
.. _`__declspec(code_seg)`: http://msdn.microsoft.com/en-us/library/dn636922.aspx
318+
}];
319+
}
320+
309321
def AllocAlignDocs : Documentation {
310322
let Category = DocCatFunction;
311323
let Content = [{

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2668,6 +2668,14 @@ def warn_mismatched_section : Warning<
26682668
def warn_attribute_section_on_redeclaration : Warning<
26692669
"section attribute is specified on redeclared variable">, InGroup<Section>;
26702670

2671+
def err_mismatched_code_seg_base : Error<
2672+
"derived class must specify the same code segment as its base classes">;
2673+
def err_mismatched_code_seg_override : Error<
2674+
"overriding virtual function must specify the same code segment as its overridden function">;
2675+
def err_conflicting_codeseg_attribute : Error<
2676+
"conflicting code segment specifiers">;
2677+
def warn_duplicate_codeseg_attribute : Warning<
2678+
"duplicate code segment specifiers">, InGroup<Section>;
26712679
def err_anonymous_property: Error<
26722680
"anonymous property is not supported">;
26732681
def err_property_is_variably_modified : Error<

clang/include/clang/Sema/Sema.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1934,6 +1934,7 @@ class Sema {
19341934
bool shouldLinkDependentDeclWithPrevious(Decl *D, Decl *OldDecl);
19351935
void CheckMain(FunctionDecl *FD, const DeclSpec &D);
19361936
void CheckMSVCRTEntryPoint(FunctionDecl *FD);
1937+
Attr *getImplicitSectionAttrForFunction(const FunctionDecl *FD, bool IsDefinition = true);
19371938
Decl *ActOnParamDeclarator(Scope *S, Declarator &D);
19381939
ParmVarDecl *BuildParmVarDeclForTypedef(DeclContext *DC,
19391940
SourceLocation Loc,
@@ -5836,6 +5837,7 @@ class Sema {
58365837
/// ensure that referenceDLLExportedClassMethods is called some point later
58375838
/// when all outer classes of Class are complete.
58385839
void checkClassLevelDLLAttribute(CXXRecordDecl *Class);
5840+
void checkClassLevelSectionAttribute(CXXRecordDecl *Class);
58395841

58405842
void referenceDLLExportedClassMethods();
58415843

clang/lib/Sema/SemaDecl.cpp

Lines changed: 76 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2667,9 +2667,14 @@ void Sema::mergeDeclAttributes(NamedDecl *New, Decl *Old,
26672667
Diag(New->getLocation(), diag::warn_attribute_section_on_redeclaration);
26682668
Diag(Old->getLocation(), diag::note_previous_declaration);
26692669
}
2670+
} else if (isa<CXXMethodDecl>(New)) {
2671+
const auto *NewSA = New->getAttr<SectionAttr>();
2672+
if (!NewSA->isImplicit()) {
2673+
Diag(New->getLocation(), diag::warn_mismatched_section);
2674+
Diag(Old->getLocation(), diag::note_previous_declaration);
2675+
}
26702676
}
26712677
}
2672-
26732678
if (!Old->hasAttrs())
26742679
return;
26752680

@@ -8716,18 +8721,18 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
87168721
PragmaClangTextSection.PragmaLocation));
87178722
}
87188723

8719-
// Apply an implicit SectionAttr if #pragma code_seg is active.
8720-
if (CodeSegStack.CurrentValue && D.isFunctionDefinition() &&
8721-
!NewFD->hasAttr<SectionAttr>()) {
8722-
NewFD->addAttr(
8723-
SectionAttr::CreateImplicit(Context, SectionAttr::Declspec_allocate,
8724-
CodeSegStack.CurrentValue->getString(),
8725-
CodeSegStack.CurrentPragmaLocation));
8726-
if (UnifySection(CodeSegStack.CurrentValue->getString(),
8727-
ASTContext::PSF_Implicit | ASTContext::PSF_Execute |
8728-
ASTContext::PSF_Read,
8729-
NewFD))
8730-
NewFD->dropAttr<SectionAttr>();
8724+
// Apply an implicit SectionAttr from class declspec or from
8725+
// #pragma code_seg if active.
8726+
if (!NewFD->hasAttr<SectionAttr>()) {
8727+
if (Attr *SAttr = getImplicitSectionAttrForFunction(NewFD,
8728+
D.isFunctionDefinition())) {
8729+
NewFD->addAttr(SAttr);
8730+
if (UnifySection(cast<SectionAttr>(SAttr)->getName(),
8731+
ASTContext::PSF_Implicit | ASTContext::PSF_Execute |
8732+
ASTContext::PSF_Read,
8733+
NewFD))
8734+
NewFD->dropAttr<SectionAttr>();
8735+
}
87318736
}
87328737

87338738
// Handle attributes.
@@ -9177,6 +9182,64 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
91779182
return NewFD;
91789183
}
91799184

9185+
/// Return a SectionAttr from a containing class. The Microsoft docs say
9186+
/// when __declspec(code_seg) "is applied to a class, all member functions of
9187+
/// the class and nested classes -- this includes compiler-generated special
9188+
/// member functions -- are put in the specified segment."
9189+
/// The actual behavior is a little more complicated. The Microsoft compiler
9190+
/// won't check outer classes if there is an active value from #pragma code_seg.
9191+
/// The section is always applied from the direct parent but only from outer
9192+
/// classes when the #pragma code_seg stack is empty. See:
9193+
/// https://reviews.llvm.org/D22931, the Microsoft feedback page is no longer
9194+
/// available since MS has removed the page.
9195+
static Attr *getImplicitSectionAttrFromClass(Sema &S, const FunctionDecl *FD) {
9196+
const auto *Method = dyn_cast<CXXMethodDecl>(FD);
9197+
if (!Method)
9198+
return nullptr;
9199+
const CXXRecordDecl *Parent = Method->getParent();
9200+
if (const auto *SAttr = Parent->getAttr<SectionAttr>()) {
9201+
Attr *NewAttr = SAttr->clone(S.getASTContext());
9202+
NewAttr->setImplicit(true);
9203+
return NewAttr;
9204+
}
9205+
9206+
// The Microsoft compiler won't check outer classes for the section
9207+
// when the #pragma code_seg stack is active.
9208+
if (S.CodeSegStack.CurrentValue)
9209+
return nullptr;
9210+
9211+
while ((Parent = dyn_cast<CXXRecordDecl>(Parent->getParent()))) {
9212+
if (const auto *SAttr = Parent->getAttr<SectionAttr>()) {
9213+
Attr *NewAttr = SAttr->clone(S.getASTContext());
9214+
NewAttr->setImplicit(true);
9215+
return NewAttr;
9216+
}
9217+
}
9218+
return nullptr;
9219+
}
9220+
9221+
/// \brief Returns an implicit SectionAttr for a function.
9222+
///
9223+
/// \param FD Function being declared.
9224+
/// \param IsDefinition Whether it is a definition or just a declarartion.
9225+
/// \returns A SectionAttr to apply to the function or nullptr if no
9226+
/// attribute should be added.
9227+
///
9228+
/// First tries to find a SectionAttr on a containing class (from
9229+
/// a __declspec(code_seg)). If not found on the class, and if the function is
9230+
/// also a definition it will use the current #pragma code_seg value.
9231+
Attr *Sema::getImplicitSectionAttrForFunction(const FunctionDecl *FD, bool IsDefinition) {
9232+
if (Attr *A = getImplicitSectionAttrFromClass(*this, FD))
9233+
return A;
9234+
if (IsDefinition && CodeSegStack.CurrentValue) {
9235+
return SectionAttr::CreateImplicit(getASTContext(),
9236+
SectionAttr::Declspec_allocate,
9237+
CodeSegStack.CurrentValue->getString(),
9238+
CodeSegStack.CurrentPragmaLocation);
9239+
}
9240+
return nullptr;
9241+
}
9242+
91809243
/// Checks if the new declaration declared in dependent context must be
91819244
/// put in the same redeclaration chain as the specified declaration.
91829245
///

clang/lib/Sema/SemaDeclAttr.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2853,6 +2853,13 @@ static void handleVecTypeHint(Sema &S, Decl *D, const AttributeList &AL) {
28532853
SectionAttr *Sema::mergeSectionAttr(Decl *D, SourceRange Range,
28542854
StringRef Name,
28552855
unsigned AttrSpellingListIndex) {
2856+
// Explicit or partial specializations do not inherit
2857+
// the code_seg attribute from the primary template.
2858+
if (const auto *FD = dyn_cast<FunctionDecl>(D)){
2859+
if (FD->isFunctionTemplateSpecialization())
2860+
return nullptr;
2861+
}
2862+
28562863
if (SectionAttr *ExistingAttr = D->getAttr<SectionAttr>()) {
28572864
if (ExistingAttr->getName() == Name)
28582865
return nullptr;
@@ -2942,6 +2949,27 @@ static void handleTargetAttr(Sema &S, Decl *D, const AttributeList &AL) {
29422949
D->addAttr(NewAttr);
29432950
}
29442951

2952+
static void handleCodeSegAttr(Sema &S, Decl *D, const AttributeList &AL) {
2953+
StringRef Str;
2954+
SourceLocation LiteralLoc;
2955+
if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &LiteralLoc))
2956+
return;
2957+
if (!S.checkSectionName(LiteralLoc, Str))
2958+
return;
2959+
if (const auto *ExistingAttr = D->getAttr<SectionAttr>()) {
2960+
if (!ExistingAttr->isImplicit()) {
2961+
S.Diag(AL.getLoc(),
2962+
ExistingAttr->getName() == Str
2963+
? diag::warn_duplicate_codeseg_attribute
2964+
: diag::err_conflicting_codeseg_attribute);
2965+
return;
2966+
}
2967+
D->dropAttr<SectionAttr>();
2968+
}
2969+
D->addAttr(::new (S.Context) SectionAttr(
2970+
AL.getRange(), S.Context, Str, AL.getAttributeSpellingListIndex()));
2971+
}
2972+
29452973
static void handleCleanupAttr(Sema &S, Decl *D, const AttributeList &AL) {
29462974
Expr *E = AL.getArgAsExpr(0);
29472975
SourceLocation Loc = E->getExprLoc();
@@ -6297,6 +6325,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
62976325
case AttributeList::AT_Uuid:
62986326
handleUuidAttr(S, D, AL);
62996327
break;
6328+
case AttributeList::AT_CodeSeg:
6329+
handleCodeSegAttr(S, D, AL);
6330+
break;
63006331
case AttributeList::AT_MSInheritance:
63016332
handleMSInheritanceAttr(S, D, AL);
63026333
break;

clang/lib/Sema/SemaDeclCXX.cpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2231,6 +2231,20 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class,
22312231
CXXRecordDecl *CXXBaseDecl = cast<CXXRecordDecl>(BaseDecl);
22322232
assert(CXXBaseDecl && "Base type is not a C++ type");
22332233

2234+
// Microsoft docs say:
2235+
// "If a base-class has a code_seg attribute, derived classes must have the
2236+
// same attribute."
2237+
const auto *BaseSA = CXXBaseDecl->getAttr<SectionAttr>();
2238+
const auto *DerivedSA = Class->getAttr<SectionAttr>();
2239+
if (BaseSA || DerivedSA) {
2240+
if (!BaseSA || !DerivedSA || BaseSA->getName() != DerivedSA->getName()) {
2241+
Diag(Class->getLocation(), diag::err_mismatched_code_seg_base);
2242+
Diag(CXXBaseDecl->getLocation(), diag::note_base_class_specified_here)
2243+
<< CXXBaseDecl;
2244+
return nullptr;
2245+
}
2246+
}
2247+
22342248
// A class which contains a flexible array member is not suitable for use as a
22352249
// base class:
22362250
// - If the layout determines that a base comes before another base,
@@ -5576,6 +5590,16 @@ static void checkForMultipleExportedDefaultConstructors(Sema &S,
55765590
}
55775591
}
55785592

5593+
void Sema::checkClassLevelSectionAttribute(CXXRecordDecl *Class) {
5594+
// Mark any compiler-generated routines with the implicit Section attribute.
5595+
for (auto *Method : Class->methods()) {
5596+
if (Method->isUserProvided())
5597+
continue;
5598+
if (Attr *A = getImplicitSectionAttrForFunction(Method))
5599+
Method->addAttr(A);
5600+
}
5601+
}
5602+
55795603
/// Check class-level dllimport/dllexport attribute.
55805604
void Sema::checkClassLevelDLLAttribute(CXXRecordDecl *Class) {
55815605
Attr *ClassAttr = getDLLAttr(Class);
@@ -6079,6 +6103,7 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
60796103
}
60806104

60816105
checkClassLevelDLLAttribute(Record);
6106+
checkClassLevelSectionAttribute(Record);
60826107

60836108
bool ClangABICompat4 =
60846109
Context.getLangOpts().getClangABICompat() <= LangOptions::ClangABI::Ver4;
@@ -14531,6 +14556,16 @@ bool Sema::CheckOverridingFunctionAttributes(const CXXMethodDecl *New,
1453114556
diag::note_overridden_marked_noescape);
1453214557
}
1453314558
}
14559+
// Virtual overrides must have the same code_seg.
14560+
const auto *OldSA = Old->getAttr<SectionAttr>();
14561+
const auto *NewSA = New->getAttr<SectionAttr>();
14562+
if (OldSA || NewSA) {
14563+
if (!OldSA || !NewSA || NewSA->getName() != OldSA->getName()) {
14564+
Diag(New->getLocation(), diag::err_mismatched_code_seg_override);
14565+
Diag(Old->getLocation(), diag::note_previous_declaration);
14566+
return true;
14567+
}
14568+
}
1453414569

1453514570
CallingConv NewCC = NewFT->getCallConv(), OldCC = OldFT->getCallConv();
1453614571

clang/lib/Sema/SemaLambda.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -910,6 +910,10 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
910910
AddRangeBasedOptnone(Method);
911911

912912
// Attributes on the lambda apply to the method.
913+
if (Attr *A = getImplicitSectionAttrForFunction(Method))
914+
Method->addAttr(A);
915+
916+
// Attributes on the lambda apply to the method.
913917
ProcessDeclAttributes(CurScope, Method, ParamInfo);
914918

915919
// CUDA lambdas get implicit attributes based on the scope in which they're

0 commit comments

Comments
 (0)