Add support for __declspec(code_seg("segname"))

This patch uses CodeSegAttr to represent __declspec(code_seg) rather than 
building on the existing support for #pragma code_seg.
The code_seg declspec is applied on functions and classes. This attribute 
enables the placement of code into separate named segments, including compiler-
generated codes and template instantiations.

For more information, please see the following:
https://msdn.microsoft.com/en-us/library/dn636922.aspx

This patch fixes the regression for the support for attribute ((section).
746b78de78

Patch by Soumi Manna (Manna)
Differential Revision: https://reviews.llvm.org/D48841



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@337420 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Erich Keane 2018-07-18 20:04:48 +00:00
parent 0e4f59d7b4
commit 1a78aeb17c
15 changed files with 829 additions and 8 deletions

View File

@ -1770,6 +1770,13 @@ def Section : InheritableAttr {
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 = [];

View File

@ -306,6 +306,18 @@ An example of how to use ``alloc_size``
}];
}
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 = [{

View File

@ -2668,11 +2668,19 @@ def err_only_annotate_after_access_spec : Error<
"access specifier can only have annotation attributes">;
def err_attribute_section_invalid_for_target : Error<
"argument to 'section' attribute is not valid for this target: %0">;
"argument to %select{'code_seg'|'section'}1 attribute is not valid for this target: %0">;
def warn_mismatched_section : Warning<
"section does not match previous declaration">, InGroup<Section>;
"%select{codeseg|section}0 does not match previous declaration">, InGroup<Section>;
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">;

View File

@ -1952,6 +1952,7 @@ public:
bool shouldLinkDependentDeclWithPrevious(Decl *D, Decl *OldDecl);
void CheckMain(FunctionDecl *FD, const DeclSpec &D);
void CheckMSVCRTEntryPoint(FunctionDecl *FD);
Attr *getImplicitCodeSegOrSectionAttrForFunction(const FunctionDecl *FD, bool IsDefinition);
Decl *ActOnParamDeclarator(Scope *S, Declarator &D);
ParmVarDecl *BuildParmVarDeclForTypedef(DeclContext *DC,
SourceLocation Loc,
@ -2446,6 +2447,8 @@ public:
int FirstArg, unsigned AttrSpellingListIndex);
SectionAttr *mergeSectionAttr(Decl *D, SourceRange Range, StringRef Name,
unsigned AttrSpellingListIndex);
CodeSegAttr *mergeCodeSegAttr(Decl *D, SourceRange Range, StringRef Name,
unsigned AttrSpellingListIndex);
AlwaysInlineAttr *mergeAlwaysInlineAttr(Decl *D, SourceRange Range,
IdentifierInfo *Ident,
unsigned AttrSpellingListIndex);
@ -5852,6 +5855,7 @@ public:
/// ensure that referenceDLLExportedClassMethods is called some point later
/// when all outer classes of Class are complete.
void checkClassLevelDLLAttribute(CXXRecordDecl *Class);
void checkClassLevelCodeSegAttribute(CXXRecordDecl *Class);
void referenceDLLExportedClassMethods();

View File

@ -1387,8 +1387,10 @@ void CodeGenModule::setNonAliasAttributes(GlobalDecl GD,
F->addAttributes(llvm::AttributeList::FunctionIndex, Attrs);
}
}
if (const SectionAttr *SA = D->getAttr<SectionAttr>())
if (const auto *CSA = D->getAttr<CodeSegAttr>())
GO->setSection(CSA->getName());
else if (const auto *SA = D->getAttr<SectionAttr>())
GO->setSection(SA->getName());
}
@ -1485,8 +1487,10 @@ void CodeGenModule::SetFunctionAttributes(GlobalDecl GD, llvm::Function *F,
setLinkageForGV(F, FD);
setGVProperties(F, FD);
if (const SectionAttr *SA = FD->getAttr<SectionAttr>())
F->setSection(SA->getName());
if (const auto *CSA = FD->getAttr<CodeSegAttr>())
F->setSection(CSA->getName());
else if (const auto *SA = FD->getAttr<SectionAttr>())
F->setSection(SA->getName());
if (FD->isReplaceableGlobalAllocationFunction()) {
// A replaceable global allocation function does not act like a builtin by

View File

@ -2452,6 +2452,9 @@ static bool mergeDeclAttribute(Sema &S, NamedDecl *D,
else if (const auto *SA = dyn_cast<SectionAttr>(Attr))
NewAttr = S.mergeSectionAttr(D, SA->getRange(), SA->getName(),
AttrSpellingListIndex);
else if (const auto *CSA = dyn_cast<CodeSegAttr>(Attr))
NewAttr = S.mergeCodeSegAttr(D, CSA->getRange(), CSA->getName(),
AttrSpellingListIndex);
else if (const auto *IA = dyn_cast<MSInheritanceAttr>(Attr))
NewAttr = S.mergeMSInheritanceAttr(D, IA->getRange(), IA->getBestCase(),
AttrSpellingListIndex,
@ -2670,6 +2673,15 @@ void Sema::mergeDeclAttributes(NamedDecl *New, Decl *Old,
}
}
// Redeclaration adds code-seg attribute.
const auto *NewCSA = New->getAttr<CodeSegAttr>();
if (NewCSA && !Old->hasAttr<CodeSegAttr>() &&
!NewCSA->isImplicit() && isa<CXXMethodDecl>(New)) {
Diag(New->getLocation(), diag::warn_mismatched_section)
<< 0 /*codeseg*/;
Diag(Old->getLocation(), diag::note_previous_declaration);
}
if (!Old->hasAttrs())
return;
@ -8723,6 +8735,15 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
NewFD->dropAttr<SectionAttr>();
}
// Apply an implicit CodeSegAttr from class declspec or
// apply an implicit SectionAttr from #pragma code_seg if active.
if (!NewFD->hasAttr<CodeSegAttr>()) {
if (Attr *SAttr = getImplicitCodeSegOrSectionAttrForFunction(NewFD,
D.isFunctionDefinition())) {
NewFD->addAttr(SAttr);
}
}
// Handle attributes.
ProcessDeclAttributes(S, NewFD, D);
@ -9170,6 +9191,64 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
return NewFD;
}
/// Return a CodeSegAttr 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 CodeSeg 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 *getImplicitCodeSegAttrFromClass(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<CodeSegAttr>()) {
Attr *NewAttr = SAttr->clone(S.getASTContext());
NewAttr->setImplicit(true);
return NewAttr;
}
// The Microsoft compiler won't check outer classes for the CodeSeg
// 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<CodeSegAttr>()) {
Attr *NewAttr = SAttr->clone(S.getASTContext());
NewAttr->setImplicit(true);
return NewAttr;
}
}
return nullptr;
}
/// Returns an implicit CodeSegAttr if a __declspec(code_seg) is found on a
/// containing class. Otherwise it will return implicit SectionAttr if the
/// function is a definition and there is an active value on CodeSegStack
/// (from the current #pragma code-seg value).
///
/// \param FD Function being declared.
/// \param IsDefinition Whether it is a definition or just a declarartion.
/// \returns A CodeSegAttr or SectionAttr to apply to the function or
/// nullptr if no attribute should be added.
Attr *Sema::getImplicitCodeSegOrSectionAttrForFunction(const FunctionDecl *FD,
bool IsDefinition) {
if (Attr *A = getImplicitCodeSegAttrFromClass(*this, FD))
return A;
if (!FD->hasAttr<SectionAttr>() && 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.
///

View File

@ -2825,10 +2825,18 @@ static void handleVecTypeHint(Sema &S, Decl *D, const ParsedAttr &AL) {
SectionAttr *Sema::mergeSectionAttr(Decl *D, SourceRange Range,
StringRef Name,
unsigned AttrSpellingListIndex) {
// Explicit or partial specializations do not inherit
// the section attribute from the primary template.
if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
if (AttrSpellingListIndex == SectionAttr::Declspec_allocate &&
FD->isFunctionTemplateSpecialization())
return nullptr;
}
if (SectionAttr *ExistingAttr = D->getAttr<SectionAttr>()) {
if (ExistingAttr->getName() == Name)
return nullptr;
Diag(ExistingAttr->getLocation(), diag::warn_mismatched_section);
Diag(ExistingAttr->getLocation(), diag::warn_mismatched_section)
<< 1 /*section*/;
Diag(Range.getBegin(), diag::note_previous_attribute);
return nullptr;
}
@ -2839,7 +2847,8 @@ SectionAttr *Sema::mergeSectionAttr(Decl *D, SourceRange Range,
bool Sema::checkSectionName(SourceLocation LiteralLoc, StringRef SecName) {
std::string Error = Context.getTargetInfo().isValidSectionSpecifier(SecName);
if (!Error.empty()) {
Diag(LiteralLoc, diag::err_attribute_section_invalid_for_target) << Error;
Diag(LiteralLoc, diag::err_attribute_section_invalid_for_target) << Error
<< 1 /*'section'*/;
return false;
}
return true;
@ -2870,6 +2879,59 @@ static void handleSectionAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
D->addAttr(NewAttr);
}
static bool checkCodeSegName(Sema&S, SourceLocation LiteralLoc, StringRef CodeSegName) {
std::string Error = S.Context.getTargetInfo().isValidSectionSpecifier(CodeSegName);
if (!Error.empty()) {
S.Diag(LiteralLoc, diag::err_attribute_section_invalid_for_target) << Error
<< 0 /*'code-seg'*/;
return false;
}
return true;
}
CodeSegAttr *Sema::mergeCodeSegAttr(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 (const auto *ExistingAttr = D->getAttr<CodeSegAttr>()) {
if (ExistingAttr->getName() == Name)
return nullptr;
Diag(ExistingAttr->getLocation(), diag::warn_mismatched_section)
<< 0 /*codeseg*/;
Diag(Range.getBegin(), diag::note_previous_attribute);
return nullptr;
}
return ::new (Context) CodeSegAttr(Range, Context, Name,
AttrSpellingListIndex);
}
static void handleCodeSegAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
StringRef Str;
SourceLocation LiteralLoc;
if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &LiteralLoc))
return;
if (!checkCodeSegName(S, LiteralLoc, Str))
return;
if (const auto *ExistingAttr = D->getAttr<CodeSegAttr>()) {
if (!ExistingAttr->isImplicit()) {
S.Diag(AL.getLoc(),
ExistingAttr->getName() == Str
? diag::warn_duplicate_codeseg_attribute
: diag::err_conflicting_codeseg_attribute);
return;
}
D->dropAttr<CodeSegAttr>();
}
if (CodeSegAttr *CSA = S.mergeCodeSegAttr(D, AL.getRange(), Str,
AL.getAttributeSpellingListIndex()))
D->addAttr(CSA);
}
// Check for things we'd like to warn about. Multiversioning issues are
// handled later in the process, once we know how many exist.
bool Sema::checkTargetAttr(SourceLocation LiteralLoc, StringRef AttrStr) {
@ -6120,6 +6182,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case ParsedAttr::AT_Section:
handleSectionAttr(S, D, AL);
break;
case ParsedAttr::AT_CodeSeg:
handleCodeSegAttr(S, D, AL);
break;
case ParsedAttr::AT_Target:
handleTargetAttr(S, D, AL);
break;

View File

@ -2243,6 +2243,19 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class,
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 *BaseCSA = CXXBaseDecl->getAttr<CodeSegAttr>();
const auto *DerivedCSA = Class->getAttr<CodeSegAttr>();
if ((DerivedCSA || BaseCSA) &&
(!BaseCSA || !DerivedCSA || BaseCSA->getName() != DerivedCSA->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,
@ -5614,6 +5627,16 @@ static void checkForMultipleExportedDefaultConstructors(Sema &S,
}
}
void Sema::checkClassLevelCodeSegAttribute(CXXRecordDecl *Class) {
// Mark any compiler-generated routines with the implicit code_seg attribute.
for (auto *Method : Class->methods()) {
if (Method->isUserProvided())
continue;
if (Attr *A = getImplicitCodeSegOrSectionAttrForFunction(Method, /*IsDefinition=*/true))
Method->addAttr(A);
}
}
/// Check class-level dllimport/dllexport attribute.
void Sema::checkClassLevelDLLAttribute(CXXRecordDecl *Class) {
Attr *ClassAttr = getDLLAttr(Class);
@ -6122,6 +6145,7 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
}
checkClassLevelDLLAttribute(Record);
checkClassLevelCodeSegAttribute(Record);
bool ClangABICompat4 =
Context.getLangOpts().getClangABICompat() <= LangOptions::ClangABI::Ver4;
@ -14589,6 +14613,16 @@ bool Sema::CheckOverridingFunctionAttributes(const CXXMethodDecl *New,
}
}
// Virtual overrides must have the same code_seg.
const auto *OldCSA = Old->getAttr<CodeSegAttr>();
const auto *NewCSA = New->getAttr<CodeSegAttr>();
if ((NewCSA || OldCSA) &&
(!OldCSA || !NewCSA || NewCSA->getName() != OldCSA->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();
// If the calling conventions match, everything is fine

View File

@ -913,6 +913,10 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
// This represents the function body for the lambda function, check if we
// have to apply optnone due to a pragma.
AddRangeBasedOptnone(Method);
// code_seg attribute on lambda apply to the method.
if (Attr *A = getImplicitCodeSegOrSectionAttrForFunction(Method, /*IsDefinition=*/true))
Method->addAttr(A);
// Attributes on the lambda apply to the method.
ProcessDeclAttributes(CurScope, Method, ParamInfo);

View File

@ -0,0 +1,139 @@
// RUN: %clang_cc1 -emit-llvm -triple i686-pc-win32 -fms-extensions -verify -o - %s | FileCheck %s
// expected-no-diagnostics
// Simple case
int __declspec(code_seg("foo_one")) bar_one() { return 1; }
//CHECK: define {{.*}}bar_one{{.*}} section "foo_one"
// Simple case - explicit attribute used over pragma
#pragma code_seg("foo_two")
int __declspec(code_seg("foo_three")) bar2() { return 2; }
//CHECK: define {{.*}}bar2{{.*}} section "foo_three"
// Check that attribute on one function doesn't affect another
int another1() { return 1001; }
//CHECK: define {{.*}}another1{{.*}} section "foo_two"
// Member functions
struct __declspec(code_seg("foo_four")) Foo {
int bar3() {return 0;}
int bar4();
int __declspec(code_seg("foo_six")) bar6() { return 6; }
int bar7() { return 7; }
struct Inner {
int bar5() { return 5; }
} z;
virtual int baz1() { return 1; }
};
struct __declspec(code_seg("foo_four")) FooTwo : Foo {
int baz1() { return 20; }
};
int caller1() {
Foo f; return f.bar3();
}
//CHECK: define {{.*}}bar3@Foo{{.*}} section "foo_four"
int Foo::bar4() { return 4; }
//CHECK: define {{.*}}bar4@Foo{{.*}} section "foo_four"
#pragma code_seg("someother")
int caller2() {
Foo f;
Foo *fp = new FooTwo;
return f.z.bar5() + f.bar6() + f.bar7() + fp->baz1();
}
// MS Compiler and Docs do not match for nested routines
// Doc says: define {{.*}}bar5@Inner@Foo{{.*}} section "foo_four"
// Compiler says: define {{.*}}bar5@Inner@Foo{{.*}} section "foo_two"
// A bug has been reported: see https://reviews.llvm.org/D22931, the
// Microsoft feedback page is no longer available.
//CHECK: define {{.*}}bar5@Inner@Foo{{.*}} section "foo_two"
//CHECK: define {{.*}}bar6@Foo{{.*}} section "foo_six"
//CHECK: define {{.*}}bar7@Foo{{.*}} section "foo_four"
// Check that code_seg active at class declaration is not used on member
// declared outside class when it is not active.
#pragma code_seg(push,"AnotherSeg")
struct FooThree {
int bar8();
int bar9() { return 9; }
};
#pragma code_seg(pop)
int FooThree::bar8() {return 0;}
int caller3()
{
FooThree f;
return f.bar8() + f.bar9();
}
//CHECK: define {{.*}}bar8@FooThree{{.*}} section "someother"
//CHECK: define {{.*}}bar9@FooThree{{.*}} section "AnotherSeg"
struct NonTrivialCopy {
NonTrivialCopy();
NonTrivialCopy(const NonTrivialCopy&);
~NonTrivialCopy();
};
// check the section for compiler-generated function with declspec.
struct __declspec(code_seg("foo_seven")) FooFour {
FooFour() {}
int __declspec(code_seg("foo_eight")) bar10(int t) { return t; }
NonTrivialCopy f;
};
//CHECK: define {{.*}}0FooFour@@QAE@ABU0@@Z{{.*}} section "foo_seven"
// check the section for compiler-generated function with no declspec.
struct FooFive {
FooFive() {}
int __declspec(code_seg("foo_nine")) bar11(int t) { return t; }
NonTrivialCopy f;
};
//CHECK: define {{.*}}0FooFive@@QAE@ABU0@@Z{{.*}} section "someother"
#pragma code_seg("YetAnother")
int caller4()
{
FooFour z1;
FooFour z2 = z1;
FooFive y1;
FooFive y2 = y1;
return z2.bar10(0) + y2.bar11(1);
}
//CHECK: define {{.*}}bar10@FooFour{{.*}} section "foo_eight"
//CHECK: define {{.*}}bar11@FooFive{{.*}} section "foo_nine"
struct FooSix {
#pragma code_seg("foo_ten")
int bar12() { return 12; }
#pragma code_seg("foo_eleven")
int bar13() { return 13; }
};
int bar14() { return 14; }
//CHECK: define {{.*}}bar14{{.*}} section "foo_eleven"
int caller5()
{
FooSix fsix;
return fsix.bar12() + fsix.bar13();
}
//CHECK: define {{.*}}bar12@FooSix{{.*}} section "foo_ten"
//CHECK: define {{.*}}bar13@FooSix{{.*}} section "foo_eleven"
//CHECK: define {{.*}}baz1@FooTwo{{.*}} section "foo_four"

View File

@ -0,0 +1,87 @@
// RUN: %clang_cc1 -emit-llvm -triple i686-pc-win32 -fms-extensions -verify -o - %s | FileCheck %s
// expected-no-diagnostics
// The Microsoft document says: "When this attribute 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."
// But the MS compiler does not always follow that. A bug has been reported:
// see https://reviews.llvm.org/D22931, the Microsoft feedback page is no
// longer available.
// The MS compiler will apply a declspec from the parent class if there is no
// #pragma code_seg active at the class definition. If there is an active
// code_seg that is used instead.
// No active code_seg
struct __declspec(code_seg("foo_outer")) Foo1 {
struct Inner {
void bar1();
static void bar2();
};
};
void Foo1::Inner::bar1() {}
void Foo1::Inner::bar2() {}
//CHECK: define {{.*}}bar1@Inner@Foo1{{.*}} section "foo_outer"
//CHECK: define {{.*}}bar2@Inner@Foo1{{.*}} section "foo_outer"
struct __declspec(code_seg("foo_outer")) Foo2 {
struct __declspec(code_seg("foo_inner")) Inner {
void bar1();
static void bar2();
};
};
void Foo2::Inner::bar1() {}
void Foo2::Inner::bar2() {}
//CHECK: define {{.*}}bar1@Inner@Foo2{{.*}} section "foo_inner"
//CHECK: define {{.*}}bar2@Inner@Foo2{{.*}} section "foo_inner"
#pragma code_seg(push, "otherseg")
struct __declspec(code_seg("foo_outer")) Foo3 {
struct Inner {
void bar1();
static void bar2();
};
};
void Foo3::Inner::bar1() {}
void Foo3::Inner::bar2() {}
//CHECK: define {{.*}}bar1@Inner@Foo3{{.*}} section "otherseg"
//CHECK: define {{.*}}bar2@Inner@Foo3{{.*}} section "otherseg"
struct __declspec(code_seg("foo_outer")) Foo4 {
struct __declspec(code_seg("foo_inner")) Inner {
void bar1();
static void bar2();
};
};
void Foo4::Inner::bar1() {}
void Foo4::Inner::bar2() {}
//CHECK: define {{.*}}bar1@Inner@Foo4{{.*}} section "foo_inner"
//CHECK: define {{.*}}bar2@Inner@Foo4{{.*}} section "foo_inner"
#pragma code_seg(pop)
// Back to no active pragma
struct __declspec(code_seg("foo_outer")) Foo5 {
struct Inner {
void bar1();
static void bar2();
struct __declspec(code_seg("inner1_seg")) Inner1 {
struct Inner2 {
void bar1();
static void bar2();
};
};
};
};
void Foo5::Inner::bar1() {}
void Foo5::Inner::bar2() {}
void Foo5::Inner::Inner1::Inner2::bar1() {}
void Foo5::Inner::Inner1::Inner2::bar2() {}
//CHECK: define {{.*}}bar1@Inner@Foo5{{.*}} section "foo_outer"
//CHECK: define {{.*}}bar2@Inner@Foo5{{.*}} section "foo_outer"
//CHECK: define {{.*}}bar1@Inner2@Inner1@Inner@Foo5{{.*}} section "inner1_seg"
//CHECK: define {{.*}}bar2@Inner2@Inner1@Inner@Foo5{{.*}} section "inner1_seg"

View File

@ -0,0 +1,111 @@
// RUN: %clang_cc1 -emit-llvm -triple i686-pc-win32 -std=c++11 -fms-extensions -verify -o - %s | FileCheck %s
// expected-no-diagnostics
// Class member templates
#pragma code_seg(push, "something")
template <typename T>
struct __declspec(code_seg("foo_one")) ClassOne {
int bar1(T t) { return int(t); }
int bar2(T t);
int bar3(T t);
};
template <typename T>
int ClassOne<T>::bar2(T t) {
return int(t);
}
int caller1() {
ClassOne<int> coi;
return coi.bar1(6) + coi.bar2(3);
}
//CHECK: define {{.*}}bar1@?$ClassOne{{.*}} section "foo_one"
//CHECK: define {{.*}}bar2@?$ClassOne{{.*}} section "foo_one"
template <typename T>
struct ClassTwo {
int bar11(T t) { return int(t); }
int bar22(T t);
int bar33(T t);
};
#pragma code_seg("newone")
template <typename T>
int ClassTwo<T>::bar22(T t) {
return int(t);
}
#pragma code_seg("someother")
template <typename T>
int ClassTwo<T>::bar33(T t) {
return int(t);
}
#pragma code_seg("yetanother")
int caller2() {
ClassTwo<int> coi;
return coi.bar11(6) + coi.bar22(3) + coi.bar33(44);
}
//CHECK: define {{.*}}bar11@?$ClassTwo{{.*}} section "something"
//CHECK: define {{.*}}bar22@?$ClassTwo{{.*}} section "newone"
//CHECK: define {{.*}}bar33@?$ClassTwo{{.*}} section "someother"
template<>
struct ClassOne<double>
{
int bar44(double d) { return 1; }
};
template<>
struct __declspec(code_seg("foo_three")) ClassOne<long>
{
int bar55(long d) { return 1; }
};
#pragma code_seg("onemore")
int caller3() {
ClassOne<double> d;
ClassOne<long> l;
return d.bar44(1.0)+l.bar55(1);
}
//CHECK: define {{.*}}bar44{{.*}} section "yetanother"
//CHECK: define {{.*}}bar55{{.*}} section "foo_three"
// Function templates
template <typename T>
int __declspec(code_seg("foo_four")) bar66(T t) { return int(t); }
// specializations do not take the segment from primary
template<>
int bar66(int i) { return 0; }
#pragma code_seg(pop)
template<>
int bar66(char c) { return 0; }
struct A1 {int i;};
template<>
int __declspec(code_seg("foo_five")) bar66(A1 a) { return a.i; }
int caller4()
{
// but instantiations do use the section from the primary
return bar66(0) + bar66(1.0) + bar66('c');
}
//CHECK: define {{.*}}bar66@H{{.*}} section "onemore"
//CHECK-NOT: define {{.*}}bar66@D{{.*}} section
//CHECK: define {{.*}}bar66@UA1{{.*}} section "foo_five"
//CHECK: define {{.*}}bar66@N{{.*}} section "foo_four"

View File

@ -0,0 +1,65 @@
// RUN: %clang_cc1 -fsyntax-only -verify -fms-extensions %s -triple x86_64-pc-win32
// expected-no-diagnostics
// Non-Member Function Overloading is involved
int __declspec(code_seg("foo_one")) bar_one(int) { return 1; }
//CHECK: define {{.*}}bar_one{{.*}} section "foo_one"
int __declspec(code_seg("foo_two")) bar_one(int,float) { return 11; }
//CHECK: define {{.*}}bar_one{{.*}} section "foo_two"
int __declspec(code_seg("foo_three")) bar_one(float) { return 12; }
//CHECK: define {{.*}}bar_one{{.*}} section "foo_three"
// virtual function overloading is involved
struct __declspec(code_seg("my_one")) Base3 {
virtual int barA(int) { return 1; }
virtual int barA(int,float) { return 2; }
virtual int barA(float) { return 3; }
virtual void __declspec(code_seg("my_two")) barB(int) { }
virtual void __declspec(code_seg("my_three")) barB(float) { }
virtual void __declspec(code_seg("my_four")) barB(int, float) { }
};
//CHECK: define {{.*}}barA@Base3{{.*}} section "my_one"
//CHECK: define {{.*}}barA@Base3{{.*}} section "my_one"
//CHECK: define {{.*}}barA@Base3{{.*}} section "my_one"
//CHECK: define {{.*}}barB@Base3{{.*}} section "my_two"
//CHECK: define {{.*}}barB@Base3{{.*}} section "my_three"
//CHECK: define {{.*}}barB@Base3{{.*}} section "my_four"
#pragma code_seg("another")
// Member functions
struct __declspec(code_seg("foo_four")) Foo {
int bar3() {return 0;}
__declspec(code_seg("foo_lala")) int bar4() {return 0;} }; int caller() {Foo f; return f.bar3() + f.bar4(); }
//CHECK: define {{.*}}bar3@Foo{{.*}} section "foo_four"
//CHECK: define {{.*}}bar4@Foo{{.*}} section "foo_lala"
// Lambdas
#pragma code_seg("something")
int __declspec(code_seg("foo")) bar1()
{
int lala = 4;
auto l = [=](int i) { return i+4; };
return l(-4);
}
//CHECK: define {{.*}}bar1{{.*}} section "foo"
//CHECK: define {{.*}}lambda{{.*}}bar1{{.*}} section "something"
double __declspec(code_seg("foo")) bar2()
{
double lala = 4.0;
auto l = [=](double d) __declspec(code_seg("another")) { return d+4.0; };
return l(4.0);
}
//CHECK: define {{.*}}bar2{{.*}} section "foo"
//CHECK: define {{.*}}lambda{{.*}}bar2{{.*}} section "another"

105
test/SemaCXX/code-seg.cpp Normal file
View File

@ -0,0 +1,105 @@
// RUN: %clang_cc1 -fsyntax-only -verify -fms-extensions %s -triple x86_64-pc-win32
struct __declspec(code_seg("my_one")) FooOne {
int barC();
};
struct FooTwo {
int __declspec(code_seg("my_three")) barD();
int barE();
};
int __declspec(code_seg("my_four")) FooOne::barC() { return 10; }
// expected-warning@-1 {{codeseg does not match previous declaration}}
// expected-note@3{{previous attribute is here}}
int __declspec(code_seg("my_five")) FooTwo::barD() { return 20; }
// expected-warning@-1 {{codeseg does not match previous declaration}}
// expected-note@8 {{previous attribute is here}}
int __declspec(code_seg("my_six")) FooTwo::barE() { return 30; }
// expected-warning@-1 {{codeseg does not match previous declaration}}
// expected-note@9 {{previous declaration is here}}
// Microsoft docs say:
// If a base-class has a code_seg attribute, derived classes must have the
// same attribute.
struct __declspec(code_seg("my_base")) Base1 {};
struct Base2 {};
struct D1 : Base1 {};
//expected-error@-1 {{derived class must specify the same code segment as its base classes}}
// expected-note@24 {{base class 'Base1' specified here}}
struct __declspec(code_seg("my_derived")) D2 : Base1 {};
// expected-error@-1 {{derived class must specify the same code segment as its base classes}}
// expected-note@24 {{base class 'Base1' specified here}}
struct __declspec(code_seg("my_derived")) D3 : Base2 {};
// expected-error@-1 {{derived class must specify the same code segment as its base classes}}
// expected-note@25 {{base class 'Base2' specified here}}
template <typename T> struct __declspec(code_seg("my_base")) MB : T { };
template <typename T> struct __declspec(code_seg("my_derived")) MD : T { };
MB<Base1> mb1; // ok
MB<Base2> mb2;
// expected-error@37 {{derived class must specify the same code segment as its base classes}}
// expected-note@-2 {{in instantiation of template class}}
// expected-note@25 {{base class 'Base2' specified here}}
MD<Base1> md1;
// expected-error@38 {{derived class must specify the same code segment as its base classes}}
// expected-note@-2 {{in instantiation of template class}}
// expected-note@24 {{base class 'Base1' specified here}}
MD<Base2> md2;
// expected-error@38 {{derived class must specify the same code segment as its base classes}}
// expected-note@-2 {{in instantiation of template class}}
// expected-note@25 {{base class 'Base2' specified here}}
// Virtual overrides must have the same code_seg.
struct __declspec(code_seg("my_one")) Base3 {
virtual int barA() { return 1; }
virtual int __declspec(code_seg("my_two")) barB() { return 2; }
};
struct __declspec(code_seg("my_one")) Derived3 : Base3 {
int barA() { return 4; } // ok
int barB() { return 6; }
// expected-error@-1 {{overriding virtual function must specify the same code segment as its overridden function}}
// expected-note@56 {{previous declaration is here}}
};
struct Base4 {
virtual int __declspec(code_seg("my_one")) barA() {return 1;}
virtual int barB() { return 2;}
};
struct Derived4 : Base4 {
virtual int barA() {return 1;}
// expected-error@-1 {{overriding virtual function must specify the same code segment as its overridden function}}
// expected-note@66 {{previous declaration is here}}
virtual int __declspec(code_seg("my_two")) barB() {return 1;}
// expected-error@-1 {{overriding virtual function must specify the same code segment as its overridden function}}
// expected-note@67 {{previous declaration is here}}
};
// MS gives an error when different code segments are used but a warning when a duplicate is used
// Function
int __declspec(code_seg("foo")) __declspec(code_seg("foo")) bar1() { return 1; }
// expected-warning@-1 {{duplicate code segment specifiers}}
int __declspec(code_seg("foo")) __declspec(code_seg("bar")) bar2() { return 1; }
// expected-error@-1 {{conflicting code segment specifiers}}
// Class
struct __declspec(code_seg("foo")) __declspec(code_seg("foo")) Foo {
// expected-warning@-1 {{duplicate code segment specifiers}}
int bar3() {return 0;}
};
struct __declspec(code_seg("foo")) __declspec(code_seg("bar")) FooSix {
// expected-error@-1 {{conflicting code segment specifiers}}
int bar3() {return 0;}
};
//Class Members
struct FooThree {
int __declspec(code_seg("foo")) __declspec(code_seg("foo")) bar1() { return 1; }
// expected-warning@-1 {{duplicate code segment specifiers}}
int __declspec(code_seg("foo")) __declspec(code_seg("bar")) bar2() { return 1; }
// expected-error@-1 {{conflicting code segment specifiers}}
int bar8();
int bar9() { return 9; }
};

View File

@ -0,0 +1,97 @@
// RUN: %clang_cc1 -fsyntax-only -verify -fms-extensions %s -triple x86_64-pc-win32
// Multiple inheritance is involved (code segmments all disagree between the bases and derived class)
struct __declspec(code_seg("my_base")) Base1 {};
struct Base2 {};
struct D1 : Base1, Base2 {};
// expected-error@-1 {{derived class must specify the same code segment as its base classes}}
// expected-note@4 {{base class 'Base1' specified here}}
struct __declspec(code_seg("my_derived")) D2 : Base2, Base1 {};
// expected-error@-1 {{derived class must specify the same code segment as its base classes}}
// expected-error@-2 {{derived class must specify the same code segment as its base classes}}
// expected-note@5 {{base class 'Base2' specified here}}
// expected-note@4 {{base class 'Base1' specified here}}
// Multiple inheritance (code segments partially agree between the bases and the derived class)
struct __declspec(code_seg("base_class")) BaseClass1 {};
struct __declspec(code_seg("base_class")) BaseClass2 {};
struct Derived1 : BaseClass1, BaseClass2 {};
// expected-error@-1 {{derived class must specify the same code segment as its base classes}}
// expected-error@-2 {{derived class must specify the same code segment as its base classes}}
// expected-note@18 {{base class 'BaseClass1' specified here}}
// expected-note@19 {{base class 'BaseClass2' specified here}}
struct __declspec(code_seg("derived_class")) Derived2 : BaseClass2, BaseClass1 {};
// expected-error@-1 {{derived class must specify the same code segment as its base classes}}
// expected-error@-2 {{derived class must specify the same code segment as its base classes}}
// expected-note@19 {{base class 'BaseClass2' specified here}}
// expected-note@18 {{base class 'BaseClass1' specified here}}
struct __declspec(code_seg("base_class")) Derived3 : BaseClass2, BaseClass1 {}; //OK
struct __declspec(code_seg("base_class")) Derived4 : BaseClass1, BaseClass2 {}; //OK
// Multiple inheritance is involved (code segmments all agree between the bases and derived class)
struct __declspec(code_seg("foo_base")) B1 {};
struct __declspec(code_seg("foo_base")) B2 {};
struct __declspec(code_seg("foo_base")) Derived : B1, B2 {};
// virtual Inheritance is involved (code segmments all disagree between the bases and derived class)
struct __declspec(code_seg("my_one")) Base {
virtual int barA() { return 1; } ;
};
struct __declspec(code_seg("my_two")) Derived5 : virtual Base {
virtual int barB() { return 2; };
};
// expected-error@-3 {{derived class must specify the same code segment as its base classes}}
// expected-note@42 {{base class 'Base' specified here}}
struct __declspec(code_seg("my_three")) Derived6 : virtual Base {
virtual int barC() { return 3; };
};
// expected-error@-3 {{derived class must specify the same code segment as its base classes}}
// expected-note@42 {{base class 'Base' specified here}}
struct __declspec(code_seg("my_four")) Derived7 : Derived5, Derived6 {};
// expected-error@-1 {{derived class must specify the same code segment as its base classes}}
// expected-error@-2 {{derived class must specify the same code segment as its base classes}}
// expected-note@46 {{base class 'Derived5' specified here}}
// expected-note@52 {{base class 'Derived6' specified here}}
// virtual Inheritance is involved (code segmments partially agree between the bases and derived class)
struct __declspec(code_seg("my_class")) BaseClass {
virtual int barA() { return 1; } ;
};
struct __declspec(code_seg("my_class")) DerivedClass1 : virtual BaseClass { //OK
virtual int barB() { return 2; };
};
struct __declspec(code_seg("my_class")) DerivedClass2 : virtual BaseClass { //OK
virtual int barC() { return 3; };
};
struct __declspec(code_seg("my_derived_one")) DerivedClass3 : DerivedClass1, DerivedClass2 {};
// expected-error@-1 {{derived class must specify the same code segment as its base classes}}
// expected-error@-2 {{derived class must specify the same code segment as its base classes}}
// expected-note@69 {{base class 'DerivedClass1' specified here}}
// expected-note@73 {{base class 'DerivedClass2' specified here}}
// virtual Inheritance is involved (code segmments all agree between the bases and derived class)
struct __declspec(code_seg("foo_one")) Class {
virtual int foo1() { return 10; } ;
};
struct __declspec(code_seg("foo_one")) Derived_One: virtual Class { //OK
virtual int foo2() { return 20; };
};
struct __declspec(code_seg("foo_one")) Derived_Two : virtual Class { //OK
virtual int foo3() { return 30; };
};
struct __declspec(code_seg("foo_one")) Derived_Three : Derived_One, Derived_Two {}; //OK