Skip to content

Commit 7e46782

Browse files
authored
[Clang] Instantiate variables referenced in decltype with an undeduced type. (llvm#161231)
Fixes llvm#160497 Fixes llvm#56652 Fixes llvm#116319 Fixes llvm#161196
1 parent b542509 commit 7e46782

File tree

4 files changed

+123
-2
lines changed

4 files changed

+123
-2
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -433,6 +433,7 @@ Bug Fixes to C++ Support
433433
object type. (#GH151531)
434434
- Suppress ``-Wdouble-promotion`` when explicitly asked for with C++ list initialization (#GH33409).
435435
- Fix the result of `__builtin_is_implicit_lifetime` for types with a user-provided constructor. (#GH160610)
436+
- Correctly deduce return types in ``decltype`` expressions. (#GH160497) (#GH56652) (#GH116319) (#GH161196)
436437

437438
Bug Fixes to AST Handling
438439
^^^^^^^^^^^^^^^^^^^^^^^^^

clang/lib/Sema/SemaExpr.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20108,8 +20108,9 @@ static void DoMarkVarDeclReferenced(
2010820108
bool NeededForConstantEvaluation =
2010920109
isPotentiallyConstantEvaluatedContext(SemaRef) && UsableInConstantExpr;
2011020110

20111-
bool NeedDefinition =
20112-
OdrUse == OdrUseContext::Used || NeededForConstantEvaluation;
20111+
bool NeedDefinition = OdrUse == OdrUseContext::Used ||
20112+
NeededForConstantEvaluation ||
20113+
Var->getType()->isUndeducedType();
2011320114

2011420115
assert(!isa<VarTemplatePartialSpecializationDecl>(Var) &&
2011520116
"Can't instantiate a partial template specialization.");

clang/test/CodeGenCXX/gh56652.cpp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// RUN: %clang_cc1 -std=c++20 -triple x86_64-elf-gnu %s -emit-llvm -o - | FileCheck %s
2+
3+
namespace GH56652{
4+
5+
struct foo {};
6+
7+
template <typename T> struct bar {
8+
using type = T;
9+
10+
template <foo> inline static constexpr auto b = true;
11+
};
12+
13+
template <typename T>
14+
concept C = requires(T a) { T::template b<foo{}>; };
15+
16+
template <typename T> auto fn(T) {
17+
if constexpr (!C<T>)
18+
return foo{};
19+
else
20+
return T{};
21+
}
22+
23+
auto a = decltype(fn(bar<int>{})){};
24+
25+
}
26+
27+
namespace GH116319 {
28+
29+
template <int = 0> struct a {
30+
template <class> static constexpr auto b = 2;
31+
template <class> static void c() noexcept(noexcept(b<int>)) {}
32+
};
33+
34+
void test() { a<>::c<int>(); }
35+
36+
37+
}
38+
39+
// CHECK: %"struct.GH56652::bar" = type { i8 }
40+
// CHECK: $_ZN8GH1163191aILi0EE1cIiEEvv = comdat any
41+
// CHECK: @_ZN7GH566521aE = global %"struct.GH56652::bar" undef

clang/test/SemaCXX/decltype.cpp

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify -Wno-c99-designator %s
2+
// RUN: %clang_cc1 -std=c++17 -fsyntax-only -verify -Wno-c99-designator %s
23

34
// PR5290
45
int const f0();
@@ -156,13 +157,90 @@ struct A {
156157
}
157158
};
158159

160+
161+
159162
// This shouldn't crash.
160163
static_assert(A<int>().f<int>() == 0, "");
161164
// The result should not be dependent.
162165
static_assert(A<int>().f<int>() != 0, ""); // expected-error {{static assertion failed due to requirement 'GH99873::A<int>().f<int>() != 0'}}
163166
// expected-note@-1 {{expression evaluates to '0 != 0'}}
164167
}
165168

169+
170+
#if __cplusplus >= 201703L
171+
namespace GH160497 {
172+
173+
template <class> struct S {
174+
template <class>
175+
inline static auto mem =
176+
[] { static_assert(false); // expected-error {{static assertion failed}} \
177+
// expected-note {{while substituting into a lambda expression here}}
178+
return 42;
179+
}();
180+
};
181+
182+
using T = decltype(S<void>::mem<void>);
183+
// expected-note@-1 {{in instantiation of static data member 'GH160497::S<void>::mem<void>' requested here}}
184+
185+
186+
template <class> struct S2 {
187+
template <class>
188+
inline static auto* mem =
189+
[] { static_assert(false); // expected-error {{static assertion failed}} \
190+
// expected-note {{while substituting into a lambda expression here}}
191+
return static_cast<int*>(nullptr);
192+
}();
193+
};
194+
195+
using T2 = decltype(S2<void>::mem<void>);
196+
//expected-note@-1 {{in instantiation of static data member 'GH160497::S2<void>::mem<void>' requested here}}
197+
198+
template <class> struct S3 {
199+
template <class>
200+
inline static int mem = // Check we don't instantiate when the type is not deduced.
201+
[] { static_assert(false);
202+
return 42;
203+
}();
204+
};
205+
206+
using T = decltype(S3<void>::mem<void>);
207+
}
208+
209+
namespace N1 {
210+
211+
template<class>
212+
struct S {
213+
template<class>
214+
inline static auto mem = 42;
215+
};
216+
217+
using T = decltype(S<void>::mem<void>);
218+
219+
T y = 42;
220+
221+
}
222+
223+
namespace GH161196 {
224+
225+
template <typename> struct A {
226+
static constexpr int digits = 0;
227+
};
228+
229+
template <typename> struct B {
230+
template <int, typename MaskInt = int, int = A<MaskInt>::digits>
231+
static constexpr auto XBitMask = 0;
232+
};
233+
234+
struct C {
235+
using ReferenceHost = B<int>;
236+
template <int> static decltype(ReferenceHost::XBitMask<0>) XBitMask;
237+
};
238+
239+
void test() { (void)C::XBitMask<0>; }
240+
241+
}
242+
#endif
243+
166244
template<typename>
167245
class conditional {
168246
};

0 commit comments

Comments
 (0)