Skip to content

Commit 9c7aeae

Browse files
committed
Itanium Mangling: Mangle __alignof__ differently than alignof.
The two operations have acted differently since Clang 8, but were unfortunately mangled the same. The new mangling uses new "vendor extended expression" syntax proposed in itanium-cxx-abi/cxx-abi#112 GCC had the same mangling problem, https://gcc.gnu.org/PR88115, and will hopefully be switching to the same mangling as implemented here. Additionally, fix the mangling of `__uuidof` to use the new extension syntax, instead of its previous nonstandard special-case. Adjusts the demangler accordingly. Differential Revision: https://reviews.llvm.org/D93922
1 parent 58aa049 commit 9c7aeae

File tree

6 files changed

+211
-111
lines changed

6 files changed

+211
-111
lines changed

clang/lib/AST/ItaniumMangle.cpp

Lines changed: 70 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -558,6 +558,7 @@ class CXXNameMangler {
558558
unsigned NumTemplateArgs);
559559
void mangleTemplateArgs(TemplateName TN, const TemplateArgumentList &AL);
560560
void mangleTemplateArg(TemplateArgument A, bool NeedExactType);
561+
void mangleTemplateArgExpr(const Expr *E);
561562
void mangleValueInTemplateArg(QualType T, const APValue &V, bool TopLevel,
562563
bool NeedExactType = false);
563564

@@ -3528,8 +3529,8 @@ void CXXNameMangler::mangleType(const DependentSizedMatrixType *T) {
35283529
Out << "u" << VendorQualifier.size() << VendorQualifier;
35293530

35303531
Out << "I";
3531-
mangleTemplateArg(T->getRowExpr(), false);
3532-
mangleTemplateArg(T->getColumnExpr(), false);
3532+
mangleTemplateArgExpr(T->getRowExpr());
3533+
mangleTemplateArgExpr(T->getColumnExpr());
35333534
mangleType(T->getElementType());
35343535
Out << "E";
35353536
}
@@ -3916,6 +3917,7 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
39163917
// ::= ds <expression> <expression> # expr.*expr
39173918
// ::= sZ <template-param> # size of a parameter pack
39183919
// ::= sZ <function-param> # size of a function parameter pack
3920+
// ::= u <source-name> <template-arg>* E # vendor extended expression
39193921
// ::= <expr-primary>
39203922
// <expr-primary> ::= L <type> <value number> E # integer literal
39213923
// ::= L <type <value float> E # floating literal
@@ -4007,14 +4009,26 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
40074009

40084010
case Expr::CXXUuidofExprClass: {
40094011
const CXXUuidofExpr *UE = cast<CXXUuidofExpr>(E);
4010-
if (UE->isTypeOperand()) {
4011-
QualType UuidT = UE->getTypeOperand(Context.getASTContext());
4012-
Out << "u8__uuidoft";
4013-
mangleType(UuidT);
4012+
// As of clang 12, uuidof uses the vendor extended expression
4013+
// mangling. Previously, it used a special-cased nonstandard extension.
4014+
if (Context.getASTContext().getLangOpts().getClangABICompat() >
4015+
LangOptions::ClangABI::Ver11) {
4016+
Out << "u8__uuidof";
4017+
if (UE->isTypeOperand())
4018+
mangleType(UE->getTypeOperand(Context.getASTContext()));
4019+
else
4020+
mangleTemplateArgExpr(UE->getExprOperand());
4021+
Out << 'E';
40144022
} else {
4015-
Expr *UuidExp = UE->getExprOperand();
4016-
Out << "u8__uuidofz";
4017-
mangleExpression(UuidExp, Arity);
4023+
if (UE->isTypeOperand()) {
4024+
QualType UuidT = UE->getTypeOperand(Context.getASTContext());
4025+
Out << "u8__uuidoft";
4026+
mangleType(UuidT);
4027+
} else {
4028+
Expr *UuidExp = UE->getExprOperand();
4029+
Out << "u8__uuidofz";
4030+
mangleExpression(UuidExp, Arity);
4031+
}
40184032
}
40194033
break;
40204034
}
@@ -4312,13 +4326,39 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
43124326
break;
43134327
}
43144328

