Skip to content

Commit 95566af

Browse files
authored
[Clang][AST] Fix MS Mangle concept uneval context template instantiation crash (#117845)
Fixes #115990. MSVC mangling got inadvertently broken here, #83997, when it was fixed what decl context a lambda is apart of for uneval contexts. https://godbolt.org/z/K6jb5v145 for reference. Given the following code snippet ``` template <typename T> concept C = requires(const T& t) { { T::test([](){}) }; }; template<typename T, typename = void> struct Widget; template <C T> struct Widget<T> {}; struct Baz { template<typename F> static constexpr decltype(auto) test(F&& f) {} }; void test() { Widget<Baz> w; } ``` `Baz::test` has a deduced return type which means we must instantiate that template even in an unevaluated context. The lambda inside the concept is within the decl context of `struct Widget<T> {};`. So we end up needing to mangle a name of `Baz::test<Widget<template-type-0-0>::lambda()>>()` since the lambda isn't apart of an instantiated substituted class `Widget` yet at the point the lambda is instantiated. Upon template instantation of `test` we end up asking for the mangled name so we can add this instantiation to `CodeGenModule::DefferredDecls` since `test` is now referenced but not yet used. I think the longer term more correct solution is to key `DefferedDecls` off of something else than the mangled name to avoid having to mangle names for instantations that are referenced but will never be used since they are only instantiated from an unevaluated context. As a fix for the regression I just created a custom mangling scheme for this case since MSVC has no comparable naming scheme as such a template will never be emitted into the resulting obj as it will never be used.
1 parent f947d5a commit 95566af

File tree

2 files changed

+34
-1
lines changed

2 files changed

+34
-1
lines changed

clang/lib/AST/MicrosoftMangle.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3372,7 +3372,15 @@ void MicrosoftCXXNameMangler::mangleType(const MemberPointerType *T,
33723372

33733373
void MicrosoftCXXNameMangler::mangleType(const TemplateTypeParmType *T,
33743374
Qualifiers, SourceRange Range) {
3375-
Error(Range.getBegin(), "template type parameter type") << Range;
3375+
Out << '?';
3376+
3377+
llvm::SmallString<64> Name;
3378+
Name += "<TTPT_";
3379+
Name += llvm::utostr(T->getDepth());
3380+
Name += "_";
3381+
Name += llvm::utostr(T->getIndex());
3382+
Name += ">";
3383+
mangleSourceName(Name);
33763384
}
33773385

33783386
void MicrosoftCXXNameMangler::mangleType(const SubstTemplateTypeParmPackType *T,
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// RUN: %clang_cc1 -std=c++20 -fms-compatibility -fms-compatibility-version=19.33 -emit-llvm %s -o - -triple=x86_64-windows-msvc | FileCheck %s
2+
3+
template <typename T>
4+
concept C = requires
5+
{
6+
{ T::test([](){}) };
7+
};
8+
9+
template<typename T>
10+
struct Widget {};
11+
12+
template <C T>
13+
struct Widget<T> {};
14+
15+
struct Baz
16+
{
17+
template<typename F>
18+
static constexpr decltype(auto) test(F&&) {}
19+
};
20+
21+
void test()
22+
{
23+
Widget<Baz> w;
24+
}
25+
// CHECK: @"?test@@YAXXZ"

0 commit comments

Comments
 (0)