mirror of https://github.com/microsoft/clang.git
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:
parent
0e4f59d7b4
commit
1a78aeb17c
|
@ -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 = [];
|
||||
|
|
|
@ -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 = [{
|
||||
|
|
|
@ -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">;
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
///
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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"
|
||||
|
|
@ -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"
|
||||
|
|
@ -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"
|
||||
|
||||
|
||||
|
|
@ -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"
|
||||
|
||||
|
|
@ -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; }
|
||||
};
|
||||
|
|
@ -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
|
||||
|
Loading…
Reference in New Issue