diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -3004,6 +3004,15 @@ SmallVector OMPTraitInfoVector; }; +/// Insertion operator for diagnostics. +inline const DiagnosticBuilder & +operator<<(const DiagnosticBuilder &DB, + const ASTContext::SectionInfo &Section) { + if (Section.Decl) + return DB << Section.Decl; + return DB << "a prior #pragma section"; +} + /// Utility function for constructing a nullary selector. inline Selector GetNullarySelector(StringRef name, ASTContext &Ctx) { IdentifierInfo* II = &Ctx.Idents.get(name); diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp --- a/clang/lib/Sema/SemaAttr.cpp +++ b/clang/lib/Sema/SemaAttr.cpp @@ -471,42 +471,49 @@ 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()) + 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()) - if (A->isImplicit()) - Diag(A->getLocation(), diag::note_pragma_entered_here); - if (auto A = OtherDecl->getAttr()) - 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; } } diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -12746,7 +12746,7 @@ if (GlobalStorage && var->isThisDeclarationADefinition() && !inTemplateInstantiation()) { PragmaStack *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()) { @@ -12756,14 +12756,19 @@ Stack = &DataSegStack; SectionFlags |= ASTContext::PSF_Write; } - if (Stack->CurrentValue && !var->hasAttr()) + if (const SectionAttr *SA = var->getAttr()) { + 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()) - if (UnifySection(SA->getName(), SectionFlags, var)) + Context, SectionName, Stack->CurrentPragmaLocation, + AttributeCommonInfo::AS_Pragma, SectionAttr::Declspec_allocate)); + if (UnifySection(SectionName, SectionFlags, var)) var->dropAttr(); + } // 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 diff --git a/clang/test/Sema/pragma-clang-section.c b/clang/test/Sema/pragma-clang-section.c --- a/clang/test/Sema/pragma-clang-section.c +++ b/clang/test/Sema/pragma-clang-section.c @@ -22,4 +22,9 @@ #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'}} + int a;