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"
|
2009-04-08 01:20:56 +08:00
|
|
|
#include "clang/AST/DeclContextInternals.h"
|
2008-06-10 05:05:31 +08:00
|
|
|
#include "clang/AST/DeclCXX.h"
|
2010-03-11 15:50:04 +08:00
|
|
|
#include "clang/AST/DeclFriend.h"
|
2009-02-05 03:02:06 +08:00
|
|
|
#include "clang/AST/DeclObjC.h"
|
|
|
|
#include "clang/AST/DeclTemplate.h"
|
2010-03-24 13:22:00 +08:00
|
|
|
#include "clang/AST/DependentDiagnostic.h"
|
2009-04-10 06:27:44 +08:00
|
|
|
#include "clang/AST/ExternalASTSource.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"
|
2009-04-27 04:35:05 +08:00
|
|
|
#include "clang/AST/Stmt.h"
|
|
|
|
#include "clang/AST/StmtCXX.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-23 08:26:44 +08:00
|
|
|
#include <vector>
|
2008-06-08 00:52:53 +08:00
|
|
|
using namespace clang;
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Statistics
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2010-05-30 15:21:58 +08:00
|
|
|
#define DECL(DERIVED, BASE) static int n##DERIVED##s = 0;
|
|
|
|
#define ABSTRACT_DECL(DECL)
|
|
|
|
#include "clang/AST/DeclNodes.inc"
|
2008-06-08 00:52:53 +08:00
|
|
|
|
|
|
|
static bool StatSwitch = false;
|
|
|
|
|
|
|
|
const char *Decl::getDeclKindName() const {
|
|
|
|
switch (DeclKind) {
|
2010-05-30 15:21:58 +08:00
|
|
|
default: assert(0 && "Declaration not in DeclNodes.inc!");
|
|
|
|
#define DECL(DERIVED, BASE) case DERIVED: return #DERIVED;
|
|
|
|
#define ABSTRACT_DECL(DECL)
|
|
|
|
#include "clang/AST/DeclNodes.inc"
|
2008-06-08 00:52:53 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-03-05 08:26:45 +08:00
|
|
|
void Decl::setInvalidDecl(bool Invalid) {
|
|
|
|
InvalidDecl = Invalid;
|
|
|
|
if (Invalid) {
|
|
|
|
// Defensive maneuver for ill-formed code: we're likely not to make it to
|
|
|
|
// a point where we set the access specifier, so default it to "public"
|
|
|
|
// to avoid triggering asserts elsewhere in the front end.
|
|
|
|
setAccess(AS_public);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-01-21 03:53:53 +08:00
|
|
|
const char *DeclContext::getDeclKindName() const {
|
|
|
|
switch (DeclKind) {
|
2010-05-30 15:21:58 +08:00
|
|
|
default: assert(0 && "Declaration context not in DeclNodes.inc!");
|
|
|
|
#define DECL(DERIVED, BASE) case Decl::DERIVED: return #DERIVED;
|
|
|
|
#define ABSTRACT_DECL(DECL)
|
|
|
|
#include "clang/AST/DeclNodes.inc"
|
2009-01-21 03:53:53 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-06-08 00:52:53 +08:00
|
|
|
bool Decl::CollectingStats(bool Enable) {
|
2009-11-29 22:54:35 +08:00
|
|
|
if (Enable) StatSwitch = true;
|
2008-06-08 00:52:53 +08:00
|
|
|
return StatSwitch;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Decl::PrintStats() {
|
|
|
|
fprintf(stderr, "*** Decl Stats:\n");
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-02-03 07:39:07 +08:00
|
|
|
int totalDecls = 0;
|
2010-05-30 15:21:58 +08:00
|
|
|
#define DECL(DERIVED, BASE) totalDecls += n##DERIVED##s;
|
|
|
|
#define ABSTRACT_DECL(DECL)
|
|
|
|
#include "clang/AST/DeclNodes.inc"
|
2009-02-03 07:39:07 +08:00
|
|
|
fprintf(stderr, " %d decls total.\n", totalDecls);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-02-03 07:39:07 +08:00
|
|
|
int totalBytes = 0;
|
2010-05-30 15:21:58 +08:00
|
|
|
#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))); \
|
2009-02-03 07:39:07 +08:00
|
|
|
}
|
2010-05-30 15:21:58 +08:00
|
|
|
#define ABSTRACT_DECL(DECL)
|
|
|
|
#include "clang/AST/DeclNodes.inc"
|
2009-09-09 23:08:12 +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
|
|
|
}
|
|
|
|
|
2010-05-30 15:21:58 +08:00
|
|
|
void Decl::add(Kind k) {
|
2008-06-08 00:52:53 +08:00
|
|
|
switch (k) {
|
2010-05-30 15:21:58 +08:00
|
|
|
default: assert(0 && "Declaration not in DeclNodes.inc!");
|
|
|
|
#define DECL(DERIVED, BASE) case DERIVED: ++n##DERIVED##s; break;
|
|
|
|
#define ABSTRACT_DECL(DECL)
|
|
|
|
#include "clang/AST/DeclNodes.inc"
|
2008-06-08 00:52:53 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-06-13 08:08:58 +08:00
|
|
|
bool Decl::isTemplateParameterPack() const {
|
|
|
|
if (const TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(this))
|
|
|
|
return TTP->isParameterPack();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-06-13 08:08:58 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2009-06-26 06:08:12 +08:00
|
|
|
bool Decl::isFunctionOrFunctionTemplate() const {
|
2009-11-17 13:59:44 +08:00
|
|
|
if (const UsingShadowDecl *UD = dyn_cast<UsingShadowDecl>(this))
|
2009-06-26 13:26:50 +08:00
|
|
|
return UD->getTargetDecl()->isFunctionOrFunctionTemplate();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-06-26 06:08:12 +08:00
|
|
|
return isa<FunctionDecl>(this) || isa<FunctionTemplateDecl>(this);
|
|
|
|
}
|
|
|
|
|
2010-01-17 04:21:20 +08:00
|
|
|
bool Decl::isDefinedOutsideFunctionOrMethod() const {
|
|
|
|
for (const DeclContext *DC = getDeclContext();
|
|
|
|
DC && !DC->isTranslationUnit();
|
|
|
|
DC = DC->getParent())
|
|
|
|
if (DC->isFunctionOrMethod())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-05 16:00:35 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// PrettyStackTraceDecl Implementation
|
|
|
|
//===----------------------------------------------------------------------===//
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-03-05 16:00:35 +08:00
|
|
|
void PrettyStackTraceDecl::print(llvm::raw_ostream &OS) const {
|
|
|
|
SourceLocation TheLoc = Loc;
|
|
|
|
if (TheLoc.isInvalid() && TheDecl)
|
|
|
|
TheLoc = TheDecl->getLocation();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-03-05 16:00:35 +08:00
|
|
|
if (TheLoc.isValid()) {
|
|
|
|
TheLoc.print(OS, SM);
|
|
|
|
OS << ": ";
|
|
|
|
}
|
|
|
|
|
|
|
|
OS << Message;
|
|
|
|
|
2009-11-21 17:05:59 +08:00
|
|
|
if (const NamedDecl *DN = dyn_cast_or_null<NamedDecl>(TheDecl))
|
2009-03-05 16:00:35 +08:00
|
|
|
OS << " '" << DN->getQualifiedNameAsString() << '\'';
|
|
|
|
OS << '\n';
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
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() {
|
|
|
|
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-09-09 23:08:12 +08:00
|
|
|
|
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()) {
|
2009-12-01 08:07:10 +08:00
|
|
|
MultipleDC *MDC = new (getASTContext()) MultipleDC();
|
2009-01-20 09:17:11 +08:00
|
|
|
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-10-01 08:25:31 +08:00
|
|
|
bool Decl::isInAnonymousNamespace() const {
|
|
|
|
const DeclContext *DC = getDeclContext();
|
|
|
|
do {
|
|
|
|
if (const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(DC))
|
|
|
|
if (ND->isAnonymousNamespace())
|
|
|
|
return true;
|
|
|
|
} while ((DC = DC->getParent()));
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2009-06-30 01:38:40 +08:00
|
|
|
TranslationUnitDecl *Decl::getTranslationUnitDecl() {
|
2009-06-30 10:34:53 +08:00
|
|
|
if (TranslationUnitDecl *TUD = dyn_cast<TranslationUnitDecl>(this))
|
|
|
|
return TUD;
|
|
|
|
|
2009-06-30 01:38:40 +08:00
|
|
|
DeclContext *DC = getDeclContext();
|
|
|
|
assert(DC && "This decl is not contained in a translation unit!");
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-06-30 01:38:40 +08:00
|
|
|
while (!DC->isTranslationUnit()) {
|
|
|
|
DC = DC->getParent();
|
|
|
|
assert(DC && "This decl is not contained in a translation unit!");
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-06-30 01:38:40 +08:00
|
|
|
return cast<TranslationUnitDecl>(DC);
|
|
|
|
}
|
|
|
|
|
|
|
|
ASTContext &Decl::getASTContext() const {
|
2009-09-09 23:08:12 +08:00
|
|
|
return getTranslationUnitDecl()->getASTContext();
|
2009-06-30 01:38:40 +08:00
|
|
|
}
|
|
|
|
|
2010-06-18 07:14:26 +08:00
|
|
|
bool Decl::isUsed(bool CheckUsedAttr) const {
|
2010-02-17 10:17:21 +08:00
|
|
|
if (Used)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
// Check for used attribute.
|
2010-06-18 07:14:26 +08:00
|
|
|
if (CheckUsedAttr && hasAttr<UsedAttr>())
|
2010-02-17 10:17:21 +08:00
|
|
|
return true;
|
|
|
|
|
|
|
|
// Check redeclarations for used attribute.
|
|
|
|
for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I) {
|
2010-06-18 07:14:26 +08:00
|
|
|
if ((CheckUsedAttr && I->hasAttr<UsedAttr>()) || I->Used)
|
2010-02-17 10:17:21 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-28 04:18:19 +08:00
|
|
|
unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
|
|
|
|
switch (DeclKind) {
|
2009-11-17 13:59:44 +08:00
|
|
|
case Function:
|
|
|
|
case CXXMethod:
|
|
|
|
case CXXConstructor:
|
|
|
|
case CXXDestructor:
|
|
|
|
case CXXConversion:
|
2009-03-28 04:18:19 +08:00
|
|
|
case EnumConstant:
|
|
|
|
case Var:
|
|
|
|
case ImplicitParam:
|
|
|
|
case ParmVar:
|
|
|
|
case NonTypeTemplateParm:
|
|
|
|
case ObjCMethod:
|
|
|
|
case ObjCProperty:
|
2010-04-23 21:07:39 +08:00
|
|
|
return IDNS_Ordinary;
|
2010-04-23 10:41:41 +08:00
|
|
|
|
2010-04-24 02:46:30 +08:00
|
|
|
case ObjCCompatibleAlias:
|
|
|
|
case ObjCInterface:
|
|
|
|
return IDNS_Ordinary | IDNS_Type;
|
|
|
|
|
|
|
|
case Typedef:
|
|
|
|
case UnresolvedUsingTypename:
|
|
|
|
case TemplateTypeParm:
|
|
|
|
return IDNS_Ordinary | IDNS_Type;
|
|
|
|
|
2009-11-17 13:59:44 +08:00
|
|
|
case UsingShadow:
|
|
|
|
return 0; // we'll actually overwrite this later
|
|
|
|
|
2009-11-18 10:36:19 +08:00
|
|
|
case UnresolvedUsingValue:
|
|
|
|
return IDNS_Ordinary | IDNS_Using;
|
2009-11-17 13:59:44 +08:00
|
|
|
|
|
|
|
case Using:
|
|
|
|
return IDNS_Using;
|
|
|
|
|
2009-03-28 04:18:19 +08:00
|
|
|
case ObjCProtocol:
|
2009-04-24 08:11:27 +08:00
|
|
|
return IDNS_ObjCProtocol;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-03-28 04:18:19 +08:00
|
|
|
case Field:
|
|
|
|
case ObjCAtDefsField:
|
|
|
|
case ObjCIvar:
|
|
|
|
return IDNS_Member;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-03-28 04:18:19 +08:00
|
|
|
case Record:
|
|
|
|
case CXXRecord:
|
|
|
|
case Enum:
|
2010-04-24 02:46:30 +08:00
|
|
|
return IDNS_Tag | IDNS_Type;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-03-28 04:18:19 +08:00
|
|
|
case Namespace:
|
2010-04-24 02:46:30 +08:00
|
|
|
case NamespaceAlias:
|
|
|
|
return IDNS_Namespace;
|
|
|
|
|
2009-03-28 04:18:19 +08:00
|
|
|
case FunctionTemplate:
|
2010-04-24 02:46:30 +08:00
|
|
|
return IDNS_Ordinary;
|
|
|
|
|
2009-03-28 04:18:19 +08:00
|
|
|
case ClassTemplate:
|
|
|
|
case TemplateTemplateParm:
|
2010-04-24 02:46:30 +08:00
|
|
|
return IDNS_Ordinary | IDNS_Tag | IDNS_Type;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-03-28 04:18:19 +08:00
|
|
|
// Never have names.
|
2009-08-28 15:59:38 +08:00
|
|
|
case Friend:
|
2009-09-17 06:47:08 +08:00
|
|
|
case FriendTemplate:
|
2010-06-05 13:09:32 +08:00
|
|
|
case AccessSpec:
|
2009-03-28 04:18:19 +08:00
|
|
|
case LinkageSpec:
|
|
|
|
case FileScopeAsm:
|
|
|
|
case StaticAssert:
|
|
|
|
case ObjCClass:
|
|
|
|
case ObjCPropertyImpl:
|
|
|
|
case ObjCForwardProtocol:
|
|
|
|
case Block:
|
|
|
|
case TranslationUnit:
|
|
|
|
|
|
|
|
case UsingDirective:
|
|
|
|
case ClassTemplateSpecialization:
|
2009-05-31 17:31:02 +08:00
|
|
|
case ClassTemplatePartialSpecialization:
|
2010-04-23 07:19:50 +08:00
|
|
|
case ObjCImplementation:
|
|
|
|
case ObjCCategory:
|
|
|
|
case ObjCCategoryImpl:
|
|
|
|
// Never looked up by name.
|
2009-03-28 04:18:19 +08:00
|
|
|
return 0;
|
|
|
|
}
|
2009-11-17 13:59:44 +08:00
|
|
|
|
|
|
|
return 0;
|
2008-06-08 00:52:53 +08:00
|
|
|
}
|
|
|
|
|
2010-06-12 07:09:25 +08:00
|
|
|
void Decl::initAttrs(Attr *attrs) {
|
|
|
|
assert(!HasAttrs && "Decl already contains attrs.");
|
|
|
|
|
|
|
|
Attr *&AttrBlank = getASTContext().getDeclAttrs(this);
|
|
|
|
assert(AttrBlank == 0 && "HasAttrs was wrong?");
|
|
|
|
|
|
|
|
AttrBlank = attrs;
|
|
|
|
HasAttrs = true;
|
|
|
|
}
|
|
|
|
|
2009-06-30 10:34:44 +08:00
|
|
|
void Decl::addAttr(Attr *NewAttr) {
|
|
|
|
Attr *&ExistingAttr = getASTContext().getDeclAttrs(this);
|
2008-06-08 00:52:53 +08:00
|
|
|
|
2010-06-12 07:09:25 +08:00
|
|
|
assert(NewAttr->getNext() == 0 && "Chain of attributes will be truncated!");
|
2008-06-08 00:52:53 +08:00
|
|
|
NewAttr->setNext(ExistingAttr);
|
|
|
|
ExistingAttr = NewAttr;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-06-08 00:52:53 +08:00
|
|
|
HasAttrs = true;
|
|
|
|
}
|
|
|
|
|
2009-06-30 10:34:44 +08:00
|
|
|
void Decl::invalidateAttrs() {
|
2008-06-08 00:52:53 +08:00
|
|
|
if (!HasAttrs) return;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-06-08 00:52:53 +08:00
|
|
|
HasAttrs = false;
|
2009-06-30 10:34:44 +08:00
|
|
|
getASTContext().eraseDeclAttrs(this);
|
2008-06-08 00:52:53 +08:00
|
|
|
}
|
|
|
|
|
2009-06-30 10:34:44 +08:00
|
|
|
const Attr *Decl::getAttrsImpl() const {
|
2009-09-09 23:08:12 +08:00
|
|
|
assert(HasAttrs && "getAttrs() should verify this!");
|
2009-06-30 10:34:44 +08:00
|
|
|
return getASTContext().getDeclAttrs(this);
|
2008-06-08 00:52:53 +08:00
|
|
|
}
|
|
|
|
|
2009-06-30 10:34:44 +08:00
|
|
|
void Decl::swapAttrs(Decl *RHS) {
|
2008-06-08 00:52:53 +08:00
|
|
|
bool HasLHSAttr = this->HasAttrs;
|
|
|
|
bool HasRHSAttr = RHS->HasAttrs;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-06-08 00:52:53 +08:00
|
|
|
// Usually, neither decl has attrs, nothing to do.
|
|
|
|
if (!HasLHSAttr && !HasRHSAttr) return;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-06-08 00:52:53 +08:00
|
|
|
// If 'this' has no attrs, swap the other way.
|
|
|
|
if (!HasLHSAttr)
|
2009-06-30 10:34:44 +08:00
|
|
|
return RHS->swapAttrs(this);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-06-30 10:34:44 +08:00
|
|
|
ASTContext &Context = getASTContext();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-06-08 00:52:53 +08:00
|
|
|
// Handle the case when both decls have attrs.
|
|
|
|
if (HasRHSAttr) {
|
2009-06-19 00:11:24 +08:00
|
|
|
std::swap(Context.getDeclAttrs(this), Context.getDeclAttrs(RHS));
|
2008-06-08 00:52:53 +08:00
|
|
|
return;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-06-08 00:52:53 +08:00
|
|
|
// Otherwise, LHS has an attr and RHS doesn't.
|
2009-06-19 00:11:24 +08:00
|
|
|
Context.getDeclAttrs(RHS) = Context.getDeclAttrs(this);
|
|
|
|
Context.eraseDeclAttrs(this);
|
2008-06-08 00:52:53 +08:00
|
|
|
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) {
|
2009-06-19 00:11:24 +08:00
|
|
|
C.getDeclAttrs(this)->Destroy(C);
|
2009-06-30 10:34:44 +08:00
|
|
|
invalidateAttrs();
|
2009-03-04 14:05:19 +08:00
|
|
|
HasAttrs = false;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
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-09-09 23:08:12 +08:00
|
|
|
|
2009-03-28 14:04:26 +08:00
|
|
|
Decl* N = getNextDeclInContext();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
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;
|
2009-09-09 23:08:12 +08:00
|
|
|
}
|
2009-01-14 03:47:12 +08:00
|
|
|
|
2009-12-01 08:07:10 +08:00
|
|
|
if (isOutOfSemaDC())
|
|
|
|
delete (C) getMultipleDC();
|
|
|
|
|
2008-06-08 00:52:53 +08:00
|
|
|
this->~Decl();
|
2009-01-28 05:25:57 +08:00
|
|
|
C.Deallocate((void *)this);
|
2009-12-01 08:07:10 +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) {
|
2010-05-30 15:21:58 +08:00
|
|
|
#define DECL(NAME, BASE)
|
|
|
|
#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.inc"
|
2009-02-16 22:29:28 +08:00
|
|
|
default:
|
2010-05-30 15:21:58 +08:00
|
|
|
#define DECL(NAME, BASE)
|
|
|
|
#define DECL_CONTEXT_BASE(NAME) \
|
|
|
|
if (DK >= first##NAME && DK <= last##NAME) \
|
|
|
|
return static_cast<NAME##Decl*>(const_cast<DeclContext*>(D));
|
|
|
|
#include "clang/AST/DeclNodes.inc"
|
2009-02-16 22:29:28 +08:00
|
|
|
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) {
|
2010-05-30 15:21:58 +08:00
|
|
|
#define DECL(NAME, BASE)
|
|
|
|
#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.inc"
|
2009-02-16 22:29:28 +08:00
|
|
|
default:
|
2010-05-30 15:21:58 +08:00
|
|
|
#define DECL(NAME, BASE)
|
|
|
|
#define DECL_CONTEXT_BASE(NAME) \
|
|
|
|
if (DK >= first##NAME && DK <= last##NAME) \
|
|
|
|
return static_cast<NAME##Decl*>(const_cast<Decl*>(D));
|
|
|
|
#include "clang/AST/DeclNodes.inc"
|
2009-02-16 22:29:28 +08:00
|
|
|
assert(false && "a decl that inherits DeclContext isn't handled");
|
|
|
|
return 0;
|
|
|
|
}
|
2008-10-13 00:14:48 +08:00
|
|
|
}
|
|
|
|
|
2009-06-30 10:35:26 +08:00
|
|
|
CompoundStmt* Decl::getCompoundBody() const {
|
|
|
|
return dyn_cast_or_null<CompoundStmt>(getBody());
|
2009-04-27 04:35:05 +08:00
|
|
|
}
|
|
|
|
|
2009-06-30 10:35:26 +08:00
|
|
|
SourceLocation Decl::getBodyRBrace() const {
|
|
|
|
Stmt *Body = getBody();
|
2009-04-27 04:35:05 +08:00
|
|
|
if (!Body)
|
|
|
|
return SourceLocation();
|
|
|
|
if (CompoundStmt *CS = dyn_cast<CompoundStmt>(Body))
|
|
|
|
return CS->getRBracLoc();
|
|
|
|
assert(isa<CXXTryStmt>(Body) &&
|
|
|
|
"Body can only be CompoundStmt or CXXTryStmt");
|
|
|
|
return cast<CXXTryStmt>(Body)->getSourceRange().getEnd();
|
|
|
|
}
|
|
|
|
|
2009-03-26 07:38:06 +08:00
|
|
|
#ifndef NDEBUG
|
|
|
|
void Decl::CheckAccessDeclContext() const {
|
2010-01-21 05:53:11 +08:00
|
|
|
// Suppress this check if any of the following hold:
|
|
|
|
// 1. this is the translation unit (and thus has no parent)
|
|
|
|
// 2. this is a template parameter (and thus doesn't belong to its context)
|
|
|
|
// 3. this is a ParmVarDecl (which can be in a record context during
|
|
|
|
// the brief period between its creation and the creation of the
|
|
|
|
// FunctionDecl)
|
|
|
|
// 4. the context is not a record
|
2009-08-30 04:47:47 +08:00
|
|
|
if (isa<TranslationUnitDecl>(this) ||
|
2010-02-23 01:53:38 +08:00
|
|
|
!isa<CXXRecordDecl>(getDeclContext()) ||
|
|
|
|
isInvalidDecl())
|
2009-08-30 04:47:47 +08:00
|
|
|
return;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
|
|
|
assert(Access != AS_none &&
|
2009-03-26 07:38:06 +08:00
|
|
|
"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()) {
|
2010-05-30 15:21:58 +08:00
|
|
|
#define DECL(NAME, BASE)
|
|
|
|
#define DECL_CONTEXT(NAME) case Decl::NAME:
|
|
|
|
#define DECL_CONTEXT_BASE(NAME)
|
|
|
|
#include "clang/AST/DeclNodes.inc"
|
2009-02-16 22:29:28 +08:00
|
|
|
return true;
|
|
|
|
default:
|
2010-05-30 15:21:58 +08:00
|
|
|
#define DECL(NAME, BASE)
|
|
|
|
#define DECL_CONTEXT_BASE(NAME) \
|
|
|
|
if (D->getKind() >= Decl::first##NAME && \
|
|
|
|
D->getKind() <= Decl::last##NAME) \
|
2009-02-16 22:29:28 +08:00
|
|
|
return true;
|
2010-05-30 15:21:58 +08:00
|
|
|
#include "clang/AST/DeclNodes.inc"
|
2009-02-16 22:29:28 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-12-12 00:49:14 +08:00
|
|
|
DeclContext::~DeclContext() {
|
2010-02-11 15:12:28 +08:00
|
|
|
// FIXME: Currently ~ASTContext will delete the StoredDeclsMaps because
|
|
|
|
// ~DeclContext() is not guaranteed to be called when ASTContext uses
|
|
|
|
// a BumpPtrAllocator.
|
2010-03-24 13:22:00 +08:00
|
|
|
// delete LookupPtr;
|
2008-12-12 00:49:14 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void DeclContext::DestroyDecls(ASTContext &C) {
|
2009-06-30 10:36:12 +08:00
|
|
|
for (decl_iterator D = decls_begin(); D != decls_end(); )
|
2009-01-20 12:25:11 +08:00
|
|
|
(*D++)->Destroy(C);
|
2008-12-12 00:49:14 +08:00
|
|
|
}
|
|
|
|
|
2009-09-11 00:57:35 +08:00
|
|
|
/// \brief Find the parent context of this context that will be
|
|
|
|
/// used for unqualified name lookup.
|
|
|
|
///
|
|
|
|
/// Generally, the parent lookup context is the semantic context. However, for
|
|
|
|
/// a friend function the parent lookup context is the lexical context, which
|
|
|
|
/// is the class in which the friend is declared.
|
|
|
|
DeclContext *DeclContext::getLookupParent() {
|
|
|
|
// FIXME: Find a better way to identify friends
|
|
|
|
if (isa<FunctionDecl>(this))
|
|
|
|
if (getParent()->getLookupContext()->isFileContext() &&
|
|
|
|
getLexicalParent()->getLookupContext()->isRecord())
|
|
|
|
return getLexicalParent();
|
|
|
|
|
|
|
|
return getParent();
|
|
|
|
}
|
|
|
|
|
2009-05-29 00:34:51 +08:00
|
|
|
bool DeclContext::isDependentContext() const {
|
|
|
|
if (isFileContext())
|
|
|
|
return false;
|
2009-05-31 17:31:02 +08:00
|
|
|
|
|
|
|
if (isa<ClassTemplatePartialSpecializationDecl>(this))
|
|
|
|
return true;
|
2009-05-29 00:34:51 +08:00
|
|
|
|
|
|
|
if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(this))
|
|
|
|
if (Record->getDescribedClassTemplate())
|
|
|
|
return true;
|
|
|
|
|
2010-03-24 13:22:00 +08:00
|
|
|
if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(this)) {
|
2009-05-29 00:34:51 +08:00
|
|
|
if (Function->getDescribedFunctionTemplate())
|
|
|
|
return true;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-03-24 13:22:00 +08:00
|
|
|
// Friend function declarations are dependent if their *lexical*
|
|
|
|
// context is dependent.
|
|
|
|
if (cast<Decl>(this)->getFriendObjectKind())
|
|
|
|
return getLexicalParent()->isDependentContext();
|
|
|
|
}
|
|
|
|
|
2009-05-29 00:34:51 +08:00
|
|
|
return getParent() && getParent()->isDependentContext();
|
|
|
|
}
|
|
|
|
|
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;
|
2010-05-30 15:21:58 +08:00
|
|
|
else if (DeclKind >= Decl::firstRecord && DeclKind <= Decl::lastRecord)
|
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-08-27 14:03:53 +08:00
|
|
|
bool DeclContext::Encloses(DeclContext *DC) {
|
|
|
|
if (getPrimaryContext() != this)
|
|
|
|
return getPrimaryContext()->Encloses(DC);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-08-27 14:03:53 +08:00
|
|
|
for (; DC; DC = DC->getParent())
|
|
|
|
if (DC->getPrimaryContext() == this)
|
|
|
|
return true;
|
2009-09-09 23:08:12 +08:00
|
|
|
return false;
|
2009-08-27 14:03:53 +08:00
|
|
|
}
|
|
|
|
|
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:
|
2009-09-09 23:08:12 +08:00
|
|
|
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:
|
2010-05-30 15:21:58 +08:00
|
|
|
if (DeclKind >= Decl::firstTag && DeclKind <= Decl::lastTag) {
|
2009-02-18 07:15:12 +08:00
|
|
|
// If this is a tag type that has a definition or is currently
|
|
|
|
// being defined, that definition is our primary context.
|
2010-03-10 11:28:59 +08:00
|
|
|
TagDecl *Tag = cast<TagDecl>(this);
|
|
|
|
assert(isa<TagType>(Tag->TypeForDecl) ||
|
|
|
|
isa<InjectedClassNameType>(Tag->TypeForDecl));
|
|
|
|
|
|
|
|
if (TagDecl *Def = Tag->getDefinition())
|
|
|
|
return Def;
|
|
|
|
|
|
|
|
if (!isa<InjectedClassNameType>(Tag->TypeForDecl)) {
|
|
|
|
const TagType *TagTy = cast<TagType>(Tag->TypeForDecl);
|
|
|
|
if (TagTy->isBeingDefined())
|
|
|
|
// FIXME: is it necessarily being defined in the decl
|
|
|
|
// that owns the type?
|
|
|
|
return TagTy->getDecl();
|
|
|
|
}
|
|
|
|
|
|
|
|
return Tag;
|
2009-02-18 07:15:12 +08:00
|
|
|
}
|
|
|
|
|
2010-05-30 15:21:58 +08:00
|
|
|
assert(DeclKind >= Decl::firstFunction && DeclKind <= Decl::lastFunction &&
|
2008-12-12 00:49:14 +08:00
|
|
|
"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-04-10 06:27:44 +08:00
|
|
|
/// \brief Load the declarations within this lexical storage from an
|
|
|
|
/// external source.
|
2009-09-09 23:08:12 +08:00
|
|
|
void
|
2009-06-30 10:36:12 +08:00
|
|
|
DeclContext::LoadLexicalDeclsFromExternalStorage() const {
|
|
|
|
ExternalASTSource *Source = getParentASTContext().getExternalSource();
|
2009-04-10 06:27:44 +08:00
|
|
|
assert(hasExternalLexicalStorage() && Source && "No external storage?");
|
|
|
|
|
2010-06-01 17:23:16 +08:00
|
|
|
llvm::SmallVector<Decl*, 64> Decls;
|
|
|
|
if (Source->FindExternalLexicalDecls(this, Decls))
|
2009-04-10 06:27:44 +08:00
|
|
|
return;
|
|
|
|
|
|
|
|
// There is no longer any lexical storage in this context
|
|
|
|
ExternalLexicalStorage = false;
|
|
|
|
|
|
|
|
if (Decls.empty())
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Resolve all of the declaration IDs into declarations, building up
|
|
|
|
// a chain of declarations via the Decl::NextDeclInContext field.
|
|
|
|
Decl *FirstNewDecl = 0;
|
|
|
|
Decl *PrevDecl = 0;
|
|
|
|
for (unsigned I = 0, N = Decls.size(); I != N; ++I) {
|
2010-06-01 17:23:16 +08:00
|
|
|
Decl *D = Decls[I];
|
2009-04-10 06:27:44 +08:00
|
|
|
if (PrevDecl)
|
|
|
|
PrevDecl->NextDeclInContext = D;
|
|
|
|
else
|
|
|
|
FirstNewDecl = D;
|
|
|
|
|
|
|
|
PrevDecl = D;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Splice the newly-read declarations into the beginning of the list
|
|
|
|
// of declarations.
|
|
|
|
PrevDecl->NextDeclInContext = FirstDecl;
|
|
|
|
FirstDecl = FirstNewDecl;
|
|
|
|
if (!LastDecl)
|
|
|
|
LastDecl = PrevDecl;
|
|
|
|
}
|
|
|
|
|
2010-06-01 17:23:16 +08:00
|
|
|
DeclContext::lookup_result
|
|
|
|
ExternalASTSource::SetNoExternalVisibleDeclsForName(const DeclContext *DC,
|
|
|
|
DeclarationName Name) {
|
|
|
|
ASTContext &Context = DC->getParentASTContext();
|
|
|
|
StoredDeclsMap *Map;
|
|
|
|
if (!(Map = DC->LookupPtr))
|
|
|
|
Map = DC->CreateStoredDeclsMap(Context);
|
|
|
|
|
|
|
|
StoredDeclsList &List = (*Map)[Name];
|
|
|
|
assert(List.isNull());
|
|
|
|
(void) List;
|
|
|
|
|
|
|
|
return DeclContext::lookup_result();
|
|
|
|
}
|
2009-04-10 06:27:44 +08:00
|
|
|
|
2010-06-01 17:23:16 +08:00
|
|
|
DeclContext::lookup_result
|
|
|
|
ExternalASTSource::SetExternalVisibleDeclsForName(const DeclContext *DC,
|
|
|
|
const VisibleDeclaration &VD) {
|
|
|
|
ASTContext &Context = DC->getParentASTContext();
|
|
|
|
StoredDeclsMap *Map;
|
|
|
|
if (!(Map = DC->LookupPtr))
|
|
|
|
Map = DC->CreateStoredDeclsMap(Context);
|
|
|
|
|
|
|
|
StoredDeclsList &List = (*Map)[VD.Name];
|
|
|
|
List.setFromDeclIDs(VD.Declarations);
|
|
|
|
return List.getLookupResult(Context);
|
|
|
|
}
|
2009-04-10 06:27:44 +08:00
|
|
|
|
2010-06-01 17:23:16 +08:00
|
|
|
DeclContext::lookup_result
|
|
|
|
ExternalASTSource::SetExternalVisibleDeclsForName(const DeclContext *DC,
|
|
|
|
DeclarationName Name,
|
|
|
|
llvm::SmallVectorImpl<NamedDecl*> &Decls) {
|
|
|
|
ASTContext &Context = DC->getParentASTContext();;
|
|
|
|
|
|
|
|
StoredDeclsMap *Map;
|
|
|
|
if (!(Map = DC->LookupPtr))
|
|
|
|
Map = DC->CreateStoredDeclsMap(Context);
|
2009-04-10 06:27:44 +08:00
|
|
|
|
2010-06-01 17:23:16 +08:00
|
|
|
StoredDeclsList &List = (*Map)[Name];
|
|
|
|
for (unsigned I = 0, N = Decls.size(); I != N; ++I) {
|
|
|
|
if (List.isNull())
|
|
|
|
List.setOnlyValue(Decls[I]);
|
|
|
|
else
|
|
|
|
List.AddSubsequentDecl(Decls[I]);
|
|
|
|
}
|
|
|
|
|
|
|
|
return List.getLookupResult(Context);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ExternalASTSource::SetExternalVisibleDecls(const DeclContext *DC,
|
|
|
|
const llvm::SmallVectorImpl<VisibleDeclaration> &Decls) {
|
|
|
|
// There is no longer any visible storage in this context.
|
|
|
|
DC->ExternalVisibleStorage = false;
|
|
|
|
|
|
|
|
assert(!DC->LookupPtr && "Have a lookup map before de-serialization?");
|
|
|
|
StoredDeclsMap *Map = DC->CreateStoredDeclsMap(DC->getParentASTContext());
|
2009-04-10 06:27:44 +08:00
|
|
|
for (unsigned I = 0, N = Decls.size(); I != N; ++I) {
|
|
|
|
(*Map)[Decls[I].Name].setFromDeclIDs(Decls[I].Declarations);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-06-01 17:23:16 +08:00
|
|
|
void ExternalASTSource::SetExternalVisibleDecls(const DeclContext *DC,
|
|
|
|
const llvm::SmallVectorImpl<NamedDecl*> &Decls) {
|
|
|
|
// There is no longer any visible storage in this context.
|
|
|
|
DC->ExternalVisibleStorage = false;
|
|
|
|
|
|
|
|
assert(!DC->LookupPtr && "Have a lookup map before de-serialization?");
|
|
|
|
StoredDeclsMap &Map = *DC->CreateStoredDeclsMap(DC->getParentASTContext());
|
|
|
|
for (unsigned I = 0, N = Decls.size(); I != N; ++I) {
|
|
|
|
StoredDeclsList &List = Map[Decls[I]->getDeclName()];
|
|
|
|
if (List.isNull())
|
|
|
|
List.setOnlyValue(Decls[I]);
|
|
|
|
else
|
|
|
|
List.AddSubsequentDecl(Decls[I]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-06-30 10:36:12 +08:00
|
|
|
DeclContext::decl_iterator DeclContext::decls_begin() const {
|
2009-04-10 06:27:44 +08:00
|
|
|
if (hasExternalLexicalStorage())
|
2009-06-30 10:36:12 +08:00
|
|
|
LoadLexicalDeclsFromExternalStorage();
|
2009-04-10 06:27:44 +08:00
|
|
|
|
|
|
|
// FIXME: Check whether we need to load some declarations from
|
|
|
|
// external storage.
|
2009-09-09 23:08:12 +08:00
|
|
|
return decl_iterator(FirstDecl);
|
2009-04-10 05:40:53 +08:00
|
|
|
}
|
|
|
|
|
2009-06-30 10:36:12 +08:00
|
|
|
DeclContext::decl_iterator DeclContext::decls_end() const {
|
2009-04-10 06:27:44 +08:00
|
|
|
if (hasExternalLexicalStorage())
|
2009-06-30 10:36:12 +08:00
|
|
|
LoadLexicalDeclsFromExternalStorage();
|
2009-04-10 06:27:44 +08:00
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
return decl_iterator();
|
2009-04-10 05:40:53 +08:00
|
|
|
}
|
|
|
|
|
2009-06-30 10:36:12 +08:00
|
|
|
bool DeclContext::decls_empty() const {
|
2009-04-11 01:25:41 +08:00
|
|
|
if (hasExternalLexicalStorage())
|
2009-06-30 10:36:12 +08:00
|
|
|
LoadLexicalDeclsFromExternalStorage();
|
2009-04-11 01:25:41 +08:00
|
|
|
|
|
|
|
return !FirstDecl;
|
|
|
|
}
|
|
|
|
|
2009-12-10 17:41:52 +08:00
|
|
|
void DeclContext::removeDecl(Decl *D) {
|
|
|
|
assert(D->getLexicalDeclContext() == this &&
|
|
|
|
"decl being removed from non-lexical context");
|
|
|
|
assert((D->NextDeclInContext || D == LastDecl) &&
|
|
|
|
"decl is not in decls list");
|
|
|
|
|
|
|
|
// Remove D from the decl chain. This is O(n) but hopefully rare.
|
|
|
|
if (D == FirstDecl) {
|
|
|
|
if (D == LastDecl)
|
|
|
|
FirstDecl = LastDecl = 0;
|
|
|
|
else
|
|
|
|
FirstDecl = D->NextDeclInContext;
|
|
|
|
} else {
|
|
|
|
for (Decl *I = FirstDecl; true; I = I->NextDeclInContext) {
|
|
|
|
assert(I && "decl not found in linked list");
|
|
|
|
if (I->NextDeclInContext == D) {
|
|
|
|
I->NextDeclInContext = D->NextDeclInContext;
|
|
|
|
if (D == LastDecl) LastDecl = I;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Mark that D is no longer in the decl chain.
|
|
|
|
D->NextDeclInContext = 0;
|
|
|
|
|
|
|
|
// Remove D from the lookup table if necessary.
|
|
|
|
if (isa<NamedDecl>(D)) {
|
|
|
|
NamedDecl *ND = cast<NamedDecl>(D);
|
|
|
|
|
2010-03-24 13:22:00 +08:00
|
|
|
StoredDeclsMap *Map = getPrimaryContext()->LookupPtr;
|
|
|
|
if (!Map) return;
|
2009-12-10 17:41:52 +08:00
|
|
|
|
|
|
|
StoredDeclsMap::iterator Pos = Map->find(ND->getDeclName());
|
|
|
|
assert(Pos != Map->end() && "no lookup entry for decl");
|
|
|
|
Pos->second.remove(ND);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-08-11 14:59:38 +08:00
|
|
|
void DeclContext::addHiddenDecl(Decl *D) {
|
2009-02-20 08:56:18 +08:00
|
|
|
assert(D->getLexicalDeclContext() == this &&
|
|
|
|
"Decl inserted into wrong lexical context");
|
2009-09-09 23:08:12 +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-08-11 14:59:38 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void DeclContext::addDecl(Decl *D) {
|
|
|
|
addHiddenDecl(D);
|
2009-01-20 09:17:11 +08:00
|
|
|
|
|
|
|
if (NamedDecl *ND = dyn_cast<NamedDecl>(D))
|
2009-06-30 10:36:12 +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-06-30 10:36:12 +08:00
|
|
|
void DeclContext::buildLookup(DeclContext *DCtx) {
|
2009-01-06 03:45:36 +08:00
|
|
|
for (; DCtx; DCtx = DCtx->getNextContext()) {
|
2009-09-09 23:08:12 +08:00
|
|
|
for (decl_iterator D = DCtx->decls_begin(),
|
|
|
|
DEnd = DCtx->decls_end();
|
2009-01-06 15:17:58 +08:00
|
|
|
D != DEnd; ++D) {
|
2009-08-11 14:59:38 +08:00
|
|
|
// Insert this declaration into the lookup structure, but only
|
|
|
|
// if it's semantically in its decl context. During non-lazy
|
|
|
|
// lookup building, this is implicitly enforced by addDecl.
|
2009-01-20 09:17:11 +08:00
|
|
|
if (NamedDecl *ND = dyn_cast<NamedDecl>(*D))
|
2009-08-11 14:59:38 +08:00
|
|
|
if (D->getDeclContext() == DCtx)
|
|
|
|
makeDeclVisibleInContextImpl(ND);
|
2009-01-06 03:45:36 +08:00
|
|
|
|
2009-11-18 06:58:30 +08:00
|
|
|
// Insert any forward-declared Objective-C interfaces into the lookup
|
|
|
|
// data structure.
|
|
|
|
if (ObjCClassDecl *Class = dyn_cast<ObjCClassDecl>(*D))
|
|
|
|
for (ObjCClassDecl::iterator I = Class->begin(), IEnd = Class->end();
|
|
|
|
I != IEnd; ++I)
|
2009-11-18 08:28:11 +08:00
|
|
|
makeDeclVisibleInContextImpl(I->getInterface());
|
2009-11-18 06:58:30 +08:00
|
|
|
|
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-06-30 10:36:12 +08:00
|
|
|
buildLookup(InnerCtx->getPrimaryContext());
|
2009-01-06 03:45:36 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
DeclContext::lookup_result
|
2009-06-30 10:36:12 +08:00
|
|
|
DeclContext::lookup(DeclarationName Name) {
|
2009-01-09 01:28:14 +08:00
|
|
|
DeclContext *PrimaryContext = getPrimaryContext();
|
2008-12-12 00:49:14 +08:00
|
|
|
if (PrimaryContext != this)
|
2009-06-30 10:36:12 +08:00
|
|
|
return PrimaryContext->lookup(Name);
|
2008-12-12 00:49:14 +08:00
|
|
|
|
2010-06-01 17:23:16 +08:00
|
|
|
if (hasExternalVisibleStorage()) {
|
|
|
|
// Check to see if we've already cached the lookup results.
|
|
|
|
if (LookupPtr) {
|
|
|
|
StoredDeclsMap::iterator I = LookupPtr->find(Name);
|
|
|
|
if (I != LookupPtr->end())
|
|
|
|
return I->second.getLookupResult(getParentASTContext());
|
|
|
|
}
|
|
|
|
|
|
|
|
ExternalASTSource *Source = getParentASTContext().getExternalSource();
|
|
|
|
return Source->FindExternalVisibleDeclsByName(this, Name);
|
|
|
|
}
|
2009-04-10 06:27:44 +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-04-10 01:29:08 +08:00
|
|
|
if (!LookupPtr) {
|
2009-06-30 10:36:12 +08:00
|
|
|
buildLookup(this);
|
2008-12-12 00:49:14 +08:00
|
|
|
|
2009-04-10 01:29:08 +08:00
|
|
|
if (!LookupPtr)
|
2010-05-11 14:18:17 +08:00
|
|
|
return lookup_result(lookup_iterator(0), lookup_iterator(0));
|
2009-04-10 01:29:08 +08:00
|
|
|
}
|
2008-12-12 00:49:14 +08:00
|
|
|
|
2010-03-24 13:22:00 +08:00
|
|
|
StoredDeclsMap::iterator Pos = LookupPtr->find(Name);
|
|
|
|
if (Pos == LookupPtr->end())
|
2010-05-11 14:18:17 +08:00
|
|
|
return lookup_result(lookup_iterator(0), lookup_iterator(0));
|
2009-06-30 10:36:12 +08:00
|
|
|
return Pos->second.getLookupResult(getParentASTContext());
|
2008-12-12 00:49:14 +08:00
|
|
|
}
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
DeclContext::lookup_const_result
|
2009-06-30 10:36:12 +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-09-01 06:39:49 +08:00
|
|
|
void DeclContext::makeDeclVisibleInContext(NamedDecl *D, bool Recoverable) {
|
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-12-08 13:40:03 +08:00
|
|
|
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
|
|
|
|
if (FD->isFunctionTemplateSpecialization())
|
|
|
|
return;
|
2009-02-18 07:15:12 +08:00
|
|
|
|
2009-01-09 01:28:14 +08:00
|
|
|
DeclContext *PrimaryContext = getPrimaryContext();
|
2008-12-12 00:49:14 +08:00
|
|
|
if (PrimaryContext != this) {
|
2009-09-01 06:39:49 +08:00
|
|
|
PrimaryContext->makeDeclVisibleInContext(D, Recoverable);
|
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.
|
2009-09-01 06:39:49 +08:00
|
|
|
if (LookupPtr || !Recoverable)
|
2009-06-30 10:36:12 +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-09-01 06:39:49 +08:00
|
|
|
getParent()->makeDeclVisibleInContext(D, Recoverable);
|
2008-12-12 00:49:14 +08:00
|
|
|
}
|
|
|
|
|
2009-06-30 10:36:12 +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;
|
|
|
|
|
2010-02-11 15:12:28 +08:00
|
|
|
ASTContext *C = 0;
|
|
|
|
if (!LookupPtr) {
|
|
|
|
C = &getParentASTContext();
|
2010-03-24 13:22:00 +08:00
|
|
|
CreateStoredDeclsMap(*C);
|
2010-02-11 15:12:28 +08:00
|
|
|
}
|
2008-12-12 00:49:14 +08:00
|
|
|
|
|
|
|
// Insert this declaration into the map.
|
2010-03-24 13:22:00 +08:00
|
|
|
StoredDeclsList &DeclNameEntries = (*LookupPtr)[D->getDeclName()];
|
2009-02-20 09:44:05 +08:00
|
|
|
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.
|
2010-02-11 15:12:28 +08:00
|
|
|
if (!C)
|
|
|
|
C = &getParentASTContext();
|
|
|
|
|
|
|
|
if (DeclNameEntries.HandleRedeclaration(*C, D))
|
2009-02-20 09:44:05 +08:00
|
|
|
return;
|
2009-09-09 23:08:12 +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.
|
2009-09-09 23:08:12 +08:00
|
|
|
DeclContext::udir_iterator_range
|
2009-06-30 10:36:12 +08:00
|
|
|
DeclContext::getUsingDirectives() const {
|
|
|
|
lookup_const_result Result = lookup(UsingDirectiveDecl::getName());
|
2009-02-04 03:21:40 +08:00
|
|
|
return udir_iterator_range(reinterpret_cast<udir_iterator>(Result.first),
|
|
|
|
reinterpret_cast<udir_iterator>(Result.second));
|
|
|
|
}
|
2009-04-10 06:27:44 +08:00
|
|
|
|
|
|
|
void StoredDeclsList::materializeDecls(ASTContext &Context) {
|
|
|
|
if (isNull())
|
|
|
|
return;
|
|
|
|
|
|
|
|
switch ((DataKind)(Data & 0x03)) {
|
|
|
|
case DK_Decl:
|
|
|
|
case DK_Decl_Vector:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DK_DeclID: {
|
|
|
|
// Resolve this declaration ID to an actual declaration by
|
|
|
|
// querying the external AST source.
|
|
|
|
unsigned DeclID = Data >> 2;
|
|
|
|
|
|
|
|
ExternalASTSource *Source = Context.getExternalSource();
|
|
|
|
assert(Source && "No external AST source available!");
|
|
|
|
|
2010-06-01 17:23:16 +08:00
|
|
|
Data = reinterpret_cast<uintptr_t>(Source->GetExternalDecl(DeclID));
|
2009-04-10 06:27:44 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case DK_ID_Vector: {
|
|
|
|
// We have a vector of declaration IDs. Resolve all of them to
|
|
|
|
// actual declarations.
|
|
|
|
VectorTy &Vector = *getAsVector();
|
|
|
|
ExternalASTSource *Source = Context.getExternalSource();
|
|
|
|
assert(Source && "No external AST source available!");
|
|
|
|
|
|
|
|
for (unsigned I = 0, N = Vector.size(); I != N; ++I)
|
2010-06-01 17:23:16 +08:00
|
|
|
Vector[I] = reinterpret_cast<uintptr_t>(Source->GetExternalDecl(Vector[I]));
|
2009-04-10 06:27:44 +08:00
|
|
|
|
|
|
|
Data = (Data & ~0x03) | DK_Decl_Vector;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2010-02-11 15:12:28 +08:00
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Creation and Destruction of StoredDeclsMaps. //
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2010-03-24 13:22:00 +08:00
|
|
|
StoredDeclsMap *DeclContext::CreateStoredDeclsMap(ASTContext &C) const {
|
|
|
|
assert(!LookupPtr && "context already has a decls map");
|
|
|
|
assert(getPrimaryContext() == this &&
|
|
|
|
"creating decls map on non-primary context");
|
|
|
|
|
|
|
|
StoredDeclsMap *M;
|
|
|
|
bool Dependent = isDependentContext();
|
|
|
|
if (Dependent)
|
|
|
|
M = new DependentStoredDeclsMap();
|
|
|
|
else
|
|
|
|
M = new StoredDeclsMap();
|
|
|
|
M->Previous = C.LastSDM;
|
|
|
|
C.LastSDM = llvm::PointerIntPair<StoredDeclsMap*,1>(M, Dependent);
|
|
|
|
LookupPtr = M;
|
2010-02-11 15:12:28 +08:00
|
|
|
return M;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ASTContext::ReleaseDeclContextMaps() {
|
2010-03-24 13:22:00 +08:00
|
|
|
// It's okay to delete DependentStoredDeclsMaps via a StoredDeclsMap
|
|
|
|
// pointer because the subclass doesn't add anything that needs to
|
|
|
|
// be deleted.
|
|
|
|
|
|
|
|
StoredDeclsMap::DestroyAll(LastSDM.getPointer(), LastSDM.getInt());
|
|
|
|
}
|
|
|
|
|
|
|
|
void StoredDeclsMap::DestroyAll(StoredDeclsMap *Map, bool Dependent) {
|
|
|
|
while (Map) {
|
|
|
|
// Advance the iteration before we invalidate memory.
|
|
|
|
llvm::PointerIntPair<StoredDeclsMap*,1> Next = Map->Previous;
|
|
|
|
|
|
|
|
if (Dependent)
|
|
|
|
delete static_cast<DependentStoredDeclsMap*>(Map);
|
|
|
|
else
|
|
|
|
delete Map;
|
|
|
|
|
|
|
|
Map = Next.getPointer();
|
|
|
|
Dependent = Next.getInt();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
DependentDiagnostic *DependentDiagnostic::Create(ASTContext &C,
|
|
|
|
DeclContext *Parent,
|
|
|
|
const PartialDiagnostic &PDiag) {
|
|
|
|
assert(Parent->isDependentContext()
|
|
|
|
&& "cannot iterate dependent diagnostics of non-dependent context");
|
|
|
|
Parent = Parent->getPrimaryContext();
|
|
|
|
if (!Parent->LookupPtr)
|
|
|
|
Parent->CreateStoredDeclsMap(C);
|
|
|
|
|
|
|
|
DependentStoredDeclsMap *Map
|
|
|
|
= static_cast<DependentStoredDeclsMap*>(Parent->LookupPtr);
|
|
|
|
|
2010-03-30 07:56:53 +08:00
|
|
|
// Allocate the copy of the PartialDiagnostic via the ASTContext's
|
2010-03-30 07:34:08 +08:00
|
|
|
// BumpPtrAllocator, rather than the ASTContext itself.
|
2010-03-30 07:56:53 +08:00
|
|
|
PartialDiagnostic::Storage *DiagStorage = 0;
|
|
|
|
if (PDiag.hasStorage())
|
|
|
|
DiagStorage = new (C) PartialDiagnostic::Storage;
|
|
|
|
|
|
|
|
DependentDiagnostic *DD = new (C) DependentDiagnostic(PDiag, DiagStorage);
|
2010-03-24 13:22:00 +08:00
|
|
|
|
|
|
|
// TODO: Maybe we shouldn't reverse the order during insertion.
|
|
|
|
DD->NextDiagnostic = Map->FirstDiagnostic;
|
|
|
|
Map->FirstDiagnostic = DD;
|
|
|
|
|
|
|
|
return DD;
|
2010-02-11 15:12:28 +08:00
|
|
|
}
|