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 @@ -13047,43 +13047,6 @@ } } - // Apply section attributes and pragmas to global variables. - bool GlobalStorage = var->hasGlobalStorage(); - if (GlobalStorage && var->isThisDeclarationADefinition() && - !inTemplateInstantiation()) { - PragmaStack *Stack = nullptr; - int SectionFlags = ASTContext::PSF_Read; - if (var->getType().isConstQualified()) - Stack = &ConstSegStack; - else if (!var->getInit()) { - Stack = &BSSSegStack; - SectionFlags |= ASTContext::PSF_Write; - } else { - Stack = &DataSegStack; - SectionFlags |= ASTContext::PSF_Write; - } - 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, 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 - // attribute. - if (CurInitSeg && var->getInit()) - var->addAttr(InitSegAttr::CreateImplicit(Context, CurInitSeg->getString(), - CurInitSegLoc, - AttributeCommonInfo::AS_Pragma)); - } if (!var->getType()->isStructureType() && var->hasInit() && isa(var->getInit())) { @@ -13133,14 +13096,6 @@ } } - // All the following checks are C++ only. - if (!getLangOpts().CPlusPlus) { - // If this variable must be emitted, add it as an initializer for the - // current module. - if (Context.DeclMustBeEmitted(var) && !ModuleScopes.empty()) - Context.addModuleInitializer(ModuleScopes.back().Module, var); - return; - } QualType type = var->getType(); @@ -13148,11 +13103,14 @@ getCurFunction()->addByrefBlockVar(var); Expr *Init = var->getInit(); + bool GlobalStorage = var->hasGlobalStorage(); bool IsGlobal = GlobalStorage && !var->isStaticLocal(); QualType baseType = Context.getBaseElementType(type); + bool HasConstInit = true; // Check whether the initializer is sufficiently constant. - if (!type->isDependentType() && Init && !Init->isValueDependent() && + if (getLangOpts().CPlusPlus && !type->isDependentType() && Init && + !Init->isValueDependent() && (GlobalStorage || var->isConstexpr() || var->mightBeUsableInConstantExpressions(Context))) { // If this variable might have a constant initializer or might be usable in @@ -13160,7 +13118,6 @@ // do this lazily, because the result might depend on things that change // later, such as which constexpr functions happen to be defined. SmallVector Notes; - bool HasConstInit; if (!getLangOpts().CPlusPlus11) { // Prior to C++11, in contexts where a constant initializer is required, // the set of valid constant initializers is described by syntactic rules @@ -13225,6 +13182,57 @@ } } + // Apply section attributes and pragmas to global variables. + if (GlobalStorage && var->isThisDeclarationADefinition() && + !inTemplateInstantiation()) { + PragmaStack *Stack = nullptr; + int SectionFlags = ASTContext::PSF_Read; + if (var->getType().isConstQualified()) { + if (HasConstInit) + Stack = &ConstSegStack; + else { + Stack = &BSSSegStack; + SectionFlags |= ASTContext::PSF_Write; + } + } else if (var->hasInit() && HasConstInit) { + Stack = &DataSegStack; + SectionFlags |= ASTContext::PSF_Write; + } else { + Stack = &BSSSegStack; + SectionFlags |= ASTContext::PSF_Write; + } + 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, 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 + // attribute. + if (CurInitSeg && var->getInit()) + var->addAttr(InitSegAttr::CreateImplicit(Context, CurInitSeg->getString(), + CurInitSegLoc, + AttributeCommonInfo::AS_Pragma)); + } + + // All the following checks are C++ only. + if (!getLangOpts().CPlusPlus) { + // If this variable must be emitted, add it as an initializer for the + // current module. + if (Context.DeclMustBeEmitted(var) && !ModuleScopes.empty()) + Context.addModuleInitializer(ModuleScopes.back().Module, var); + return; + } + // Require the destructor. if (!type->isDependentType()) if (const RecordType *recordType = baseType->getAs()) diff --git a/clang/test/CodeGenCXX/clang-sections-1.cpp b/clang/test/CodeGenCXX/clang-sections-1.cpp new file mode 100644 --- /dev/null +++ b/clang/test/CodeGenCXX/clang-sections-1.cpp @@ -0,0 +1,50 @@ +// RUN: %clang_cc1 -triple x86_64-linux -emit-llvm -o - %s | FileCheck %s --check-prefix=LLVM +// RUN: %clang_cc1 -triple x86_64-linux -S -o - %s | FileCheck %s --check-prefix=ASM +// Actually, any ELF target would do +// REQUIRES: x86_64-linux + +#pragma clang section bss = "B$$" data = "d@t@" rodata = "r0d@t@" + +const int a = 1; +const int *f() { return &a; } + +int init(); +const int b = init(); + +int c = 2; + +int d = init(); + +int e; + +// LLVM: @_ZL1a = internal constant i32 1, align 4 #[[#A:]] +// LLVM: @_ZL1b = internal global i32 0, align 4 #[[#A]] +// LLVM: @c = {{.*}}global i32 2, align 4 #[[#A]] +// LLVM: @d = {{.*}}global i32 0, align 4 #[[#A]] +// LLVM: @e = {{.*}}global i32 0, align 4 #[[#A]] + +// LLVM: attributes #[[#A]] = { "bss-section"="B$$" "data-section"="d@t@" "rodata-section"="r0d@t@" } + +// ASM: .section "r0d@t@","a",@progbits +// ASM-NOT: .section +// ASM-LABEL: _ZL1a: +// ASM-NEXT: .long 1 + +// ASM: .section "B$$","aw",@nobits +// ASM-NOT: .section +// ASM-LABEL: _ZL1b: +// ASM-NEXT: .long 0 + +// ASM: .section "d@t@","aw",@progbits +// ASM-NOT: .section +// ASM-LABEL: c: +// ASM: .long 2 + +// ASM: .section "B$$","aw",@nobits +// ASM-NOT: .section +// ASM-LABEL: d: +// ASM: .long 0 + +// ASM-NOT: .section +// ASM-LABEL: e: +// ASM .long 0 diff --git a/clang/test/CodeGenCXX/const-dynamic-init.cpp b/clang/test/CodeGenCXX/const-dynamic-init.cpp new file mode 100644 --- /dev/null +++ b/clang/test/CodeGenCXX/const-dynamic-init.cpp @@ -0,0 +1,25 @@ +// RUN: %clang_cc1 -triple x86_64-linux -emit-llvm -o - %s | FileCheck %s + +__attribute__((section("A"))) +const int a = 1; +const int *f() { return &a; } +// CHECK: @_ZL1a = internal constant i32 1, section "A" + +int init(); +__attribute__((section("B"))) +const int b = init(); +// Even if it's const-qualified, it must not be LLVM IR `constant` since it's +// dynamically initialised. +// CHECK: @_ZL1b = internal global i32 0, section "B" + +__attribute__((section("C"))) +int c = 2; +// CHECK: @c = {{.*}}global i32 2, section "C" + +__attribute__((section("D"))) +int d = init(); +// CHECK: @d = {{.*}}global i32 0, section "D" + +__attribute__((section("E"))) +int e; +// CHECK: @e = {{.*}}global i32 0, section "E", align 4