[clang] 4bcb85c - Stop evaluating trailing requires clause after overload resolution
Erich Keane via cfe-commits
cfe-commits at lists.llvm.org
Tue Oct 18 06:09:09 PDT 2022
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
More information about the cfe-commits
mailing list