forked from OSchip/llvm-project
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
This commit is contained in:
parent
2946b25299
commit
4bcb85c638
|
@ -5304,11 +5304,22 @@ public:
|
||||||
// Expression Parsing Callbacks: SemaExpr.cpp.
|
// Expression Parsing Callbacks: SemaExpr.cpp.
|
||||||
|
|
||||||
bool CanUseDecl(NamedDecl *D, bool TreatUnavailableAsInvalid);
|
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,
|
bool DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs,
|
||||||
const ObjCInterfaceDecl *UnknownObjCClass = nullptr,
|
const ObjCInterfaceDecl *UnknownObjCClass = nullptr,
|
||||||
bool ObjCPropertyAccess = false,
|
bool ObjCPropertyAccess = false,
|
||||||
bool AvoidPartialAvailabilityChecks = false,
|
bool AvoidPartialAvailabilityChecks = false,
|
||||||
ObjCInterfaceDecl *ClassReciever = nullptr);
|
ObjCInterfaceDecl *ClassReciever = nullptr,
|
||||||
|
bool SkipTrailingRequiresClause = false);
|
||||||
void NoteDeletedFunction(FunctionDecl *FD);
|
void NoteDeletedFunction(FunctionDecl *FD);
|
||||||
void NoteDeletedInheritingConstructor(CXXConstructorDecl *CD);
|
void NoteDeletedInheritingConstructor(CXXConstructorDecl *CD);
|
||||||
bool DiagnosePropertyAccessorMismatch(ObjCPropertyDecl *PD,
|
bool DiagnosePropertyAccessorMismatch(ObjCPropertyDecl *PD,
|
||||||
|
|
|
@ -15551,7 +15551,10 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
|
||||||
SourceRange ParenRange) {
|
SourceRange ParenRange) {
|
||||||
if (auto *Shadow = dyn_cast<ConstructorUsingShadowDecl>(FoundDecl)) {
|
if (auto *Shadow = dyn_cast<ConstructorUsingShadowDecl>(FoundDecl)) {
|
||||||
Constructor = findInheritingConstructor(ConstructLoc, Constructor, Shadow);
|
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();
|
return ExprError();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -222,7 +222,8 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs,
|
||||||
const ObjCInterfaceDecl *UnknownObjCClass,
|
const ObjCInterfaceDecl *UnknownObjCClass,
|
||||||
bool ObjCPropertyAccess,
|
bool ObjCPropertyAccess,
|
||||||
bool AvoidPartialAvailabilityChecks,
|
bool AvoidPartialAvailabilityChecks,
|
||||||
ObjCInterfaceDecl *ClassReceiver) {
|
ObjCInterfaceDecl *ClassReceiver,
|
||||||
|
bool SkipTrailingRequiresClause) {
|
||||||
SourceLocation Loc = Locs.front();
|
SourceLocation Loc = Locs.front();
|
||||||
if (getLangOpts().CPlusPlus && isa<FunctionDecl>(D)) {
|
if (getLangOpts().CPlusPlus && isa<FunctionDecl>(D)) {
|
||||||
// If there were any diagnostics suppressed by template argument deduction,
|
// 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.
|
// 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
|
// Check this before deducing the return type, as it might instantiate the
|
||||||
// definition.
|
// definition.
|
||||||
if (FD->getTrailingRequiresClause()) {
|
if (!SkipTrailingRequiresClause && FD->getTrailingRequiresClause()) {
|
||||||
ConstraintSatisfaction Satisfaction;
|
ConstraintSatisfaction Satisfaction;
|
||||||
if (CheckFunctionConstraints(FD, Satisfaction, Loc,
|
if (CheckFunctionConstraints(FD, Satisfaction, Loc,
|
||||||
/*ForOverloadResolution*/ true))
|
/*ForOverloadResolution*/ true))
|
||||||
|
@ -6761,8 +6762,8 @@ ExprResult Sema::BuildCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc,
|
||||||
nullptr, DRE->isNonOdrUse());
|
nullptr, DRE->isNonOdrUse());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (isa<MemberExpr>(NakedFn))
|
} else if (auto *ME = dyn_cast<MemberExpr>(NakedFn))
|
||||||
NDecl = cast<MemberExpr>(NakedFn)->getMemberDecl();
|
NDecl = ME->getMemberDecl();
|
||||||
|
|
||||||
if (FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(NDecl)) {
|
if (FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(NDecl)) {
|
||||||
if (CallingNDeclIndirectly && !checkAddressOfFunctionIsAvailable(
|
if (CallingNDeclIndirectly && !checkAddressOfFunctionIsAvailable(
|
||||||
|
|
|
@ -14680,7 +14680,7 @@ ExprResult Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
|
||||||
Method = cast<CXXMethodDecl>(Best->Function);
|
Method = cast<CXXMethodDecl>(Best->Function);
|
||||||
FoundDecl = Best->FoundDecl;
|
FoundDecl = Best->FoundDecl;
|
||||||
CheckUnresolvedMemberAccess(UnresExpr, Best->FoundDecl);
|
CheckUnresolvedMemberAccess(UnresExpr, Best->FoundDecl);
|
||||||
if (DiagnoseUseOfDecl(Best->FoundDecl, UnresExpr->getNameLoc()))
|
if (DiagnoseUseOfOverloadedDecl(Best->FoundDecl, UnresExpr->getNameLoc()))
|
||||||
break;
|
break;
|
||||||
// If FoundDecl is different from Method (such as if one is a template
|
// If FoundDecl is different from Method (such as if one is a template
|
||||||
// and the other a specialization), make sure DiagnoseUseOfDecl is
|
// 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
|
// DiagnoseUseOfDecl to accept both the FoundDecl and the decl
|
||||||
// being used.
|
// being used.
|
||||||
if (Method != FoundDecl.getDecl() &&
|
if (Method != FoundDecl.getDecl() &&
|
||||||
DiagnoseUseOfDecl(Method, UnresExpr->getNameLoc()))
|
DiagnoseUseOfOverloadedDecl(Method, UnresExpr->getNameLoc()))
|
||||||
break;
|
break;
|
||||||
Succeeded = true;
|
Succeeded = true;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -708,3 +708,60 @@ Container<5>::var_templ<int> inst_fail;
|
||||||
// expected-note@#CMVT_REQ{{because 'sizeof(int) == arity' (4 == 5) evaluated to false}}
|
// expected-note@#CMVT_REQ{{because 'sizeof(int) == arity' (4 == 5) evaluated to false}}
|
||||||
} // namespace ConstrainedMemberVarTemplate
|
} // 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
|
||||||
|
|
Loading…
Reference in New Issue