Author: Erich Keane Date: 2022-10-18T06:08:10-07:00 New Revision: 4bcb85c638c1c1719c5c01a70ee2e376e4032d2a
URL: https://github.com/llvm/llvm-project/commit/4bcb85c638c1c1719c5c01a70ee2e376e4032d2a DIFF: https://github.com/llvm/llvm-project/commit/4bcb85c638c1c1719c5c01a70ee2e376e4032d2a.diff LOG: Stop evaluating trailing requires clause after overload resolution Reported as it showed up as a constriants failure after the deferred instantiation patch, we were checking constraints TWICE after overload resolution. The first is during overload resolution, the second is when diagnosing a use. This patch modifies DiagnoseUseOfDecl to skip the trailing requires clause check in some cases. First, of course, after choosing a candidate after overload resolution. The second is when evaluating a shadow using constructor, which had its constraints checked when picking a constructor (as this is ALWAYS an overload situation!). Differential Revision: https://reviews.llvm.org/D135772 Added: Modified: clang/include/clang/Sema/Sema.h clang/lib/Sema/SemaDeclCXX.cpp clang/lib/Sema/SemaExpr.cpp clang/lib/Sema/SemaOverload.cpp clang/test/SemaTemplate/concepts.cpp Removed: ################################################################################ diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index a7f3ac1f57c31..6b422c3897c38 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -5304,11 +5304,22 @@ class Sema final { // 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<SourceLocation> 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 index 280af69da6a2b..5fe6f82fe3d08 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -15551,7 +15551,10 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, SourceRange ParenRange) { if (auto *Shadow = dyn_cast<ConstructorUsingShadowDecl>(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 index 7faae7e7ee430..f950e4313f5e9 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -222,7 +222,8 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs, const ObjCInterfaceDecl *UnknownObjCClass, bool ObjCPropertyAccess, bool AvoidPartialAvailabilityChecks, - ObjCInterfaceDecl *ClassReceiver) { + ObjCInterfaceDecl *ClassReceiver, + bool SkipTrailingRequiresClause) { SourceLocation Loc = Locs.front(); if (getLangOpts().CPlusPlus && isa<FunctionDecl>(D)) { // If there were any diagnostics suppressed by template argument deduction, @@ -281,7 +282,7 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs, // 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 @@ ExprResult Sema::BuildCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc, nullptr, DRE->isNonOdrUse()); } } - } else if (isa<MemberExpr>(NakedFn)) - NDecl = cast<MemberExpr>(NakedFn)->getMemberDecl(); + } else if (auto *ME = dyn_cast<MemberExpr>(NakedFn)) + NDecl = ME->getMemberDecl(); if (FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(NDecl)) { if (CallingNDeclIndirectly && !checkAddressOfFunctionIsAvailable( diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index c7e66d1e1d2ab..89df99fb6320f 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -14680,7 +14680,7 @@ ExprResult Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, Method = cast<CXXMethodDecl>(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 diff erent from Method (such as if one is a template // and the other a specialization), make sure DiagnoseUseOfDecl is @@ -14689,7 +14689,7 @@ ExprResult Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, // 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 index 5163fc8e01471..362b429fe2758 100644 --- a/clang/test/SemaTemplate/concepts.cpp +++ b/clang/test/SemaTemplate/concepts.cpp @@ -708,3 +708,60 @@ Container<5>::var_templ<int> inst_fail; // 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<class C> +constexpr bool Check = true; + +template<typename T> +struct Foo { + template<typename U> + Foo(U&&) requires (Check<U>){} + template<typename U> + void MemFunc(U&&) requires (Check<U>){} + template<typename U> + static void StaticMemFunc(U&&) requires (Check<U>){} + ~Foo() requires (Check<T>){} +}; + +template<> + struct Foo<void> : Foo<int> { + using Foo<int>::Foo; + using Foo<int>::MemFunc; + using Foo<int>::StaticMemFunc; + }; + +void use() { + Foo<void> F {1.1}; + F.MemFunc(1.1); + Foo<void>::StaticMemFunc(1.1); +} + +template<typename T> +struct counted_iterator { + constexpr auto operator->() const noexcept requires false { + return T::Invalid; + }; +}; + +template<class _Ip> +concept __has_member_pointer = requires { typename _Ip::pointer; }; + +template<class> +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<class _Ip> + 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<counted_iterator<int>> f; +} +}// namespace InheritedFromPartialSpec _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits