Don't push OverloadedFunctionDecls onto the chain of declarations

attached to an identifier. Instead, all overloaded functions will be
pushed into scope, and we'll synthesize an OverloadedFunctionDecl on
the fly when we need it. 



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@61386 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Douglas Gregor 2008-12-23 21:05:05 +00:00
Родитель 46a98a7df0
Коммит 6ed40e351a
7 изменённых файлов: 153 добавлений и 175 удалений

Просмотреть файл

@ -200,6 +200,15 @@ public:
return true;
}
/// declarationReplaces - Determine whether this declaration, if
/// known to be well-formed within its context, will replace the
/// declaration OldD if introduced into scope. A declaration will
/// replace another declaration if, for example, it is a
/// redeclaration of the same variable or function, but not if it is
/// a declaration of a different kind (function vs. class) or an
/// overloaded function.
bool declarationReplaces(NamedDecl *OldD) const;
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) {
return D->getKind() >= ScopedFirst && D->getKind() <= ScopedLast;

Просмотреть файл

@ -174,6 +174,19 @@ ScopedDecl::~ScopedDecl() {
delete getMultipleDC();
}
bool ScopedDecl::declarationReplaces(NamedDecl *OldD) const {
assert(getDeclName() == OldD->getDeclName() && "Declaration name mismatch");
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(this))
// For function declarations, we keep track of redeclarations.
return FD->getPreviousDeclaration() == OldD;
// For non-function declarations, if the declarations are of the
// same kind then this must be a redeclaration, or semantic analysis
// would not have given us the new declaration.
return this->getKind() == OldD->getKind();
}
//===----------------------------------------------------------------------===//
// VarDecl Implementation
//===----------------------------------------------------------------------===//

Просмотреть файл

