https://github.com/zyn0217 updated https://github.com/llvm/llvm-project/pull/199617
>From dd85ecb9ba4217f2d49746c97da3478d14d9d513 Mon Sep 17 00:00:00 2001 From: Younan Zhang <[email protected]> Date: Tue, 26 May 2026 15:12:52 +0800 Subject: [PATCH] [Clang] Profile the NNS of UnresolvedUsingType correctly in concept hashing They were sometimes incorrect because the written type doesn't contain an NNS which contains template parameters we're interested in. --- clang/lib/Sema/SemaConcept.cpp | 14 +++ .../test/SemaTemplate/concepts-using-decl.cpp | 98 +++++++++++++++++++ 2 files changed, 112 insertions(+) diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp index ea03c3f408986..f41f37b8a3d19 100644 --- a/clang/lib/Sema/SemaConcept.cpp +++ b/clang/lib/Sema/SemaConcept.cpp @@ -381,6 +381,10 @@ class HashParameterMapping : public RecursiveASTVisitor<HashParameterMapping> { return true; } + bool TraverseCXXThisExpr(CXXThisExpr *E) { + return inherited::TraverseType(E->getType()); + } + bool TraverseTypeLoc(TypeLoc TL, bool TraverseQualifier = true) { // We don't care about TypeLocs. So traverse Types instead. return TraverseType(TL.getType().getCanonicalType(), TraverseQualifier); @@ -399,6 +403,16 @@ class HashParameterMapping : public RecursiveASTVisitor<HashParameterMapping> { return true; } + bool TraverseUnresolvedUsingType(UnresolvedUsingType *T, + bool TraverseQualifier) { + // Sometimes the written type doesn't contain a qualifier which contains + // necessary template arguments, whereas the declaration does. + if (NestedNameSpecifier NNS = T->getDecl()->getQualifier(); + TraverseQualifier && NNS) + return inherited::TraverseNestedNameSpecifier(NNS); + return inherited::TraverseUnresolvedUsingType(T, TraverseQualifier); + } + bool TraverseInjectedClassNameType(InjectedClassNameType *T, bool TraverseQualifier) { return TraverseTemplateArguments(T->getTemplateArgs(SemaRef.Context)); diff --git a/clang/test/SemaTemplate/concepts-using-decl.cpp b/clang/test/SemaTemplate/concepts-using-decl.cpp index 26bd0b60b691c..00df6b899782c 100644 --- a/clang/test/SemaTemplate/concepts-using-decl.cpp +++ b/clang/test/SemaTemplate/concepts-using-decl.cpp @@ -197,3 +197,101 @@ struct child : base<int> { }; } + +namespace GH198663 { + +template <class T> +concept HasIsTransparent = requires { typename T::is_transparent; }; + +template <class K, class V, class Compare> +struct FlatMapBase { + using key_compare = Compare; +}; + +template <class K, class V, class Compare> +struct FlatMap : FlatMapBase<K, V, Compare> { + using Base = FlatMapBase<K, V, Compare>; + + using typename Base::key_compare; + + void at(const K&) {} + void at(const K&) const {} + template <class Other> + void at(const Other&) + requires HasIsTransparent<key_compare> + {} + template <class Other> + void at(const Other&) const + requires HasIsTransparent<key_compare> + {} +}; + +template <class T> +struct Transparent { + T t; +}; + +struct TransparentComparator { + using is_transparent = void; + + template <class T> + bool operator()(const T&, const Transparent<T>&) const; + + template <class T> + bool operator()(const Transparent<T>&, const T& t) const; + + template <class T> + bool operator()(const T&, const T&) const; +}; + +struct NonTransparentComparator { + template <class T> + bool operator()(const T&, const Transparent<T>&) const; + + template <class T> + bool operator()(const Transparent<T>&, const T&) const; + + template <class T> + bool operator()(const T&, const T&) const; +}; + +template <class M> +concept CanAt = requires(M m, Transparent<int> k) { m.at(k); }; + +using TransparentMap = FlatMap<int, double, TransparentComparator>; +using NonTransparentMap = FlatMap<int, double, NonTransparentComparator>; + +static_assert(CanAt<TransparentMap>); + +static_assert(!CanAt<NonTransparentMap>); + +} + +namespace GH198663_2 { + +template<typename T> +auto mv(T& t) -> T&&; + +template<typename S, typename T> +concept does_foo = requires(S s) { + s.template foo<T>(); +}; + +template<typename S> +struct type { + S member; + template<typename T> + auto foo() -> T requires does_foo<decltype(mv(member)), T>; +}; + +struct returns_int { + template<typename T> + auto foo() -> T; +}; + +struct nothing {}; + +static_assert(does_foo<type<returns_int>&, int>); +static_assert(not does_foo<type<nothing>&, int>); + +} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