4329+
auto MangleAlignofSizeofArg = [&] {
4330+
if (SAE->isArgumentType()) {
4331+
Out << 't';
4332+
mangleType(SAE->getArgumentType());
4333+
} else {
4334+
Out << 'z';
4335+
mangleExpression(SAE->getArgumentExpr());
4336+
}
4337+
};
4338+
43154339
switch(SAE->getKind()) {
43164340
case UETT_SizeOf:
43174341
Out << 's';
4342+
MangleAlignofSizeofArg();
43184343
break;
43194344
case UETT_PreferredAlignOf:
4345+
// As of clang 12, we mangle __alignof__ differently than alignof. (They
4346+
// have acted differently since Clang 8, but were previously mangled the
4347+
// same.)
4348+
if (Context.getASTContext().getLangOpts().getClangABICompat() >
4349+
LangOptions::ClangABI::Ver11) {
4350+
Out << "u11__alignof__";
4351+
if (SAE->isArgumentType())
4352+
mangleType(SAE->getArgumentType());
4353+
else
4354+
mangleTemplateArgExpr(SAE->getArgumentExpr());
4355+
Out << 'E';
4356+
break;
4357+
}
4358+
LLVM_FALLTHROUGH;
43204359
case UETT_AlignOf:
43214360
Out << 'a';
4361+
MangleAlignofSizeofArg();
43224362
break;
43234363
case UETT_VecStep: {
43244364
DiagnosticsEngine &Diags = Context.getDiags();
@@ -4336,13 +4376,6 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
43364376
return;
43374377
}
43384378
}
4339-
if (SAE->isArgumentType()) {
4340-
Out << 't';
4341-
mangleType(SAE->getArgumentType());
4342-
} else {
4343-
Out << 'z';
4344-
mangleExpression(SAE->getArgumentExpr());
4345-
}
43464379
break;
43474380
}
43484381

@@ -4971,23 +5004,7 @@ void CXXNameMangler::mangleTemplateArg(TemplateArgument A, bool NeedExactType) {
49715004
mangleType(A.getAsTemplateOrTemplatePattern());
49725005
break;
49735006
case TemplateArgument::Expression: {
4974-
// It's possible to end up with a DeclRefExpr here in certain
4975-
// dependent cases, in which case we should mangle as a
4976-
// declaration.
4977-
const Expr *E = A.getAsExpr()->IgnoreParenImpCasts();
4978-
if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) {
4979-
const ValueDecl *D = DRE->getDecl();
4980-
if (isa<VarDecl>(D) || isa<FunctionDecl>(D)) {
4981-
Out << 'L';
4982-
mangle(D);
4983-
Out << 'E';
4984-
break;
4985-
}
4986-
}
4987-
4988-
Out << 'X';
4989-
mangleExpression(E);
4990-
Out << 'E';
5007+
mangleTemplateArgExpr(A.getAsExpr());
49915008
break;
49925009
}
49935010
case TemplateArgument::Integral:
@@ -5044,6 +5061,26 @@ void CXXNameMangler::mangleTemplateArg(TemplateArgument A, bool NeedExactType) {
50445061
}
50455062
}
50465063

5064+
void CXXNameMangler::mangleTemplateArgExpr(const Expr *E) {
5065+
// It's possible to end up with a DeclRefExpr here in certain
5066+
// dependent cases, in which case we should mangle as a
5067+
// declaration.
5068+
E = E->IgnoreParenImpCasts();
5069+
if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) {
5070+
const ValueDecl *D = DRE->getDecl();
5071+
if (isa<VarDecl>(D) || isa<FunctionDecl>(D)) {
5072+
Out << 'L';
5073+
mangle(D);
5074+
Out << 'E';
5075+
return;
5076+
}
5077+
}
5078+
5079+
Out << 'X';
5080+
mangleExpression(E);
5081+
Out << 'E';
5082+
}
5083+
50475084
/// Determine whether a given value is equivalent to zero-initialization for
50485085
/// the purpose of discarding a trailing portion of a 'tl' mangling.
50495086
///
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// RUN: %clang_cc1 -std=c++11 -Wno-gnu-alignof-expression -emit-llvm %s -o - -triple=%itanium_abi_triple | FileCheck %s --check-prefix=CHECK-NEW
2+
// RUN: %clang_cc1 -std=c++11 -Wno-gnu-alignof-expression -emit-llvm %s -o - -triple=%itanium_abi_triple -fclang-abi-compat=11 | FileCheck %s --check-prefix=CHECK-OLD
3+
4+
// Verify the difference in mangling for alignof and __alignof__ in a new ABI
5+
// compat mode.
6+
7+
template <class T> void f1(decltype(alignof(T))) {}
8+
template void f1<int>(__SIZE_TYPE__);
9+
// CHECK-OLD: void @_Z2f1IiEvDTatT_E
10+
// CHECK-NEW: void @_Z2f1IiEvDTatT_E
11+
12+
template <class T> void f2(decltype(__alignof__(T))) {}
13+
template void f2<int>(__SIZE_TYPE__);
14+
// CHECK-OLD: void @_Z2f2IiEvDTatT_E
15+
// CHECK-NEW: void @_Z2f2IiEvDTu11__alignof__T_E
16+
17+
template <class T> void f3(decltype(alignof(T(0)))) {}
18+
template void f3<int>(__SIZE_TYPE__);
19+
// CHECK-OLD: void @_Z2f3IiEvDTazcvT_Li0EE
20+
// CHECK-NEW: void @_Z2f3IiEvDTazcvT_Li0EE
21+
22+
template <class T> void f4(decltype(__alignof__(T(0)))) {}
23+
template void f4<int>(__SIZE_TYPE__);
24+
// CHECK-OLD: void @_Z2f4IiEvDTazcvT_Li0EE
25+
// CHECK-NEW: void @_Z2f4IiEvDTu11__alignof__XcvT_Li0EEEE

