aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2009-07-08 10:57:20 +0000
committerDouglas Gregor <dgregor@apple.com>2009-07-08 10:57:20 +0000
commitdaa439a6c47d3299157b94a496bf22389bbc77a3 (patch)
tree6feee6febbc6cd97f259c21b977c4b303da7d4cc
parent466850963074ea7becc6fdc3de3dfa226cc87bdd (diff)
Fix a corner case with argument-dependent lookup and overloaded function sets.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@74999 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/AST/DeclCXX.h50
-rw-r--r--lib/AST/DeclCXX.cpp33
-rw-r--r--lib/Sema/SemaLookup.cpp25
-rw-r--r--test/CXX/basic/basic.lookup/basic.lookup.argdep/p2-template-id.cpp11
4 files changed, 110 insertions, 9 deletions
diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h
index 741998def1..90c86b17d2 100644
--- a/include/clang/AST/DeclCXX.h
+++ b/include/clang/AST/DeclCXX.h
@@ -132,6 +132,56 @@ public:
}
static bool classof(const OverloadedFunctionDecl *D) { return true; }
};
+
+/// \brief Provides uniform iteration syntax for an overload set, function,
+/// or function template.
+class OverloadIterator {
+ /// \brief An overloaded function set, function declaration, or
+ /// function template declaration.
+ NamedDecl *D;
+
+ /// \brief If the declaration is an overloaded function set, this is the
+ /// iterator pointing to the current position within that overloaded
+ /// function set.
+ OverloadedFunctionDecl::function_iterator Iter;
+
+public:
+ typedef AnyFunctionDecl value_type;
+ typedef value_type reference;
+ typedef NamedDecl *pointer;
+ typedef int difference_type;
+ typedef std::forward_iterator_tag iterator_category;
+
+ OverloadIterator() : D(0) { }
+
+ OverloadIterator(FunctionDecl *FD) : D(FD) { }
+ OverloadIterator(FunctionTemplateDecl *FTD)
+ : D(reinterpret_cast<NamedDecl*>(FTD)) { }
+ OverloadIterator(OverloadedFunctionDecl *Ovl)
+ : D(Ovl), Iter(Ovl->function_begin()) { }
+
+ reference operator*() const;
+
+ pointer operator->() const { return (**this).get(); }
+
+ OverloadIterator &operator++();
+
+ OverloadIterator operator++(int) {
+ OverloadIterator Temp(*this);
+ ++(*this);
+ return Temp;
+ }
+
+ bool Equals(const OverloadIterator &Other) const;
+};
+
+inline bool operator==(const OverloadIterator &X, const OverloadIterator &Y) {
+ return X.Equals(Y);
+}
+
+inline bool operator!=(const OverloadIterator &X, const OverloadIterator &Y) {
+ return !(X == Y);
+}
/// CXXBaseSpecifier - A base class of a C++ class.
///
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index 6be675ad83..f525667ad0 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -451,6 +451,39 @@ void OverloadedFunctionDecl::addOverload(AnyFunctionDecl F) {
this->setLocation(F.get()->getLocation());
}
+OverloadIterator::reference OverloadIterator::operator*() const {
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
+ return FD;
+
+ if (FunctionTemplateDecl *FTD = dyn_cast<FunctionTemplateDecl>(D))
+ return FTD;
+
+ assert(isa<OverloadedFunctionDecl>(D));
+ return *Iter;
+}
+
+OverloadIterator &OverloadIterator::operator++() {
+ if (isa<FunctionDecl>(D) || isa<FunctionTemplateDecl>(D)) {
+ D = 0;
+ return *this;
+ }
+
+ if (++Iter == cast<OverloadedFunctionDecl>(D)->function_end())
+ D = 0;
+
+ return *this;
+}
+
+bool OverloadIterator::Equals(const OverloadIterator &Other) const {
+ if (!D || !Other.D)
+ return D == Other.D;
+
+ if (D != Other.D)
+ return false;
+
+ return !isa<OverloadedFunctionDecl>(D) || Iter == Other.Iter;
+}
+
LinkageSpecDecl *LinkageSpecDecl::Create(ASTContext &C,
DeclContext *DC,
SourceLocation L,
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index 343cbae673..c88321e1a3 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/lib/Sema/SemaLookup.cpp
@@ -19,6 +19,7 @@
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
+#include "clang/AST/ExprCXX.h"
#include "clang/Parse/DeclSpec.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/LangOptions.h"
@@ -1579,18 +1580,24 @@ Sema::FindAssociatedClassesAndNamespaces(Expr **Args, unsigned NumArgs,
// classes and namespaces associated with its (non-dependent)
// parameter types and return type.
DeclRefExpr *DRE = 0;
+ TemplateIdRefExpr *TIRE = 0;
+ Arg = Arg->IgnoreParens();
if (UnaryOperator *unaryOp = dyn_cast<UnaryOperator>(Arg)) {
- if (unaryOp->getOpcode() == UnaryOperator::AddrOf)
+ if (unaryOp->getOpcode() == UnaryOperator::AddrOf) {
DRE = dyn_cast<DeclRefExpr>(unaryOp->getSubExpr());
- } else
+ TIRE = dyn_cast<TemplateIdRefExpr>(unaryOp->getSubExpr());
+ }
+ } else {
DRE = dyn_cast<DeclRefExpr>(Arg);
- if (!DRE)
- continue;
-
- // FIXME: The declaration might be a FunctionTemplateDecl (by itself)
- // or might be buried in a TemplateIdRefExpr.
- OverloadedFunctionDecl *Ovl
- = dyn_cast<OverloadedFunctionDecl>(DRE->getDecl());
+ TIRE = dyn_cast<TemplateIdRefExpr>(Arg);
+ }
+
+ OverloadedFunctionDecl *Ovl = 0;
+ if (DRE)
+ Ovl = dyn_cast<OverloadedFunctionDecl>(DRE->getDecl());
+ else if (TIRE)
+ Ovl = dyn_cast_or_null<OverloadedFunctionDecl>(
+ TIRE->getTemplateName().getAsTemplateDecl());
if (!Ovl)
continue;
diff --git a/test/CXX/basic/basic.lookup/basic.lookup.argdep/p2-template-id.cpp b/test/CXX/basic/basic.lookup/basic.lookup.argdep/p2-template-id.cpp
index 525afd89ec..e2c76f9183 100644
--- a/test/CXX/basic/basic.lookup/basic.lookup.argdep/p2-template-id.cpp
+++ b/test/CXX/basic/basic.lookup/basic.lookup.argdep/p2-template-id.cpp
@@ -14,3 +14,14 @@ namespace N3 {
int &ir = f((N2::Y<N1::X>*)0);
}
}
+
+int g(void *);
+long g(N1::X);
+
+namespace N1 {
+ void h(int (*)(void *));
+}
+
+void test() {
+ h((&g));
+}