https://github.com/syzaara updated https://github.com/llvm/llvm-project/pull/226572
>From fa0920dce6c6ed913593bceab00fb2ba983c6997 Mon Sep 17 00:00:00 2001 From: Zaara Syeda <[email protected]> Date: Fri, 25 Sep 2026 15:03:11 -0400 Subject: [PATCH 1/6] [Clang] Retain constructor/destructor variants when symbol must be kept With -mconstructor-aliases, complete constructor and destructor variants with discardable-if-unused linkage can be silently replaced in the IR (RAUW) rather than emitted as distinct symbols. This prevents -fkeep-inline-functions and __attribute__((used)) from retaining the complete (C1/D1) variants. Skip RAUW when the declaration requires its symbol to be kept by introducing structorSymbolMustBeRetained(), which returns true when __attribute__((used)) is present or -fkeep-inline-functions is active for an inline definition that is not available_externally. Assisted-by: IBM Bob --- clang/lib/CodeGen/ItaniumCXXABI.cpp | 15 ++++++- clang/test/CodeGen/keep-inline-functions.cpp | 26 ++++-------- .../mconstructor-aliases-used-attr.cpp | 41 +++++++++++++++++++ 3 files changed, 63 insertions(+), 19 deletions(-) create mode 100644 clang/test/CodeGen/mconstructor-aliases-used-attr.cpp diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp index 754511e6a7d41..1c739e5175d33 100644 --- a/clang/lib/CodeGen/ItaniumCXXABI.cpp +++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp @@ -4735,7 +4735,19 @@ ItaniumCXXABI::RTTIUniquenessKind ItaniumCXXABI::classifyRTTIUniqueness( // Find out how to codegen the complete destructor and constructor namespace { enum class StructorCodegen { Emit, RAUW, Alias, COMDAT }; +} // namespace + +// Returns true if the complete constructor/destructor variant must be retained +// as a distinct symbol rather than being silently replaced in the IR (RAUW). +static bool +structorSymbolMustBeRetained(CodeGenModule &CGM, const CXXMethodDecl *MD, + llvm::GlobalValue::LinkageTypes Linkage) { + if (MD->hasAttr<UsedAttr>()) + return true; + return CGM.getCodeGenOpts().KeepInlineFunctions && MD->isInlined() && + Linkage != llvm::GlobalValue::AvailableExternallyLinkage; } + static StructorCodegen getCodegenToUse(CodeGenModule &CGM, const CXXMethodDecl *MD) { if (!CGM.getCodeGenOpts().CXXCtorDtorAliases) @@ -4755,7 +4767,8 @@ static StructorCodegen getCodegenToUse(CodeGenModule &CGM, } llvm::GlobalValue::LinkageTypes Linkage = CGM.getFunctionLinkage(AliasDecl); - if (llvm::GlobalValue::isDiscardableIfUnused(Linkage)) + if (llvm::GlobalValue::isDiscardableIfUnused(Linkage) && + !structorSymbolMustBeRetained(CGM, MD, Linkage)) return StructorCodegen::RAUW; // FIXME: Should we allow available_externally aliases? diff --git a/clang/test/CodeGen/keep-inline-functions.cpp b/clang/test/CodeGen/keep-inline-functions.cpp index 4c56fabaecc00..1c64a1d083895 100644 --- a/clang/test/CodeGen/keep-inline-functions.cpp +++ b/clang/test/CodeGen/keep-inline-functions.cpp @@ -5,12 +5,18 @@ // RUN: %clang_cc1 -O2 -fkeep-inline-functions -emit-llvm %s -o - -triple x86_64-pc-windows-msvc | FileCheck %s --check-prefix=MSVC // RUN: %clang_cc1 -O2 -fkeep-inline-functions -emit-llvm %s -o - -triple powerpc64-ibm-aix-xcoff | FileCheck %s // RUN: %clang_cc1 -O0 -fkeep-inline-functions -emit-llvm %s -o - -triple powerpc64-ibm-aix-xcoff | FileCheck %s -// RUN: %clang_cc1 -O0 -mconstructor-aliases -fkeep-inline-functions -emit-llvm %s -o - -triple powerpc64-ibm-aix-xcoff | FileCheck %s --check-prefix=CONSTRUCTOR-ALIASES + +// The driver enables -mconstructor-aliases by default for this target, but +// -cc1 does not, so pass it explicitly here. +// With -fkeep-inline-functions, C1/D1 must be emitted instead of being +// silently replaced in the IR (RAUW), so they remain available in the used +// list. +// RUN: %clang_cc1 -O0 -mconstructor-aliases -fkeep-inline-functions -emit-llvm %s -o - -triple powerpc64-ibm-aix-xcoff | FileCheck %s +// RUN: %clang_cc1 -O2 -mconstructor-aliases -fkeep-inline-functions -emit-llvm %s -o - -triple powerpc64-ibm-aix-xcoff | FileCheck %s // -fkeep-inline-functions retains inline function definitions available in // this translation unit. Definitions emitted with available_externally // linkage are excluded. - // Retained: // f1 explicit inline and referenced // f2 static inline @@ -77,22 +83,6 @@ int use(S s) { // CHECK-DAG: define {{.*}}@_ZN12TestCtorDtorC2Ev // CHECK-DAG: define {{.*}}@_ZN12TestCtorDtorD2Ev -// FIXME: -mconstructor-aliases is enabled by default by the driver for this -// target, but is not enabled by default for -cc1. With -mconstructor-aliases, -// the C1/D1 constructor and destructor variants are not emitted as separate -// definitions. - -// CONSTRUCTOR-ALIASES: @llvm{{(\.compiler)?}}.used = appending global [8 x ptr] - -// CONSTRUCTOR-ALIASES-DAG: define {{.*}}@_Z2f1i -// CONSTRUCTOR-ALIASES-DAG: define internal {{.*}}@_ZL2f2i -// CONSTRUCTOR-ALIASES-DAG: define {{.*}}@_Z2f3i -// CONSTRUCTOR-ALIASES-DAG: define {{.*}}@_ZN1S2f4Ev -// CONSTRUCTOR-ALIASES-DAG: define {{.*}}@_Z2f7i -// CONSTRUCTOR-ALIASES-DAG: define {{.*}}@_Z2f8IiET_S0_ -// CONSTRUCTOR-ALIASES-DAG: define {{.*}}@_ZN12TestCtorDtorC2Ev -// CONSTRUCTOR-ALIASES-DAG: define {{.*}}@_ZN12TestCtorDtorD2Ev - // MSVC: @llvm{{(\.compiler)?}}.used = appending global [8 x ptr] // MSVC-DAG: define {{.*}}@"?f1@@YAHH@Z" diff --git a/clang/test/CodeGen/mconstructor-aliases-used-attr.cpp b/clang/test/CodeGen/mconstructor-aliases-used-attr.cpp new file mode 100644 index 0000000000000..fdff81cb587f0 --- /dev/null +++ b/clang/test/CodeGen/mconstructor-aliases-used-attr.cpp @@ -0,0 +1,41 @@ +// Test that __attribute__((used)) on a constructor/destructor retains the +// C1/D1 complete variants when -mconstructor-aliases is active. +// +// Without the fix, -mconstructor-aliases causes C1/D1 to be silently replaced +// in the IR (RAUW) before SetCommonAttributes can add them to llvm.used, so +// __attribute__((used)) does not work as expected. + +// RUN: %clang_cc1 -O0 -mconstructor-aliases -emit-llvm %s -o - \ +// RUN: -triple powerpc64-ibm-aix-xcoff \ +// RUN: | FileCheck %s --check-prefixes=XCOFF,USED +// RUN: %clang_cc1 -O2 -mconstructor-aliases -emit-llvm %s -o - \ +// RUN: -triple powerpc64-ibm-aix-xcoff \ +// RUN: | FileCheck %s --check-prefixes=XCOFF,USED +// RUN: %clang_cc1 -O0 -mconstructor-aliases -emit-llvm %s -o - \ +// RUN: -triple x86_64-unknown-linux-gnu \ +// RUN: | FileCheck %s --check-prefixes=ELF,USED + +// Without -mconstructor-aliases the complete variants are always emitted as +// separate definitions and the normal path handles __attribute__((used)). +// RUN: %clang_cc1 -O0 -emit-llvm %s -o - \ +// RUN: -triple powerpc64-ibm-aix-xcoff \ +// RUN: | FileCheck %s --check-prefixes=XCOFF,USED + +struct Foo { + __attribute__((used)) Foo() {} + __attribute__((used)) ~Foo() {} +}; +// All four variants must appear in llvm.used/llvm.compiler.used. +// USED: @llvm{{(\.compiler)?}}.used = appending global [4 x ptr] + +// On XCOFF, C1/D1 are full definitions +// XCOFF-DAG: define {{.*}}@_ZN3FooC1Ev +// XCOFF-DAG: define {{.*}}@_ZN3FooC2Ev +// XCOFF-DAG: define {{.*}}@_ZN3FooD1Ev +// XCOFF-DAG: define {{.*}}@_ZN3FooD2Ev + +// On ELF, C1/D1 are aliases to C2/D2 +// ELF-DAG: @_ZN3FooC1Ev = {{.*}}alias{{.*}}@_ZN3FooC2Ev +// ELF-DAG: @_ZN3FooD1Ev = {{.*}}alias{{.*}}@_ZN3FooD2Ev +// ELF-DAG: define {{.*}}@_ZN3FooC2Ev +// ELF-DAG: define {{.*}}@_ZN3FooD2Ev >From 3c28cfafcfc8053c387f100e7b43c926c0bb85b8 Mon Sep 17 00:00:00 2001 From: Zaara Syeda <[email protected]> Date: Fri, 25 Sep 2026 15:10:12 -0400 Subject: [PATCH 2/6] clang-format --- clang/lib/CodeGen/ItaniumCXXABI.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp index 1c739e5175d33..460950b35c41e 100644 --- a/clang/lib/CodeGen/ItaniumCXXABI.cpp +++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp @@ -4741,7 +4741,7 @@ enum class StructorCodegen { Emit, RAUW, Alias, COMDAT }; // as a distinct symbol rather than being silently replaced in the IR (RAUW). static bool structorSymbolMustBeRetained(CodeGenModule &CGM, const CXXMethodDecl *MD, - llvm::GlobalValue::LinkageTypes Linkage) { + llvm::GlobalValue::LinkageTypes Linkage) { if (MD->hasAttr<UsedAttr>()) return true; return CGM.getCodeGenOpts().KeepInlineFunctions && MD->isInlined() && >From b543fea65f33f054d02d88e4b0c407d3fdc679fa Mon Sep 17 00:00:00 2001 From: Zaara Syeda <[email protected]> Date: Mon, 28 Sep 2026 16:00:00 -0400 Subject: [PATCH 3/6] Address review comments --- .../mconstructor-aliases-used-attr.cpp | 45 +++++++++++++++---- 1 file changed, 36 insertions(+), 9 deletions(-) diff --git a/clang/test/CodeGen/mconstructor-aliases-used-attr.cpp b/clang/test/CodeGen/mconstructor-aliases-used-attr.cpp index fdff81cb587f0..bf02a91f530fd 100644 --- a/clang/test/CodeGen/mconstructor-aliases-used-attr.cpp +++ b/clang/test/CodeGen/mconstructor-aliases-used-attr.cpp @@ -19,23 +19,50 @@ // separate definitions and the normal path handles __attribute__((used)). // RUN: %clang_cc1 -O0 -emit-llvm %s -o - \ // RUN: -triple powerpc64-ibm-aix-xcoff \ -// RUN: | FileCheck %s --check-prefixes=XCOFF,USED +// RUN: | FileCheck %s --check-prefixes=XCOFF-NOALIAS,USED struct Foo { __attribute__((used)) Foo() {} __attribute__((used)) ~Foo() {} }; -// All four variants must appear in llvm.used/llvm.compiler.used. -// USED: @llvm{{(\.compiler)?}}.used = appending global [4 x ptr] -// On XCOFF, C1/D1 are full definitions -// XCOFF-DAG: define {{.*}}@_ZN3FooC1Ev -// XCOFF-DAG: define {{.*}}@_ZN3FooC2Ev -// XCOFF-DAG: define {{.*}}@_ZN3FooD1Ev -// XCOFF-DAG: define {{.*}}@_ZN3FooD2Ev +namespace { +struct Bar { + __attribute__((used)) Bar() {} + __attribute__((used)) ~Bar() {} +}; +} + +// All eight variants (four for Foo, four for Bar) must appear in +// llvm.used/llvm.compiler.used. +// USED: @llvm{{(\.compiler)?}}.used = appending global [8 x ptr] + +// On XCOFF, C1/D1 are full definitions for externally visible Foo, +// while they are aliases to C2/D2 for internal-linkage Bar. +// XCOFF-DAG: define linkonce_odr {{.*}}@_ZN3FooC1Ev +// XCOFF-DAG: define linkonce_odr {{.*}}@_ZN3FooC2Ev +// XCOFF-DAG: define linkonce_odr {{.*}}@_ZN3FooD1Ev +// XCOFF-DAG: define linkonce_odr {{.*}}@_ZN3FooD2Ev +// XCOFF-DAG: @_ZN12_GLOBAL__N_13BarC1Ev = internal {{.*}}alias{{.*}}@_ZN12_GLOBAL__N_13BarC2Ev +// XCOFF-DAG: @_ZN12_GLOBAL__N_13BarD1Ev = internal {{.*}}alias{{.*}}@_ZN12_GLOBAL__N_13BarD2Ev +// XCOFF-DAG: define internal {{.*}}@_ZN12_GLOBAL__N_13BarC2Ev +// XCOFF-DAG: define internal {{.*}}@_ZN12_GLOBAL__N_13BarD2Ev + +// XCOFF-NOALIAS-DAG: define linkonce_odr {{.*}}@_ZN3FooC1Ev +// XCOFF-NOALIAS-DAG: define linkonce_odr {{.*}}@_ZN3FooC2Ev +// XCOFF-NOALIAS-DAG: define linkonce_odr {{.*}}@_ZN3FooD1Ev +// XCOFF-NOALIAS-DAG: define linkonce_odr {{.*}}@_ZN3FooD2Ev +// XCOFF-NOALIAS-DAG: define internal {{.*}}@_ZN12_GLOBAL__N_13BarC1Ev +// XCOFF-NOALIAS-DAG: define internal {{.*}}@_ZN12_GLOBAL__N_13BarC2Ev +// XCOFF-NOALIAS-DAG: define internal {{.*}}@_ZN12_GLOBAL__N_13BarD1Ev +// XCOFF-NOALIAS-DAG: define internal {{.*}}@_ZN12_GLOBAL__N_13BarD2Ev -// On ELF, C1/D1 are aliases to C2/D2 +// On ELF, C1/D1 are aliases to C2/D2 for both Foo and Bar. // ELF-DAG: @_ZN3FooC1Ev = {{.*}}alias{{.*}}@_ZN3FooC2Ev // ELF-DAG: @_ZN3FooD1Ev = {{.*}}alias{{.*}}@_ZN3FooD2Ev // ELF-DAG: define {{.*}}@_ZN3FooC2Ev // ELF-DAG: define {{.*}}@_ZN3FooD2Ev +// ELF-DAG: @_ZN12_GLOBAL__N_13BarC1Ev = internal {{.*}}alias{{.*}}@_ZN12_GLOBAL__N_13BarC2Ev +// ELF-DAG: @_ZN12_GLOBAL__N_13BarD1Ev = internal {{.*}}alias{{.*}}@_ZN12_GLOBAL__N_13BarD2Ev +// ELF-DAG: define internal {{.*}}@_ZN12_GLOBAL__N_13BarC2Ev +// ELF-DAG: define internal {{.*}}@_ZN12_GLOBAL__N_13BarD2Ev >From daa09fd578c77f7d2589606b858c7bbce7affa36 Mon Sep 17 00:00:00 2001 From: Zaara Syeda <[email protected]> Date: Mon, 28 Sep 2026 16:39:42 -0400 Subject: [PATCH 4/6] Address review comments --- .../mconstructor-aliases-used-attr.cpp | 68 ------------------- clang/test/CodeGenCXX/attr-used.cpp | 63 +++++++++++++++++ 2 files changed, 63 insertions(+), 68 deletions(-) delete mode 100644 clang/test/CodeGen/mconstructor-aliases-used-attr.cpp diff --git a/clang/test/CodeGen/mconstructor-aliases-used-attr.cpp b/clang/test/CodeGen/mconstructor-aliases-used-attr.cpp deleted file mode 100644 index bf02a91f530fd..0000000000000 --- a/clang/test/CodeGen/mconstructor-aliases-used-attr.cpp +++ /dev/null @@ -1,68 +0,0 @@ -// Test that __attribute__((used)) on a constructor/destructor retains the -// C1/D1 complete variants when -mconstructor-aliases is active. -// -// Without the fix, -mconstructor-aliases causes C1/D1 to be silently replaced -// in the IR (RAUW) before SetCommonAttributes can add them to llvm.used, so -// __attribute__((used)) does not work as expected. - -// RUN: %clang_cc1 -O0 -mconstructor-aliases -emit-llvm %s -o - \ -// RUN: -triple powerpc64-ibm-aix-xcoff \ -// RUN: | FileCheck %s --check-prefixes=XCOFF,USED -// RUN: %clang_cc1 -O2 -mconstructor-aliases -emit-llvm %s -o - \ -// RUN: -triple powerpc64-ibm-aix-xcoff \ -// RUN: | FileCheck %s --check-prefixes=XCOFF,USED -// RUN: %clang_cc1 -O0 -mconstructor-aliases -emit-llvm %s -o - \ -// RUN: -triple x86_64-unknown-linux-gnu \ -// RUN: | FileCheck %s --check-prefixes=ELF,USED - -// Without -mconstructor-aliases the complete variants are always emitted as -// separate definitions and the normal path handles __attribute__((used)). -// RUN: %clang_cc1 -O0 -emit-llvm %s -o - \ -// RUN: -triple powerpc64-ibm-aix-xcoff \ -// RUN: | FileCheck %s --check-prefixes=XCOFF-NOALIAS,USED - -struct Foo { - __attribute__((used)) Foo() {} - __attribute__((used)) ~Foo() {} -}; - -namespace { -struct Bar { - __attribute__((used)) Bar() {} - __attribute__((used)) ~Bar() {} -}; -} - -// All eight variants (four for Foo, four for Bar) must appear in -// llvm.used/llvm.compiler.used. -// USED: @llvm{{(\.compiler)?}}.used = appending global [8 x ptr] - -// On XCOFF, C1/D1 are full definitions for externally visible Foo, -// while they are aliases to C2/D2 for internal-linkage Bar. -// XCOFF-DAG: define linkonce_odr {{.*}}@_ZN3FooC1Ev -// XCOFF-DAG: define linkonce_odr {{.*}}@_ZN3FooC2Ev -// XCOFF-DAG: define linkonce_odr {{.*}}@_ZN3FooD1Ev -// XCOFF-DAG: define linkonce_odr {{.*}}@_ZN3FooD2Ev -// XCOFF-DAG: @_ZN12_GLOBAL__N_13BarC1Ev = internal {{.*}}alias{{.*}}@_ZN12_GLOBAL__N_13BarC2Ev -// XCOFF-DAG: @_ZN12_GLOBAL__N_13BarD1Ev = internal {{.*}}alias{{.*}}@_ZN12_GLOBAL__N_13BarD2Ev -// XCOFF-DAG: define internal {{.*}}@_ZN12_GLOBAL__N_13BarC2Ev -// XCOFF-DAG: define internal {{.*}}@_ZN12_GLOBAL__N_13BarD2Ev - -// XCOFF-NOALIAS-DAG: define linkonce_odr {{.*}}@_ZN3FooC1Ev -// XCOFF-NOALIAS-DAG: define linkonce_odr {{.*}}@_ZN3FooC2Ev -// XCOFF-NOALIAS-DAG: define linkonce_odr {{.*}}@_ZN3FooD1Ev -// XCOFF-NOALIAS-DAG: define linkonce_odr {{.*}}@_ZN3FooD2Ev -// XCOFF-NOALIAS-DAG: define internal {{.*}}@_ZN12_GLOBAL__N_13BarC1Ev -// XCOFF-NOALIAS-DAG: define internal {{.*}}@_ZN12_GLOBAL__N_13BarC2Ev -// XCOFF-NOALIAS-DAG: define internal {{.*}}@_ZN12_GLOBAL__N_13BarD1Ev -// XCOFF-NOALIAS-DAG: define internal {{.*}}@_ZN12_GLOBAL__N_13BarD2Ev - -// On ELF, C1/D1 are aliases to C2/D2 for both Foo and Bar. -// ELF-DAG: @_ZN3FooC1Ev = {{.*}}alias{{.*}}@_ZN3FooC2Ev -// ELF-DAG: @_ZN3FooD1Ev = {{.*}}alias{{.*}}@_ZN3FooD2Ev -// ELF-DAG: define {{.*}}@_ZN3FooC2Ev -// ELF-DAG: define {{.*}}@_ZN3FooD2Ev -// ELF-DAG: @_ZN12_GLOBAL__N_13BarC1Ev = internal {{.*}}alias{{.*}}@_ZN12_GLOBAL__N_13BarC2Ev -// ELF-DAG: @_ZN12_GLOBAL__N_13BarD1Ev = internal {{.*}}alias{{.*}}@_ZN12_GLOBAL__N_13BarD2Ev -// ELF-DAG: define internal {{.*}}@_ZN12_GLOBAL__N_13BarC2Ev -// ELF-DAG: define internal {{.*}}@_ZN12_GLOBAL__N_13BarD2Ev diff --git a/clang/test/CodeGenCXX/attr-used.cpp b/clang/test/CodeGenCXX/attr-used.cpp index 8ca37f6194ec2..dd0dc18b6d62c 100644 --- a/clang/test/CodeGenCXX/attr-used.cpp +++ b/clang/test/CodeGenCXX/attr-used.cpp @@ -1,4 +1,16 @@ // RUN: %clang_cc1 -emit-llvm -triple %itanium_abi_triple -o - %s | FileCheck %s +// RUN: %clang_cc1 -O0 -mconstructor-aliases -emit-llvm %s -o - \ +// RUN: -triple powerpc64-ibm-aix-xcoff \ +// RUN: | FileCheck %s --check-prefixes=XCOFF +// RUN: %clang_cc1 -O2 -mconstructor-aliases -emit-llvm %s -o - \ +// RUN: -triple powerpc64-ibm-aix-xcoff \ +// RUN: | FileCheck %s --check-prefixes=XCOFF +// RUN: %clang_cc1 -O0 -mconstructor-aliases -emit-llvm %s -o - \ +// RUN: -triple x86_64-unknown-linux-gnu \ +// RUN: | FileCheck %s --check-prefixes=ELF +// RUN: %clang_cc1 -O0 -emit-llvm %s -o - \ +// RUN: -triple powerpc64-ibm-aix-xcoff \ +// RUN: | FileCheck %s --check-prefixes=XCOFF-NOALIAS // clang++ not respecting __attribute__((used)) on destructors struct X0 { @@ -25,3 +37,54 @@ struct X2 { // CHECK-DAG: define linkonce_odr {{.*}} @_ZN2X23barEv // CHECK-DAG: define linkonce_odr {{.*}} @_ZN2X23fooEv }; + +// Test that __attribute__((used)) on a constructor/destructor retains the +// C1/D1 complete variants when -mconstructor-aliases is active. +// +// Without the fix, -mconstructor-aliases causes C1/D1 to be silently replaced +// in the IR (RAUW) before SetCommonAttributes can add them to llvm.used, so +// __attribute__((used)) does not work as expected. + +struct Foo { + __attribute__((used)) Foo() {} + __attribute__((used)) ~Foo() {} +}; + +namespace { +struct Bar { + __attribute__((used)) Bar() {} + __attribute__((used)) ~Bar() {} +}; +} // namespace + + +// On XCOFF, C1/D1 are full definitions for externally visible Foo, +// while they are aliases to C2/D2 for internal-linkage Bar. +// XCOFF-DAG: define linkonce_odr {{.*}}@_ZN3FooC1Ev +// XCOFF-DAG: define linkonce_odr {{.*}}@_ZN3FooC2Ev +// XCOFF-DAG: define linkonce_odr {{.*}}@_ZN3FooD1Ev +// XCOFF-DAG: define linkonce_odr {{.*}}@_ZN3FooD2Ev +// XCOFF-DAG: @_ZN12_GLOBAL__N_13BarC1Ev = internal {{.*}}alias{{.*}}@_ZN12_GLOBAL__N_13BarC2Ev +// XCOFF-DAG: @_ZN12_GLOBAL__N_13BarD1Ev = internal {{.*}}alias{{.*}}@_ZN12_GLOBAL__N_13BarD2Ev +// XCOFF-DAG: define internal {{.*}}@_ZN12_GLOBAL__N_13BarC2Ev +// XCOFF-DAG: define internal {{.*}}@_ZN12_GLOBAL__N_13BarD2Ev + +// XCOFF without -mconstructor-aliases: all variants are full definitions. +// XCOFF-NOALIAS-DAG: define linkonce_odr {{.*}}@_ZN3FooC1Ev +// XCOFF-NOALIAS-DAG: define linkonce_odr {{.*}}@_ZN3FooC2Ev +// XCOFF-NOALIAS-DAG: define linkonce_odr {{.*}}@_ZN3FooD1Ev +// XCOFF-NOALIAS-DAG: define linkonce_odr {{.*}}@_ZN3FooD2Ev +// XCOFF-NOALIAS-DAG: define internal {{.*}}@_ZN12_GLOBAL__N_13BarC1Ev +// XCOFF-NOALIAS-DAG: define internal {{.*}}@_ZN12_GLOBAL__N_13BarC2Ev +// XCOFF-NOALIAS-DAG: define internal {{.*}}@_ZN12_GLOBAL__N_13BarD1Ev +// XCOFF-NOALIAS-DAG: define internal {{.*}}@_ZN12_GLOBAL__N_13BarD2Ev + +// On ELF, C1/D1 are aliases to C2/D2 for both Foo and Bar. +// ELF-DAG: @_ZN3FooC1Ev = {{.*}}alias{{.*}}@_ZN3FooC2Ev +// ELF-DAG: @_ZN3FooD1Ev = {{.*}}alias{{.*}}@_ZN3FooD2Ev +// ELF-DAG: define {{.*}}@_ZN3FooC2Ev +// ELF-DAG: define {{.*}}@_ZN3FooD2Ev +// ELF-DAG: @_ZN12_GLOBAL__N_13BarC1Ev = internal {{.*}}alias{{.*}}@_ZN12_GLOBAL__N_13BarC2Ev +// ELF-DAG: @_ZN12_GLOBAL__N_13BarD1Ev = internal {{.*}}alias{{.*}}@_ZN12_GLOBAL__N_13BarD2Ev +// ELF-DAG: define internal {{.*}}@_ZN12_GLOBAL__N_13BarC2Ev +// ELF-DAG: define internal {{.*}}@_ZN12_GLOBAL__N_13BarD2Ev >From 3844ea683a9bdaa1c6869181c675be0fc0eefe9e Mon Sep 17 00:00:00 2001 From: Zaara Syeda <[email protected]> Date: Mon, 28 Sep 2026 17:14:50 -0400 Subject: [PATCH 5/6] Address review comments --- clang/test/CodeGenCXX/attr-used.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/clang/test/CodeGenCXX/attr-used.cpp b/clang/test/CodeGenCXX/attr-used.cpp index dd0dc18b6d62c..f1bb63d798988 100644 --- a/clang/test/CodeGenCXX/attr-used.cpp +++ b/clang/test/CodeGenCXX/attr-used.cpp @@ -58,8 +58,11 @@ struct Bar { } // namespace -// On XCOFF, C1/D1 are full definitions for externally visible Foo, -// while they are aliases to C2/D2 for internal-linkage Bar. +// On XCOFF, Foo's constructors/destructors have linkonce_odr linkage. C1/D1 +// are emitted as full definitions since linkonce_odr does not guarantee that +// an alias and its target will be retained from the same translation unit. +// Bar's C1/D1 have internal linkage, so they are confined to the translation +// unit and can safely be aliases to C2/D2. // XCOFF-DAG: define linkonce_odr {{.*}}@_ZN3FooC1Ev // XCOFF-DAG: define linkonce_odr {{.*}}@_ZN3FooC2Ev // XCOFF-DAG: define linkonce_odr {{.*}}@_ZN3FooD1Ev >From 361c1e8f3bd603a7da39bd0964e3c26e739835ad Mon Sep 17 00:00:00 2001 From: Zaara Syeda <[email protected]> Date: Mon, 28 Sep 2026 18:02:02 -0400 Subject: [PATCH 6/6] Address review comments --- clang/test/CodeGenCXX/attr-used.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/clang/test/CodeGenCXX/attr-used.cpp b/clang/test/CodeGenCXX/attr-used.cpp index f1bb63d798988..ced13cd2cbeac 100644 --- a/clang/test/CodeGenCXX/attr-used.cpp +++ b/clang/test/CodeGenCXX/attr-used.cpp @@ -58,11 +58,11 @@ struct Bar { } // namespace -// On XCOFF, Foo's constructors/destructors have linkonce_odr linkage. C1/D1 -// are emitted as full definitions since linkonce_odr does not guarantee that -// an alias and its target will be retained from the same translation unit. -// Bar's C1/D1 have internal linkage, so they are confined to the translation -// unit and can safely be aliases to C2/D2. +// C1/D1 are aliases to C2/D2 when the linkage is not weak-for-linker. +// Bar has internal linkage (not weak-for-linker), so C1/D1 are aliases. +// Foo has linkonce_odr linkage (weak-for-linker): on ELF this produces a +// COMDAT, but XCOFF does not support COMDAT so C1/D1 are emitted as full +// definitions instead. // XCOFF-DAG: define linkonce_odr {{.*}}@_ZN3FooC1Ev // XCOFF-DAG: define linkonce_odr {{.*}}@_ZN3FooC2Ev // XCOFF-DAG: define linkonce_odr {{.*}}@_ZN3FooD1Ev _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