clang/test/CodeGenCXX/microsoft-uuidof-mangling.cpp

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
// RUN: %clang_cc1 -emit-llvm %s -o - -triple x86_64-unknown-unknown -fms-extensions | FileCheck %s
1+
// RUN: %clang_cc1 -emit-llvm %s -o - -triple x86_64-unknown-unknown -fms-extensions | FileCheck %s --check-prefixes=CHECK,CHECK-V12
2+
// RUN: %clang_cc1 -emit-llvm %s -o - -triple x86_64-unknown-unknown -fms-extensions -fclang-abi-compat=11 | FileCheck %s --check-prefixes=CHECK,CHECK-V11
23
// rdar://17784718
34

45
typedef struct _GUID
@@ -24,11 +25,16 @@ struct __declspec(uuid("EAFA1952-66F8-438B-8FBA-AF1BBAE42191")) TestStruct
2425

2526
struct __declspec(uuid("EAFA1952-66F8-438B-8FBA-AF1BBAE42191")) OtherStruct {};
2627

27-
template <class T> void test_uuidofType(void *arg[sizeof(__uuidof(T))] = 0) {}
28+
template <class T> void test_uuidofType(decltype(__uuidof(T)) arg) {}
2829

29-
template <class T> void test_uuidofExpr(void *arg[sizeof(__uuidof(typename T::member))] = 0) {}
30+
template <class T> void test_uuidofExpr(decltype(__uuidof(T::member)) arg) {}
3031

31-
struct HasMember { typedef TestStruct member; };
32+
struct HasMember {
33+
TestStruct member;
34+
};
35+
36+
// Ensure that mangling an "expr-primary" argument is handled properly.
37+
template <class T> void test_uuidofExpr2(decltype(T{}, __uuidof(HasMember::member)) arg) {}
3238

3339
template<const GUID&> struct UUIDTestTwo { UUIDTestTwo(); };
3440

@@ -39,19 +45,29 @@ int main(int argc, const char * argv[])
3945
// type had better not mention TestStruct or OtherStruct!
4046
UUIDTestTwo<__uuidof(TestStruct)> uuidof_test2;
4147
UUIDTestTwo<__uuidof(OtherStruct)> uuidof_test3;
42-
test_uuidofType<TestStruct>();
43-
test_uuidofExpr<HasMember>();
48+
test_uuidofType<TestStruct>(GUID{});
49+
test_uuidofExpr<HasMember>(GUID{});
50+
test_uuidofExpr2<TestStruct>(GUID{});
4451
return 0;
4552
}
4653

