Skip to content

Commit 533d157

Browse files
Adds an arbitrary pseudonym to clang"s windows mangler to handle template argument values that are pointers one-past-the-end of a non-array symbol. Also improves error messages in other template argument scenarios where clang bails.
1 parent d1dc416 commit 533d157

File tree

2 files changed

+90
-14
lines changed

2 files changed

+90
-14
lines changed

clang/lib/AST/MicrosoftMangle.cpp

Lines changed: 43 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1922,9 +1922,12 @@ void MicrosoftCXXNameMangler::mangleTemplateArgValue(QualType T,
19221922
if (WithScalarType)
19231923
mangleType(T, SourceRange(), QMM_Escape);
19241924

1925-
// We don't know how to mangle past-the-end pointers yet.
1926-
if (V.isLValueOnePastTheEnd())
1927-
break;
1925+
// msvc does not support this, so no mangling will ever be "right", so this
1926+
// was picked arbitrarily.
1927+
if (V.isLValueOnePastTheEnd()) {
1928+
Out << "@IN"; // for "invalid pointer" since it always is invalid.
1929+
return;
1930+
}
19281931

19291932
APValue::LValueBase Base = V.getLValueBase();
19301933
if (!V.hasLValuePath() || V.getLValuePath().empty()) {
@@ -1938,12 +1941,23 @@ void MicrosoftCXXNameMangler::mangleTemplateArgValue(QualType T,
19381941
mangleNumber(V.getLValueOffset().getQuantity());
19391942
} else if (!V.hasLValuePath()) {
19401943
// FIXME: This can only happen as an extension. Invent a mangling.
1941-
break;
1944+
DiagnosticsEngine &Diags = Context.getDiags();
1945+
unsigned DiagID =
1946+
Diags.getCustomDiagID(DiagnosticsEngine::Error,
1947+
"cannot mangle this template argument yet "
1948+
"(non-null base with null lvalue path)");
1949+
Diags.Report(DiagID);
1950+
return;
19421951
} else if (auto *VD = Base.dyn_cast<const ValueDecl*>()) {
19431952
Out << "E";
19441953
mangle(VD);
19451954
} else {
1946-
break;
1955+
DiagnosticsEngine &Diags = Context.getDiags();
1956+
unsigned DiagID = Diags.getCustomDiagID(
1957+
DiagnosticsEngine::Error,
1958+
"cannot mangle this template argument yet (empty lvalue path)");
1959+
Diags.Report(DiagID);
1960+
return;
19471961
}
19481962
} else {
19491963
if (TAK == TplArgKind::ClassNTTP && T->isPointerType())
@@ -1988,8 +2002,14 @@ void MicrosoftCXXNameMangler::mangleTemplateArgValue(QualType T,
19882002
Out << *I;
19892003

19902004
auto *VD = Base.dyn_cast<const ValueDecl*>();
1991-
if (!VD)
1992-
break;
2005+
if (!VD) {
2006+
DiagnosticsEngine &Diags = Context.getDiags();
2007+
unsigned DiagID = Diags.getCustomDiagID(
2008+
DiagnosticsEngine::Error,
2009+
"cannot mangle this template argument yet (null value decl)");
2010+
Diags.Report(DiagID);
2011+
return;
2012+
}
19932013
Out << (TAK == TplArgKind::ClassNTTP ? 'E' : '1');
19942014
mangle(VD);
19952015

@@ -2104,15 +2124,24 @@ void MicrosoftCXXNameMangler::mangleTemplateArgValue(QualType T,
21042124
return;
21052125
}
21062126

2107-
case APValue::AddrLabelDiff:
2108-
case APValue::FixedPoint:
2109-
break;
2127+
case APValue::AddrLabelDiff: {
2128+
DiagnosticsEngine &Diags = Context.getDiags();
2129+
unsigned DiagID = Diags.getCustomDiagID(
2130+
DiagnosticsEngine::Error, "cannot mangle this template argument yet "
2131+
"(value type: address label diff)");
2132+
Diags.Report(DiagID);
2133+
return;
21102134
}
21112135

2112-
DiagnosticsEngine &Diags = Context.getDiags();
2113-
unsigned DiagID = Diags.getCustomDiagID(
2114-
DiagnosticsEngine::Error, "cannot mangle this template argument yet");
2115-
Diags.Report(DiagID);
2136+
case APValue::FixedPoint: {
2137+
DiagnosticsEngine &Diags = Context.getDiags();
2138+
unsigned DiagID = Diags.getCustomDiagID(
2139+
DiagnosticsEngine::Error,
2140+
"cannot mangle this template argument yet (value type: fixed point)");
2141+
Diags.Report(DiagID);
2142+
return;
2143+
}
2144+
}
21162145
}
21172146

21182147
void MicrosoftCXXNameMangler::mangleObjCProtocol(const ObjCProtocolDecl *PD) {
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -emit-llvm -std=c++20 -x c++ < %s | FileCheck -check-prefix=WIN64 %s
2+
3+
/*
4+
5+
This works (linux host):
6+
clang++ -std=c++20 -c ms_mangler_templatearg_opte.cpp -o /dev/null
7+
8+
Before this case's corresponding patch, this did not:
9+
clang -cc1 -triple x86_64-pc-windows-msvc19.33.0 -emit-obj -std=c++20 -o ms_mangler_templatearg_opte.obj -x c++ ms_mangler_templatearg_opte.cpp
10+
11+
The first pass is fine, it's the final pass of cesum where L.data = (&ints)+1 that clang bawks at. Obviously this address can't be dereferenced, but the `if constexpr` sees to that. The unused template param should not break the mangler.
12+
13+
*/
14+
15+
16+
typedef long long unsigned size_t;
17+
18+
template<class T> struct llist {
19+
const T* data;
20+
size_t len;
21+
constexpr llist(const T* data, size_t len) : data(data), len(len) {};
22+
constexpr inline bool empty() const { return len == 0; };
23+
constexpr llist<T> next() const { return { data+1, len-1 }; };
24+
constexpr const T& peek() const { return data[0]; };
25+
};
26+
27+
//recurse to iterate over the list, without the need for a terminal overload or duplicated handling of the terminal case
28+
template<llist<int> L> int cesum() {
29+
if constexpr(L.empty()) {
30+
return 0;
31+
} else {
32+
return L.peek() + cesum<L.next()>();
33+
}
34+
};
35+
36+
// WIN64: {{cesum.*ints}}
37+
constexpr int ints[] = { 1, 2, 7, 8, 9, -17, -10 }; //Note: this does NOT break the unpatched mangler
38+
39+
// WIN64: {{cesum.*one_int}}
40+
constexpr int one_int = 7;
41+
42+
int template_instance() {
43+
cesum<llist<int>(ints, sizeof(ints)/sizeof(int))>();
44+
cesum<llist<int>(&one_int, 1)>();
45+
return 0;
46+
}
47+

0 commit comments

Comments
 (0)