diff options
author | ed <ed@FreeBSD.org> | 2009-06-02 17:58:47 +0000 |
---|---|---|
committer | ed <ed@FreeBSD.org> | 2009-06-02 17:58:47 +0000 |
commit | f27e5a09a0d815b8a4814152954ff87dadfdefc0 (patch) | |
tree | ce7d964cbb5e39695b71481698f10cb099c23d4a /lib/AST/Decl.cpp | |
download | FreeBSD-src-f27e5a09a0d815b8a4814152954ff87dadfdefc0.zip FreeBSD-src-f27e5a09a0d815b8a4814152954ff87dadfdefc0.tar.gz |
Import Clang, at r72732.
Diffstat (limited to 'lib/AST/Decl.cpp')
-rw-r--r-- | lib/AST/Decl.cpp | 630 |
1 files changed, 630 insertions, 0 deletions
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp new file mode 100644 index 0000000..cb3ec1f --- /dev/null +++ b/lib/AST/Decl.cpp @@ -0,0 +1,630 @@ +//===--- Decl.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 subclasses. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Stmt.h" +#include "clang/AST/Expr.h" +#include "clang/AST/PrettyPrinter.h" +#include "clang/Basic/IdentifierTable.h" +#include <vector> + +using namespace clang; + +void Attr::Destroy(ASTContext &C) { + if (Next) { + Next->Destroy(C); + Next = 0; + } + this->~Attr(); + C.Deallocate((void*)this); +} + + +//===----------------------------------------------------------------------===// +// Decl Allocation/Deallocation Method Implementations +//===----------------------------------------------------------------------===// + + +TranslationUnitDecl *TranslationUnitDecl::Create(ASTContext &C) { + return new (C) TranslationUnitDecl(); +} + +NamespaceDecl *NamespaceDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation L, IdentifierInfo *Id) { + return new (C) NamespaceDecl(DC, L, Id); +} + +void NamespaceDecl::Destroy(ASTContext& C) { + // NamespaceDecl uses "NextDeclarator" to chain namespace declarations + // together. They are all top-level Decls. + + this->~NamespaceDecl(); + C.Deallocate((void *)this); +} + + +ImplicitParamDecl *ImplicitParamDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation L, IdentifierInfo *Id, QualType T) { + return new (C) ImplicitParamDecl(ImplicitParam, DC, L, Id, T); +} + +const char *VarDecl::getStorageClassSpecifierString(StorageClass SC) { + switch (SC) { + case VarDecl::None: break; + case VarDecl::Auto: return "auto"; break; + case VarDecl::Extern: return "extern"; break; + case VarDecl::PrivateExtern: return "__private_extern__"; break; + case VarDecl::Register: return "register"; break; + case VarDecl::Static: return "static"; break; + } + + assert(0 && "Invalid storage class"); + return 0; +} + +ParmVarDecl *ParmVarDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation L, IdentifierInfo *Id, + QualType T, StorageClass S, + Expr *DefArg) { + return new (C) ParmVarDecl(ParmVar, DC, L, Id, T, S, DefArg); +} + +QualType ParmVarDecl::getOriginalType() const { + if (const OriginalParmVarDecl *PVD = + dyn_cast<OriginalParmVarDecl>(this)) + return PVD->OriginalType; + return getType(); +} + +void VarDecl::setInit(ASTContext &C, Expr *I) { + if (EvaluatedStmt *Eval = Init.dyn_cast<EvaluatedStmt *>()) { + Eval->~EvaluatedStmt(); + C.Deallocate(Eval); + } + + Init = I; + } + +bool VarDecl::isExternC(ASTContext &Context) const { + if (!Context.getLangOptions().CPlusPlus) + return (getDeclContext()->isTranslationUnit() && + getStorageClass() != Static) || + (getDeclContext()->isFunctionOrMethod() && hasExternalStorage()); + + for (const DeclContext *DC = getDeclContext(); !DC->isTranslationUnit(); + DC = DC->getParent()) { + if (const LinkageSpecDecl *Linkage = dyn_cast<LinkageSpecDecl>(DC)) { + if (Linkage->getLanguage() == LinkageSpecDecl::lang_c) + return getStorageClass() != Static; + + break; + } + + if (DC->isFunctionOrMethod()) + return false; + } + + return false; +} + +OriginalParmVarDecl *OriginalParmVarDecl::Create( + ASTContext &C, DeclContext *DC, + SourceLocation L, IdentifierInfo *Id, + QualType T, QualType OT, StorageClass S, + Expr *DefArg) { + return new (C) OriginalParmVarDecl(DC, L, Id, T, OT, S, DefArg); +} + +FunctionDecl *FunctionDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation L, + DeclarationName N, QualType T, + StorageClass S, bool isInline, + bool hasWrittenPrototype, + SourceLocation TypeSpecStartLoc) { + FunctionDecl *New + = new (C) FunctionDecl(Function, DC, L, N, T, S, isInline, + TypeSpecStartLoc); + New->HasWrittenPrototype = hasWrittenPrototype; + return New; +} + +BlockDecl *BlockDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L) { + return new (C) BlockDecl(DC, L); +} + +FieldDecl *FieldDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, + IdentifierInfo *Id, QualType T, Expr *BW, + bool Mutable) { + return new (C) FieldDecl(Decl::Field, DC, L, Id, T, BW, Mutable); +} + +bool FieldDecl::isAnonymousStructOrUnion() const { + if (!isImplicit() || getDeclName()) + return false; + + if (const RecordType *Record = getType()->getAsRecordType()) + return Record->getDecl()->isAnonymousStructOrUnion(); + + return false; +} + +EnumConstantDecl *EnumConstantDecl::Create(ASTContext &C, EnumDecl *CD, + SourceLocation L, + IdentifierInfo *Id, QualType T, + Expr *E, const llvm::APSInt &V) { + return new (C) EnumConstantDecl(CD, L, Id, T, E, V); +} + +void EnumConstantDecl::Destroy(ASTContext& C) { + if (Init) Init->Destroy(C); + Decl::Destroy(C); +} + +TypedefDecl *TypedefDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation L, + IdentifierInfo *Id, QualType T) { + return new (C) TypedefDecl(DC, L, Id, T); +} + +EnumDecl *EnumDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, + IdentifierInfo *Id, + EnumDecl *PrevDecl) { + EnumDecl *Enum = new (C) EnumDecl(DC, L, Id); + C.getTypeDeclType(Enum, PrevDecl); + return Enum; +} + +void EnumDecl::Destroy(ASTContext& C) { + Decl::Destroy(C); +} + +void EnumDecl::completeDefinition(ASTContext &C, QualType NewType) { + assert(!isDefinition() && "Cannot redefine enums!"); + IntegerType = NewType; + TagDecl::completeDefinition(); +} + +FileScopeAsmDecl *FileScopeAsmDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation L, + StringLiteral *Str) { + return new (C) FileScopeAsmDecl(DC, L, Str); +} + +//===----------------------------------------------------------------------===// +// NamedDecl Implementation +//===----------------------------------------------------------------------===// + +std::string NamedDecl::getQualifiedNameAsString() const { + std::vector<std::string> Names; + std::string QualName; + const DeclContext *Ctx = getDeclContext(); + + if (Ctx->isFunctionOrMethod()) + return getNameAsString(); + + while (Ctx) { + if (Ctx->isFunctionOrMethod()) + // FIXME: That probably will happen, when D was member of local + // scope class/struct/union. How do we handle this case? + break; + + if (const ClassTemplateSpecializationDecl *Spec + = dyn_cast<ClassTemplateSpecializationDecl>(Ctx)) { + const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs(); + PrintingPolicy Policy; + Policy.CPlusPlus = true; + std::string TemplateArgsStr + = TemplateSpecializationType::PrintTemplateArgumentList( + TemplateArgs.getFlatArgumentList(), + TemplateArgs.flat_size(), + Policy); + Names.push_back(Spec->getIdentifier()->getName() + TemplateArgsStr); + } else if (const NamedDecl *ND = dyn_cast<NamedDecl>(Ctx)) + Names.push_back(ND->getNameAsString()); + else + break; + + Ctx = Ctx->getParent(); + } + + std::vector<std::string>::reverse_iterator + I = Names.rbegin(), + End = Names.rend(); + + for (; I!=End; ++I) + QualName += *I + "::"; + + QualName += getNameAsString(); + + return QualName; +} + + +bool NamedDecl::declarationReplaces(NamedDecl *OldD) const { + assert(getDeclName() == OldD->getDeclName() && "Declaration name mismatch"); + + // UsingDirectiveDecl's are not really NamedDecl's, and all have same name. + // We want to keep it, unless it nominates same namespace. + if (getKind() == Decl::UsingDirective) { + return cast<UsingDirectiveDecl>(this)->getNominatedNamespace() == + cast<UsingDirectiveDecl>(OldD)->getNominatedNamespace(); + } + + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(this)) + // For function declarations, we keep track of redeclarations. + return FD->getPreviousDeclaration() == OldD; + + // For method declarations, we keep track of redeclarations. + if (isa<ObjCMethodDecl>(this)) + return false; + + // 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(); +} + +bool NamedDecl::hasLinkage() const { + if (const VarDecl *VD = dyn_cast<VarDecl>(this)) + return VD->hasExternalStorage() || VD->isFileVarDecl(); + + if (isa<FunctionDecl>(this) && !isa<CXXMethodDecl>(this)) + return true; + + return false; +} + +//===----------------------------------------------------------------------===// +// VarDecl Implementation +//===----------------------------------------------------------------------===// + +VarDecl *VarDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, + IdentifierInfo *Id, QualType T, StorageClass S, + SourceLocation TypeSpecStartLoc) { + return new (C) VarDecl(Var, DC, L, Id, T, S, TypeSpecStartLoc); +} + +void VarDecl::Destroy(ASTContext& C) { + Expr *Init = getInit(); + if (Init) { + Init->Destroy(C); + if (EvaluatedStmt *Eval = this->Init.dyn_cast<EvaluatedStmt *>()) { + Eval->~EvaluatedStmt(); + C.Deallocate(Eval); + } + } + this->~VarDecl(); + C.Deallocate((void *)this); +} + +VarDecl::~VarDecl() { +} + +bool VarDecl::isTentativeDefinition(ASTContext &Context) const { + if (!isFileVarDecl() || Context.getLangOptions().CPlusPlus) + return false; + + const VarDecl *Def = 0; + return (!getDefinition(Def) && + (getStorageClass() == None || getStorageClass() == Static)); +} + +const Expr *VarDecl::getDefinition(const VarDecl *&Def) const { + Def = this; + while (Def && !Def->getInit()) + Def = Def->getPreviousDeclaration(); + + return Def? Def->getInit() : 0; +} + +//===----------------------------------------------------------------------===// +// FunctionDecl Implementation +//===----------------------------------------------------------------------===// + +void FunctionDecl::Destroy(ASTContext& C) { + if (Body && Body.isOffset()) + Body.get(C.getExternalSource())->Destroy(C); + + for (param_iterator I=param_begin(), E=param_end(); I!=E; ++I) + (*I)->Destroy(C); + + C.Deallocate(ParamInfo); + + Decl::Destroy(C); +} + + +Stmt *FunctionDecl::getBody(ASTContext &Context, + const FunctionDecl *&Definition) const { + for (const FunctionDecl *FD = this; FD != 0; FD = FD->PreviousDeclaration) { + if (FD->Body) { + Definition = FD; + return FD->Body.get(Context.getExternalSource()); + } + } + + return 0; +} + +Stmt *FunctionDecl::getBodyIfAvailable() const { + for (const FunctionDecl *FD = this; FD != 0; FD = FD->PreviousDeclaration) { + if (FD->Body && !FD->Body.isOffset()) { + return FD->Body.get(0); + } + } + + return 0; +} + +bool FunctionDecl::isMain() const { + return getDeclContext()->getLookupContext()->isTranslationUnit() && + getIdentifier() && getIdentifier()->isStr("main"); +} + +bool FunctionDecl::isExternC(ASTContext &Context) const { + // In C, any non-static, non-overloadable function has external + // linkage. + if (!Context.getLangOptions().CPlusPlus) + return getStorageClass() != Static && !getAttr<OverloadableAttr>(); + + for (const DeclContext *DC = getDeclContext(); !DC->isTranslationUnit(); + DC = DC->getParent()) { + if (const LinkageSpecDecl *Linkage = dyn_cast<LinkageSpecDecl>(DC)) { + if (Linkage->getLanguage() == LinkageSpecDecl::lang_c) + return getStorageClass() != Static && !getAttr<OverloadableAttr>(); + + break; + } + } + + return false; +} + +bool FunctionDecl::isGlobal() const { + if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(this)) + return Method->isStatic(); + + if (getStorageClass() == Static) + return false; + + for (const DeclContext *DC = getDeclContext(); + DC->isNamespace(); + DC = DC->getParent()) { + if (const NamespaceDecl *Namespace = cast<NamespaceDecl>(DC)) { + if (!Namespace->getDeclName()) + return false; + break; + } + } + + return true; +} + +/// \brief Returns a value indicating whether this function +/// corresponds to a builtin function. +/// +/// The function corresponds to a built-in function if it is +/// declared at translation scope or within an extern "C" block and +/// its name matches with the name of a builtin. The returned value +/// will be 0 for functions that do not correspond to a builtin, a +/// value of type \c Builtin::ID if in the target-independent range +/// \c [1,Builtin::First), or a target-specific builtin value. +unsigned FunctionDecl::getBuiltinID(ASTContext &Context) const { + if (!getIdentifier() || !getIdentifier()->getBuiltinID()) + return 0; + + unsigned BuiltinID = getIdentifier()->getBuiltinID(); + if (!Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID)) + return BuiltinID; + + // This function has the name of a known C library + // function. Determine whether it actually refers to the C library + // function or whether it just has the same name. + + // If this is a static function, it's not a builtin. + if (getStorageClass() == Static) + return 0; + + // If this function is at translation-unit scope and we're not in + // C++, it refers to the C library function. + if (!Context.getLangOptions().CPlusPlus && + getDeclContext()->isTranslationUnit()) + return BuiltinID; + + // If the function is in an extern "C" linkage specification and is + // not marked "overloadable", it's the real function. + if (isa<LinkageSpecDecl>(getDeclContext()) && + cast<LinkageSpecDecl>(getDeclContext())->getLanguage() + == LinkageSpecDecl::lang_c && + !getAttr<OverloadableAttr>()) + return BuiltinID; + + // Not a builtin + return 0; +} + + +/// getNumParams - Return the number of parameters this function must have +/// based on its FunctionType. This is the length of the PararmInfo array +/// after it has been created. +unsigned FunctionDecl::getNumParams() const { + const FunctionType *FT = getType()->getAsFunctionType(); + if (isa<FunctionNoProtoType>(FT)) + return 0; + return cast<FunctionProtoType>(FT)->getNumArgs(); + +} + +void FunctionDecl::setParams(ASTContext& C, ParmVarDecl **NewParamInfo, + unsigned NumParams) { + assert(ParamInfo == 0 && "Already has param info!"); + assert(NumParams == getNumParams() && "Parameter count mismatch!"); + + // Zero params -> null pointer. + if (NumParams) { + void *Mem = C.Allocate(sizeof(ParmVarDecl*)*NumParams); + ParamInfo = new (Mem) ParmVarDecl*[NumParams]; + memcpy(ParamInfo, NewParamInfo, sizeof(ParmVarDecl*)*NumParams); + } +} + +/// getMinRequiredArguments - Returns the minimum number of arguments +/// needed to call this function. This may be fewer than the number of +/// function parameters, if some of the parameters have default +/// arguments (in C++). +unsigned FunctionDecl::getMinRequiredArguments() const { + unsigned NumRequiredArgs = getNumParams(); + while (NumRequiredArgs > 0 + && getParamDecl(NumRequiredArgs-1)->getDefaultArg()) + --NumRequiredArgs; + + return NumRequiredArgs; +} + +bool FunctionDecl::hasActiveGNUInlineAttribute() const { + if (!isInline() || !hasAttr<GNUInlineAttr>()) + return false; + + for (const FunctionDecl *FD = getPreviousDeclaration(); FD; + FD = FD->getPreviousDeclaration()) { + if (FD->isInline() && !FD->hasAttr<GNUInlineAttr>()) + return false; + } + + return true; +} + +bool FunctionDecl::isExternGNUInline() const { + if (!hasActiveGNUInlineAttribute()) + return false; + + for (const FunctionDecl *FD = this; FD; FD = FD->getPreviousDeclaration()) + if (FD->getStorageClass() == Extern && FD->hasAttr<GNUInlineAttr>()) + return true; + + return false; +} + +/// getOverloadedOperator - Which C++ overloaded operator this +/// function represents, if any. +OverloadedOperatorKind FunctionDecl::getOverloadedOperator() const { + if (getDeclName().getNameKind() == DeclarationName::CXXOperatorName) + return getDeclName().getCXXOverloadedOperator(); + else + return OO_None; +} + +//===----------------------------------------------------------------------===// +// TagDecl Implementation +//===----------------------------------------------------------------------===// + +void TagDecl::startDefinition() { + TagType *TagT = const_cast<TagType *>(TypeForDecl->getAsTagType()); + TagT->decl.setPointer(this); + TagT->getAsTagType()->decl.setInt(1); +} + +void TagDecl::completeDefinition() { + assert((!TypeForDecl || + TypeForDecl->getAsTagType()->decl.getPointer() == this) && + "Attempt to redefine a tag definition?"); + IsDefinition = true; + TagType *TagT = const_cast<TagType *>(TypeForDecl->getAsTagType()); + TagT->decl.setPointer(this); + TagT->decl.setInt(0); +} + +TagDecl* TagDecl::getDefinition(ASTContext& C) const { + QualType T = C.getTypeDeclType(const_cast<TagDecl*>(this)); + TagDecl* D = cast<TagDecl>(T->getAsTagType()->getDecl()); + return D->isDefinition() ? D : 0; +} + +//===----------------------------------------------------------------------===// +// RecordDecl Implementation +//===----------------------------------------------------------------------===// + +RecordDecl::RecordDecl(Kind DK, TagKind TK, DeclContext *DC, SourceLocation L, + IdentifierInfo *Id) + : TagDecl(DK, TK, DC, L, Id) { + HasFlexibleArrayMember = false; + AnonymousStructOrUnion = false; + assert(classof(static_cast<Decl*>(this)) && "Invalid Kind!"); +} + +RecordDecl *RecordDecl::Create(ASTContext &C, TagKind TK, DeclContext *DC, + SourceLocation L, IdentifierInfo *Id, + RecordDecl* PrevDecl) { + + RecordDecl* R = new (C) RecordDecl(Record, TK, DC, L, Id); + C.getTypeDeclType(R, PrevDecl); + return R; +} + +RecordDecl::~RecordDecl() { +} + +void RecordDecl::Destroy(ASTContext& C) { + TagDecl::Destroy(C); +} + +bool RecordDecl::isInjectedClassName() const { + return isImplicit() && getDeclName() && getDeclContext()->isRecord() && + cast<RecordDecl>(getDeclContext())->getDeclName() == getDeclName(); +} + +/// completeDefinition - Notes that the definition of this type is now +/// complete. +void RecordDecl::completeDefinition(ASTContext& C) { + assert(!isDefinition() && "Cannot redefine record!"); + TagDecl::completeDefinition(); +} + +//===----------------------------------------------------------------------===// +// BlockDecl Implementation +//===----------------------------------------------------------------------===// + +BlockDecl::~BlockDecl() { +} + +void BlockDecl::Destroy(ASTContext& C) { + if (Body) + Body->Destroy(C); + + for (param_iterator I=param_begin(), E=param_end(); I!=E; ++I) + (*I)->Destroy(C); + + C.Deallocate(ParamInfo); + Decl::Destroy(C); +} + +void BlockDecl::setParams(ASTContext& C, ParmVarDecl **NewParamInfo, + unsigned NParms) { + assert(ParamInfo == 0 && "Already has param info!"); + + // Zero params -> null pointer. + if (NParms) { + NumParams = NParms; + void *Mem = C.Allocate(sizeof(ParmVarDecl*)*NumParams); + ParamInfo = new (Mem) ParmVarDecl*[NumParams]; + memcpy(ParamInfo, NewParamInfo, sizeof(ParmVarDecl*)*NumParams); + } +} + +unsigned BlockDecl::getNumParams() const { + return NumParams; +} |