summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/CodeGen/CodeGenModule.cpp12
-rw-r--r--clang/lib/Sema/SemaDecl.cpp79
-rw-r--r--clang/lib/Sema/SemaDeclAttr.cpp69
-rw-r--r--clang/lib/Sema/SemaDeclCXX.cpp34
-rw-r--r--clang/lib/Sema/SemaLambda.cpp4
5 files changed, 192 insertions, 6 deletions
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index b412d3083f5..68868708888 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -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
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index a754cc912d9..b6381dc1e4b 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -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.
///
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index 47ef872e439..f549aa0468b 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -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;
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index eda6e161954..d2a2bb20206 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -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
diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp
index 0b768cc9fab..04d9e55bc67 100644
--- a/clang/lib/Sema/SemaLambda.cpp
+++ b/clang/lib/Sema/SemaLambda.cpp
@@ -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);
OpenPOWER on IntegriCloud