diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -5304,11 +5304,22 @@ // Expression Parsing Callbacks: SemaExpr.cpp. bool CanUseDecl(NamedDecl *D, bool TreatUnavailableAsInvalid); + // A version of DiagnoseUseOfDecl that should be used if overload resolution + // has been used to find this declaration, which means we don't have to bother + // checking the trailing requires clause. + bool DiagnoseUseOfOverloadedDecl(NamedDecl *D, SourceLocation Loc) { + return DiagnoseUseOfDecl( + D, Loc, /*UnknownObjCClass=*/nullptr, /*ObjCPropertyAccess=*/false, + /*AvoidPartialAvailabilityChecks=*/false, /*ClassReceiver=*/nullptr, + /*SkipTrailingRequiresClause=*/true); + } + bool DiagnoseUseOfDecl(NamedDecl *D, ArrayRef Locs, const ObjCInterfaceDecl *UnknownObjCClass = nullptr, bool ObjCPropertyAccess = false, bool AvoidPartialAvailabilityChecks = false, - ObjCInterfaceDecl *ClassReciever = nullptr); + ObjCInterfaceDecl *ClassReciever = nullptr, + bool SkipTrailingRequiresClause = false); void NoteDeletedFunction(FunctionDecl *FD); void NoteDeletedInheritingConstructor(CXXConstructorDecl *CD); bool DiagnosePropertyAccessorMismatch(ObjCPropertyDecl *PD, diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -15551,7 +15551,10 @@ SourceRange ParenRange) { if (auto *Shadow = dyn_cast(FoundDecl)) { Constructor = findInheritingConstructor(ConstructLoc, Constructor, Shadow); - if (DiagnoseUseOfDecl(Constructor, ConstructLoc)) + // The only way to get here is if we did overlaod resolution to find the + // shadow decl, so we don't need to worry about re-checking the trailing + // requires clause. + if (DiagnoseUseOfOverloadedDecl(Constructor, ConstructLoc)) return ExprError(); } diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -222,7 +222,8 @@ const ObjCInterfaceDecl *UnknownObjCClass, bool ObjCPropertyAccess, bool AvoidPartialAvailabilityChecks, - ObjCInterfaceDecl *ClassReceiver) { + ObjCInterfaceDecl *ClassReceiver, + bool SkipTrailingRequiresClause) { SourceLocation Loc = Locs.front(); if (getLangOpts().CPlusPlus && isa(D)) { // If there were any diagnostics suppressed by template argument deduction, @@ -281,7 +282,7 @@ // See if this is a function with constraints that need to be satisfied. // Check this before deducing the return type, as it might instantiate the // definition. - if (FD->getTrailingRequiresClause()) { + if (!SkipTrailingRequiresClause && FD->getTrailingRequiresClause()) { ConstraintSatisfaction Satisfaction; if (CheckFunctionConstraints(FD, Satisfaction, Loc, /*ForOverloadResolution*/ true)) @@ -6761,8 +6762,8 @@ nullptr, DRE->isNonOdrUse()); } } - } else if (isa(NakedFn)) - NDecl = cast(NakedFn)->getMemberDecl(); + } else if (auto *ME = dyn_cast(NakedFn)) + NDecl = ME->getMemberDecl(); if (FunctionDecl *FD = dyn_cast_or_null(NDecl)) { if (CallingNDeclIndirectly && !checkAddressOfFunctionIsAvailable( diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -14680,7 +14680,7 @@ Method = cast(Best->Function); FoundDecl = Best->FoundDecl; CheckUnresolvedMemberAccess(UnresExpr, Best->FoundDecl); - if (DiagnoseUseOfDecl(Best->FoundDecl, UnresExpr->getNameLoc())) + if (DiagnoseUseOfOverloadedDecl(Best->FoundDecl, UnresExpr->getNameLoc())) break; // If FoundDecl is different from Method (such as if one is a template // and the other a specialization), make sure DiagnoseUseOfDecl is @@ -14689,7 +14689,7 @@ // DiagnoseUseOfDecl to accept both the FoundDecl and the decl // being used. if (Method != FoundDecl.getDecl() && - DiagnoseUseOfDecl(Method, UnresExpr->getNameLoc())) + DiagnoseUseOfOverloadedDecl(Method, UnresExpr->getNameLoc())) break; Succeeded = true; break; diff --git a/clang/test/SemaTemplate/concepts.cpp b/clang/test/SemaTemplate/concepts.cpp --- a/clang/test/SemaTemplate/concepts.cpp +++ b/clang/test/SemaTemplate/concepts.cpp @@ -708,3 +708,60 @@ // expected-note@#CMVT_REQ{{because 'sizeof(int) == arity' (4 == 5) evaluated to false}} } // namespace ConstrainedMemberVarTemplate +// These should not diagnose, where we were unintentionally doing so before by +// checking trailing requires clause twice, yet not having the ability to the +// 2nd time, since it was no longer a dependent variant. +namespace InheritedFromPartialSpec { +template +constexpr bool Check = true; + +template +struct Foo { + template + Foo(U&&) requires (Check){} + template + void MemFunc(U&&) requires (Check){} + template + static void StaticMemFunc(U&&) requires (Check){} + ~Foo() requires (Check){} +}; + +template<> + struct Foo : Foo { + using Foo::Foo; + using Foo::MemFunc; + using Foo::StaticMemFunc; + }; + +void use() { + Foo F {1.1}; + F.MemFunc(1.1); + Foo::StaticMemFunc(1.1); +} + +template +struct counted_iterator { + constexpr auto operator->() const noexcept requires false { + return T::Invalid; + }; +}; + +template +concept __has_member_pointer = requires { typename _Ip::pointer; }; + +template +struct __iterator_traits_member_pointer_or_arrow_or_void { using type = void; }; +template<__has_member_pointer _Ip> +struct __iterator_traits_member_pointer_or_arrow_or_void<_Ip> { using type = typename _Ip::pointer; }; + +template + requires requires(_Ip& __i) { __i.operator->(); } && (!__has_member_pointer<_Ip>) +struct __iterator_traits_member_pointer_or_arrow_or_void<_Ip> { + using type = decltype(declval<_Ip&>().operator->()); +}; + + +void use2() { + __iterator_traits_member_pointer_or_arrow_or_void> f; +} +}// namespace InheritedFromPartialSpec