forked from OSchip/llvm-project
[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:
parent
0dac639f28
commit
9d39df03a9
|
@ -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);
|
||||
|
|
|
@ -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";
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue