forked from OSchip/llvm-project
PR19452: Implement more of [over.match.oper]p3's restrictions on which non-member overloaded operators can be found when no operand is of class type. We used to fail to implement this rule if there was an operand of dependent type.
llvm-svn: 206435
This commit is contained in:
parent
649f030819
commit
688866ba3e
|
@ -2431,6 +2431,9 @@ public:
|
|||
decls_iterator decls_end() const {
|
||||
return UnresolvedSetIterator(Results + NumResults);
|
||||
}
|
||||
llvm::iterator_range<decls_iterator> decls() const {
|
||||
return llvm::iterator_range<decls_iterator>(decls_begin(), decls_end());
|
||||
}
|
||||
|
||||
/// \brief Gets the number of declarations in the unresolved set.
|
||||
unsigned getNumDecls() const { return NumResults; }
|
||||
|
|
|
@ -2564,6 +2564,9 @@ public:
|
|||
void LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S,
|
||||
QualType T1, QualType T2,
|
||||
UnresolvedSetImpl &Functions);
|
||||
void addOverloadedOperatorToUnresolvedSet(UnresolvedSetImpl &Functions,
|
||||
DeclAccessPair Operator,
|
||||
QualType T1, QualType T2);
|
||||
|
||||
LabelDecl *LookupOrCreateLabel(IdentifierInfo *II, SourceLocation IdentLoc,
|
||||
SourceLocation GnuLabelLoc = SourceLocation());
|
||||
|
|
|
@ -2390,20 +2390,24 @@ void Sema::LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S,
|
|||
if (Operators.empty())
|
||||
return;
|
||||
|
||||
for (LookupResult::iterator Op = Operators.begin(), OpEnd = Operators.end();
|
||||
Op != OpEnd; ++Op) {
|
||||
NamedDecl *Found = (*Op)->getUnderlyingDecl();
|
||||
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(Found)) {
|
||||
if (IsAcceptableNonMemberOperatorCandidate(FD, T1, T2, Context))
|
||||
Functions.addDecl(*Op, Op.getAccess()); // FIXME: canonical FD
|
||||
} else if (FunctionTemplateDecl *FunTmpl
|
||||
= dyn_cast<FunctionTemplateDecl>(Found)) {
|
||||
// FIXME: friend operators?
|
||||
// FIXME: do we need to check IsAcceptableNonMemberOperatorCandidate,
|
||||
// later?
|
||||
if (!FunTmpl->getDeclContext()->isRecord())
|
||||
Functions.addDecl(*Op, Op.getAccess());
|
||||
}
|
||||
for (auto I = Operators.begin(), E = Operators.end(); I != E; ++I)
|
||||
addOverloadedOperatorToUnresolvedSet(Functions, I.getPair(), T1, T2);
|
||||
}
|
||||
|
||||
void Sema::addOverloadedOperatorToUnresolvedSet(UnresolvedSetImpl &Functions,
|
||||
DeclAccessPair Op,
|
||||
QualType T1, QualType T2) {
|
||||
NamedDecl *Found = Op->getUnderlyingDecl();
|
||||
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(Found)) {
|
||||
if (IsAcceptableNonMemberOperatorCandidate(FD, T1, T2, Context))
|
||||
Functions.addDecl(Op, Op.getAccess()); // FIXME: canonical FD
|
||||
} else if (FunctionTemplateDecl *FunTmpl
|
||||
= dyn_cast<FunctionTemplateDecl>(Found)) {
|
||||
// FIXME: friend operators?
|
||||
// FIXME: do we need to check IsAcceptableNonMemberOperatorCandidate,
|
||||
// later?
|
||||
if (!FunTmpl->getDeclContext()->isRecord())
|
||||
Functions.addDecl(Op, Op.getAccess());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -9760,9 +9760,10 @@ TreeTransform<Derived>::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op,
|
|||
if (UnresolvedLookupExpr *ULE = dyn_cast<UnresolvedLookupExpr>(Callee)) {
|
||||
assert(ULE->requiresADL());
|
||||
|
||||
// FIXME: Do we have to check
|
||||
// IsAcceptableNonMemberOperatorCandidate for each of these?
|
||||
Functions.append(ULE->decls_begin(), ULE->decls_end());
|
||||
for (auto I = ULE->decls_begin(), E = ULE->decls_end(); I != E; ++I)
|
||||
SemaRef.addOverloadedOperatorToUnresolvedSet(
|
||||
Functions, I.getPair(), First->getType(),
|
||||
Second ? Second->getType() : QualType());
|
||||
} else {
|
||||
// If we've resolved this to a particular non-member function, just call
|
||||
// that function. If we resolved it to a member function,
|
||||
|
|
|
@ -1,5 +1,29 @@
|
|||
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
|
||||
// expected-no-diagnostics
|
||||
|
||||
namespace bullet2 {
|
||||
|
||||
// For non-member candidates, if no operand has a class type, only those
|
||||
// non-member functions that have a matching enumeration parameter are
|
||||
// candidates.
|
||||
|
||||
struct B { template<typename T> B(T); };
|
||||
int operator~(B); // expected-note {{declared prior to the call site}}
|
||||
template<typename T> int operator%(B, T);
|
||||
enum class E { e };
|
||||
|
||||
// FIXME: This is the wrong diagnostic.
|
||||
template<typename T> int f(T t) { return ~t; } // expected-error {{call to}}
|
||||
template<typename T, typename U> int f(T t, U u) { return t % u; }
|
||||
|
||||
int b1 = ~E::e; // expected-error {{invalid argument type}}
|
||||
int b2 = f(E::e); // expected-note {{in instantiation of}}
|
||||
int b3 = f(0, E::e);
|
||||
// FIXME: This should be rejected.
|
||||
int b4 = f(E::e, 0);
|
||||
|
||||
}
|
||||
|
||||
namespace bullet3 {
|
||||
|
||||
// This is specifically testing the bullet:
|
||||
// "do not have the same parameter-type-list as any non-template
|
||||
|
@ -26,4 +50,6 @@ extern bool test2;
|
|||
extern decltype(a <= a) test2;
|
||||
|
||||
extern A test3;
|
||||
extern decltype(a <= b) test3;
|
||||
extern decltype(a <= b) test3;
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue