Skip to content

Commit 43b8885

Browse files
authored
[clang-cl] [AST] Reapply llvm#102848 Fix placeholder return type name mangling for MSVC 1920+ / VS2019+ (llvm#104722)
Reapply llvm#102848. The description in this PR will detail the changes from the reverted original PR above. For `auto&&` return types that can partake in reference collapsing we weren't properly handling that mangling that can arise. When collapsing occurs an inner reference is created with the collapsed reference type. If we return `int&` from such a function then an inner reference of `int&` is created within the `auto&&` return type. `getPointeeType` on a reference type goes through all inner references before returning the pointee type which ends up being a builtin type, `int`, which is unexpected. We can use `getPointeeTypeAsWritten` to get the `AutoType` as expected however for the instantiated template declaration reference collapsing already occurred on the return type. This means `auto&&` is turned into `auto&` in our example above. We end up mangling an lvalue reference type. This is unintended as MSVC mangles on the declaration of the return type, `auto&&` in this case, which is treated as an rvalue reference. ``` template<class T> auto&& AutoReferenceCollapseT(int& x) { return static_cast<int&>(x); } void test() { int x = 1; auto&& rref = AutoReferenceCollapseT<void>(x); // "??$AutoReferenceCollapseT@X@@ya$$QEA_PAEAH@Z" // Mangled as an rvalue reference to auto } ``` If we are mangling a template with a placeholder return type we want to get the first template declaration and use its return type to do the mangling of any instantiations. This fixes the bug reported in the original PR that caused the revert with libcxx `std::variant`. I also tested locally with libcxx and the following test code which fails in the original PR but now works in this PR. ``` #include <variant> void test() { std::variant<int> v{ 1 }; int& r = std::get<0>(v); (void)r; } ```
1 parent 9f82f6d commit 43b8885

6 files changed

+556
-19
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ C++ Specific Potentially Breaking Changes
7777
ABI Changes in This Version
7878
---------------------------
7979

80+
- Fixed Microsoft name mangling of placeholder, auto and decltype(auto), return types for MSVC 1920+. This change resolves incompatibilities with code compiled by MSVC 1920+ but will introduce incompatibilities with code compiled by earlier versions of Clang unless such code is built with the compiler option -fms-compatibility-version=19.14 to imitate the MSVC 1914 mangling behavior.
81+
8082
AST Dumping Potentially Breaking Changes
8183
----------------------------------------
8284

clang/lib/AST/MicrosoftMangle.cpp

Lines changed: 161 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,8 @@ class MicrosoftCXXNameMangler {
408408
void mangleSourceName(StringRef Name);
409409
void mangleNestedName(GlobalDecl GD);
410410

411+
void mangleAutoReturnType(QualType T, QualifierMangleMode QMM);
412+
411413
private:
412414
bool isStructorDecl(const NamedDecl *ND) const {
413415
return ND == Structor || getStructor(ND) == Structor;
@@ -477,6 +479,11 @@ class MicrosoftCXXNameMangler {
477479
SourceRange Range);
478480
void mangleObjCKindOfType(const ObjCObjectType *T, Qualifiers Quals,
479481
SourceRange Range);
482+
483+
void mangleAutoReturnType(const MemberPointerType *T, Qualifiers Quals);
484+
void mangleAutoReturnType(const PointerType *T, Qualifiers Quals);
485+
void mangleAutoReturnType(const LValueReferenceType *T, Qualifiers Quals);
486+
void mangleAutoReturnType(const RValueReferenceType *T, Qualifiers Quals);
480487
};
481488
}
482489

@@ -2494,6 +2501,57 @@ void MicrosoftCXXNameMangler::mangleAddressSpaceType(QualType T,
24942501
mangleArtificialTagType(TagTypeKind::Struct, ASMangling, {"__clang"});
24952502
}
24962503

