Skip to content

Commit b3c1403

Browse files
authored
[clang] Fix std::tm etc. mangling on Solaris (#106353)
Recently, Solaris bootstrap got broken because Solaris uses a non-standard mangling of `std::tm` and a few others. This was fixed with a hack in PR #100724. The Solaris ABI requires mangling `std::tm` as `tm` and similarly for `std::div_t`, `std::ldiv_t`, and `std::lconv`, which is what this patch implements. The hack needs to stay in place to allow building with older versions of `clang`. Tested on `amd64-pc-solaris2.11`, `sparcv9-sun-solaris2.11` (2-stage builds with both `clang-19` and `gcc-14` as build compiler), and `x86_64-pc-linux-gnu`.
1 parent 971b579 commit b3c1403

File tree

4 files changed

+60
-3
lines changed

4 files changed

+60
-3
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -510,6 +510,10 @@ OpenACC Specific Changes
510510
Target Specific Changes
511511
-----------------------
512512

513+
- Clang now implements the Solaris-specific mangling of ``std::tm`` as
514+
``tm``, same for ``std::div_t``, ``std::ldiv_t``, and
515+
``std::lconv``, for Solaris ABI compatibility. (#GH33114)
516+
513517
AMDGPU Support
514518
^^^^^^^^^^^^^^
515519

clang/lib/AST/ItaniumMangle.cpp

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1164,8 +1164,25 @@ void CXXNameMangler::mangleUnscopedName(GlobalDecl GD, const DeclContext *DC,
11641164
// ::= St <unqualified-name> # ::std::
11651165

11661166
assert(!isa<LinkageSpecDecl>(DC) && "unskipped LinkageSpecDecl");
1167-
if (isStdNamespace(DC))
1167+
if (isStdNamespace(DC)) {
1168+
if (getASTContext().getTargetInfo().getTriple().isOSSolaris()) {
1169+
const NamedDecl *ND = cast<NamedDecl>(GD.getDecl());
1170+
if (const RecordDecl *RD = dyn_cast<RecordDecl>(ND)) {
1171+
// Issue #33114: Need non-standard mangling of std::tm etc. for
1172+
// Solaris ABI compatibility.
1173+
//
1174+
// <substitution> ::= tm # ::std::tm, same for the others
1175+
if (const IdentifierInfo *II = RD->getIdentifier()) {
1176+
StringRef type = II->getName();
1177+
if (llvm::is_contained({"div_t", "ldiv_t", "lconv", "tm"}, type)) {
1178+
Out << type.size() << type;
1179+
return;
1180+
}
1181+
}
1182+
}
1183+
}
11681184
Out << "St";
1185+
}
11691186

11701187
mangleUnqualifiedName(GD, DC, AdditionalAbiTags);
11711188
}

clang/lib/Lex/PPMacroExpansion.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1604,10 +1604,12 @@ static bool isTargetVariantEnvironment(const TargetInfo &TI,
16041604
return false;
16051605
}
16061606

1607-
#if defined(__sun__) && defined(__svr4__)
1607+
#if defined(__sun__) && defined(__svr4__) && defined(__clang__) && \
1608+
__clang__ < 20
16081609
// GCC mangles std::tm as tm for binary compatibility on Solaris (Issue
16091610
// #33114). We need to match this to allow the std::put_time calls to link
1610-
// (PR #99075).
1611+
// (PR #99075). clang 20 contains a fix, but the workaround is still needed
1612+
// with older versions.
16111613
asm("_ZNKSt8time_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE3putES3_"
16121614
"RSt8ios_basecPKSt2tmPKcSB_ = "
16131615
"_ZNKSt8time_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE3putES3_"

clang/test/AST/solaris-tm.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/// Check that std::tm and a few others are mangled as tm on Solaris only.
2+
/// Issue #33114.
3+
///
4+
// RUN: %clang_cc1 -emit-llvm %s -o - -triple amd64-pc-solaris2.11 | FileCheck --check-prefix=CHECK-SOLARIS %s
5+
// RUN: %clang_cc1 -emit-llvm %s -o - -triple x86_64-unknown-linux-gnu | FileCheck --check-prefix=CHECK-LINUX %s
6+
//
7+
// REQUIRES: x86-registered-target
8+
9+
namespace std {
10+
extern "C" {
11+
struct tm {
12+
int tm_sec;
13+
};
14+
struct ldiv_t {
15+
long quot;
16+
};
17+
}
18+
}
19+
20+
// CHECK-SOLARIS: @_Z6tmfunc2tm
21+
// CHECK-SOLARIS: @_Z9tmccpfunc2tmPKcS1_
22+
// CHECK-SOLARIS: @_Z7tm2func2tmS_
23+
// CHECK-LINUX: @_Z6tmfuncSt2tm
24+
// CHECK-LINUX: @_Z9tmccpfuncSt2tmPKcS1_
25+
// CHECK-LINUX: @_Z7tm2funcSt2tmS_
26+
27+
void tmfunc (std::tm tm) {}
28+
void tmccpfunc (std::tm tm, const char *ccp, const char *ccp2) {}
29+
void tm2func (std::tm tm, std::tm tm2) {}
30+
31+
// CHECK-SOLARIS: @_Z7ldtfunc6ldiv_t
32+
// CHECK-LINUX: @_Z7ldtfuncSt6ldiv_t
33+
34+
void ldtfunc (std::ldiv_t ldt) {}

0 commit comments

Comments
 (0)