4754
// CHECK: define{{.*}} i32 @main
48-
// CHECK: call void @_ZN8UUIDTestI10TestStructL_Z42_GUID_eafa1952_66f8_438b_8fba_af1bbae42191EEC1Ev
49-
// CHECK: call void @_ZN11UUIDTestTwoIL_Z42_GUID_eafa1952_66f8_438b_8fba_af1bbae42191EEC1Ev
50-
// CHECK: call void @_ZN11UUIDTestTwoIL_Z42_GUID_eafa1952_66f8_438b_8fba_af1bbae42191EEC1Ev
51-
// CHECK: call void @_Z15test_uuidofTypeI10TestStructEvPPv(i8** null)
52-
// CHECK: call void @_Z15test_uuidofExprI9HasMemberEvPPv(i8** null)
53-
55+
// CHECK: call void @_ZN8UUIDTestI10TestStructL_Z42_GUID_eafa1952_66f8_438b_8fba_af1bbae42191EEC1Ev(
56+
// CHECK: call void @_ZN11UUIDTestTwoIL_Z42_GUID_eafa1952_66f8_438b_8fba_af1bbae42191EEC1Ev(
57+
// CHECK: call void @_ZN11UUIDTestTwoIL_Z42_GUID_eafa1952_66f8_438b_8fba_af1bbae42191EEC1Ev(
58+
// CHECK-V11: call void @_Z15test_uuidofTypeI10TestStructEvDTu8__uuidoftT_E(
59+
// CHECK-V12: call void @_Z15test_uuidofTypeI10TestStructEvDTu8__uuidofT_EE(
60+
// CHECK-V11: call void @_Z15test_uuidofExprI9HasMemberEvDTu8__uuidofzsrT_6memberE(
61+
// CHECK-V12: call void @_Z15test_uuidofExprI9HasMemberEvDTu8__uuidofXsrT_6memberEEE(
62+
// CHECK-V11: call void @_Z16test_uuidofExpr2I10TestStructEvDTcmtlT_Eu8__uuidofzL_ZN9HasMember6memberEEE(
63+
// CHECK-V12: call void @_Z16test_uuidofExpr2I10TestStructEvDTcmtlT_Eu8__uuidofXL_ZN9HasMember6memberEEEEE(
64+
// TODO: the above mangling is wrong -- the X/E shouldn't be emitted: ^ ^
5465
// CHECK: define linkonce_odr void @_ZN8UUIDTestI10TestStructL_Z42_GUID_eafa1952_66f8_438b_8fba_af1bbae42191EEC1Ev
55-
// CHECK: define linkonce_odr void @_Z15test_uuidofTypeI10TestStructEvPPv
56-
// CHECK: define linkonce_odr void @_Z15test_uuidofExprI9HasMemberEvPPv
66+
// CHECK-V11: define linkonce_odr void @_Z15test_uuidofTypeI10TestStructEvDTu8__uuidoftT_E(
67+
// CHECK-V12: define linkonce_odr void @_Z15test_uuidofTypeI10TestStructEvDTu8__uuidofT_EE(
68+
// CHECK-V11: define linkonce_odr void @_Z15test_uuidofExprI9HasMemberEvDTu8__uuidofzsrT_6memberE(
69+
// CHECK-V12: define linkonce_odr void @_Z15test_uuidofExprI9HasMemberEvDTu8__uuidofXsrT_6memberEEE(
70+
// CHECK-V11: define linkonce_odr void @_Z16test_uuidofExpr2I10TestStructEvDTcmtlT_Eu8__uuidofzL_ZN9HasMember6memberEEE(
71+
// CHECK-V12: define linkonce_odr void @_Z16test_uuidofExpr2I10TestStructEvDTcmtlT_Eu8__uuidofXL_ZN9HasMember6memberEEEEE(
72+
// TODO: the above mangling is wrong -- the X/E shouldn't be emitted: ^ ^
5773
// CHECK: define linkonce_odr void @_ZN8UUIDTestI10TestStructL_Z42_GUID_eafa1952_66f8_438b_8fba_af1bbae42191EEC2Ev

libcxxabi/src/demangle/ItaniumDemangle.h

Lines changed: 37 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,6 @@
9696
X(InitListExpr) \
9797
X(FoldExpr) \
9898
X(ThrowExpr) \
99-
X(UUIDOfExpr) \
10099
X(BoolExpr) \
101100
X(StringLiteral) \
102101
X(LambdaExpr) \
@@ -2035,21 +2034,6 @@ class ThrowExpr : public Node {
20352034
}
20362035
};
20372036