@ -17,6 +17,8 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/Type.h"
#include "llvm/ADT/DenseMap.h"
#include <algorithm>
#include <functional>
#include <vector>
using namespace clang;
@ -543,19 +545,6 @@ void DeclContext::insert(ASTContext &Context, ScopedDecl *D) {
insertImpl(D);
}
static bool isRedeclarationOf(ScopedDecl *D, ScopedDecl *OldD) {
assert(D->getDeclName() == OldD->getDeclName() && "Declaration name mismatch");
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
// For function declarations, we keep track of redeclarations.
return FD->getPreviousDeclaration() == OldD;
// For non-function declarations, if the declarations are of the
// same kind then this must be a redeclaration, or semantic analysis
// would not have given us the new declaration.
return D->getKind() == OldD->getKind();
}
void DeclContext::insertImpl(ScopedDecl *D) {
bool MayBeRedeclaration = true;
@ -591,7 +580,7 @@ void DeclContext::insertImpl(ScopedDecl *D) {
if (Array[LastMatch]->getDeclName() != D->getDeclName())
break;
if (isRedeclarationOf(D, Array[LastMatch])) {
if (D->declarationReplaces(Array[LastMatch])) {
// D is a redeclaration of an existing element in the
// array. Replace that element with D.
Array[LastMatch] = D;
@ -640,15 +629,13 @@ void DeclContext::insertImpl(ScopedDecl *D) {
if (Pos != Map->end()) {
if (MayBeRedeclaration) {
// Determine if this declaration is actually a redeclaration.
for (std::vector<ScopedDecl *>::iterator I = Pos->second.begin(),
IEnd = Pos->second.end();
I != IEnd; ++I) {
if (isRedeclarationOf(D, *I)) {
// D is a redeclaration of *I. Replace *I with D and we're
// done.
*I = D;
return;
}
std::vector<ScopedDecl *>::iterator Redecl
= std::find_if(Pos->second.begin(), Pos->second.end(),
std::bind1st(std::mem_fun(&ScopedDecl::declarationReplaces),
D));
if (Redecl != Pos->second.end()) {
*Redecl = D;
return;
}
}

Просмотреть файл

@ -128,6 +128,13 @@ public:
/// It will walk or not the parent declaration contexts depending on how
/// it was instantiated.
class iterator {
public:
typedef NamedDecl * value_type;
typedef NamedDecl * reference;
typedef NamedDecl * pointer;
typedef std::input_iterator_tag iterator_category;
typedef std::ptrdiff_t difference_type;
/// Ptr - There are 3 forms that 'Ptr' represents:
/// 1) A single NamedDecl. (Ptr & 0x1 == 0)
/// 2) A IdDeclInfo::DeclsTy::iterator that traverses only the decls of the

Просмотреть файл

@ -26,6 +26,8 @@
#include "clang/Lex/HeaderSearch.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/STLExtras.h"
#include <algorithm>
#include <functional>
using namespace clang;
@ -93,6 +95,12 @@ void Sema::PopDeclContext() {
void Sema::PushOnScopeChains(NamedDecl *D, Scope *S) {
S->AddDecl(D);
// Add scoped declarations into their context, so that they can be
// found later. Declarations without a context won't be inserted
// into any context.
if (ScopedDecl *SD = dyn_cast<ScopedDecl>(D))
CurContext->addDecl(Context, SD);
// C++ [basic.scope]p4:
// -- exactly one declaration shall declare a class name or
// enumeration name that is not a typedef name and the other
@ -105,74 +113,56 @@ void Sema::PushOnScopeChains(NamedDecl *D, Scope *S) {
// We're pushing the tag into the current context, which might
// require some reshuffling in the identifier resolver.
IdentifierResolver::iterator
I = IdResolver.begin(TD->getIdentifier(), CurContext,
false/*LookInParentCtx*/);
if (I != IdResolver.end()) {
// There is already a declaration with the same name in the same
// scope. It must be found before we find the new declaration,
// so swap the order on the shadowed declaration chain.
IdResolver.AddShadowedDecl(TD, *I);
I = IdResolver.begin(TD->getDeclName(), CurContext,
false/*LookInParentCtx*/),
IEnd = IdResolver.end();
if (I != IEnd && isDeclInScope(*I, CurContext, S)) {
NamedDecl *PrevDecl = *I;
for (; I != IEnd && isDeclInScope(*I, CurContext, S);
PrevDecl = *I, ++I) {
if (TD->declarationReplaces(*I)) {
// This is a redeclaration. Remove it from the chain and
// break out, so that we'll add in the shadowed
// declaration.
S->RemoveDecl(*I);
if (PrevDecl == *I) {
IdResolver.RemoveDecl(*I);
IdResolver.AddDecl(TD);
return;
} else {
IdResolver.RemoveDecl(*I);
break;
}
}
}
// Add this declaration to the current context.
CurContext->addDecl(Context, TD);
return;
// There is already a declaration with the same name in the same
// scope, which is not a tag declaration. It must be found
// before we find the new declaration, so insert the new
// declaration at the end of the chain.
IdResolver.AddShadowedDecl(TD, PrevDecl);
return;
}
}
} else if (getLangOptions().CPlusPlus && isa<FunctionDecl>(D)) {
// We are pushing the name of a function, which might be an
// overloaded name.
FunctionDecl *FD = cast<FunctionDecl>(D);
if (CurContext == FD->getDeclContext()) {
IdentifierResolver::iterator
I = IdResolver.begin(FD->getDeclName(), CurContext,
false/*LookInParentCtx*/);
if (I != IdResolver.end() &&
(isa<OverloadedFunctionDecl>(*I) || isa<FunctionDecl>(*I))) {
// There is already a declaration with the same name in
// the same scope. It must be a function or an overloaded
// function.
OverloadedFunctionDecl* Ovl = dyn_cast<OverloadedFunctionDecl>(*I);
if (!Ovl) {
// We haven't yet overloaded this function. Take the existing
// FunctionDecl and put it into an OverloadedFunctionDecl.
Ovl = OverloadedFunctionDecl::Create(Context,
FD->getDeclContext(),
FD->getDeclName());
Ovl->addOverload(cast<FunctionDecl>(*I));
IdResolver.RemoveDecl(*I);
S->RemoveDecl(*I);
// Add the name binding for the OverloadedFunctionDecl.
IdResolver.AddDecl(Ovl);
S->AddDecl(Ovl);
}
// We added this function declaration to the scope earlier, but
// we don't want it there because it is part of the overloaded
// function declaration.
S->RemoveDecl(FD);
// We have an OverloadedFunctionDecl. Add the new FunctionDecl
// to its list of overloads.
Ovl->addOverload(FD);
// Add this new function declaration to the declaration context.
CurContext->addDecl(Context, FD);
return;
}
IdentifierResolver::iterator Redecl
= std::find_if(IdResolver.begin(FD->getDeclName(), CurContext,
false/*LookInParentCtx*/),
IdResolver.end(),
std::bind1st(std::mem_fun(&ScopedDecl::declarationReplaces),
FD));
if (Redecl != IdResolver.end()) {
// There is already a declaration of a function on our
// IdResolver chain. Replace it with this declaration.
S->RemoveDecl(*Redecl);
IdResolver.RemoveDecl(*Redecl);
}
}
// Add scoped declarations into their context, so that they can be
// found later. Declarations without a context won't be inserted
// into any context.
if (ScopedDecl *SD = dyn_cast<ScopedDecl>(D))
CurContext->addDecl(Context, SD);
IdResolver.AddDecl(D);
}
@ -217,10 +207,10 @@ ObjCInterfaceDecl *Sema::getObjCInterfaceDecl(IdentifierInfo *Id) {
/// probably be able to return multiple results, to deal with cases of
/// ambiguity and overloaded functions without needing to create a
/// Decl node.
template<typename DeclIterator>
static Decl *
MaybeConstructOverloadSet(ASTContext &Context, const DeclContext *DC,
DeclContext::lookup_const_iterator I,
DeclContext::lookup_const_iterator IEnd) {
MaybeConstructOverloadSet(ASTContext &Context,
DeclIterator I, DeclIterator IEnd) {
assert(I != IEnd && "Iterator range cannot be empty");
assert(!isa<OverloadedFunctionDecl>(*I) &&
"Cannot have an overloaded function");
@ -228,7 +218,7 @@ MaybeConstructOverloadSet(ASTContext &Context, const DeclContext *DC,
if (isa<FunctionDecl>(*I)) {
// If we found a function, there might be more functions. If
// so, collect them into an overload set.
DeclContext::lookup_const_iterator Last = I;
DeclIterator Last = I;
OverloadedFunctionDecl *Ovl = 0;
for (++Last; Last != IEnd && isa<FunctionDecl>(*Last); ++Last) {
if (!Ovl) {
@ -236,7 +226,7 @@ MaybeConstructOverloadSet(ASTContext &Context, const DeclContext *DC,
// stop building the declarations for these overload sets, so
// there will be nothing to leak.
Ovl = OverloadedFunctionDecl::Create(Context,
const_cast<DeclContext *>(DC),
cast<ScopedDecl>(*I)->getDeclContext(),
(*I)->getDeclName());
Ovl->addOverload(cast<FunctionDecl>(*I));
}
@ -285,7 +275,7 @@ Decl *Sema::LookupDecl(DeclarationName Name, unsigned NSI, Scope *S,
DeclContext::lookup_const_iterator I, E;
for (llvm::tie(I, E) = LookupCtx->lookup(Context, Name); I != E; ++I)
if ((*I)->getIdentifierNamespace() & NS)
return MaybeConstructOverloadSet(Context, LookupCtx, I, E);
return MaybeConstructOverloadSet(Context, I, E);
} else {
// Name lookup for ordinary names and tag names in C++ requires
// looking into scopes that aren't strictly lexical, and
@ -297,9 +287,21 @@ Decl *Sema::LookupDecl(DeclarationName Name, unsigned NSI, Scope *S,
for (; S; S = S->getParent()) {
// Check whether the IdResolver has anything in this scope.
// FIXME: The isDeclScope check could be expensive. Can we do better?
for (; I != IEnd && S->isDeclScope(*I); ++I)
if ((*I)->getIdentifierNamespace() & NS)
return *I;
for (; I != IEnd && S->isDeclScope(*I); ++I) {
if ((*I)->getIdentifierNamespace() & NS) {
// We found something. Look for anything else in our scope
// with this same name and in an acceptable identifier
// namespace, so that we can construct an overload set if we
// need to.
IdentifierResolver::iterator LastI = I;
for (++LastI; LastI != IEnd; ++LastI) {
if (((*LastI)->getIdentifierNamespace() & NS) == 0 ||
!S->isDeclScope(*LastI))
break;
}
return MaybeConstructOverloadSet(Context, I, LastI);
}
}
// If there is an entity associated with this scope, it's a
// DeclContext. We might need to perform qualified lookup into
@ -313,7 +315,7 @@ Decl *Sema::LookupDecl(DeclarationName Name, unsigned NSI, Scope *S,
for (llvm::tie(I, E) = Ctx->lookup(Context, Name); I != E; ++I) {
// FIXME: Cache this result in the IdResolver
if ((*I)->getIdentifierNamespace() & NS)
return MaybeConstructOverloadSet(Context, LookupCtx, I, E);
return MaybeConstructOverloadSet(Context, I, E);
}
Ctx = Ctx->getParent();
@ -652,6 +654,8 @@ void Sema::CheckForFileScopedRedefinitions(Scope *S, VarDecl *VD) {
bool VDIsTentative = isTentativeDefinition(VD);
bool VDIsIncompleteArray = VD->getType()->isIncompleteArrayType();
// FIXME: I don't this will actually see all of the
// redefinitions. Can't we check this property on-the-fly?
for (IdentifierResolver::iterator
I = IdResolver.begin(VD->getIdentifier(),
VD->getDeclContext(), false/*LookInParentCtx*/),
@ -1132,7 +1136,7 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl,
assert(DC->isCXXRecord() &&
"Constructors can only be declared in a member context");
bool isInvalidDecl = CheckConstructorDeclarator(D, R, SC);
InvalidDecl = InvalidDecl || CheckConstructorDeclarator(D, R, SC);
// Create the new declaration
NewFD = CXXConstructorDecl::Create(Context,
@ -1141,12 +1145,12 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl,
isExplicit, isInline,
/*isImplicitlyDeclared=*/false);
if (isInvalidDecl)
if (InvalidDecl)
NewFD->setInvalidDecl();
} else if (D.getKind() == Declarator::DK_Destructor) {
// This is a C++ destructor declaration.
if (DC->isCXXRecord()) {
bool isInvalidDecl = CheckDestructorDeclarator(D, R, SC);
InvalidDecl = InvalidDecl || CheckDestructorDeclarator(D, R, SC);
NewFD = CXXDestructorDecl::Create(Context,
cast<CXXRecordDecl>(DC),
@ -1154,16 +1158,18 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl,
isInline,
/*isImplicitlyDeclared=*/false);
if (isInvalidDecl)
if (InvalidDecl)
NewFD->setInvalidDecl();
} else {
Diag(D.getIdentifierLoc(), diag::err_destructor_not_member);
// Create a FunctionDecl to satisfy the function definition parsing
// code path.
NewFD = FunctionDecl::Create(Context, DC, D.getIdentifierLoc(),
Name, R, SC, isInline, LastDeclarator,
// FIXME: Move to DeclGroup...
D.getDeclSpec().getSourceRange().getBegin());
InvalidDecl = true;
NewFD->setInvalidDecl();
}
} else if (D.getKind() == Declarator::DK_Conversion) {
@ -1172,14 +1178,14 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl,
diag::err_conv_function_not_member);
return 0;
} else {
bool isInvalidDecl = CheckConversionDeclarator(D, R, SC);
InvalidDecl = InvalidDecl || CheckConversionDeclarator(D, R, SC);
NewFD = CXXConversionDecl::Create(Context,
cast<CXXRecordDecl>(DC),
D.getIdentifierLoc(), Name, R,
isInline, isExplicit);
if (isInvalidDecl)
if (InvalidDecl)
NewFD->setInvalidDecl();
}
} else if (DC->isCXXRecord()) {
@ -1316,48 +1322,14 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl,
if (Redeclaration) {
NewFD->setPreviousDeclaration(cast<FunctionDecl>(OldDecl));
if (OldDecl == PrevDecl) {
// Remove the name binding for the previous
// declaration.
if (S->isDeclScope(PrevDecl)) {
IdResolver.RemoveDecl(cast<NamedDecl>(PrevDecl));
S->RemoveDecl(PrevDecl);
}
// Introduce the new binding for this declaration.
IdResolver.AddDecl(NewFD);
if (getLangOptions().CPlusPlus && NewFD->getParent())
NewFD->getParent()->insert(Context, NewFD);
// Add the redeclaration to the current scope, since we'll
// be skipping PushOnScopeChains.
S->AddDecl(NewFD);
} else {
// We need to update the OverloadedFunctionDecl with the
// latest declaration of this function, so that name
// lookup will always refer to the latest declaration of
// this function.
*MatchedDecl = NewFD;
}
if (getLangOptions().CPlusPlus) {
// Add this declaration to the current context.
CurContext->addDecl(Context, NewFD, false);
// Check default arguments now that we have merged decls.
CheckCXXDefaultArguments(NewFD);
// An out-of-line member function declaration must also be a
// definition (C++ [dcl.meaning]p1).
if (!IsFunctionDefinition && D.getCXXScopeSpec().isSet() &&
!InvalidDecl) {
Diag(NewFD->getLocation(), diag::err_out_of_line_declaration)
<< D.getCXXScopeSpec().getRange();
NewFD->setInvalidDecl();
}
// An out-of-line member function declaration must also be a
// definition (C++ [dcl.meaning]p1).
if (!IsFunctionDefinition && D.getCXXScopeSpec().isSet() &&
!InvalidDecl) {
Diag(NewFD->getLocation(), diag::err_out_of_line_declaration)
<< D.getCXXScopeSpec().getRange();
NewFD->setInvalidDecl();
}
return NewFD;
}
}
@ -1417,7 +1389,7 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl,
// An out-of-line member function declaration must also be a
// definition (C++ [dcl.meaning]p1).
if (!IsFunctionDefinition && D.getCXXScopeSpec().isSet()) {
if (!IsFunctionDefinition && D.getCXXScopeSpec().isSet() && !InvalidDecl) {
Diag(NewFD->getLocation(), diag::err_out_of_line_declaration)
<< D.getCXXScopeSpec().getRange();
InvalidDecl = true;

Просмотреть файл

@ -515,26 +515,15 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
DeclContext *GlobalCtx = Context.getTranslationUnitDecl();
// Check if this function is already declared.
IdentifierResolver::iterator I = IdResolver.begin(Name, GlobalCtx,
/*CheckParent=*/false);
if (I != IdResolver.end()) {
NamedDecl *Decl = *I;
if (FunctionDecl *Fn = dyn_cast<FunctionDecl>(Decl)) {
// The return type fits. This is checked when the function is declared.
if (Fn->getNumParams() == 1 &&
Context.getCanonicalType(Fn->getParamDecl(0)->getType()) == Argument)
{
DeclContext::decl_iterator Alloc, AllocEnd;
for (llvm::tie(Alloc, AllocEnd) = GlobalCtx->lookup(Context, Name);
Alloc != AllocEnd; ++Alloc) {
// FIXME: Do we need to check for default arguments here?
FunctionDecl *Func = cast<FunctionDecl>(*Alloc);
if (Func->getNumParams() == 1 &&
Context.getCanonicalType(Func->getParamDecl(0)->getType()) == Argument)
return;
} else if(OverloadedFunctionDecl *Ovl =
dyn_cast<OverloadedFunctionDecl>(Decl)) {
for (OverloadedFunctionDecl::function_iterator F = Ovl->function_begin(),
FEnd = Ovl->function_end();
F != FEnd; ++F) {
if ((*F)->getNumParams() == 1 &&
Context.getCanonicalType((*F)->getParamDecl(0)->getType())
== Argument)
return;
}
}
}
@ -548,6 +537,9 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
0, Argument, VarDecl::None, 0, 0);
Alloc->setParams(&Param, 1);
// FIXME: Also add this declaration to the IdentifierResolver, but
// make sure it is at the end of the chain to coincide with the
// global scope.
((DeclContext *)TUScope->getEntity())->addDecl(Context, Alloc);
}

Просмотреть файл

@ -2160,10 +2160,10 @@ void Sema::AddOperatorCandidates(OverloadedOperatorKind Op, Scope *S,
// of type T2 or “reference to (possibly cv-qualified) T2”,
// when T2 is an enumeration type, are candidate functions.
{
NamedDecl *NonMemberOps = 0;
for (IdentifierResolver::iterator I
= IdResolver.begin(OpName, CurContext, true/*LookInParentCtx*/);
I != IdResolver.end(); ++I) {
IdentifierResolver::iterator
I = IdResolver.begin(OpName, CurContext, true/*LookInParentCtx*/),
IEnd = IdResolver.end();
for (; I != IEnd; ++I) {
// We don't need to check the identifier namespace, because
// operator names can only be ordinary identifiers.
@ -2174,22 +2174,20 @@ void Sema::AddOperatorCandidates(OverloadedOperatorKind Op, Scope *S,
}
// We found something with this name. We're done.
NonMemberOps = *I;
break;
}
if (FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(NonMemberOps)) {
if (IsAcceptableNonMemberOperatorCandidate(FD, T1, T2, Context))
AddOverloadCandidate(FD, Args, NumArgs, CandidateSet,
/*SuppressUserConversions=*/false);
} else if (OverloadedFunctionDecl *Ovl
= dyn_cast_or_null<OverloadedFunctionDecl>(NonMemberOps)) {
for (OverloadedFunctionDecl::function_iterator F = Ovl->function_begin(),
FEnd = Ovl->function_end();
F != FEnd; ++F) {
if (IsAcceptableNonMemberOperatorCandidate(*F, T1, T2, Context))
AddOverloadCandidate(*F, Args, NumArgs, CandidateSet,
/*SuppressUserConversions=*/false);
if (I != IEnd && isa<ScopedDecl>(*I)) {
ScopedDecl *FirstDecl = cast<ScopedDecl>(*I);
for (; I != IEnd; ++I) {
ScopedDecl *SD = cast<ScopedDecl>(*I);
if (FirstDecl->getDeclContext() != SD->getDeclContext())
break;
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*I))
if (IsAcceptableNonMemberOperatorCandidate(FD, T1, T2, Context))
AddOverloadCandidate(FD, Args, NumArgs, CandidateSet,
/*SuppressUserConversions=*/false);
}
}
}