[Clang][Sema] Capturing section type conflicts between #pragma clang section and section attributes

Summary:
Conflicting types for the same section name defined in clang section
pragmas and GNU-style section attributes were not properly captured by
Clang's Sema. The lack of diagnostics was caused by the fact the section
specification coming from attributes was handled by Sema as implicit,
even though explicitly defined by the user.

This patch enables the diagnostics for section type conflicts between
those specifications by making sure sections defined in section
attributes are correctly handled as explicit.

Reviewers: hans, rnk, javed.absar

Reviewed By: rnk

Subscribers: cfe-commits

Tags: #clang

Differential Revision: https://reviews.llvm.org/D78573
This commit is contained in:
Lucas Prates 2020-04-21 17:25:18 +01:00
parent 0dac639f28
commit 9d39df03a9
5 changed files with 60 additions and 30 deletions

View File

@ -3006,6 +3006,10 @@ private:
SmallVector<std::unique_ptr<OMPTraitInfo>, 4> OMPTraitInfoVector;
};
/// Insertion operator for diagnostics.
const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
const ASTContext::SectionInfo &Section);
/// Utility function for constructing a nullary selector.
inline Selector GetNullarySelector(StringRef name, ASTContext &Ctx) {
IdentifierInfo* II = &Ctx.Idents.get(name);

View File

@ -11011,3 +11011,11 @@ OMPTraitInfo &ASTContext::getNewOMPTraitInfo() {
OMPTraitInfoVector.emplace_back(new OMPTraitInfo());
return *OMPTraitInfoVector.back();
}
const DiagnosticBuilder &
clang::operator<<(const DiagnosticBuilder &DB,
const ASTContext::SectionInfo &Section) {
if (Section.Decl)
return DB << Section.Decl;
return DB << "a prior #pragma section";
}

View File

@ -530,42 +530,49 @@ void Sema::PragmaStack<ValueType>::Act(SourceLocation PragmaLocation,
bool Sema::UnifySection(StringRef SectionName,
int SectionFlags,
DeclaratorDecl *Decl) {
auto Section = Context.SectionInfos.find(SectionName);
if (Section == Context.SectionInfos.end()) {
SourceLocation PragmaLocation;
if (auto A = Decl->getAttr<SectionAttr>())
if (A->isImplicit())
PragmaLocation = A->getLocation();
auto SectionIt = Context.SectionInfos.find(SectionName);
if (SectionIt == Context.SectionInfos.end()) {
Context.SectionInfos[SectionName] =
ASTContext::SectionInfo(Decl, SourceLocation(), SectionFlags);
ASTContext::SectionInfo(Decl, PragmaLocation, SectionFlags);
return false;
}
// A pre-declared section takes precedence w/o diagnostic.
if (Section->second.SectionFlags == SectionFlags ||
!(Section->second.SectionFlags & ASTContext::PSF_Implicit))
const auto &Section = SectionIt->second;
if (Section.SectionFlags == SectionFlags ||
((SectionFlags & ASTContext::PSF_Implicit) &&
!(Section.SectionFlags & ASTContext::PSF_Implicit)))
return false;
auto OtherDecl = Section->second.Decl;
Diag(Decl->getLocation(), diag::err_section_conflict)
<< Decl << OtherDecl;
Diag(OtherDecl->getLocation(), diag::note_declared_at)
<< OtherDecl->getName();
if (auto A = Decl->getAttr<SectionAttr>())
if (A->isImplicit())
Diag(A->getLocation(), diag::note_pragma_entered_here);
if (auto A = OtherDecl->getAttr<SectionAttr>())
if (A->isImplicit())
Diag(A->getLocation(), diag::note_pragma_entered_here);
Diag(Decl->getLocation(), diag::err_section_conflict) << Decl << Section;
if (Section.Decl)
Diag(Section.Decl->getLocation(), diag::note_declared_at)
<< Section.Decl->getName();
if (PragmaLocation.isValid())
Diag(PragmaLocation, diag::note_pragma_entered_here);
if (Section.PragmaSectionLocation.isValid())
Diag(Section.PragmaSectionLocation, diag::note_pragma_entered_here);
return true;
}
bool Sema::UnifySection(StringRef SectionName,
int SectionFlags,
SourceLocation PragmaSectionLocation) {
auto Section = Context.SectionInfos.find(SectionName);
if (Section != Context.SectionInfos.end()) {
if (Section->second.SectionFlags == SectionFlags)
auto SectionIt = Context.SectionInfos.find(SectionName);
if (SectionIt != Context.SectionInfos.end()) {
const auto &Section = SectionIt->second;
if (Section.SectionFlags == SectionFlags)
return false;
if (!(Section->second.SectionFlags & ASTContext::PSF_Implicit)) {
if (!(Section.SectionFlags & ASTContext::PSF_Implicit)) {
Diag(PragmaSectionLocation, diag::err_section_conflict)
<< "this" << "a prior #pragma section";
Diag(Section->second.PragmaSectionLocation,
diag::note_pragma_entered_here);
<< "this" << Section;
if (Section.Decl)
Diag(Section.Decl->getLocation(), diag::note_declared_at)
<< Section.Decl->getName();
if (Section.PragmaSectionLocation.isValid())
Diag(Section.PragmaSectionLocation, diag::note_pragma_entered_here);
return true;
}
}

View File

@ -12754,7 +12754,7 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
if (GlobalStorage && var->isThisDeclarationADefinition() &&
!inTemplateInstantiation()) {
PragmaStack<StringLiteral *> *Stack = nullptr;
int SectionFlags = ASTContext::PSF_Implicit | ASTContext::PSF_Read;
int SectionFlags = ASTContext::PSF_Read;
if (var->getType().isConstQualified())
Stack = &ConstSegStack;
else if (!var->getInit()) {
@ -12764,14 +12764,19 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
Stack = &DataSegStack;
SectionFlags |= ASTContext::PSF_Write;
}
if (Stack->CurrentValue && !var->hasAttr<SectionAttr>())
if (const SectionAttr *SA = var->getAttr<SectionAttr>()) {
if (SA->getSyntax() == AttributeCommonInfo::AS_Declspec)
SectionFlags |= ASTContext::PSF_Implicit;
UnifySection(SA->getName(), SectionFlags, var);
} else if (Stack->CurrentValue) {
SectionFlags |= ASTContext::PSF_Implicit;
auto SectionName = Stack->CurrentValue->getString();
var->addAttr(SectionAttr::CreateImplicit(
Context, Stack->CurrentValue->getString(),
Stack->CurrentPragmaLocation, AttributeCommonInfo::AS_Pragma,
SectionAttr::Declspec_allocate));
if (const SectionAttr *SA = var->getAttr<SectionAttr>())
if (UnifySection(SA->getName(), SectionFlags, var))
Context, SectionName, Stack->CurrentPragmaLocation,
AttributeCommonInfo::AS_Pragma, SectionAttr::Declspec_allocate));
if (UnifySection(SectionName, SectionFlags, var))
var->dropAttr<SectionAttr>();
}
// Apply the init_seg attribute if this has an initializer. If the
// initializer turns out to not be dynamic, we'll end up ignoring this

View File

@ -22,4 +22,10 @@
#pragma clang section bss = "myrodata.1" // expected-error {{this causes a section type conflict with a prior #pragma section}}
#pragma clang section text = "mybss.3" // expected-error {{this causes a section type conflict with a prior #pragma section}}
#pragma clang section rodata = "myrodata.4" // expected-note {{#pragma entered here}}
int x __attribute__((section("myrodata.4"))); // expected-error {{'x' causes a section type conflict with a prior #pragma section}}
const int y __attribute__((section("myrodata.5"))) = 10; // expected-note {{declared here}}
#pragma clang section data = "myrodata.5" // expected-error {{this causes a section type conflict with 'y'}}
const int z __attribute__((section("myrodata.6"))) = 11;
int a;