diff options
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/CodeGen/CodeGenModule.cpp | 12 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 79 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDeclAttr.cpp | 69 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDeclCXX.cpp | 34 | ||||
-rw-r--r-- | clang/lib/Sema/SemaLambda.cpp | 4 |
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); |