Skip to content

Commit b65aa9b

Browse files
zyn0217dyung
authored andcommitted
[Clang] Profile the NNS of UnresolvedUsingType and CXXThisType correctly in concept hashing (#199617)
They were sometimes incorrect because the written type doesn't contain an NNS which contains template parameters we're interested in. No release note because the bug broke MS STL and I want to backport it to the last 22.x release Fixes #198663 (cherry picked from commit 06ffb65)
1 parent b4fe388 commit b65aa9b

2 files changed

Lines changed: 112 additions & 0 deletions

File tree

clang/lib/Sema/SemaConcept.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,10 @@ class HashParameterMapping : public RecursiveASTVisitor<HashParameterMapping> {
381381
return true;
382382
}
383383

384+
bool TraverseCXXThisExpr(CXXThisExpr *E) {
385+
return inherited::TraverseType(E->getType());
386+
}
387+
384388
bool TraverseTypeLoc(TypeLoc TL, bool TraverseQualifier = true) {
385389
// We don't care about TypeLocs. So traverse Types instead.
386390
return TraverseType(TL.getType().getCanonicalType(), TraverseQualifier);
@@ -394,6 +398,16 @@ class HashParameterMapping : public RecursiveASTVisitor<HashParameterMapping> {
394398
return true;
395399
}
396400

401+
bool TraverseUnresolvedUsingType(UnresolvedUsingType *T,
402+
bool TraverseQualifier) {
403+
// Sometimes the written type doesn't contain a qualifier which contains
404+
// necessary template arguments, whereas the declaration does.
405+
if (NestedNameSpecifier NNS = T->getDecl()->getQualifier();
406+
TraverseQualifier && NNS)
407+
return inherited::TraverseNestedNameSpecifier(NNS);
408+
return inherited::TraverseUnresolvedUsingType(T, TraverseQualifier);
409+
}
410+
397411
bool TraverseInjectedClassNameType(InjectedClassNameType *T,
398412
bool TraverseQualifier) {
399413
return TraverseTemplateArguments(T->getTemplateArgs(SemaRef.Context));

clang/test/SemaTemplate/concepts-using-decl.cpp

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,3 +197,101 @@ struct child : base<int> {
197197
};
198198

199199
}
200+
201+
namespace GH198663 {
202+
203+
template <class T>
204+
concept HasIsTransparent = requires { typename T::is_transparent; };
205+
206+
template <class K, class V, class Compare>
207+
struct FlatMapBase {
208+
using key_compare = Compare;
209+
};
210+
211+
template <class K, class V, class Compare>
212+
struct FlatMap : FlatMapBase<K, V, Compare> {
213+
using Base = FlatMapBase<K, V, Compare>;
214+
215+
using typename Base::key_compare;
216+
217+
void at(const K&) {}
218+
void at(const K&) const {}
219+
template <class Other>
220+
void at(const Other&)
221+
requires HasIsTransparent<key_compare>
222+
{}
223+
template <class Other>
224+
void at(const Other&) const
225+
requires HasIsTransparent<key_compare>
226+
{}
227+
};
228+
229+
template <class T>
230+
struct Transparent {
231+
T t;
232+
};
233+
234+
struct TransparentComparator {
235+
using is_transparent = void;
236+
237+
template <class T>
238+
bool operator()(const T&, const Transparent<T>&) const;
239+
240+
template <class T>
241+
bool operator()(const Transparent<T>&, const T& t) const;
242+
243+
template <class T>
244+
bool operator()(const T&, const T&) const;
245+
};
246+
247+
struct NonTransparentComparator {
248+
template <class T>
249+
bool operator()(const T&, const Transparent<T>&) const;
250+
251+
template <class T>
252+
bool operator()(const Transparent<T>&, const T&) const;
253+
254+
template <class T>
255+
bool operator()(const T&, const T&) const;
256+
};
257+
258+
template <class M>
259+
concept CanAt = requires(M m, Transparent<int> k) { m.at(k); };
260+
261+
using TransparentMap = FlatMap<int, double, TransparentComparator>;
262+
using NonTransparentMap = FlatMap<int, double, NonTransparentComparator>;
263+
264+
static_assert(CanAt<TransparentMap>);
265+
266+
static_assert(!CanAt<NonTransparentMap>);
267+
268+
}
269+
270+
namespace GH198663_2 {
271+
272+
template<typename T>
273+
auto mv(T& t) -> T&&;
274+
275+
template<typename S, typename T>
276+
concept does_foo = requires(S s) {
277+
s.template foo<T>();
278+
};
279+
280+
template<typename S>
281+
struct type {
282+
S member;
283+
template<typename T>
284+
auto foo() -> T requires does_foo<decltype(mv(member)), T>;
285+
};
286+
287+
struct returns_int {
288+
template<typename T>
289+
auto foo() -> T;
290+
};
291+
292+
struct nothing {};
293+
294+
static_assert(does_foo<type<returns_int>&, int>);
295+
static_assert(not does_foo<type<nothing>&, int>);
296+
297+
}

0 commit comments

Comments
 (0)