2038-
// MSVC __uuidof extension, generated by clang in -fms-extensions mode.
2039-
class UUIDOfExpr : public Node {
2040-
Node *Operand;
2041-
public:
2042-
UUIDOfExpr(Node *Operand_) : Node(KUUIDOfExpr), Operand(Operand_) {}
2043-
2044-
template<typename Fn> void match(Fn F) const { F(Operand); }
2045-
2046-
void printLeft(OutputStream &S) const override {
2047-
S << "__uuidof(";
2048-
Operand->print(S);
2049-
S << ")";
2050-
}
2051-
};
2052-
20532037
class BoolExpr : public Node {
20542038
bool Value;
20552039

@@ -5013,6 +4997,43 @@ Node *AbstractManglingParser<Derived, Alloc>::parseExpr() {
50134997
}
50144998
}
50154999
return nullptr;
5000+
case 'u': {
5001+
++First;
5002+
Node *Name = getDerived().parseSourceName(/*NameState=*/nullptr);
5003+
if (!Name)
5004+
return nullptr;
5005+
// Special case legacy __uuidof mangling. The 't' and 'z' appear where the
5006+
// standard encoding expects a <template-arg>, and would be otherwise be
5007+
// interpreted as <type> node 'short' or 'ellipsis'. However, neither
5008+
// __uuidof(short) nor __uuidof(...) can actually appear, so there is no
5009+
// actual conflict here.
5010+
if (Name->getBaseName() == "__uuidof") {
5011+
if (numLeft() < 2)
5012+
return nullptr;
5013+
if (*First == 't') {
5014+
++First;
5015+
Node *Ty = getDerived().parseType();
5016+
if (!Ty)
5017+
return nullptr;
5018+
return make<CallExpr>(Name, makeNodeArray(&Ty, &Ty + 1));
5019+
}
5020+
if (*First == 'z') {
5021+
++First;
5022+
Node *Ex = getDerived().parseExpr();
5023+
if (!Ex)
5024+
return nullptr;
5025+
return make<CallExpr>(Name, makeNodeArray(&Ex, &Ex + 1));
5026+
}
5027+
}
5028+
size_t ExprsBegin = Names.size();
5029+
while (!consumeIf('E')) {
5030+
Node *E = getDerived().parseTemplateArg();
5031+
if (E == nullptr)
5032+
return E;
5033+
Names.push_back(E);
5034+
}
5035+
return make<CallExpr>(Name, popTrailingNodeArray(ExprsBegin));
5036+
}
50165037
case '1':
50175038
case '2':
50185039
case '3':
@@ -5024,21 +5045,6 @@ Node *AbstractManglingParser<Derived, Alloc>::parseExpr() {
50245045
case '9':
50255046
return getDerived().parseUnresolvedName();
50265047
}
5027-
5028-
if (consumeIf("u8__uuidoft")) {
5029-
Node *Ty = getDerived().parseType();
5030-
if (!Ty)
5031-
return nullptr;
5032-
return make<UUIDOfExpr>(Ty);
5033-
}
5034-
5035-
if (consumeIf("u8__uuidofz")) {
5036-
Node *Ex = getDerived().parseExpr();
5037-
if (!Ex)
5038-
return nullptr;
5039-
return make<UUIDOfExpr>(Ex);
5040-
}
5041-
50425048
return nullptr;
50435049
}
50445050

libcxxabi/test/test_demangle.pass.cpp

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29776,8 +29776,18 @@ const char* cases[][2] =
2977629776
// Vendor extension types are substitution candidates.
2977729777
{"_Z1fu3fooS_", "f(foo, foo)"},
2977829778

29779-
{"_ZN3FooIXu8__uuidofzdeL_Z3sucEEEC1Ev", "Foo<__uuidof(*(suc))>::Foo()"},
29780-
{"_ZN3FooIXu8__uuidoft13SomeUUIDClassEEC1Ev", "Foo<__uuidof(SomeUUIDClass)>::Foo()"},
29779+
// alignof with type and expression, and __alignof__ with the same.
29780+
{"_Z2f1IiEvDTatT_E", "void f1<int>(decltype(alignof (int)))"},
29781+
{"_Z2f3IiEvDTazcvT_Li0EE", "void f3<int>(decltype(alignof ((int)(0))))"},
29782+
{"_Z2f2IiEvDTu11__alignof__T_EE", "void f2<int>(decltype(__alignof__(int)))"},
29783+
{"_Z2f4IiEvDTu11__alignof__XcvT_Li0EEEE", "void f4<int>(decltype(__alignof__((int)(0))))"},
29784+
29785+
// Legacy nonstandard mangling for __uuidof.
29786+
{"_Z15test_uuidofTypeI10TestStructEvDTu8__uuidoftT_E", "void test_uuidofType<TestStruct>(decltype(__uuidof(TestStruct)))"},
29787+
{"_Z15test_uuidofExprI9HasMemberEvDTu8__uuidofXsrT_6memberEEE", "void test_uuidofExpr<HasMember>(decltype(__uuidof(HasMember::member)))"},
29788+
// Current __uuidof mangling using vendor extended expression.
29789+
{"_Z15test_uuidofTypeI10TestStructEvDTu8__uuidofT_EE", "void test_uuidofType<TestStruct>(decltype(__uuidof(TestStruct)))"},
29790+
{"_Z15test_uuidofExprI9HasMemberEvDTu8__uuidofXsrT_6memberEEE", "void test_uuidofExpr<HasMember>(decltype(__uuidof(HasMember::member)))"},
2978129791

2978229792
// C++2a char8_t:
2978329793
{"_ZTSPDu", "typeinfo name for char8_t*"},

0 commit comments

Comments
 (0)