[clang] [Sema] Don't call isNonConstantStorage on incomplete variable types (PR #161590)
Akira Hatanaka via cfe-commits
cfe-commits at lists.llvm.org
Thu Oct 9 11:04:45 PDT 2025
https://github.com/ahatanak updated https://github.com/llvm/llvm-project/pull/161590
>From a46d41190f491e7f6f3cf7bcdbbbdf1d4ab7b030 Mon Sep 17 00:00:00 2001
From: Akira Hatanaka <ahatanak at gmail.com>
Date: Wed, 1 Oct 2025 11:58:31 -0700
Subject: [PATCH 1/3] [Sema] Don't call isNonConstantStorage on incomplete
variable types
The code that applies section attributes to global variables was
crashing when it encountered a variable whose type was incomplete. This
change adds a check to ensure the variable's type is complete before
calling the function.
Fixes #120371
rdar://155577913
---
clang/lib/Sema/SemaDecl.cpp | 95 +++++++++++++++--------------
clang/test/SemaCXX/attr-section.cpp | 8 +++
2 files changed, 58 insertions(+), 45 deletions(-)
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 0069b08f1991a..e6271745e7ac1 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -14918,52 +14918,57 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
}
// Apply section attributes and pragmas to global variables.
- if (GlobalStorage && var->isThisDeclarationADefinition() &&
- !inTemplateInstantiation()) {
- PragmaStack<StringLiteral *> *Stack = nullptr;
- int SectionFlags = ASTContext::PSF_Read;
- bool MSVCEnv =
- Context.getTargetInfo().getTriple().isWindowsMSVCEnvironment();
- std::optional<QualType::NonConstantStorageReason> Reason;
- if (HasConstInit &&
- !(Reason = var->getType().isNonConstantStorage(Context, true, false))) {
- Stack = &ConstSegStack;
- } else {
- SectionFlags |= ASTContext::PSF_Write;
- Stack = var->hasInit() && HasConstInit ? &DataSegStack : &BSSSegStack;
- }
- if (const SectionAttr *SA = var->getAttr<SectionAttr>()) {
- if (SA->getSyntax() == AttributeCommonInfo::AS_Declspec)
+ [&]() {
+ if (GlobalStorage && var->isThisDeclarationADefinition() &&
+ !inTemplateInstantiation()) {
+ PragmaStack<StringLiteral *> *Stack = nullptr;
+ int SectionFlags = ASTContext::PSF_Read;
+ bool MSVCEnv =
+ Context.getTargetInfo().getTriple().isWindowsMSVCEnvironment();
+ std::optional<QualType::NonConstantStorageReason> Reason;
+ if (HasConstInit && var->getType()->isIncompleteType())
+ return;
+ if (HasConstInit && !(Reason = var->getType().isNonConstantStorage(
+ Context, true, false))) {
+ Stack = &ConstSegStack;
+ } else {
+ SectionFlags |= ASTContext::PSF_Write;
+ Stack = var->hasInit() && HasConstInit ? &DataSegStack : &BSSSegStack;
+ }
+ 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) {
+ if (Stack != &ConstSegStack && MSVCEnv &&
+ ConstSegStack.CurrentValue != ConstSegStack.DefaultValue &&
+ var->getType().isConstQualified()) {
+ assert((!Reason || Reason != QualType::NonConstantStorageReason::
+ NonConstNonReferenceType) &&
+ "This case should've already been handled elsewhere");
+ Diag(var->getLocation(), diag::warn_section_msvc_compat)
+ << var << ConstSegStack.CurrentValue
+ << (int)(!HasConstInit
+ ? QualType::NonConstantStorageReason::NonTrivialCtor
+ : *Reason);
+ }
SectionFlags |= ASTContext::PSF_Implicit;
- UnifySection(SA->getName(), SectionFlags, var);
- } else if (Stack->CurrentValue) {
- if (Stack != &ConstSegStack && MSVCEnv &&
- ConstSegStack.CurrentValue != ConstSegStack.DefaultValue &&
- var->getType().isConstQualified()) {
- assert((!Reason || Reason != QualType::NonConstantStorageReason::
- NonConstNonReferenceType) &&
- "This case should've already been handled elsewhere");
- Diag(var->getLocation(), diag::warn_section_msvc_compat)
- << var << ConstSegStack.CurrentValue << (int)(!HasConstInit
- ? QualType::NonConstantStorageReason::NonTrivialCtor
- : *Reason);
- }
- SectionFlags |= ASTContext::PSF_Implicit;
- auto SectionName = Stack->CurrentValue->getString();
- var->addAttr(SectionAttr::CreateImplicit(Context, SectionName,
- Stack->CurrentPragmaLocation,
- 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
- // attribute.
- if (CurInitSeg && var->getInit())
- var->addAttr(InitSegAttr::CreateImplicit(Context, CurInitSeg->getString(),
- CurInitSegLoc));
- }
+ auto SectionName = Stack->CurrentValue->getString();
+ var->addAttr(SectionAttr::CreateImplicit(
+ Context, SectionName, Stack->CurrentPragmaLocation,
+ 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
+ // attribute.
+ if (CurInitSeg && var->getInit())
+ var->addAttr(InitSegAttr::CreateImplicit(
+ Context, CurInitSeg->getString(), CurInitSegLoc));
+ }
+ }();
// All the following checks are C++ only.
if (!getLangOpts().CPlusPlus) {
diff --git a/clang/test/SemaCXX/attr-section.cpp b/clang/test/SemaCXX/attr-section.cpp
index 1c07e3dd8bba2..3ec455d860ff0 100644
--- a/clang/test/SemaCXX/attr-section.cpp
+++ b/clang/test/SemaCXX/attr-section.cpp
@@ -69,3 +69,11 @@ __attribute__((section("non_trivial_ctor"))) const t1 v1; // expected-note {{dec
extern const t1 v2;
__attribute__((section("non_trivial_ctor"))) const t1 v2{3}; // expected-error {{'v2' causes a section type conflict with 'v1'}}
} // namespace non_trivial_ctor
+
+namespace incomplete_type {
+template <class T>
+struct A {
+ struct B;
+ static constexpr B b{nullptr};
+};
+}
>From 1ce03356207e1ea745ffa0b8a2d04de1d857e81a Mon Sep 17 00:00:00 2001
From: Akira Hatanaka <ahatanak at gmail.com>
Date: Thu, 2 Oct 2025 12:53:40 -0700
Subject: [PATCH 2/3] Don't emit the diagnostic unless the variable is
instantiated
---
clang/lib/Sema/SemaDecl.cpp | 95 ++++++++++++++---------------
clang/test/SemaCXX/attr-section.cpp | 14 ++++-
2 files changed, 56 insertions(+), 53 deletions(-)
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index e6271745e7ac1..95aa7fbc0a321 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -14918,57 +14918,52 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
}
// Apply section attributes and pragmas to global variables.
- [&]() {
- if (GlobalStorage && var->isThisDeclarationADefinition() &&
- !inTemplateInstantiation()) {
- PragmaStack<StringLiteral *> *Stack = nullptr;
- int SectionFlags = ASTContext::PSF_Read;
- bool MSVCEnv =
- Context.getTargetInfo().getTriple().isWindowsMSVCEnvironment();
- std::optional<QualType::NonConstantStorageReason> Reason;
- if (HasConstInit && var->getType()->isIncompleteType())
- return;
- if (HasConstInit && !(Reason = var->getType().isNonConstantStorage(
- Context, true, false))) {
- Stack = &ConstSegStack;
- } else {
- SectionFlags |= ASTContext::PSF_Write;
- Stack = var->hasInit() && HasConstInit ? &DataSegStack : &BSSSegStack;
- }
- 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) {
- if (Stack != &ConstSegStack && MSVCEnv &&
- ConstSegStack.CurrentValue != ConstSegStack.DefaultValue &&
- var->getType().isConstQualified()) {
- assert((!Reason || Reason != QualType::NonConstantStorageReason::
- NonConstNonReferenceType) &&
- "This case should've already been handled elsewhere");
- Diag(var->getLocation(), diag::warn_section_msvc_compat)
- << var << ConstSegStack.CurrentValue
- << (int)(!HasConstInit
- ? QualType::NonConstantStorageReason::NonTrivialCtor
- : *Reason);
- }
+ if (GlobalStorage && var->isThisDeclarationADefinition() &&
+ !var->getDeclContext()->isDependentContext()) {
+ PragmaStack<StringLiteral *> *Stack = nullptr;
+ int SectionFlags = ASTContext::PSF_Read;
+ bool MSVCEnv =
+ Context.getTargetInfo().getTriple().isWindowsMSVCEnvironment();
+ std::optional<QualType::NonConstantStorageReason> Reason;
+ if (HasConstInit &&
+ !(Reason = var->getType().isNonConstantStorage(Context, true, false))) {
+ Stack = &ConstSegStack;
+ } else {
+ SectionFlags |= ASTContext::PSF_Write;
+ Stack = var->hasInit() && HasConstInit ? &DataSegStack : &BSSSegStack;
+ }
+ if (const SectionAttr *SA = var->getAttr<SectionAttr>()) {
+ if (SA->getSyntax() == AttributeCommonInfo::AS_Declspec)
SectionFlags |= ASTContext::PSF_Implicit;
- auto SectionName = Stack->CurrentValue->getString();
- var->addAttr(SectionAttr::CreateImplicit(
- Context, SectionName, Stack->CurrentPragmaLocation,
- 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
- // attribute.
- if (CurInitSeg && var->getInit())
- var->addAttr(InitSegAttr::CreateImplicit(
- Context, CurInitSeg->getString(), CurInitSegLoc));
- }
- }();
+ UnifySection(SA->getName(), SectionFlags, var);
+ } else if (Stack->CurrentValue) {
+ if (Stack != &ConstSegStack && MSVCEnv &&
+ ConstSegStack.CurrentValue != ConstSegStack.DefaultValue &&
+ var->getType().isConstQualified()) {
+ assert((!Reason || Reason != QualType::NonConstantStorageReason::
+ NonConstNonReferenceType) &&
+ "This case should've already been handled elsewhere");
+ Diag(var->getLocation(), diag::warn_section_msvc_compat)
+ << var << ConstSegStack.CurrentValue << (int)(!HasConstInit
+ ? QualType::NonConstantStorageReason::NonTrivialCtor
+ : *Reason);
+ }
+ SectionFlags |= ASTContext::PSF_Implicit;
+ auto SectionName = Stack->CurrentValue->getString();
+ var->addAttr(SectionAttr::CreateImplicit(Context, SectionName,
+ Stack->CurrentPragmaLocation,
+ 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
+ // attribute.
+ if (CurInitSeg && var->getInit())
+ var->addAttr(InitSegAttr::CreateImplicit(Context, CurInitSeg->getString(),
+ CurInitSegLoc));
+ }
// All the following checks are C++ only.
if (!getLangOpts().CPlusPlus) {
diff --git a/clang/test/SemaCXX/attr-section.cpp b/clang/test/SemaCXX/attr-section.cpp
index 3ec455d860ff0..76fd97e34ad87 100644
--- a/clang/test/SemaCXX/attr-section.cpp
+++ b/clang/test/SemaCXX/attr-section.cpp
@@ -65,15 +65,23 @@ struct t1 {
constexpr t1(int) { }
};
extern const t1 v1;
-__attribute__((section("non_trivial_ctor"))) const t1 v1; // expected-note {{declared here}}
+__attribute__((section("non_trivial_ctor"))) const t1 v1; // expected-note 2 {{declared here}}
extern const t1 v2;
__attribute__((section("non_trivial_ctor"))) const t1 v2{3}; // expected-error {{'v2' causes a section type conflict with 'v1'}}
} // namespace non_trivial_ctor
-namespace incomplete_type {
+namespace dependent_context {
template <class T>
struct A {
struct B;
- static constexpr B b{nullptr};
+ static constexpr B b{nullptr}; // This used to crash.
};
+
+template <class T>
+struct C {
+ __attribute__((section("non_trivial_ctor")))
+ static constexpr int m{123}; // expected-error {{'m' causes a section type conflict with 'v1'}}
+};
+
+auto *p = &C<int>::m; // expected-note {{in instantiation of static data member 'dependent_context::C<int>::m' requested here}}
}
>From f74f86cc547e704e23472fb3d6da2fec26307183 Mon Sep 17 00:00:00 2001
From: Akira Hatanaka <ahatanak at gmail.com>
Date: Thu, 9 Oct 2025 11:04:03 -0700
Subject: [PATCH 3/3] Add test case
---
clang/test/SemaCXX/attr-section.cpp | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/clang/test/SemaCXX/attr-section.cpp b/clang/test/SemaCXX/attr-section.cpp
index 76fd97e34ad87..6ed432f1cf7e0 100644
--- a/clang/test/SemaCXX/attr-section.cpp
+++ b/clang/test/SemaCXX/attr-section.cpp
@@ -77,6 +77,13 @@ struct A {
static constexpr B b{nullptr}; // This used to crash.
};
+struct B1 { void *p; };
+template <class T>
+struct A1 {
+ __attribute__((section("non_trivial_ctor")))
+ static constexpr B1 b{nullptr}; // no diagnostic expected
+};
+
template <class T>
struct C {
__attribute__((section("non_trivial_ctor")))
More information about the cfe-commits
mailing list