2008-06-08 00:52:53 +08:00
|
|
|
//===--- DeclBase.cpp - Declaration AST Node Implementation ---------------===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This file implements the Decl and DeclContext classes.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "clang/AST/DeclBase.h"
|
2009-02-03 07:39:07 +08:00
|
|
|
#include "clang/AST/Decl.h"
|
2008-06-10 05:05:31 +08:00
|
|
|
#include "clang/AST/DeclCXX.h"
|
2009-02-05 03:02:06 +08:00
|
|
|
#include "clang/AST/DeclObjC.h"
|
|
|
|
#include "clang/AST/DeclTemplate.h"
|
2008-06-08 00:52:53 +08:00
|
|
|
#include "clang/AST/ASTContext.h"
|
2008-12-12 00:49:14 +08:00
|
|
|
#include "clang/AST/Type.h"
|
2008-06-08 00:52:53 +08:00
|
|
|
#include "llvm/ADT/DenseMap.h"
|
2009-03-05 16:00:35 +08:00
|
|
|
#include "llvm/Support/raw_ostream.h"
|
2008-12-24 05:05:05 +08:00
|
|
|
#include <algorithm>
|
2009-03-03 06:20:04 +08:00
|
|
|
#include <cstdio>
|
2008-12-24 05:05:05 +08:00
|
|
|
#include <functional>
|
2008-12-23 08:26:44 +08:00
|
|
|
#include <vector>
|
2008-06-08 00:52:53 +08:00
|
|
|
using namespace clang;
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Statistics
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2009-02-03 07:39:07 +08:00
|
|
|
#define DECL(Derived, Base) static int n##Derived##s = 0;
|
|
|
|
#include "clang/AST/DeclNodes.def"
|
2008-06-08 00:52:53 +08:00
|
|
|
|
|
|
|
static bool StatSwitch = false;
|
|
|
|
|
|
|
|
// This keeps track of all decl attributes. Since so few decls have attrs, we
|
|
|
|
// keep them in a hash map instead of wasting space in the Decl class.
|
|
|
|
typedef llvm::DenseMap<const Decl*, Attr*> DeclAttrMapTy;
|
|
|
|
|
|
|
|
static DeclAttrMapTy *DeclAttrs = 0;
|
|
|
|
|
|
|
|
const char *Decl::getDeclKindName() const {
|
|
|
|
switch (DeclKind) {
|
2009-02-03 07:39:07 +08:00
|
|
|
default: assert(0 && "Declaration not in DeclNodes.def!");
|
|
|
|
#define DECL(Derived, Base) case Derived: return #Derived;
|
|
|
|
#include "clang/AST/DeclNodes.def"
|
2008-06-08 00:52:53 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-01-21 03:53:53 +08:00
|
|
|
const char *DeclContext::getDeclKindName() const {
|
|
|
|
switch (DeclKind) {
|
2009-02-03 07:39:07 +08:00
|
|
|
default: assert(0 && "Declaration context not in DeclNodes.def!");
|
2009-02-16 22:28:33 +08:00
|
|
|
#define DECL(Derived, Base) case Decl::Derived: return #Derived;
|
2009-02-03 07:39:07 +08:00
|
|
|
#include "clang/AST/DeclNodes.def"
|
2009-01-21 03:53:53 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-06-08 00:52:53 +08:00
|
|
|
bool Decl::CollectingStats(bool Enable) {
|
|
|
|
if (Enable)
|
|
|
|
StatSwitch = true;
|
|
|
|
return StatSwitch;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Decl::PrintStats() {
|
|
|
|
fprintf(stderr, "*** Decl Stats:\n");
|
|
|
|
|
2009-02-03 07:39:07 +08:00
|
|
|
int totalDecls = 0;
|
|
|
|
#define DECL(Derived, Base) totalDecls += n##Derived##s;
|
|
|
|
#include "clang/AST/DeclNodes.def"
|
|
|
|
fprintf(stderr, " %d decls total.\n", totalDecls);
|
|
|
|
|
|
|
|
int totalBytes = 0;
|
|
|
|
#define DECL(Derived, Base) \
|
|
|
|
if (n##Derived##s > 0) { \
|
|
|
|
totalBytes += (int)(n##Derived##s * sizeof(Derived##Decl)); \
|
|
|
|
fprintf(stderr, " %d " #Derived " decls, %d each (%d bytes)\n", \
|
|
|
|
n##Derived##s, (int)sizeof(Derived##Decl), \
|
|
|
|
(int)(n##Derived##s * sizeof(Derived##Decl))); \
|
|
|
|
}
|
|
|
|
#include "clang/AST/DeclNodes.def"
|
2008-06-08 00:52:53 +08:00
|
|
|
|
2009-02-03 07:39:07 +08:00
|
|
|
fprintf(stderr, "Total bytes = %d\n", totalBytes);
|
2008-06-08 00:52:53 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void Decl::addDeclKind(Kind k) {
|
|
|
|
switch (k) {
|
2009-02-03 07:39:07 +08:00
|
|
|
default: assert(0 && "Declaration not in DeclNodes.def!");
|
|
|
|
#define DECL(Derived, Base) case Derived: ++n##Derived##s; break;
|
|
|
|
#include "clang/AST/DeclNodes.def"
|
2008-06-08 00:52:53 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-03-05 16:00:35 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// PrettyStackTraceDecl Implementation
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
void PrettyStackTraceDecl::print(llvm::raw_ostream &OS) const {
|
|
|
|
SourceLocation TheLoc = Loc;
|
|
|
|
if (TheLoc.isInvalid() && TheDecl)
|
|
|
|
TheLoc = TheDecl->getLocation();
|
|
|
|
|
|
|
|
if (TheLoc.isValid()) {
|
|
|
|
TheLoc.print(OS, SM);
|
|
|
|
OS << ": ";
|
|
|
|
}
|
|
|
|
|
|
|
|
OS << Message;
|
|
|
|
|
|
|
|
if (NamedDecl *DN = dyn_cast_or_null<NamedDecl>(TheDecl))
|
|
|
|
OS << " '" << DN->getQualifiedNameAsString() << '\'';
|
|
|
|
OS << '\n';
|
|
|
|
}
|
|
|
|
|
2008-06-08 00:52:53 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Decl Implementation
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2009-03-28 04:18:19 +08:00
|
|
|
// Out-of-line virtual method providing a home for Decl.
|
|
|
|
Decl::~Decl() {
|
|
|
|
if (isOutOfSemaDC())
|
|
|
|
delete getMultipleDC();
|
|
|
|
|
|
|
|
assert(!HasAttrs && "attributes should have been freed by Destroy");
|
|
|
|
}
|
|
|
|
|
2009-01-20 09:17:11 +08:00
|
|
|
void Decl::setDeclContext(DeclContext *DC) {
|
|
|
|
if (isOutOfSemaDC())
|
|
|
|
delete getMultipleDC();
|
|
|
|
|
2009-03-29 14:06:59 +08:00
|
|
|
DeclCtx = DC;
|
2009-01-20 09:17:11 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void Decl::setLexicalDeclContext(DeclContext *DC) {
|
|
|
|
if (DC == getLexicalDeclContext())
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (isInSemaDC()) {
|
|
|
|
MultipleDC *MDC = new MultipleDC();
|
|
|
|
MDC->SemanticDC = getDeclContext();
|
|
|
|
MDC->LexicalDC = DC;
|
2009-03-29 14:06:59 +08:00
|
|
|
DeclCtx = MDC;
|
2009-01-20 09:17:11 +08:00
|
|
|
} else {
|
|
|
|
getMultipleDC()->LexicalDC = DC;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-03-28 04:18:19 +08:00
|
|
|
unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
|
|
|
|
switch (DeclKind) {
|
|
|
|
default:
|
|
|
|
if (DeclKind >= FunctionFirst && DeclKind <= FunctionLast)
|
|
|
|
return IDNS_Ordinary;
|
|
|
|
assert(0 && "Unknown decl kind!");
|
|
|
|
case OverloadedFunction:
|
|
|
|
case Typedef:
|
|
|
|
case EnumConstant:
|
|
|
|
case Var:
|
|
|
|
case ImplicitParam:
|
|
|
|
case ParmVar:
|
|
|
|
case OriginalParmVar:
|
|
|
|
case NonTypeTemplateParm:
|
|
|
|
case ObjCMethod:
|
|
|
|
case ObjCContainer:
|
|
|
|
case ObjCCategory:
|
|
|
|
case ObjCInterface:
|
|
|
|
case ObjCCategoryImpl:
|
|
|
|
case ObjCProperty:
|
|
|
|
case ObjCCompatibleAlias:
|
|
|
|
return IDNS_Ordinary;
|
|
|
|
|
|
|
|
case ObjCProtocol:
|
|
|
|
return IDNS_Protocol;
|
|
|
|
|
|
|
|
case Field:
|
|
|
|
case ObjCAtDefsField:
|
|
|
|
case ObjCIvar:
|
|
|
|
return IDNS_Member;
|
|
|
|
|
|
|
|
case Record:
|
|
|
|
case CXXRecord:
|
|
|
|
case Enum:
|
|
|
|
case TemplateTypeParm:
|
|
|
|
return IDNS_Tag;
|
|
|
|
|
|
|
|
case Namespace:
|
|
|
|
case Template:
|
|
|
|
case FunctionTemplate:
|
|
|
|
case ClassTemplate:
|
|
|
|
case TemplateTemplateParm:
|
2009-03-29 07:02:53 +08:00
|
|
|
case NamespaceAlias:
|
2009-03-28 04:18:19 +08:00
|
|
|
return IDNS_Tag | IDNS_Ordinary;
|
|
|
|
|
|
|
|
// Never have names.
|
|
|
|
case LinkageSpec:
|
|
|
|
case FileScopeAsm:
|
|
|
|
case StaticAssert:
|
|
|
|
case ObjCClass:
|
|
|
|
case ObjCImplementation:
|
|
|
|
case ObjCPropertyImpl:
|
|
|
|
case ObjCForwardProtocol:
|
|
|
|
case Block:
|
|
|
|
case TranslationUnit:
|
|
|
|
|
|
|
|
// Aren't looked up?
|
|
|
|
case UsingDirective:
|
|
|
|
case ClassTemplateSpecialization:
|
|
|
|
return 0;
|
|
|
|
}
|
2008-06-08 00:52:53 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void Decl::addAttr(Attr *NewAttr) {
|
|
|
|
if (!DeclAttrs)
|
|
|
|
DeclAttrs = new DeclAttrMapTy();
|
|
|
|
|
|
|
|
Attr *&ExistingAttr = (*DeclAttrs)[this];
|
|
|
|
|
|
|
|
NewAttr->setNext(ExistingAttr);
|
|
|
|
ExistingAttr = NewAttr;
|
|
|
|
|
|
|
|
HasAttrs = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Decl::invalidateAttrs() {
|
|
|
|
if (!HasAttrs) return;
|
|
|
|
|
|
|
|
HasAttrs = false;
|
|
|
|
(*DeclAttrs)[this] = 0;
|
|
|
|
DeclAttrs->erase(this);
|
|
|
|
|
|
|
|
if (DeclAttrs->empty()) {
|
|
|
|
delete DeclAttrs;
|
|
|
|
DeclAttrs = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-03-21 14:27:31 +08:00
|
|
|
const Attr *Decl::getAttrsImpl() const {
|
|
|
|
assert(HasAttrs && "getAttrs() should verify this!");
|
2008-06-08 00:52:53 +08:00
|
|
|
return (*DeclAttrs)[this];
|
|
|
|
}
|
|
|
|
|
|
|
|
void Decl::swapAttrs(Decl *RHS) {
|
|
|
|
bool HasLHSAttr = this->HasAttrs;
|
|
|
|
bool HasRHSAttr = RHS->HasAttrs;
|
|
|
|
|
|
|
|
// Usually, neither decl has attrs, nothing to do.
|
|
|
|
if (!HasLHSAttr && !HasRHSAttr) return;
|
|
|
|
|
|
|
|
// If 'this' has no attrs, swap the other way.
|
|
|
|
if (!HasLHSAttr)
|
|
|
|
return RHS->swapAttrs(this);
|
|
|
|
|
|
|
|
// Handle the case when both decls have attrs.
|
|
|
|
if (HasRHSAttr) {
|
|
|
|
std::swap((*DeclAttrs)[this], (*DeclAttrs)[RHS]);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Otherwise, LHS has an attr and RHS doesn't.
|
|
|
|
(*DeclAttrs)[RHS] = (*DeclAttrs)[this];
|
|
|
|
(*DeclAttrs).erase(this);
|
|
|
|
this->HasAttrs = false;
|
|
|
|
RHS->HasAttrs = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-04 14:05:19 +08:00
|
|
|
void Decl::Destroy(ASTContext &C) {
|
|
|
|
// Free attributes for this decl.
|
|
|
|
if (HasAttrs) {
|
|
|
|
DeclAttrMapTy::iterator it = DeclAttrs->find(this);
|
|
|
|
assert(it != DeclAttrs->end() && "No attrs found but HasAttrs is true!");
|
|
|
|
|
|
|
|
// release attributes.
|
|
|
|
it->second->Destroy(C);
|
|
|
|
invalidateAttrs();
|
|
|
|
HasAttrs = false;
|
|
|
|
}
|
|
|
|
|
2009-01-14 03:47:12 +08:00
|
|
|
#if 0
|
2009-01-20 12:25:11 +08:00
|
|
|
// FIXME: Once ownership is fully understood, we can enable this code
|
|
|
|
if (DeclContext *DC = dyn_cast<DeclContext>(this))
|
|
|
|
DC->decls_begin()->Destroy(C);
|
2008-06-08 00:52:53 +08:00
|
|
|
|
2009-03-28 14:04:26 +08:00
|
|
|
// Observe the unrolled recursion. By setting N->NextDeclInContext = 0x0
|
2009-01-20 09:17:11 +08:00
|
|
|
// within the loop, only the Destroy method for the first Decl
|
|
|
|
// will deallocate all of the Decls in a chain.
|
|
|
|
|
2009-03-28 14:04:26 +08:00
|
|
|
Decl* N = getNextDeclInContext();
|
2009-01-20 09:17:11 +08:00
|
|
|
|
|
|
|
while (N) {
|
2009-03-28 14:04:26 +08:00
|
|
|
Decl* Tmp = N->getNextDeclInContext();
|
|
|
|
N->NextDeclInContext = 0;
|
2009-01-20 09:17:11 +08:00
|
|
|
N->Destroy(C);
|
|
|
|
N = Tmp;
|
2008-06-08 00:52:53 +08:00
|
|
|
}
|
2009-01-14 03:47:12 +08:00
|
|
|
|
2008-06-08 00:52:53 +08:00
|
|
|
this->~Decl();
|
2009-01-28 05:25:57 +08:00
|
|
|
C.Deallocate((void *)this);
|
2009-01-20 12:25:11 +08:00
|
|
|
#endif
|
2008-06-08 00:52:53 +08:00
|
|
|
}
|
|
|
|
|
2008-10-13 00:14:48 +08:00
|
|
|
Decl *Decl::castFromDeclContext (const DeclContext *D) {
|
2009-02-16 22:29:28 +08:00
|
|
|
Decl::Kind DK = D->getDeclKind();
|
|
|
|
switch(DK) {
|
|
|
|
#define DECL_CONTEXT(Name) \
|
|
|
|
case Decl::Name: \
|
|
|
|
return static_cast<Name##Decl*>(const_cast<DeclContext*>(D));
|
|
|
|
#define DECL_CONTEXT_BASE(Name)
|
|
|
|
#include "clang/AST/DeclNodes.def"
|
|
|
|
default:
|
|
|
|
#define DECL_CONTEXT_BASE(Name) \
|
|
|
|
if (DK >= Decl::Name##First && DK <= Decl::Name##Last) \
|
|
|
|
return static_cast<Name##Decl*>(const_cast<DeclContext*>(D));
|
|
|
|
#include "clang/AST/DeclNodes.def"
|
|
|
|
assert(false && "a decl that inherits DeclContext isn't handled");
|
|
|
|
return 0;
|
|
|
|
}
|
2008-10-13 00:14:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
DeclContext *Decl::castToDeclContext(const Decl *D) {
|
2009-02-16 22:29:28 +08:00
|
|
|
Decl::Kind DK = D->getKind();
|
|
|
|
switch(DK) {
|
|
|
|
#define DECL_CONTEXT(Name) \
|
|
|
|
case Decl::Name: \
|
|
|
|
return static_cast<Name##Decl*>(const_cast<Decl*>(D));
|
|
|
|
#define DECL_CONTEXT_BASE(Name)
|
|
|
|
#include "clang/AST/DeclNodes.def"
|
|
|
|
default:
|
|
|
|
#define DECL_CONTEXT_BASE(Name) \
|
|
|
|
if (DK >= Decl::Name##First && DK <= Decl::Name##Last) \
|
|
|
|
return static_cast<Name##Decl*>(const_cast<Decl*>(D));
|
|
|
|
#include "clang/AST/DeclNodes.def"
|
|
|
|
assert(false && "a decl that inherits DeclContext isn't handled");
|
|
|
|
return 0;
|
|
|
|
}
|
2008-10-13 00:14:48 +08:00
|
|
|
}
|
|
|
|
|
2009-03-26 07:38:06 +08:00
|
|
|
#ifndef NDEBUG
|
|
|
|
void Decl::CheckAccessDeclContext() const {
|
|
|
|
assert((Access != AS_none || !isa<CXXRecordDecl>(getDeclContext())) &&
|
|
|
|
"Access specifier is AS_none inside a record decl");
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2008-06-08 00:52:53 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// DeclContext Implementation
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2009-02-16 22:29:28 +08:00
|
|
|
bool DeclContext::classof(const Decl *D) {
|
|
|
|
switch (D->getKind()) {
|
|
|
|
#define DECL_CONTEXT(Name) case Decl::Name:
|
|
|
|
#define DECL_CONTEXT_BASE(Name)
|
|
|
|
#include "clang/AST/DeclNodes.def"
|
|
|
|
return true;
|
|
|
|
default:
|
|
|
|
#define DECL_CONTEXT_BASE(Name) \
|
|
|
|
if (D->getKind() >= Decl::Name##First && \
|
|
|
|
D->getKind() <= Decl::Name##Last) \
|
|
|
|
return true;
|
|
|
|
#include "clang/AST/DeclNodes.def"
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-02-20 09:44:05 +08:00
|
|
|
/// StoredDeclsList - This is an array of decls optimized a common case of only
|
|
|
|
/// containing one entry.
|
|
|
|
struct StoredDeclsList {
|
|
|
|
/// VectorTy - When in vector form, this is what the Data pointer points to.
|
|
|
|
typedef llvm::SmallVector<NamedDecl*, 4> VectorTy;
|
2009-03-29 14:43:22 +08:00
|
|
|
|
|
|
|
/// Data - Union of NamedDecl*/VectorTy*.
|
|
|
|
llvm::PointerUnion<NamedDecl*, VectorTy*> Data;
|
2009-02-20 09:44:05 +08:00
|
|
|
public:
|
|
|
|
StoredDeclsList() {}
|
|
|
|
StoredDeclsList(const StoredDeclsList &RHS) : Data(RHS.Data) {
|
|
|
|
if (isVector())
|
2009-03-29 14:43:22 +08:00
|
|
|
Data = new VectorTy(*Data.get<VectorTy*>());
|
2009-02-20 09:44:05 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
~StoredDeclsList() {
|
|
|
|
// If this is a vector-form, free the vector.
|
|
|
|
if (isVector())
|
2009-03-29 14:43:22 +08:00
|
|
|
delete Data.get<VectorTy*>();
|
2009-02-20 09:44:05 +08:00
|
|
|
}
|
|
|
|
|
2009-02-24 02:17:44 +08:00
|
|
|
StoredDeclsList &operator=(const StoredDeclsList &RHS) {
|
|
|
|
if (isVector())
|
2009-03-29 14:43:22 +08:00
|
|
|
delete Data.get<VectorTy*>();
|
2009-02-24 02:17:44 +08:00
|
|
|
Data = RHS.Data;
|
|
|
|
if (isVector())
|
2009-03-29 14:43:22 +08:00
|
|
|
Data = new VectorTy(*Data.get<VectorTy*>());
|
2009-02-24 02:17:44 +08:00
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2009-03-29 14:43:22 +08:00
|
|
|
bool isVector() const { return Data.is<VectorTy*>(); }
|
|
|
|
bool isInline() const { return Data.is<NamedDecl*>(); }
|
|
|
|
bool isNull() const { return Data.isNull(); }
|
2009-02-20 09:44:05 +08:00
|
|
|
|
|
|
|
void setOnlyValue(NamedDecl *ND) {
|
|
|
|
assert(isInline() && "Not inline");
|
2009-03-29 14:43:22 +08:00
|
|
|
Data = ND;
|
2009-02-20 09:44:05 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// getLookupResult - Return an array of all the decls that this list
|
|
|
|
/// represents.
|
|
|
|
DeclContext::lookup_result getLookupResult() {
|
|
|
|
// If we have a single inline unit, return it.
|
|
|
|
if (isInline()) {
|
|
|
|
assert(!isNull() && "Empty list isn't allowed");
|
|
|
|
|
|
|
|
// Data is a raw pointer to a NamedDecl*, return it.
|
|
|
|
void *Ptr = &Data;
|
|
|
|
return DeclContext::lookup_result((NamedDecl**)Ptr, (NamedDecl**)Ptr+1);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Otherwise, we have a range result.
|
2009-03-29 14:43:22 +08:00
|
|
|
VectorTy &V = *Data.get<VectorTy*>();
|
2009-02-20 09:44:05 +08:00
|
|
|
return DeclContext::lookup_result(&V[0], &V[0]+V.size());
|
|
|
|
}
|
|
|
|
|
|
|
|
/// HandleRedeclaration - If this is a redeclaration of an existing decl,
|
|
|
|
/// replace the old one with D and return true. Otherwise return false.
|
|
|
|
bool HandleRedeclaration(NamedDecl *D) {
|
|
|
|
// Most decls only have one entry in their list, special case it.
|
|
|
|
if (isInline()) {
|
2009-03-29 14:43:22 +08:00
|
|
|
if (!D->declarationReplaces(Data.get<NamedDecl*>()))
|
2009-02-20 09:44:05 +08:00
|
|
|
return false;
|
|
|
|
setOnlyValue(D);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Determine if this declaration is actually a redeclaration.
|
2009-03-29 14:43:22 +08:00
|
|
|
VectorTy &Vec = *Data.get<VectorTy*>();
|
2009-02-20 09:44:05 +08:00
|
|
|
VectorTy::iterator RDI
|
|
|
|
= std::find_if(Vec.begin(), Vec.end(),
|
|
|
|
std::bind1st(std::mem_fun(&NamedDecl::declarationReplaces),
|
|
|
|
D));
|
|
|
|
if (RDI == Vec.end())
|
|
|
|
return false;
|
|
|
|
*RDI = D;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// AddSubsequentDecl - This is called on the second and later decl when it is
|
|
|
|
/// not a redeclaration to merge it into the appropriate place in our list.
|
|
|
|
///
|
|
|
|
void AddSubsequentDecl(NamedDecl *D) {
|
|
|
|
// If this is the second decl added to the list, convert this to vector
|
|
|
|
// form.
|
|
|
|
if (isInline()) {
|
2009-03-29 14:43:22 +08:00
|
|
|
NamedDecl *OldD = Data.get<NamedDecl*>();
|
2009-02-20 09:44:05 +08:00
|
|
|
VectorTy *VT = new VectorTy();
|
|
|
|
VT->push_back(OldD);
|
2009-03-29 14:43:22 +08:00
|
|
|
Data = VT;
|
2009-02-20 09:44:05 +08:00
|
|
|
}
|
|
|
|
|
2009-03-29 14:43:22 +08:00
|
|
|
VectorTy &Vec = *Data.get<VectorTy*>();
|
2009-02-20 09:44:05 +08:00
|
|
|
if (isa<UsingDirectiveDecl>(D) ||
|
|
|
|
D->getIdentifierNamespace() == Decl::IDNS_Tag)
|
|
|
|
Vec.push_back(D);
|
|
|
|
else if (Vec.back()->getIdentifierNamespace() == Decl::IDNS_Tag) {
|
|
|
|
NamedDecl *TagD = Vec.back();
|
|
|
|
Vec.back() = D;
|
|
|
|
Vec.push_back(TagD);
|
|
|
|
} else
|
|
|
|
Vec.push_back(D);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
typedef llvm::DenseMap<DeclarationName, StoredDeclsList> StoredDeclsMap;
|
2008-12-12 00:49:14 +08:00
|
|
|
|
|
|
|
DeclContext::~DeclContext() {
|
2009-03-28 04:18:19 +08:00
|
|
|
if (isLookupMap())
|
2009-02-20 08:55:03 +08:00
|
|
|
delete static_cast<StoredDeclsMap*>(LookupPtr.getPointer());
|
|
|
|
else
|
|
|
|
delete [] static_cast<NamedDecl**>(LookupPtr.getPointer());
|
2008-12-12 00:49:14 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void DeclContext::DestroyDecls(ASTContext &C) {
|
2009-01-20 12:25:11 +08:00
|
|
|
for (decl_iterator D = decls_begin(); D != decls_end(); )
|
|
|
|
(*D++)->Destroy(C);
|
2008-12-12 00:49:14 +08:00
|
|
|
}
|
|
|
|
|
2009-01-06 03:45:36 +08:00
|
|
|
bool DeclContext::isTransparentContext() const {
|
|
|
|
if (DeclKind == Decl::Enum)
|
|
|
|
return true; // FIXME: Check for C++0x scoped enums
|
|
|
|
else if (DeclKind == Decl::LinkageSpec)
|
|
|
|
return true;
|
2009-02-26 08:02:51 +08:00
|
|
|
else if (DeclKind >= Decl::RecordFirst && DeclKind <= Decl::RecordLast)
|
2009-01-07 08:43:41 +08:00
|
|
|
return cast<RecordDecl>(this)->isAnonymousStructOrUnion();
|
2009-01-06 03:45:36 +08:00
|
|
|
else if (DeclKind == Decl::Namespace)
|
|
|
|
return false; // FIXME: Check for C++0x inline namespaces
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2009-01-09 01:28:14 +08:00
|
|
|
DeclContext *DeclContext::getPrimaryContext() {
|
2008-12-12 00:49:14 +08:00
|
|
|
switch (DeclKind) {
|
|
|
|
case Decl::TranslationUnit:
|
2009-01-06 03:45:36 +08:00
|
|
|
case Decl::LinkageSpec:
|
|
|
|
case Decl::Block:
|
2008-12-12 00:49:14 +08:00
|
|
|
// There is only one DeclContext for these entities.
|
|
|
|
return this;
|
|
|
|
|
|
|
|
case Decl::Namespace:
|
|
|
|
// The original namespace is our primary context.
|
|
|
|
return static_cast<NamespaceDecl*>(this)->getOriginalNamespace();
|
|
|
|
|
|
|
|
case Decl::ObjCMethod:
|
|
|
|
return this;
|
|
|
|
|
|
|
|
case Decl::ObjCInterface:
|
2009-01-09 01:28:14 +08:00
|
|
|
case Decl::ObjCProtocol:
|
|
|
|
case Decl::ObjCCategory:
|
2008-12-12 00:49:14 +08:00
|
|
|
// FIXME: Can Objective-C interfaces be forward-declared?
|
|
|
|
return this;
|
|
|
|
|
2009-01-09 01:28:14 +08:00
|
|
|
case Decl::ObjCImplementation:
|
|
|
|
case Decl::ObjCCategoryImpl:
|
|
|
|
return this;
|
|
|
|
|
2008-12-12 00:49:14 +08:00
|
|
|
default:
|
2009-02-18 07:15:12 +08:00
|
|
|
if (DeclKind >= Decl::TagFirst && DeclKind <= Decl::TagLast) {
|
|
|
|
// If this is a tag type that has a definition or is currently
|
|
|
|
// being defined, that definition is our primary context.
|
2009-03-28 14:04:26 +08:00
|
|
|
if (const TagType *TagT =cast<TagDecl>(this)->TypeForDecl->getAsTagType())
|
2009-02-18 07:15:12 +08:00
|
|
|
if (TagT->isBeingDefined() ||
|
|
|
|
(TagT->getDecl() && TagT->getDecl()->isDefinition()))
|
|
|
|
return TagT->getDecl();
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
2008-12-12 00:49:14 +08:00
|
|
|
assert(DeclKind >= Decl::FunctionFirst && DeclKind <= Decl::FunctionLast &&
|
|
|
|
"Unknown DeclContext kind");
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
DeclContext *DeclContext::getNextContext() {
|
|
|
|
switch (DeclKind) {
|
|
|
|
case Decl::Namespace:
|
|
|
|
// Return the next namespace
|
|
|
|
return static_cast<NamespaceDecl*>(this)->getNextNamespace();
|
|
|
|
|
|
|
|
default:
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-01-20 09:17:11 +08:00
|
|
|
void DeclContext::addDecl(Decl *D) {
|
2009-02-20 08:56:18 +08:00
|
|
|
assert(D->getLexicalDeclContext() == this &&
|
|
|
|
"Decl inserted into wrong lexical context");
|
2009-03-28 14:04:26 +08:00
|
|
|
assert(!D->getNextDeclInContext() && D != LastDecl &&
|
2009-01-10 03:42:16 +08:00
|
|
|
"Decl already inserted into a DeclContext");
|
|
|
|
|
|
|
|
if (FirstDecl) {
|
2009-03-28 14:04:26 +08:00
|
|
|
LastDecl->NextDeclInContext = D;
|
2009-01-10 03:42:16 +08:00
|
|
|
LastDecl = D;
|
|
|
|
} else {
|
|
|
|
FirstDecl = LastDecl = D;
|
|
|
|
}
|
2009-01-20 09:17:11 +08:00
|
|
|
|
|
|
|
if (NamedDecl *ND = dyn_cast<NamedDecl>(D))
|
2009-01-21 00:54:50 +08:00
|
|
|
ND->getDeclContext()->makeDeclVisibleInContext(ND);
|
2008-12-12 00:49:14 +08:00
|
|
|
}
|
|
|
|
|
2009-01-06 03:45:36 +08:00
|
|
|
/// buildLookup - Build the lookup data structure with all of the
|
|
|
|
/// declarations in DCtx (and any other contexts linked to it or
|
|
|
|
/// transparent contexts nested within it).
|
2009-01-09 01:28:14 +08:00
|
|
|
void DeclContext::buildLookup(DeclContext *DCtx) {
|
2009-01-06 03:45:36 +08:00
|
|
|
for (; DCtx; DCtx = DCtx->getNextContext()) {
|
2009-01-06 15:17:58 +08:00
|
|
|
for (decl_iterator D = DCtx->decls_begin(), DEnd = DCtx->decls_end();
|
|
|
|
D != DEnd; ++D) {
|
2009-01-06 03:45:36 +08:00
|
|
|
// Insert this declaration into the lookup structure
|
2009-01-20 09:17:11 +08:00
|
|
|
if (NamedDecl *ND = dyn_cast<NamedDecl>(*D))
|
2009-01-21 00:54:50 +08:00
|
|
|
makeDeclVisibleInContextImpl(ND);
|
2009-01-06 03:45:36 +08:00
|
|
|
|
|
|
|
// If this declaration is itself a transparent declaration context,
|
|
|
|
// add its members (recursively).
|
|
|
|
if (DeclContext *InnerCtx = dyn_cast<DeclContext>(*D))
|
|
|
|
if (InnerCtx->isTransparentContext())
|
2009-01-09 01:28:14 +08:00
|
|
|
buildLookup(InnerCtx->getPrimaryContext());
|
2009-01-06 03:45:36 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-12-12 00:49:14 +08:00
|
|
|
DeclContext::lookup_result
|
2009-01-09 01:28:14 +08:00
|
|
|
DeclContext::lookup(DeclarationName Name) {
|
|
|
|
DeclContext *PrimaryContext = getPrimaryContext();
|
2008-12-12 00:49:14 +08:00
|
|
|
if (PrimaryContext != this)
|
2009-01-09 01:28:14 +08:00
|
|
|
return PrimaryContext->lookup(Name);
|
2008-12-12 00:49:14 +08:00
|
|
|
|
2008-12-23 08:26:44 +08:00
|
|
|
/// If there is no lookup data structure, build one now by walking
|
2008-12-12 00:49:14 +08:00
|
|
|
/// all of the linked DeclContexts (in declaration order!) and
|
|
|
|
/// inserting their values.
|
2009-01-06 03:45:36 +08:00
|
|
|
if (LookupPtr.getPointer() == 0)
|
2009-01-09 01:28:14 +08:00
|
|
|
buildLookup(this);
|
2008-12-12 00:49:14 +08:00
|
|
|
|
|
|
|
if (isLookupMap()) {
|
|
|
|
StoredDeclsMap *Map = static_cast<StoredDeclsMap*>(LookupPtr.getPointer());
|
|
|
|
StoredDeclsMap::iterator Pos = Map->find(Name);
|
2009-02-20 08:55:03 +08:00
|
|
|
if (Pos == Map->end())
|
|
|
|
return lookup_result(0, 0);
|
2009-02-20 09:44:05 +08:00
|
|
|
return Pos->second.getLookupResult();
|
2008-12-12 00:49:14 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// We have a small array. Look into it.
|
|
|
|
unsigned Size = LookupPtr.getInt();
|
2009-01-20 09:17:11 +08:00
|
|
|
NamedDecl **Array = static_cast<NamedDecl**>(LookupPtr.getPointer());
|
2008-12-12 04:41:00 +08:00
|
|
|
for (unsigned Idx = 0; Idx != Size; ++Idx)
|
2008-12-12 00:49:14 +08:00
|
|
|
if (Array[Idx]->getDeclName() == Name) {
|
2008-12-23 08:26:44 +08:00
|
|
|
unsigned Last = Idx + 1;
|
|
|
|
while (Last != Size && Array[Last]->getDeclName() == Name)
|
|
|
|
++Last;
|
|
|
|
return lookup_result(&Array[Idx], &Array[Last]);
|
2008-12-12 00:49:14 +08:00
|
|
|
}
|
|
|
|
|
2008-12-23 08:26:44 +08:00
|
|
|
return lookup_result(0, 0);
|
2008-12-12 00:49:14 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
DeclContext::lookup_const_result
|
2009-01-09 01:28:14 +08:00
|
|
|
DeclContext::lookup(DeclarationName Name) const {
|
|
|
|
return const_cast<DeclContext*>(this)->lookup(Name);
|
2008-12-12 00:49:14 +08:00
|
|
|
}
|
|
|
|
|
2009-03-28 03:19:59 +08:00
|
|
|
DeclContext *DeclContext::getLookupContext() {
|
|
|
|
DeclContext *Ctx = this;
|
Unify the code for defining tags in C and C++, so that we always
introduce a Scope for the body of a tag. This reduces the number of
semantic differences between C and C++ structs and unions, and will
help with other features (e.g., anonymous unions) in C. Some important
points:
- Fields are now in the "member" namespace (IDNS_Member), to keep
them separate from tags and ordinary names in C. See the new test
in Sema/member-reference.c for an example of why this matters. In
C++, ordinary and member name lookup will find members in both the
ordinary and member namespace, so the difference between
IDNS_Member and IDNS_Ordinary is erased by Sema::LookupDecl (but
only in C++!).
- We always introduce a Scope and push a DeclContext when we're
defining a tag, in both C and C++. Previously, we had different
actions and different Scope/CurContext behavior for enums, C
structs/unions, and C++ structs/unions/classes. Now, it's one pair
of actions. (Yay!)
There's still some fuzziness in the handling of struct/union/enum
definitions within other struct/union/enum definitions in C. We'll
need to do some more cleanup to eliminate some reliance on CurContext
before we can solve this issue for real. What we want is for something
like this:
struct X {
struct T { int x; } t;
};
to introduce T into translation unit scope (placing it at the
appropriate point in the IdentifierResolver chain, too), but it should
still have struct X as its lexical declaration
context. PushOnScopeChains isn't smart enough to do that yet, though,
so there's a FIXME test in nested-redef.c
llvm-svn: 61940
2009-01-09 04:45:30 +08:00
|
|
|
// Skip through transparent contexts.
|
2009-01-07 07:51:29 +08:00
|
|
|
while (Ctx->isTransparentContext())
|
|
|
|
Ctx = Ctx->getParent();
|
|
|
|
return Ctx;
|
|
|
|
}
|
|
|
|
|
2009-02-26 06:02:03 +08:00
|
|
|
DeclContext *DeclContext::getEnclosingNamespaceContext() {
|
|
|
|
DeclContext *Ctx = this;
|
|
|
|
// Skip through non-namespace, non-translation-unit contexts.
|
|
|
|
while (!Ctx->isFileContext() || Ctx->isTransparentContext())
|
|
|
|
Ctx = Ctx->getParent();
|
|
|
|
return Ctx->getPrimaryContext();
|
|
|
|
}
|
|
|
|
|
2009-01-21 00:54:50 +08:00
|
|
|
void DeclContext::makeDeclVisibleInContext(NamedDecl *D) {
|
2009-02-18 07:15:12 +08:00
|
|
|
// FIXME: This feels like a hack. Should DeclarationName support
|
|
|
|
// template-ids, or is there a better way to keep specializations
|
|
|
|
// from being visible?
|
|
|
|
if (isa<ClassTemplateSpecializationDecl>(D))
|
|
|
|
return;
|
|
|
|
|
2009-01-09 01:28:14 +08:00
|
|
|
DeclContext *PrimaryContext = getPrimaryContext();
|
2008-12-12 00:49:14 +08:00
|
|
|
if (PrimaryContext != this) {
|
2009-01-21 00:54:50 +08:00
|
|
|
PrimaryContext->makeDeclVisibleInContext(D);
|
2008-12-12 00:49:14 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we already have a lookup data structure, perform the insertion
|
|
|
|
// into it. Otherwise, be lazy and don't build that structure until
|
|
|
|
// someone asks for it.
|
|
|
|
if (LookupPtr.getPointer())
|
2009-01-21 00:54:50 +08:00
|
|
|
makeDeclVisibleInContextImpl(D);
|
2009-01-06 03:45:36 +08:00
|
|
|
|
|
|
|
// If we are a transparent context, insert into our parent context,
|
|
|
|
// too. This operation is recursive.
|
|
|
|
if (isTransparentContext())
|
2009-01-21 00:54:50 +08:00
|
|
|
getParent()->makeDeclVisibleInContext(D);
|
2008-12-12 00:49:14 +08:00
|
|
|
}
|
|
|
|
|
2009-01-21 00:54:50 +08:00
|
|
|
void DeclContext::makeDeclVisibleInContextImpl(NamedDecl *D) {
|
2009-01-06 03:45:36 +08:00
|
|
|
// Skip unnamed declarations.
|
|
|
|
if (!D->getDeclName())
|
|
|
|
return;
|
|
|
|
|
2009-02-18 07:15:12 +08:00
|
|
|
// FIXME: This feels like a hack. Should DeclarationName support
|
|
|
|
// template-ids, or is there a better way to keep specializations
|
|
|
|
// from being visible?
|
|
|
|
if (isa<ClassTemplateSpecializationDecl>(D))
|
|
|
|
return;
|
|
|
|
|
2008-12-23 08:26:44 +08:00
|
|
|
bool MayBeRedeclaration = true;
|
|
|
|
|
2008-12-12 00:49:14 +08:00
|
|
|
if (!isLookupMap()) {
|
|
|
|
unsigned Size = LookupPtr.getInt();
|
|
|
|
|
|
|
|
// The lookup data is stored as an array. Search through the array
|
|
|
|
// to find the insertion location.
|
2009-01-20 09:17:11 +08:00
|
|
|
NamedDecl **Array;
|
2008-12-12 00:49:14 +08:00
|
|
|
if (Size == 0) {
|
2009-01-20 09:17:11 +08:00
|
|
|
Array = new NamedDecl*[LookupIsMap - 1];
|
2008-12-12 00:49:14 +08:00
|
|
|
LookupPtr.setPointer(Array);
|
|
|
|
} else {
|
2009-01-20 09:17:11 +08:00
|
|
|
Array = static_cast<NamedDecl **>(LookupPtr.getPointer());
|
2008-12-12 00:49:14 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// We always keep declarations of the same name next to each other
|
|
|
|
// in the array, so that it is easy to return multiple results
|
2008-12-23 08:26:44 +08:00
|
|
|
// from lookup().
|
|
|
|
unsigned FirstMatch;
|
|
|
|
for (FirstMatch = 0; FirstMatch != Size; ++FirstMatch)
|
|
|
|
if (Array[FirstMatch]->getDeclName() == D->getDeclName())
|
2008-12-12 04:41:00 +08:00
|
|
|
break;
|
2008-12-12 00:49:14 +08:00
|
|
|
|
2008-12-23 08:26:44 +08:00
|
|
|
unsigned InsertPos = FirstMatch;
|
|
|
|
if (FirstMatch != Size) {
|
|
|
|
// We found another declaration with the same name. First
|
|
|
|
// determine whether this is a redeclaration of an existing
|
|
|
|
// declaration in this scope, in which case we will replace the
|
|
|
|
// existing declaration.
|
|
|
|
unsigned LastMatch = FirstMatch;
|
|
|
|
for (; LastMatch != Size; ++LastMatch) {
|
|
|
|
if (Array[LastMatch]->getDeclName() != D->getDeclName())
|
|
|
|
break;
|
|
|
|
|
2008-12-24 05:05:05 +08:00
|
|
|
if (D->declarationReplaces(Array[LastMatch])) {
|
2008-12-23 08:26:44 +08:00
|
|
|
// D is a redeclaration of an existing element in the
|
|
|
|
// array. Replace that element with D.
|
|
|
|
Array[LastMatch] = D;
|
|
|
|
return;
|
|
|
|
}
|
2008-12-12 00:49:14 +08:00
|
|
|
}
|
|
|
|
|
2008-12-23 08:26:44 +08:00
|
|
|
// [FirstMatch, LastMatch) contains the set of declarations that
|
|
|
|
// have the same name as this declaration. Determine where the
|
2009-02-04 03:21:40 +08:00
|
|
|
// declaration D will be inserted into this range.
|
|
|
|
if (D->getKind() == Decl::UsingDirective ||
|
|
|
|
D->getIdentifierNamespace() == Decl::IDNS_Tag)
|
2008-12-23 08:26:44 +08:00
|
|
|
InsertPos = LastMatch;
|
|
|
|
else if (Array[LastMatch-1]->getIdentifierNamespace() == Decl::IDNS_Tag)
|
|
|
|
InsertPos = LastMatch - 1;
|
|
|
|
else
|
|
|
|
InsertPos = LastMatch;
|
2008-12-12 00:49:14 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (Size < LookupIsMap - 1) {
|
|
|
|
// The new declaration will fit in the array. Insert the new
|
|
|
|
// declaration at the position Match in the array.
|
2008-12-23 08:26:44 +08:00
|
|
|
for (unsigned Idx = Size; Idx > InsertPos; --Idx)
|
2008-12-12 00:49:14 +08:00
|
|
|
Array[Idx] = Array[Idx-1];
|
|
|
|
|
2008-12-23 08:26:44 +08:00
|
|
|
Array[InsertPos] = D;
|
2008-12-12 00:49:14 +08:00
|
|
|
LookupPtr.setInt(Size + 1);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// We've reached capacity in this array. Create a map and copy in
|
|
|
|
// all of the declarations that were stored in the array.
|
|
|
|
StoredDeclsMap *Map = new StoredDeclsMap(16);
|
|
|
|
LookupPtr.setPointer(Map);
|
|
|
|
LookupPtr.setInt(LookupIsMap);
|
2008-12-12 04:41:00 +08:00
|
|
|
for (unsigned Idx = 0; Idx != LookupIsMap - 1; ++Idx)
|
2009-01-21 00:54:50 +08:00
|
|
|
makeDeclVisibleInContextImpl(Array[Idx]);
|
2008-12-12 00:49:14 +08:00
|
|
|
delete [] Array;
|
|
|
|
|
|
|
|
// Fall through to perform insertion into the map.
|
2008-12-23 08:26:44 +08:00
|
|
|
MayBeRedeclaration = false;
|
|
|
|
}
|
2008-12-12 00:49:14 +08:00
|
|
|
|
|
|
|
// Insert this declaration into the map.
|
2009-02-20 09:44:05 +08:00
|
|
|
StoredDeclsMap &Map = *static_cast<StoredDeclsMap*>(LookupPtr.getPointer());
|
|
|
|
StoredDeclsList &DeclNameEntries = Map[D->getDeclName()];
|
|
|
|
if (DeclNameEntries.isNull()) {
|
|
|
|
DeclNameEntries.setOnlyValue(D);
|
2009-02-19 15:00:44 +08:00
|
|
|
return;
|
2008-12-12 00:49:14 +08:00
|
|
|
}
|
2009-02-20 08:55:03 +08:00
|
|
|
|
2009-02-20 09:10:07 +08:00
|
|
|
// If it is possible that this is a redeclaration, check to see if there is
|
|
|
|
// already a decl for which declarationReplaces returns true. If there is
|
|
|
|
// one, just replace it and return.
|
2009-02-20 09:44:05 +08:00
|
|
|
if (MayBeRedeclaration && DeclNameEntries.HandleRedeclaration(D))
|
|
|
|
return;
|
2009-02-20 08:55:03 +08:00
|
|
|
|
2009-02-19 15:00:44 +08:00
|
|
|
// Put this declaration into the appropriate slot.
|
2009-02-20 09:44:05 +08:00
|
|
|
DeclNameEntries.AddSubsequentDecl(D);
|
2008-12-12 00:49:14 +08:00
|
|
|
}
|
2009-02-04 03:21:40 +08:00
|
|
|
|
|
|
|
/// Returns iterator range [First, Last) of UsingDirectiveDecls stored within
|
|
|
|
/// this context.
|
|
|
|
DeclContext::udir_iterator_range DeclContext::getUsingDirectives() const {
|
|
|
|
lookup_const_result Result = lookup(UsingDirectiveDecl::getName());
|
|
|
|
return udir_iterator_range(reinterpret_cast<udir_iterator>(Result.first),
|
|
|
|
reinterpret_cast<udir_iterator>(Result.second));
|
|
|
|
}
|
|
|
|
|