From 49c8dad960b99faa2f1f14566317b4e3d2cb7b0a Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Thu, 17 Apr 2014 01:12:17 +0000 Subject: [PATCH] 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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@206435 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/ExprCXX.h | 3 ++ include/clang/Sema/Sema.h | 3 ++ lib/Sema/SemaLookup.cpp | 32 +++++++++++-------- lib/Sema/TreeTransform.h | 7 ++-- .../over.match.funcs/over.match.oper/p3.cpp | 30 +++++++++++++++-- 5 files changed, 56 insertions(+), 19 deletions(-) diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h index 6ed55ca02d..aff0021a77 100644 --- a/include/clang/AST/ExprCXX.h +++ b/include/clang/AST/ExprCXX.h @@ -2431,6 +2431,9 @@ public: decls_iterator decls_end() const { return UnresolvedSetIterator(Results + NumResults); } + llvm::iterator_range decls() const { + return llvm::iterator_range(decls_begin(), decls_end()); + } /// \brief Gets the number of declarations in the unresolved set. unsigned getNumDecls() const { return NumResults; } diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index b3e3e43ffe..2b48155abc 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -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()); diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index 172a07906d..ba9bcd6561 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -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(Found)) { - if (IsAcceptableNonMemberOperatorCandidate(FD, T1, T2, Context)) - Functions.addDecl(*Op, Op.getAccess()); // FIXME: canonical FD - } else if (FunctionTemplateDecl *FunTmpl - = dyn_cast(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(Found)) { + if (IsAcceptableNonMemberOperatorCandidate(FD, T1, T2, Context)) + Functions.addDecl(Op, Op.getAccess()); // FIXME: canonical FD + } else if (FunctionTemplateDecl *FunTmpl + = dyn_cast(Found)) { + // FIXME: friend operators? + // FIXME: do we need to check IsAcceptableNonMemberOperatorCandidate, + // later? + if (!FunTmpl->getDeclContext()->isRecord()) + Functions.addDecl(Op, Op.getAccess()); } } diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 27cf43fd74..4094f5a716 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -9760,9 +9760,10 @@ TreeTransform::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op, if (UnresolvedLookupExpr *ULE = dyn_cast(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, diff --git a/test/CXX/over/over.match/over.match.funcs/over.match.oper/p3.cpp b/test/CXX/over/over.match/over.match.funcs/over.match.oper/p3.cpp index 35f8808fff..b3cc3bf41c 100644 --- a/test/CXX/over/over.match/over.match.funcs/over.match.oper/p3.cpp +++ b/test/CXX/over/over.match/over.match.funcs/over.match.oper/p3.cpp @@ -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 B(T); }; +int operator~(B); // expected-note {{declared prior to the call site}} +template int operator%(B, T); +enum class E { e }; + +// FIXME: This is the wrong diagnostic. +template int f(T t) { return ~t; } // expected-error {{call to}} +template 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; \ No newline at end of file +extern decltype(a <= b) test3; + +} -- 2.40.0