2504+
void MicrosoftCXXNameMangler::mangleAutoReturnType(QualType T,
2505+
QualifierMangleMode QMM) {
2506+
assert(getASTContext().getLangOpts().isCompatibleWithMSVC(
2507+
LangOptions::MSVC2019) &&
2508+
"Cannot mangle MSVC 2017 auto return types!");
2509+
2510+
if (isa<AutoType>(T)) {
2511+
const auto *AT = T->getContainedAutoType();
2512+
Qualifiers Quals = T.getLocalQualifiers();
2513+
2514+
if (QMM == QMM_Result)
2515+
Out << '?';
2516+
if (QMM != QMM_Drop)
2517+
mangleQualifiers(Quals, false);
2518+
Out << (AT->isDecltypeAuto() ? "_T" : "_P");
2519+
return;
2520+
}
2521+
2522+
T = T.getDesugaredType(getASTContext());
2523+
Qualifiers Quals = T.getLocalQualifiers();
2524+
2525+
switch (QMM) {
2526+
case QMM_Drop:
2527+
case QMM_Result:
2528+
break;
2529+
case QMM_Mangle:
2530+
mangleQualifiers(Quals, false);
2531+
break;
2532+
default:
2533+
llvm_unreachable("QMM_Escape unexpected");
2534+
}
2535+
2536+
const Type *ty = T.getTypePtr();
2537+
switch (ty->getTypeClass()) {
2538+
case Type::MemberPointer:
2539+
mangleAutoReturnType(cast<MemberPointerType>(ty), Quals);
2540+
break;
2541+
case Type::Pointer:
2542+
mangleAutoReturnType(cast<PointerType>(ty), Quals);
2543+
break;
2544+
case Type::LValueReference:
2545+
mangleAutoReturnType(cast<LValueReferenceType>(ty), Quals);
2546+
break;
2547+
case Type::RValueReference:
2548+
mangleAutoReturnType(cast<RValueReferenceType>(ty), Quals);
2549+
break;
2550+
default:
2551+
llvm_unreachable("Invalid type expected");
2552+
}
2553+
}
2554+
24972555
void MicrosoftCXXNameMangler::mangleType(QualType T, SourceRange Range,
24982556
QualifierMangleMode QMM) {
24992557
// Don't use the canonical types. MSVC includes things like 'const' on
@@ -2907,17 +2965,60 @@ void MicrosoftCXXNameMangler::mangleFunctionType(const FunctionType *T,
29072965
// can differ by their calling convention and are typically deduced. So
29082966
// we make sure that this type gets mangled properly.
29092967
mangleType(ResultType, Range, QMM_Result);
2910-
} else if (const auto *AT = dyn_cast_or_null<AutoType>(
2911-
ResultType->getContainedAutoType())) {
2912-
Out << '?';
2913-
mangleQualifiers(ResultType.getLocalQualifiers(), /*IsMember=*/false);
2914-
Out << '?';
2968+
} else if (IsInLambda) {
2969+
if (const auto *AT = ResultType->getContainedAutoType()) {
2970+
assert(AT->getKeyword() == AutoTypeKeyword::Auto &&
2971+
"should only need to mangle auto!");
2972+
(void)AT;
2973+
Out << '?';
2974+
mangleQualifiers(ResultType.getLocalQualifiers(), /*IsMember=*/false);
2975+
Out << '?';
2976+
mangleSourceName("<auto>");
2977+
Out << '@';
2978+
} else {
2979+
Out << '@';
2980+
}
2981+
} else if (const auto *AT = ResultType->getContainedAutoType()) {
29152982
assert(AT->getKeyword() != AutoTypeKeyword::GNUAutoType &&
29162983
"shouldn't need to mangle __auto_type!");
2917-
mangleSourceName(AT->isDecltypeAuto() ? "<decltype-auto>" : "<auto>");
2918-
Out << '@';
2919-
} else if (IsInLambda) {
2920-
Out << '@';
2984+
2985+
// If we have any pointer types with the clang address space extension
2986+
// then defer to the custom clang mangling to keep backwards
2987+
// compatibility. See `mangleType(const PointerType *T, Qualifiers Quals,
2988+
// SourceRange Range)` for details.
2989+
auto UseClangMangling = [](QualType ResultType) {
2990+
QualType T = ResultType;
2991+
while (isa<PointerType>(T.getTypePtr())) {
2992+
T = T->getPointeeType();
2993+
if (T.getQualifiers().hasAddressSpace())
2994+
return true;
2995+
}
2996+
return false;
2997+
};
2998+
2999+
if (getASTContext().getLangOpts().isCompatibleWithMSVC(
3000+
LangOptions::MSVC2019) &&
3001+
!UseClangMangling(ResultType)) {
3002+
if (D && !D->getPrimaryTemplate()) {
3003+
Out << '@';
3004+
} else {
3005+
if (D && D->getPrimaryTemplate()) {
3006+
const FunctionProtoType *FPT = D->getPrimaryTemplate()
3007+
->getTemplatedDecl()
3008+
->getFirstDecl()
3009+
->getType()
3010+
->castAs<FunctionProtoType>();
3011+
ResultType = FPT->getReturnType();
3012+
}
3013+
mangleAutoReturnType(ResultType, QMM_Result);
3014+
}
3015+
} else {
3016+
Out << '?';
3017+
mangleQualifiers(ResultType.getLocalQualifiers(), /*IsMember=*/false);
3018+
Out << '?';
3019+
mangleSourceName(AT->isDecltypeAuto() ? "<decltype-auto>" : "<auto>");
3020+
Out << '@';
3021+
}
29213022
} else {
29223023
if (ResultType->isVoidType())
29233024
ResultType = ResultType.getUnqualifiedType();
@@ -4220,6 +4321,57 @@ void MicrosoftMangleContextImpl::mangleStringLiteral(const StringLiteral *SL,
42204321
Mangler.getStream() << '@';
42214322
}
42224323

4324+
void MicrosoftCXXNameMangler::mangleAutoReturnType(const MemberPointerType *T,
4325+
Qualifiers Quals) {
4326+
QualType PointeeType = T->getPointeeType();
4327+
manglePointerCVQualifiers(Quals);
4328+
manglePointerExtQualifiers(Quals, PointeeType);
4329+
if (const FunctionProtoType *FPT = PointeeType->getAs<FunctionProtoType>()) {
4330+
Out << '8';
4331+
mangleName(T->getClass()->castAs<RecordType>()->getDecl());
4332+
mangleFunctionType(FPT, nullptr, true);
4333+
} else {
4334+
mangleQualifiers(PointeeType.getQualifiers(), true);
4335+
mangleName(T->getClass()->castAs<RecordType>()->getDecl());
4336+
mangleAutoReturnType(PointeeType, QMM_Drop);
4337+
}
4338+
}
4339+
4340+
void MicrosoftCXXNameMangler::mangleAutoReturnType(const PointerType *T,
4341+
Qualifiers Quals) {
4342+
QualType PointeeType = T->getPointeeType();
4343+
assert(!PointeeType.getQualifiers().hasAddressSpace() &&
4344+
"Unexpected address space mangling required");
4345+
4346+
manglePointerCVQualifiers(Quals);
4347+
manglePointerExtQualifiers(Quals, PointeeType);
4348+
4349+
if (const FunctionProtoType *FPT = PointeeType->getAs<FunctionProtoType>()) {
4350+
Out << '6';
4351+
mangleFunctionType(FPT);
4352+
} else {
4353+
mangleAutoReturnType(PointeeType, QMM_Mangle);
4354+
}
4355+
}
4356+
4357+
void MicrosoftCXXNameMangler::mangleAutoReturnType(const LValueReferenceType *T,
4358+
Qualifiers Quals) {
4359+
QualType PointeeType = T->getPointeeType();
4360+
assert(!Quals.hasConst() && !Quals.hasVolatile() && "unexpected qualifier!");
4361+
Out << 'A';
4362+
manglePointerExtQualifiers(Quals, PointeeType);
4363+
mangleAutoReturnType(PointeeType, QMM_Mangle);
4364+
}
4365+
4366+
void MicrosoftCXXNameMangler::mangleAutoReturnType(const RValueReferenceType *T,
4367+
Qualifiers Quals) {
4368+
QualType PointeeType = T->getPointeeType();
4369+
assert(!Quals.hasConst() && !Quals.hasVolatile() && "unexpected qualifier!");
4370+
Out << "$$Q";
4371+
manglePointerExtQualifiers(Quals, PointeeType);
4372+
mangleAutoReturnType(PointeeType, QMM_Mangle);
4373+
}
4374+
42234375
MicrosoftMangleContext *MicrosoftMangleContext::create(ASTContext &Context,
42244376
DiagnosticsEngine &Diags,
42254377
bool IsAux) {

0 commit comments

Comments
 (0)