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 { 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 { 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 { }; } + +namespace GH198663 { + +template +concept HasIsTransparent = requires { typename T::is_transparent; }; + +template +struct FlatMapBase { + using key_compare = Compare; +}; + +template +struct FlatMap : FlatMapBase { + using Base = FlatMapBase; + + using typename Base::key_compare; + + void at(const K&) {} + void at(const K&) const {} + template + void at(const Other&) + requires HasIsTransparent + {} + template + void at(const Other&) const + requires HasIsTransparent + {} +}; + +template +struct Transparent { + T t; +}; + +struct TransparentComparator { + using is_transparent = void; + + template + bool operator()(const T&, const Transparent&) const; + + template + bool operator()(const Transparent&, const T& t) const; + + template + bool operator()(const T&, const T&) const; +}; + +struct NonTransparentComparator { + template + bool operator()(const T&, const Transparent&) const; + + template + bool operator()(const Transparent&, const T&) const; + + template + bool operator()(const T&, const T&) const; +}; + +template +concept CanAt = requires(M m, Transparent k) { m.at(k); }; + +using TransparentMap = FlatMap; +using NonTransparentMap = FlatMap; + +static_assert(CanAt); + +static_assert(!CanAt); + +} + +namespace GH198663_2 { + +template +auto mv(T& t) -> T&&; + +template +concept does_foo = requires(S s) { + s.template foo(); +}; + +template +struct type { + S member; + template + auto foo() -> T requires does_foo; +}; + +struct returns_int { + template + auto foo() -> T; +}; + +struct nothing {}; + +static_assert(does_foo&, int>); +static_assert(not does_foo&, int>); + +}