2006-10-16 06:34:45 +08:00
|
|
|
//===--- Decl.cpp - Declaration AST Node Implementation -------------------===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
2007-12-30 03:59:25 +08:00
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
2006-10-16 06:34:45 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
2008-06-04 21:04:04 +08:00
|
|
|
// This file implements the Decl subclasses.
|
2006-10-16 06:34:45 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "clang/AST/Decl.h"
|
2009-02-04 03:21:40 +08:00
|
|
|
#include "clang/AST/DeclCXX.h"
|
2009-02-23 03:35:57 +08:00
|
|
|
#include "clang/AST/DeclObjC.h"
|
2009-05-11 06:57:19 +08:00
|
|
|
#include "clang/AST/DeclTemplate.h"
|
2008-03-15 14:12:44 +08:00
|
|
|
#include "clang/AST/ASTContext.h"
|
2008-08-11 12:54:23 +08:00
|
|
|
#include "clang/AST/Stmt.h"
|
2008-12-18 07:39:55 +08:00
|
|
|
#include "clang/AST/Expr.h"
|
2009-05-30 04:38:28 +08:00
|
|
|
#include "clang/AST/PrettyPrinter.h"
|
2009-06-14 09:54:56 +08:00
|
|
|
#include "clang/Basic/Builtins.h"
|
2008-08-11 12:54:23 +08:00
|
|
|
#include "clang/Basic/IdentifierTable.h"
|
2009-02-05 01:27:36 +08:00
|
|
|
#include <vector>
|
2008-05-20 08:43:19 +08:00
|
|
|
|
2006-10-25 13:11:20 +08:00
|
|
|
using namespace clang;
|
2006-10-16 06:34:45 +08:00
|
|
|
|
2009-03-04 14:34:08 +08:00
|
|
|
void Attr::Destroy(ASTContext &C) {
|
|
|
|
if (Next) {
|
|
|
|
Next->Destroy(C);
|
|
|
|
Next = 0;
|
|
|
|
}
|
|
|
|
this->~Attr();
|
|
|
|
C.Deallocate((void*)this);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-03-15 14:12:44 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Decl Allocation/Deallocation Method Implementations
|
|
|
|
//===----------------------------------------------------------------------===//
|
2008-04-27 21:50:30 +08:00
|
|
|
|
2009-03-04 14:34:08 +08:00
|
|
|
|
2008-04-17 22:40:12 +08:00
|
|
|
TranslationUnitDecl *TranslationUnitDecl::Create(ASTContext &C) {
|
2009-06-30 01:38:40 +08:00
|
|
|
return new (C) TranslationUnitDecl(C);
|
2008-04-17 22:40:12 +08:00
|
|
|
}
|
|
|
|
|
2008-04-27 21:50:30 +08:00
|
|
|
NamespaceDecl *NamespaceDecl::Create(ASTContext &C, DeclContext *DC,
|
|
|
|
SourceLocation L, IdentifierInfo *Id) {
|
2009-01-28 05:25:57 +08:00
|
|
|
return new (C) NamespaceDecl(DC, L, Id);
|
2008-04-27 21:50:30 +08:00
|
|
|
}
|
|
|
|
|
2008-05-20 12:49:55 +08:00
|
|
|
void NamespaceDecl::Destroy(ASTContext& C) {
|
|
|
|
// NamespaceDecl uses "NextDeclarator" to chain namespace declarations
|
|
|
|
// together. They are all top-level Decls.
|
|
|
|
|
2008-05-24 23:09:56 +08:00
|
|
|
this->~NamespaceDecl();
|
2009-01-28 05:25:57 +08:00
|
|
|
C.Deallocate((void *)this);
|
2008-05-20 12:49:55 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-06-18 02:05:57 +08:00
|
|
|
ImplicitParamDecl *ImplicitParamDecl::Create(ASTContext &C, DeclContext *DC,
|
2009-01-20 09:17:11 +08:00
|
|
|
SourceLocation L, IdentifierInfo *Id, QualType T) {
|
2009-01-28 05:25:57 +08:00
|
|
|
return new (C) ImplicitParamDecl(ImplicitParam, DC, L, Id, T);
|
2008-06-18 02:05:57 +08:00
|
|
|
}
|
|
|
|
|
2009-04-14 10:08:49 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2008-04-23 02:39:57 +08:00
|
|
|
ParmVarDecl *ParmVarDecl::Create(ASTContext &C, DeclContext *DC,
|
2008-04-04 14:12:32 +08:00
|
|
|
SourceLocation L, IdentifierInfo *Id,
|
|
|
|
QualType T, StorageClass S,
|
2009-01-20 09:17:11 +08:00
|
|
|
Expr *DefArg) {
|
2009-01-28 05:25:57 +08:00
|
|
|
return new (C) ParmVarDecl(ParmVar, DC, L, Id, T, S, DefArg);
|
2008-12-21 07:29:59 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
QualType ParmVarDecl::getOriginalType() const {
|
2009-02-03 07:39:07 +08:00
|
|
|
if (const OriginalParmVarDecl *PVD =
|
|
|
|
dyn_cast<OriginalParmVarDecl>(this))
|
2008-12-21 07:29:59 +08:00
|
|
|
return PVD->OriginalType;
|
|
|
|
return getType();
|
2008-03-16 05:10:16 +08:00
|
|
|
}
|
|
|
|
|
2009-05-27 02:54:04 +08:00
|
|
|
void VarDecl::setInit(ASTContext &C, Expr *I) {
|
|
|
|
if (EvaluatedStmt *Eval = Init.dyn_cast<EvaluatedStmt *>()) {
|
|
|
|
Eval->~EvaluatedStmt();
|
|
|
|
C.Deallocate(Eval);
|
|
|
|
}
|
|
|
|
|
|
|
|
Init = I;
|
|
|
|
}
|
|
|
|
|
2009-03-02 08:19:53 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2009-02-03 07:39:07 +08:00
|
|
|
OriginalParmVarDecl *OriginalParmVarDecl::Create(
|
2008-12-21 04:56:12 +08:00
|
|
|
ASTContext &C, DeclContext *DC,
|
|
|
|
SourceLocation L, IdentifierInfo *Id,
|
|
|
|
QualType T, QualType OT, StorageClass S,
|
2009-01-20 09:17:11 +08:00
|
|
|
Expr *DefArg) {
|
2009-02-03 07:39:07 +08:00
|
|
|
return new (C) OriginalParmVarDecl(DC, L, Id, T, OT, S, DefArg);
|
2008-12-21 04:56:12 +08:00
|
|
|
}
|
|
|
|
|
2008-04-23 02:39:57 +08:00
|
|
|
FunctionDecl *FunctionDecl::Create(ASTContext &C, DeclContext *DC,
|
2008-04-04 14:12:32 +08:00
|
|
|
SourceLocation L,
|
2008-11-18 06:58:34 +08:00
|
|
|
DeclarationName N, QualType T,
|
2008-03-16 05:24:04 +08:00
|
|
|
StorageClass S, bool isInline,
|
2009-05-15 05:46:00 +08:00
|
|
|
bool hasWrittenPrototype,
|
2008-10-03 08:02:03 +08:00
|
|
|
SourceLocation TypeSpecStartLoc) {
|
2009-02-26 00:33:18 +08:00
|
|
|
FunctionDecl *New
|
|
|
|
= new (C) FunctionDecl(Function, DC, L, N, T, S, isInline,
|
|
|
|
TypeSpecStartLoc);
|
2009-05-15 05:46:00 +08:00
|
|
|
New->HasWrittenPrototype = hasWrittenPrototype;
|
2009-02-26 00:33:18 +08:00
|
|
|
return New;
|
2008-03-16 05:24:04 +08:00
|
|
|
}
|
|
|
|
|
2008-10-10 09:28:17 +08:00
|
|
|
BlockDecl *BlockDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L) {
|
2009-01-28 05:25:57 +08:00
|
|
|
return new (C) BlockDecl(DC, L);
|
2008-10-09 01:01:13 +08:00
|
|
|
}
|
|
|
|
|
2008-12-12 00:49:14 +08:00
|
|
|
FieldDecl *FieldDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L,
|
|
|
|
IdentifierInfo *Id, QualType T, Expr *BW,
|
2009-01-20 09:17:11 +08:00
|
|
|
bool Mutable) {
|
2009-01-28 05:25:57 +08:00
|
|
|
return new (C) FieldDecl(Decl::Field, DC, L, Id, T, BW, Mutable);
|
2008-03-16 08:16:02 +08:00
|
|
|
}
|
|
|
|
|
2009-01-08 03:46:03 +08:00
|
|
|
bool FieldDecl::isAnonymousStructOrUnion() const {
|
|
|
|
if (!isImplicit() || getDeclName())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (const RecordType *Record = getType()->getAsRecordType())
|
|
|
|
return Record->getDecl()->isAnonymousStructOrUnion();
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
2008-03-16 05:24:04 +08:00
|
|
|
|
2008-04-04 14:12:32 +08:00
|
|
|
EnumConstantDecl *EnumConstantDecl::Create(ASTContext &C, EnumDecl *CD,
|
|
|
|
SourceLocation L,
|
2008-03-16 05:32:50 +08:00
|
|
|
IdentifierInfo *Id, QualType T,
|
2009-01-20 09:17:11 +08:00
|
|
|
Expr *E, const llvm::APSInt &V) {
|
2009-01-28 05:25:57 +08:00
|
|
|
return new (C) EnumConstantDecl(CD, L, Id, T, E, V);
|
2008-03-15 14:12:44 +08:00
|
|
|
}
|
|
|
|
|
2008-05-20 12:49:55 +08:00
|
|
|
void EnumConstantDecl::Destroy(ASTContext& C) {
|
|
|
|
if (Init) Init->Destroy(C);
|
|
|
|
Decl::Destroy(C);
|
|
|
|
}
|
|
|
|
|
2008-04-23 02:39:57 +08:00
|
|
|
TypedefDecl *TypedefDecl::Create(ASTContext &C, DeclContext *DC,
|
2008-04-04 14:12:32 +08:00
|
|
|
SourceLocation L,
|
2009-01-20 09:17:11 +08:00
|
|
|
IdentifierInfo *Id, QualType T) {
|
2009-01-28 05:25:57 +08:00
|
|
|
return new (C) TypedefDecl(DC, L, Id, T);
|
2008-03-15 14:12:44 +08:00
|
|
|
}
|
|
|
|
|
2008-04-23 02:39:57 +08:00
|
|
|
EnumDecl *EnumDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L,
|
2008-04-04 14:12:32 +08:00
|
|
|
IdentifierInfo *Id,
|
2008-12-16 00:32:14 +08:00
|
|
|
EnumDecl *PrevDecl) {
|
2009-01-28 07:20:32 +08:00
|
|
|
EnumDecl *Enum = new (C) EnumDecl(DC, L, Id);
|
2008-12-16 00:32:14 +08:00
|
|
|
C.getTypeDeclType(Enum, PrevDecl);
|
|
|
|
return Enum;
|
2008-03-15 14:12:44 +08:00
|
|
|
}
|
|
|
|
|
2008-09-03 04:13:32 +08:00
|
|
|
void EnumDecl::Destroy(ASTContext& C) {
|
|
|
|
Decl::Destroy(C);
|
|
|
|
}
|
|
|
|
|
2008-12-12 00:49:14 +08:00
|
|
|
void EnumDecl::completeDefinition(ASTContext &C, QualType NewType) {
|
|
|
|
assert(!isDefinition() && "Cannot redefine enums!");
|
|
|
|
IntegerType = NewType;
|
2009-01-17 08:42:38 +08:00
|
|
|
TagDecl::completeDefinition();
|
2008-12-12 00:49:14 +08:00
|
|
|
}
|
|
|
|
|
2009-01-20 09:17:11 +08:00
|
|
|
FileScopeAsmDecl *FileScopeAsmDecl::Create(ASTContext &C, DeclContext *DC,
|
2008-04-04 14:12:32 +08:00
|
|
|
SourceLocation L,
|
2008-03-16 08:16:02 +08:00
|
|
|
StringLiteral *Str) {
|
2009-01-28 05:25:57 +08:00
|
|
|
return new (C) FileScopeAsmDecl(DC, L, Str);
|
2008-03-16 08:16:02 +08:00
|
|
|
}
|
|
|
|
|
2008-03-31 08:36:02 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
2009-01-20 09:17:11 +08:00
|
|
|
// NamedDecl Implementation
|
2008-11-10 07:41:00 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2009-02-05 01:27:36 +08:00
|
|
|
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;
|
|
|
|
|
2009-05-19 01:01:57 +08:00
|
|
|
if (const ClassTemplateSpecializationDecl *Spec
|
|
|
|
= dyn_cast<ClassTemplateSpecializationDecl>(Ctx)) {
|
|
|
|
const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs();
|
2009-06-30 09:26:17 +08:00
|
|
|
PrintingPolicy Policy(getASTContext().getLangOptions());
|
2009-05-19 01:01:57 +08:00
|
|
|
std::string TemplateArgsStr
|
|
|
|
= TemplateSpecializationType::PrintTemplateArgumentList(
|
|
|
|
TemplateArgs.getFlatArgumentList(),
|
2009-05-30 04:38:28 +08:00
|
|
|
TemplateArgs.flat_size(),
|
|
|
|
Policy);
|
2009-05-19 01:01:57 +08:00
|
|
|
Names.push_back(Spec->getIdentifier()->getName() + TemplateArgsStr);
|
|
|
|
} else if (const NamedDecl *ND = dyn_cast<NamedDecl>(Ctx))
|
2009-02-05 01:27:36 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-01-20 09:17:11 +08:00
|
|
|
bool NamedDecl::declarationReplaces(NamedDecl *OldD) const {
|
2008-12-24 05:05:05 +08:00
|
|
|
assert(getDeclName() == OldD->getDeclName() && "Declaration name mismatch");
|
|
|
|
|
2009-02-04 03:21:40 +08:00
|
|
|
// 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();
|
|
|
|
}
|
|
|
|
|
2008-12-24 05:05:05 +08:00
|
|
|
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(this))
|
|
|
|
// For function declarations, we keep track of redeclarations.
|
|
|
|
return FD->getPreviousDeclaration() == OldD;
|
|
|
|
|
2009-06-26 06:08:12 +08:00
|
|
|
// For function templates, the underlying function declarations are linked.
|
|
|
|
if (const FunctionTemplateDecl *FunctionTemplate
|
|
|
|
= dyn_cast<FunctionTemplateDecl>(this))
|
|
|
|
if (const FunctionTemplateDecl *OldFunctionTemplate
|
|
|
|
= dyn_cast<FunctionTemplateDecl>(OldD))
|
|
|
|
return FunctionTemplate->getTemplatedDecl()
|
|
|
|
->declarationReplaces(OldFunctionTemplate->getTemplatedDecl());
|
|
|
|
|
2009-02-23 03:35:57 +08:00
|
|
|
// For method declarations, we keep track of redeclarations.
|
|
|
|
if (isa<ObjCMethodDecl>(this))
|
|
|
|
return false;
|
|
|
|
|
2008-12-24 05:05:05 +08:00
|
|
|
// 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();
|
|
|
|
}
|
|
|
|
|
2009-02-25 04:03:32 +08:00
|
|
|
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;
|
|
|
|
}
|
2009-01-20 09:17:11 +08:00
|
|
|
|
2009-06-26 14:29:23 +08:00
|
|
|
NamedDecl *NamedDecl::getUnderlyingDecl() {
|
|
|
|
NamedDecl *ND = this;
|
|
|
|
while (true) {
|
|
|
|
if (UsingDecl *UD = dyn_cast<UsingDecl>(ND))
|
|
|
|
ND = UD->getTargetDecl();
|
|
|
|
else if (ObjCCompatibleAliasDecl *AD
|
|
|
|
= dyn_cast<ObjCCompatibleAliasDecl>(ND))
|
|
|
|
return AD->getClassInterface();
|
|
|
|
else
|
|
|
|
return ND;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-12-18 07:39:55 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// VarDecl Implementation
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2009-01-20 09:17:11 +08:00
|
|
|
VarDecl *VarDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L,
|
|
|
|
IdentifierInfo *Id, QualType T, StorageClass S,
|
2008-12-18 07:39:55 +08:00
|
|
|
SourceLocation TypeSpecStartLoc) {
|
2009-01-28 05:25:57 +08:00
|
|
|
return new (C) VarDecl(Var, DC, L, Id, T, S, TypeSpecStartLoc);
|
2008-12-18 07:39:55 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void VarDecl::Destroy(ASTContext& C) {
|
2009-02-05 23:12:41 +08:00
|
|
|
Expr *Init = getInit();
|
2009-05-27 02:54:04 +08:00
|
|
|
if (Init) {
|
2009-02-05 23:12:41 +08:00
|
|
|
Init->Destroy(C);
|
2009-05-27 02:54:04 +08:00
|
|
|
if (EvaluatedStmt *Eval = this->Init.dyn_cast<EvaluatedStmt *>()) {
|
|
|
|
Eval->~EvaluatedStmt();
|
|
|
|
C.Deallocate(Eval);
|
|
|
|
}
|
|
|
|
}
|
2008-12-18 07:39:55 +08:00
|
|
|
this->~VarDecl();
|
2009-01-28 05:25:57 +08:00
|
|
|
C.Deallocate((void *)this);
|
2008-12-18 07:39:55 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
VarDecl::~VarDecl() {
|
|
|
|
}
|
|
|
|
|
2009-06-20 16:09:14 +08:00
|
|
|
SourceRange VarDecl::getSourceRange() const {
|
|
|
|
if (getInit())
|
|
|
|
return SourceRange(getLocation(), getInit()->getLocEnd());
|
|
|
|
return SourceRange(getLocation(), getLocation());
|
|
|
|
}
|
|
|
|
|
2009-03-11 07:43:53 +08:00
|
|
|
bool VarDecl::isTentativeDefinition(ASTContext &Context) const {
|
|
|
|
if (!isFileVarDecl() || Context.getLangOptions().CPlusPlus)
|
|
|
|
return false;
|
|
|
|
|
2009-04-22 01:11:58 +08:00
|
|
|
const VarDecl *Def = 0;
|
|
|
|
return (!getDefinition(Def) &&
|
2009-03-11 07:43:53 +08:00
|
|
|
(getStorageClass() == None || getStorageClass() == Static));
|
|
|
|
}
|
|
|
|
|
2009-03-21 05:35:28 +08:00
|
|
|
const Expr *VarDecl::getDefinition(const VarDecl *&Def) const {
|
2009-03-11 07:43:53 +08:00
|
|
|
Def = this;
|
|
|
|
while (Def && !Def->getInit())
|
|
|
|
Def = Def->getPreviousDeclaration();
|
|
|
|
|
|
|
|
return Def? Def->getInit() : 0;
|
|
|
|
}
|
|
|
|
|
2008-11-10 07:41:00 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
2008-03-31 08:36:02 +08:00
|
|
|
// FunctionDecl Implementation
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2008-05-20 08:43:19 +08:00
|
|
|
void FunctionDecl::Destroy(ASTContext& C) {
|
2009-04-18 08:07:54 +08:00
|
|
|
if (Body && Body.isOffset())
|
|
|
|
Body.get(C.getExternalSource())->Destroy(C);
|
2008-05-20 11:56:00 +08:00
|
|
|
|
|
|
|
for (param_iterator I=param_begin(), E=param_end(); I!=E; ++I)
|
|
|
|
(*I)->Destroy(C);
|
2009-01-19 03:57:27 +08:00
|
|
|
|
2009-01-28 05:25:57 +08:00
|
|
|
C.Deallocate(ParamInfo);
|
2009-01-19 03:57:27 +08:00
|
|
|
|
2008-05-20 08:43:19 +08:00
|
|
|
Decl::Destroy(C);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-04-27 04:35:05 +08:00
|
|
|
Stmt *FunctionDecl::getBody(ASTContext &Context,
|
|
|
|
const FunctionDecl *&Definition) const {
|
2008-04-21 10:02:58 +08:00
|
|
|
for (const FunctionDecl *FD = this; FD != 0; FD = FD->PreviousDeclaration) {
|
|
|
|
if (FD->Body) {
|
|
|
|
Definition = FD;
|
2009-04-27 04:35:05 +08:00
|
|
|
return FD->Body.get(Context.getExternalSource());
|
2008-04-21 10:02:58 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
2007-01-21 15:42:07 +08:00
|
|
|
}
|
|
|
|
|
2009-04-27 04:35:05 +08:00
|
|
|
Stmt *FunctionDecl::getBodyIfAvailable() const {
|
2009-04-18 08:02:19 +08:00
|
|
|
for (const FunctionDecl *FD = this; FD != 0; FD = FD->PreviousDeclaration) {
|
2009-04-18 08:07:54 +08:00
|
|
|
if (FD->Body && !FD->Body.isOffset()) {
|
2009-04-27 04:35:05 +08:00
|
|
|
return FD->Body.get(0);
|
2009-04-18 08:07:54 +08:00
|
|
|
}
|
2009-04-18 08:02:19 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-06-20 16:09:14 +08:00
|
|
|
void FunctionDecl::setBody(Stmt *B) {
|
|
|
|
Body = B;
|
2009-06-23 01:13:31 +08:00
|
|
|
if (B)
|
2009-06-20 16:09:14 +08:00
|
|
|
EndRangeLoc = B->getLocEnd();
|
|
|
|
}
|
|
|
|
|
2009-02-24 09:23:02 +08:00
|
|
|
bool FunctionDecl::isMain() const {
|
|
|
|
return getDeclContext()->getLookupContext()->isTranslationUnit() &&
|
|
|
|
getIdentifier() && getIdentifier()->isStr("main");
|
|
|
|
}
|
|
|
|
|
2009-03-02 08:19:53 +08:00
|
|
|
bool FunctionDecl::isExternC(ASTContext &Context) const {
|
|
|
|
// In C, any non-static, non-overloadable function has external
|
|
|
|
// linkage.
|
|
|
|
if (!Context.getLangOptions().CPlusPlus)
|
2009-06-30 10:34:44 +08:00
|
|
|
return getStorageClass() != Static && !getAttr<OverloadableAttr>();
|
2009-03-02 08:19:53 +08:00
|
|
|
|
|
|
|
for (const DeclContext *DC = getDeclContext(); !DC->isTranslationUnit();
|
|
|
|
DC = DC->getParent()) {
|
|
|
|
if (const LinkageSpecDecl *Linkage = dyn_cast<LinkageSpecDecl>(DC)) {
|
|
|
|
if (Linkage->getLanguage() == LinkageSpecDecl::lang_c)
|
2009-06-19 00:11:24 +08:00
|
|
|
return getStorageClass() != Static &&
|
2009-06-30 10:34:44 +08:00
|
|
|
!getAttr<OverloadableAttr>();
|
2009-03-02 08:19:53 +08:00
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2009-04-01 00:35:03 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
Implicitly declare certain C library functions (malloc, strcpy, memmove,
etc.) when we perform name lookup on them. This ensures that we
produce the correct signature for these functions, which has two
practical impacts:
1) When we're supporting the "implicit function declaration" feature
of C99, these functions will be implicitly declared with the right
signature rather than as a function returning "int" with no
prototype. See PR3541 for the reason why this is important (hint:
GCC always predeclares these functions).
2) If users attempt to redeclare one of these library functions with
an incompatible signature, we produce a hard error.
This patch does a little bit of work to give reasonable error
messages. For example, when we hit case #1 we complain that we're
implicitly declaring this function with a specific signature, and then
we give a note that asks the user to include the appropriate header
(e.g., "please include <stdlib.h> or explicitly declare 'malloc'"). In
case #2, we show the type of the implicit builtin that was incorrectly
declared, so the user can see the problem. We could do better here:
for example, when displaying this latter error message we say
something like:
'strcpy' was implicitly declared here with type 'char *(char *, char
const *)'
but we should really print out a fake code line showing the
declaration, like this:
'strcpy' was implicitly declared here as:
char *strcpy(char *, char const *)
This would also be good for printing built-in candidates with C++
operator overloading.
The set of C library functions supported by this patch includes all
functions from the C99 specification's <stdlib.h> and <string.h> that
(a) are predefined by GCC and (b) have signatures that could cause
codegen issues if they are treated as functions with no prototype
returning and int. Future work could extend this set of functions to
other C library functions that we know about.
llvm-svn: 64504
2009-02-14 07:20:09 +08:00
|
|
|
/// \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.
|
2009-02-15 02:57:46 +08:00
|
|
|
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.
|
|
|
|
|
2009-02-17 11:23:10 +08:00
|
|
|
// If this is a static function, it's not a builtin.
|
|
|
|
if (getStorageClass() == Static)
|
|
|
|
return 0;
|
|
|
|
|
2009-02-15 02:57:46 +08:00
|
|
|
// 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 &&
|
2009-06-30 10:34:44 +08:00
|
|
|
!getAttr<OverloadableAttr>())
|
2009-02-15 02:57:46 +08:00
|
|
|
return BuiltinID;
|
|
|
|
|
|
|
|
// Not a builtin
|
Implicitly declare certain C library functions (malloc, strcpy, memmove,
etc.) when we perform name lookup on them. This ensures that we
produce the correct signature for these functions, which has two
practical impacts:
1) When we're supporting the "implicit function declaration" feature
of C99, these functions will be implicitly declared with the right
signature rather than as a function returning "int" with no
prototype. See PR3541 for the reason why this is important (hint:
GCC always predeclares these functions).
2) If users attempt to redeclare one of these library functions with
an incompatible signature, we produce a hard error.
This patch does a little bit of work to give reasonable error
messages. For example, when we hit case #1 we complain that we're
implicitly declaring this function with a specific signature, and then
we give a note that asks the user to include the appropriate header
(e.g., "please include <stdlib.h> or explicitly declare 'malloc'"). In
case #2, we show the type of the implicit builtin that was incorrectly
declared, so the user can see the problem. We could do better here:
for example, when displaying this latter error message we say
something like:
'strcpy' was implicitly declared here with type 'char *(char *, char
const *)'
but we should really print out a fake code line showing the
declaration, like this:
'strcpy' was implicitly declared here as:
char *strcpy(char *, char const *)
This would also be good for printing built-in candidates with C++
operator overloading.
The set of C library functions supported by this patch includes all
functions from the C99 specification's <stdlib.h> and <string.h> that
(a) are predefined by GCC and (b) have signatures that could cause
codegen issues if they are treated as functions with no prototype
returning and int. Future work could extend this set of functions to
other C library functions that we know about.
llvm-svn: 64504
2009-02-14 07:20:09 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-04-25 14:03:53 +08:00
|
|
|
/// getNumParams - Return the number of parameters this function must have
|
2009-04-25 14:12:16 +08:00
|
|
|
/// based on its FunctionType. This is the length of the PararmInfo array
|
2009-04-25 14:03:53 +08:00
|
|
|
/// after it has been created.
|
|
|
|
unsigned FunctionDecl::getNumParams() const {
|
2009-04-25 13:56:45 +08:00
|
|
|
const FunctionType *FT = getType()->getAsFunctionType();
|
2009-02-27 07:50:07 +08:00
|
|
|
if (isa<FunctionNoProtoType>(FT))
|
2008-03-15 13:43:15 +08:00
|
|
|
return 0;
|
2009-02-27 07:50:07 +08:00
|
|
|
return cast<FunctionProtoType>(FT)->getNumArgs();
|
2009-04-25 13:56:45 +08:00
|
|
|
|
2007-01-21 15:42:07 +08:00
|
|
|
}
|
|
|
|
|
2009-01-14 08:42:25 +08:00
|
|
|
void FunctionDecl::setParams(ASTContext& C, ParmVarDecl **NewParamInfo,
|
|
|
|
unsigned NumParams) {
|
2007-01-21 15:42:07 +08:00
|
|
|
assert(ParamInfo == 0 && "Already has param info!");
|
2009-04-25 14:12:16 +08:00
|
|
|
assert(NumParams == getNumParams() && "Parameter count mismatch!");
|
2007-01-21 15:42:07 +08:00
|
|
|
|
2007-01-22 03:04:10 +08:00
|
|
|
// Zero params -> null pointer.
|
|
|
|
if (NumParams) {
|
2009-01-28 07:20:32 +08:00
|
|
|
void *Mem = C.Allocate(sizeof(ParmVarDecl*)*NumParams);
|
2009-01-14 08:42:25 +08:00
|
|
|
ParamInfo = new (Mem) ParmVarDecl*[NumParams];
|
2007-06-14 04:44:40 +08:00
|
|
|
memcpy(ParamInfo, NewParamInfo, sizeof(ParmVarDecl*)*NumParams);
|
2009-06-20 16:09:14 +08:00
|
|
|
|
2009-06-23 08:42:00 +08:00
|
|
|
// Update source range. The check below allows us to set EndRangeLoc before
|
|
|
|
// setting the parameters.
|
2009-06-23 08:42:15 +08:00
|
|
|
if (EndRangeLoc.isInvalid() || EndRangeLoc == getLocation())
|
2009-06-20 16:09:14 +08:00
|
|
|
EndRangeLoc = NewParamInfo[NumParams-1]->getLocEnd();
|
2007-01-22 03:04:10 +08:00
|
|
|
}
|
2007-01-21 15:42:07 +08:00
|
|
|
}
|
2007-01-25 12:52:46 +08:00
|
|
|
|
2008-04-10 10:22:51 +08:00
|
|
|
/// 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
|
2008-04-13 07:52:44 +08:00
|
|
|
/// arguments (in C++).
|
2008-04-10 10:22:51 +08:00
|
|
|
unsigned FunctionDecl::getMinRequiredArguments() const {
|
|
|
|
unsigned NumRequiredArgs = getNumParams();
|
|
|
|
while (NumRequiredArgs > 0
|
2009-06-06 12:14:07 +08:00
|
|
|
&& getParamDecl(NumRequiredArgs-1)->hasDefaultArg())
|
2008-04-10 10:22:51 +08:00
|
|
|
--NumRequiredArgs;
|
|
|
|
|
|
|
|
return NumRequiredArgs;
|
|
|
|
}
|
|
|
|
|
2009-06-19 00:11:24 +08:00
|
|
|
bool FunctionDecl::hasActiveGNUInlineAttribute(ASTContext &Context) const {
|
2009-06-30 10:34:44 +08:00
|
|
|
if (!isInline() || !hasAttr<GNUInlineAttr>())
|
2009-04-28 14:37:30 +08:00
|
|
|
return false;
|
|
|
|
|
|
|
|
for (const FunctionDecl *FD = getPreviousDeclaration(); FD;
|
|
|
|
FD = FD->getPreviousDeclaration()) {
|
2009-06-30 10:34:44 +08:00
|
|
|
if (FD->isInline() && !FD->hasAttr<GNUInlineAttr>())
|
2009-04-28 14:37:30 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2009-06-19 00:11:24 +08:00
|
|
|
bool FunctionDecl::isExternGNUInline(ASTContext &Context) const {
|
|
|
|
if (!hasActiveGNUInlineAttribute(Context))
|
2009-04-28 14:37:30 +08:00
|
|
|
return false;
|
|
|
|
|
|
|
|
for (const FunctionDecl *FD = this; FD; FD = FD->getPreviousDeclaration())
|
2009-06-30 10:34:44 +08:00
|
|
|
if (FD->getStorageClass() == Extern && FD->hasAttr<GNUInlineAttr>())
|
2009-04-28 14:37:30 +08:00
|
|
|
return true;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2009-06-30 04:59:39 +08:00
|
|
|
void
|
|
|
|
FunctionDecl::setPreviousDeclaration(FunctionDecl *PrevDecl) {
|
|
|
|
PreviousDeclaration = PrevDecl;
|
|
|
|
|
|
|
|
if (FunctionTemplateDecl *FunTmpl = getDescribedFunctionTemplate()) {
|
|
|
|
FunctionTemplateDecl *PrevFunTmpl
|
|
|
|
= PrevDecl? PrevDecl->getDescribedFunctionTemplate() : 0;
|
|
|
|
assert((!PrevDecl || PrevFunTmpl) && "Function/function template mismatch");
|
|
|
|
FunTmpl->setPreviousDeclaration(PrevFunTmpl);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-11-07 06:13:31 +08:00
|
|
|
/// getOverloadedOperator - Which C++ overloaded operator this
|
|
|
|
/// function represents, if any.
|
|
|
|
OverloadedOperatorKind FunctionDecl::getOverloadedOperator() const {
|
Extend DeclarationName to support C++ overloaded operators, e.g.,
operator+, directly, using the same mechanism as all other special
names.
Removed the "special" identifiers for the overloaded operators from
the identifier table and IdentifierInfo data structure. IdentifierInfo
is back to representing only real identifiers.
Added a new Action, ActOnOperatorFunctionIdExpr, that builds an
expression from an parsed operator-function-id (e.g., "operator
+"). ActOnIdentifierExpr used to do this job, but
operator-function-ids are no longer represented by IdentifierInfo's.
Extended Declarator to store overloaded operator names.
Sema::GetNameForDeclarator now knows how to turn the operator
name into a DeclarationName for the overloaded operator.
Except for (perhaps) consolidating the functionality of
ActOnIdentifier, ActOnOperatorFunctionIdExpr, and
ActOnConversionFunctionExpr into a common routine that builds an
appropriate DeclRefExpr by looking up a DeclarationName, all of the
work on normalizing declaration names should be complete with this
commit.
llvm-svn: 59526
2008-11-18 22:39:36 +08:00
|
|
|
if (getDeclName().getNameKind() == DeclarationName::CXXOperatorName)
|
|
|
|
return getDeclName().getCXXOverloadedOperator();
|
2008-11-07 06:13:31 +08:00
|
|
|
else
|
|
|
|
return OO_None;
|
|
|
|
}
|
|
|
|
|
2009-06-30 01:30:29 +08:00
|
|
|
FunctionTemplateDecl *FunctionDecl::getPrimaryTemplate() const {
|
|
|
|
if (FunctionTemplateSpecializationInfo *Info
|
|
|
|
= TemplateOrSpecialization
|
|
|
|
.dyn_cast<FunctionTemplateSpecializationInfo*>()) {
|
2009-06-30 06:39:32 +08:00
|
|
|
return Info->Template.getPointer();
|
2009-06-30 01:30:29 +08:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
const TemplateArgumentList *
|
|
|
|
FunctionDecl::getTemplateSpecializationArgs() const {
|
|
|
|
if (FunctionTemplateSpecializationInfo *Info
|
|
|
|
= TemplateOrSpecialization
|
|
|
|
.dyn_cast<FunctionTemplateSpecializationInfo*>()) {
|
|
|
|
return Info->TemplateArguments;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-06-26 08:10:03 +08:00
|
|
|
void
|
|
|
|
FunctionDecl::setFunctionTemplateSpecialization(ASTContext &Context,
|
|
|
|
FunctionTemplateDecl *Template,
|
2009-06-30 04:59:39 +08:00
|
|
|
const TemplateArgumentList *TemplateArgs,
|
|
|
|
void *InsertPos) {
|
2009-06-30 01:30:29 +08:00
|
|
|
FunctionTemplateSpecializationInfo *Info
|
|
|
|
= TemplateOrSpecialization.dyn_cast<FunctionTemplateSpecializationInfo*>();
|
2009-06-26 08:10:03 +08:00
|
|
|
if (!Info)
|
2009-06-30 01:30:29 +08:00
|
|
|
Info = new (Context) FunctionTemplateSpecializationInfo;
|
2009-06-26 08:10:03 +08:00
|
|
|
|
2009-06-30 04:59:39 +08:00
|
|
|
Info->Function = this;
|
2009-06-30 06:39:32 +08:00
|
|
|
Info->Template.setPointer(Template);
|
|
|
|
Info->Template.setInt(0); // Implicit instantiation, unless told otherwise
|
2009-06-26 08:10:03 +08:00
|
|
|
Info->TemplateArguments = TemplateArgs;
|
|
|
|
TemplateOrSpecialization = Info;
|
2009-06-30 04:59:39 +08:00
|
|
|
|
|
|
|
// Insert this function template specialization into the set of known
|
|
|
|
// function template specialiations.
|
|
|
|
Template->getSpecializations().InsertNode(Info, InsertPos);
|
2009-06-26 08:10:03 +08:00
|
|
|
}
|
|
|
|
|
2009-06-30 06:39:32 +08:00
|
|
|
bool FunctionDecl::isExplicitSpecialization() const {
|
|
|
|
// FIXME: check this property for explicit specializations of member
|
|
|
|
// functions of class templates.
|
|
|
|
FunctionTemplateSpecializationInfo *Info
|
|
|
|
= TemplateOrSpecialization.dyn_cast<FunctionTemplateSpecializationInfo*>();
|
|
|
|
if (!Info)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return Info->isExplicitSpecialization();
|
|
|
|
}
|
|
|
|
|
|
|
|
void FunctionDecl::setExplicitSpecialization(bool ES) {
|
|
|
|
// FIXME: set this property for explicit specializations of member functions
|
|
|
|
// of class templates.
|
|
|
|
FunctionTemplateSpecializationInfo *Info
|
|
|
|
= TemplateOrSpecialization.dyn_cast<FunctionTemplateSpecializationInfo*>();
|
|
|
|
if (Info)
|
|
|
|
Info->setExplicitSpecialization(ES);
|
|
|
|
}
|
|
|
|
|
Change struct forward declarations and definitions to use unique RecordDecls, as opposed to creating a single RecordDecl and reusing it.
This change effects both RecordDecls and CXXRecordDecls, but does not effect EnumDecls (yet).
The motivation of this patch is as follows:
- Capture more source information, necessary for refactoring/rewriting clients.
- Pave the way to resolve ownership issues with RecordDecls with the forthcoming
addition of DeclGroups.
Current caveats:
- Until DeclGroups are in place, we will leak RecordDecls not explicitly
referenced by the AST. For example:
typedef struct { ... } x;
The RecordDecl for the struct will be leaked because the TypedefDecl doesn't
refer to it. This will be solved with DeclGroups.
- This patch also (temporarily) breaks CodeGen. More below.
High-level changes:
- As before, TagType still refers to a TagDecl, but it doesn't own it. When
a struct/union/class is first referenced, a RecordType and RecordDecl are
created for it, and the RecordType refers to that RecordDecl. Later, if
a new RecordDecl is created, the pointer to a RecordDecl in RecordType is
updated to point to the RecordDecl that defines the struct/union/class.
- TagDecl and RecordDecl now how a method 'getDefinition()' to return the
TagDecl*/RecordDecl* that refers to the TagDecl* that defines a particular
enum/struct/class/union. This is useful from going from a RecordDecl* that
defines a forward declaration to the RecordDecl* that provides the actual
definition. Note that this also works for EnumDecls, except that in this case
there is no distinction between forward declarations and definitions (yet).
- Clients should no longer assume that 'isDefinition()' returns true from a
RecordDecl if the corresponding struct/union/class has been defined.
isDefinition() only returns true if a particular RecordDecl is the defining
Decl. Use 'getDefinition()' instead to determine if a struct has been defined.
- The main changes to Sema happen in ActOnTag. To make the changes more
incremental, I split off the processing of enums and structs et al into two
code paths. Enums use the original code path (which is in ActOnTag) and
structs use the ActOnTagStruct. Eventually the two code paths will be merged,
but the idea was to preserve the original logic both for comparison and not to
change the logic for both enums and structs all at once.
- There is NO CHAINING of RecordDecls for the same RecordType. All RecordDecls
that correspond to the same type simply have a pointer to that type. If we
need to figure out what are all the RecordDecls for a given type we can build
a backmap.
- The diff in CXXRecordDecl.[cpp,h] is actually very small; it just mimics the
changes to RecordDecl. For some reason 'svn' marks the entire file as changed.
Why is CodeGen broken:
- Codegen assumes that there is an equivalence between RecordDecl* and
RecordType*. This was true before because we only created one RecordDecl* for
a given RecordType*, but it is no longer true. I believe this shouldn't be too
hard to change, but the patch was big enough as it is.
I have tested this patch on both the clang test suite, and by running the static analyzer over Postgresql and a large Apple-internal project (mix of Objective-C and C).
llvm-svn: 55839
2008-09-06 01:16:31 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
2009-01-07 08:43:41 +08:00
|
|
|
// TagDecl Implementation
|
Change struct forward declarations and definitions to use unique RecordDecls, as opposed to creating a single RecordDecl and reusing it.
This change effects both RecordDecls and CXXRecordDecls, but does not effect EnumDecls (yet).
The motivation of this patch is as follows:
- Capture more source information, necessary for refactoring/rewriting clients.
- Pave the way to resolve ownership issues with RecordDecls with the forthcoming
addition of DeclGroups.
Current caveats:
- Until DeclGroups are in place, we will leak RecordDecls not explicitly
referenced by the AST. For example:
typedef struct { ... } x;
The RecordDecl for the struct will be leaked because the TypedefDecl doesn't
refer to it. This will be solved with DeclGroups.
- This patch also (temporarily) breaks CodeGen. More below.
High-level changes:
- As before, TagType still refers to a TagDecl, but it doesn't own it. When
a struct/union/class is first referenced, a RecordType and RecordDecl are
created for it, and the RecordType refers to that RecordDecl. Later, if
a new RecordDecl is created, the pointer to a RecordDecl in RecordType is
updated to point to the RecordDecl that defines the struct/union/class.
- TagDecl and RecordDecl now how a method 'getDefinition()' to return the
TagDecl*/RecordDecl* that refers to the TagDecl* that defines a particular
enum/struct/class/union. This is useful from going from a RecordDecl* that
defines a forward declaration to the RecordDecl* that provides the actual
definition. Note that this also works for EnumDecls, except that in this case
there is no distinction between forward declarations and definitions (yet).
- Clients should no longer assume that 'isDefinition()' returns true from a
RecordDecl if the corresponding struct/union/class has been defined.
isDefinition() only returns true if a particular RecordDecl is the defining
Decl. Use 'getDefinition()' instead to determine if a struct has been defined.
- The main changes to Sema happen in ActOnTag. To make the changes more
incremental, I split off the processing of enums and structs et al into two
code paths. Enums use the original code path (which is in ActOnTag) and
structs use the ActOnTagStruct. Eventually the two code paths will be merged,
but the idea was to preserve the original logic both for comparison and not to
change the logic for both enums and structs all at once.
- There is NO CHAINING of RecordDecls for the same RecordType. All RecordDecls
that correspond to the same type simply have a pointer to that type. If we
need to figure out what are all the RecordDecls for a given type we can build
a backmap.
- The diff in CXXRecordDecl.[cpp,h] is actually very small; it just mimics the
changes to RecordDecl. For some reason 'svn' marks the entire file as changed.
Why is CodeGen broken:
- Codegen assumes that there is an equivalence between RecordDecl* and
RecordType*. This was true before because we only created one RecordDecl* for
a given RecordType*, but it is no longer true. I believe this shouldn't be too
hard to change, but the patch was big enough as it is.
I have tested this patch on both the clang test suite, and by running the static analyzer over Postgresql and a large Apple-internal project (mix of Objective-C and C).
llvm-svn: 55839
2008-09-06 01:16:31 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2009-01-17 08:42:38 +08:00
|
|
|
void TagDecl::startDefinition() {
|
2009-02-27 06:19:44 +08:00
|
|
|
TagType *TagT = const_cast<TagType *>(TypeForDecl->getAsTagType());
|
|
|
|
TagT->decl.setPointer(this);
|
|
|
|
TagT->getAsTagType()->decl.setInt(1);
|
2009-01-17 08:42:38 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void TagDecl::completeDefinition() {
|
|
|
|
assert((!TypeForDecl ||
|
2009-02-27 06:19:44 +08:00
|
|
|
TypeForDecl->getAsTagType()->decl.getPointer() == this) &&
|
2009-01-17 08:42:38 +08:00
|
|
|
"Attempt to redefine a tag definition?");
|
|
|
|
IsDefinition = true;
|
2009-02-27 06:19:44 +08:00
|
|
|
TagType *TagT = const_cast<TagType *>(TypeForDecl->getAsTagType());
|
|
|
|
TagT->decl.setPointer(this);
|
|
|
|
TagT->decl.setInt(0);
|
2009-01-17 08:42:38 +08:00
|
|
|
}
|
|
|
|
|
Change struct forward declarations and definitions to use unique RecordDecls, as opposed to creating a single RecordDecl and reusing it.
This change effects both RecordDecls and CXXRecordDecls, but does not effect EnumDecls (yet).
The motivation of this patch is as follows:
- Capture more source information, necessary for refactoring/rewriting clients.
- Pave the way to resolve ownership issues with RecordDecls with the forthcoming
addition of DeclGroups.
Current caveats:
- Until DeclGroups are in place, we will leak RecordDecls not explicitly
referenced by the AST. For example:
typedef struct { ... } x;
The RecordDecl for the struct will be leaked because the TypedefDecl doesn't
refer to it. This will be solved with DeclGroups.
- This patch also (temporarily) breaks CodeGen. More below.
High-level changes:
- As before, TagType still refers to a TagDecl, but it doesn't own it. When
a struct/union/class is first referenced, a RecordType and RecordDecl are
created for it, and the RecordType refers to that RecordDecl. Later, if
a new RecordDecl is created, the pointer to a RecordDecl in RecordType is
updated to point to the RecordDecl that defines the struct/union/class.
- TagDecl and RecordDecl now how a method 'getDefinition()' to return the
TagDecl*/RecordDecl* that refers to the TagDecl* that defines a particular
enum/struct/class/union. This is useful from going from a RecordDecl* that
defines a forward declaration to the RecordDecl* that provides the actual
definition. Note that this also works for EnumDecls, except that in this case
there is no distinction between forward declarations and definitions (yet).
- Clients should no longer assume that 'isDefinition()' returns true from a
RecordDecl if the corresponding struct/union/class has been defined.
isDefinition() only returns true if a particular RecordDecl is the defining
Decl. Use 'getDefinition()' instead to determine if a struct has been defined.
- The main changes to Sema happen in ActOnTag. To make the changes more
incremental, I split off the processing of enums and structs et al into two
code paths. Enums use the original code path (which is in ActOnTag) and
structs use the ActOnTagStruct. Eventually the two code paths will be merged,
but the idea was to preserve the original logic both for comparison and not to
change the logic for both enums and structs all at once.
- There is NO CHAINING of RecordDecls for the same RecordType. All RecordDecls
that correspond to the same type simply have a pointer to that type. If we
need to figure out what are all the RecordDecls for a given type we can build
a backmap.
- The diff in CXXRecordDecl.[cpp,h] is actually very small; it just mimics the
changes to RecordDecl. For some reason 'svn' marks the entire file as changed.
Why is CodeGen broken:
- Codegen assumes that there is an equivalence between RecordDecl* and
RecordType*. This was true before because we only created one RecordDecl* for
a given RecordType*, but it is no longer true. I believe this shouldn't be too
hard to change, but the patch was big enough as it is.
I have tested this patch on both the clang test suite, and by running the static analyzer over Postgresql and a large Apple-internal project (mix of Objective-C and C).
llvm-svn: 55839
2008-09-06 01:16:31 +08:00
|
|
|
TagDecl* TagDecl::getDefinition(ASTContext& C) const {
|
|
|
|
QualType T = C.getTypeDeclType(const_cast<TagDecl*>(this));
|
2009-02-27 06:19:44 +08:00
|
|
|
TagDecl* D = cast<TagDecl>(T->getAsTagType()->getDecl());
|
Change struct forward declarations and definitions to use unique RecordDecls, as opposed to creating a single RecordDecl and reusing it.
This change effects both RecordDecls and CXXRecordDecls, but does not effect EnumDecls (yet).
The motivation of this patch is as follows:
- Capture more source information, necessary for refactoring/rewriting clients.
- Pave the way to resolve ownership issues with RecordDecls with the forthcoming
addition of DeclGroups.
Current caveats:
- Until DeclGroups are in place, we will leak RecordDecls not explicitly
referenced by the AST. For example:
typedef struct { ... } x;
The RecordDecl for the struct will be leaked because the TypedefDecl doesn't
refer to it. This will be solved with DeclGroups.
- This patch also (temporarily) breaks CodeGen. More below.
High-level changes:
- As before, TagType still refers to a TagDecl, but it doesn't own it. When
a struct/union/class is first referenced, a RecordType and RecordDecl are
created for it, and the RecordType refers to that RecordDecl. Later, if
a new RecordDecl is created, the pointer to a RecordDecl in RecordType is
updated to point to the RecordDecl that defines the struct/union/class.
- TagDecl and RecordDecl now how a method 'getDefinition()' to return the
TagDecl*/RecordDecl* that refers to the TagDecl* that defines a particular
enum/struct/class/union. This is useful from going from a RecordDecl* that
defines a forward declaration to the RecordDecl* that provides the actual
definition. Note that this also works for EnumDecls, except that in this case
there is no distinction between forward declarations and definitions (yet).
- Clients should no longer assume that 'isDefinition()' returns true from a
RecordDecl if the corresponding struct/union/class has been defined.
isDefinition() only returns true if a particular RecordDecl is the defining
Decl. Use 'getDefinition()' instead to determine if a struct has been defined.
- The main changes to Sema happen in ActOnTag. To make the changes more
incremental, I split off the processing of enums and structs et al into two
code paths. Enums use the original code path (which is in ActOnTag) and
structs use the ActOnTagStruct. Eventually the two code paths will be merged,
but the idea was to preserve the original logic both for comparison and not to
change the logic for both enums and structs all at once.
- There is NO CHAINING of RecordDecls for the same RecordType. All RecordDecls
that correspond to the same type simply have a pointer to that type. If we
need to figure out what are all the RecordDecls for a given type we can build
a backmap.
- The diff in CXXRecordDecl.[cpp,h] is actually very small; it just mimics the
changes to RecordDecl. For some reason 'svn' marks the entire file as changed.
Why is CodeGen broken:
- Codegen assumes that there is an equivalence between RecordDecl* and
RecordType*. This was true before because we only created one RecordDecl* for
a given RecordType*, but it is no longer true. I believe this shouldn't be too
hard to change, but the patch was big enough as it is.
I have tested this patch on both the clang test suite, and by running the static analyzer over Postgresql and a large Apple-internal project (mix of Objective-C and C).
llvm-svn: 55839
2008-09-06 01:16:31 +08:00
|
|
|
return D->isDefinition() ? D : 0;
|
|
|
|
}
|
|
|
|
|
2008-03-31 08:36:02 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// RecordDecl Implementation
|
|
|
|
//===----------------------------------------------------------------------===//
|
2007-01-25 12:52:46 +08:00
|
|
|
|
2008-10-15 08:42:39 +08:00
|
|
|
RecordDecl::RecordDecl(Kind DK, TagKind TK, DeclContext *DC, SourceLocation L,
|
2008-09-05 09:34:33 +08:00
|
|
|
IdentifierInfo *Id)
|
2009-01-20 09:17:11 +08:00
|
|
|
: TagDecl(DK, TK, DC, L, Id) {
|
2008-09-03 05:12:32 +08:00
|
|
|
HasFlexibleArrayMember = false;
|
2009-01-07 08:43:41 +08:00
|
|
|
AnonymousStructOrUnion = false;
|
2008-09-03 05:12:32 +08:00
|
|
|
assert(classof(static_cast<Decl*>(this)) && "Invalid Kind!");
|
|
|
|
}
|
|
|
|
|
|
|
|
RecordDecl *RecordDecl::Create(ASTContext &C, TagKind TK, DeclContext *DC,
|
Change struct forward declarations and definitions to use unique RecordDecls, as opposed to creating a single RecordDecl and reusing it.
This change effects both RecordDecls and CXXRecordDecls, but does not effect EnumDecls (yet).
The motivation of this patch is as follows:
- Capture more source information, necessary for refactoring/rewriting clients.
- Pave the way to resolve ownership issues with RecordDecls with the forthcoming
addition of DeclGroups.
Current caveats:
- Until DeclGroups are in place, we will leak RecordDecls not explicitly
referenced by the AST. For example:
typedef struct { ... } x;
The RecordDecl for the struct will be leaked because the TypedefDecl doesn't
refer to it. This will be solved with DeclGroups.
- This patch also (temporarily) breaks CodeGen. More below.
High-level changes:
- As before, TagType still refers to a TagDecl, but it doesn't own it. When
a struct/union/class is first referenced, a RecordType and RecordDecl are
created for it, and the RecordType refers to that RecordDecl. Later, if
a new RecordDecl is created, the pointer to a RecordDecl in RecordType is
updated to point to the RecordDecl that defines the struct/union/class.
- TagDecl and RecordDecl now how a method 'getDefinition()' to return the
TagDecl*/RecordDecl* that refers to the TagDecl* that defines a particular
enum/struct/class/union. This is useful from going from a RecordDecl* that
defines a forward declaration to the RecordDecl* that provides the actual
definition. Note that this also works for EnumDecls, except that in this case
there is no distinction between forward declarations and definitions (yet).
- Clients should no longer assume that 'isDefinition()' returns true from a
RecordDecl if the corresponding struct/union/class has been defined.
isDefinition() only returns true if a particular RecordDecl is the defining
Decl. Use 'getDefinition()' instead to determine if a struct has been defined.
- The main changes to Sema happen in ActOnTag. To make the changes more
incremental, I split off the processing of enums and structs et al into two
code paths. Enums use the original code path (which is in ActOnTag) and
structs use the ActOnTagStruct. Eventually the two code paths will be merged,
but the idea was to preserve the original logic both for comparison and not to
change the logic for both enums and structs all at once.
- There is NO CHAINING of RecordDecls for the same RecordType. All RecordDecls
that correspond to the same type simply have a pointer to that type. If we
need to figure out what are all the RecordDecls for a given type we can build
a backmap.
- The diff in CXXRecordDecl.[cpp,h] is actually very small; it just mimics the
changes to RecordDecl. For some reason 'svn' marks the entire file as changed.
Why is CodeGen broken:
- Codegen assumes that there is an equivalence between RecordDecl* and
RecordType*. This was true before because we only created one RecordDecl* for
a given RecordType*, but it is no longer true. I believe this shouldn't be too
hard to change, but the patch was big enough as it is.
I have tested this patch on both the clang test suite, and by running the static analyzer over Postgresql and a large Apple-internal project (mix of Objective-C and C).
llvm-svn: 55839
2008-09-06 01:16:31 +08:00
|
|
|
SourceLocation L, IdentifierInfo *Id,
|
|
|
|
RecordDecl* PrevDecl) {
|
2008-09-05 09:34:33 +08:00
|
|
|
|
2009-01-28 05:25:57 +08:00
|
|
|
RecordDecl* R = new (C) RecordDecl(Record, TK, DC, L, Id);
|
Change struct forward declarations and definitions to use unique RecordDecls, as opposed to creating a single RecordDecl and reusing it.
This change effects both RecordDecls and CXXRecordDecls, but does not effect EnumDecls (yet).
The motivation of this patch is as follows:
- Capture more source information, necessary for refactoring/rewriting clients.
- Pave the way to resolve ownership issues with RecordDecls with the forthcoming
addition of DeclGroups.
Current caveats:
- Until DeclGroups are in place, we will leak RecordDecls not explicitly
referenced by the AST. For example:
typedef struct { ... } x;
The RecordDecl for the struct will be leaked because the TypedefDecl doesn't
refer to it. This will be solved with DeclGroups.
- This patch also (temporarily) breaks CodeGen. More below.
High-level changes:
- As before, TagType still refers to a TagDecl, but it doesn't own it. When
a struct/union/class is first referenced, a RecordType and RecordDecl are
created for it, and the RecordType refers to that RecordDecl. Later, if
a new RecordDecl is created, the pointer to a RecordDecl in RecordType is
updated to point to the RecordDecl that defines the struct/union/class.
- TagDecl and RecordDecl now how a method 'getDefinition()' to return the
TagDecl*/RecordDecl* that refers to the TagDecl* that defines a particular
enum/struct/class/union. This is useful from going from a RecordDecl* that
defines a forward declaration to the RecordDecl* that provides the actual
definition. Note that this also works for EnumDecls, except that in this case
there is no distinction between forward declarations and definitions (yet).
- Clients should no longer assume that 'isDefinition()' returns true from a
RecordDecl if the corresponding struct/union/class has been defined.
isDefinition() only returns true if a particular RecordDecl is the defining
Decl. Use 'getDefinition()' instead to determine if a struct has been defined.
- The main changes to Sema happen in ActOnTag. To make the changes more
incremental, I split off the processing of enums and structs et al into two
code paths. Enums use the original code path (which is in ActOnTag) and
structs use the ActOnTagStruct. Eventually the two code paths will be merged,
but the idea was to preserve the original logic both for comparison and not to
change the logic for both enums and structs all at once.
- There is NO CHAINING of RecordDecls for the same RecordType. All RecordDecls
that correspond to the same type simply have a pointer to that type. If we
need to figure out what are all the RecordDecls for a given type we can build
a backmap.
- The diff in CXXRecordDecl.[cpp,h] is actually very small; it just mimics the
changes to RecordDecl. For some reason 'svn' marks the entire file as changed.
Why is CodeGen broken:
- Codegen assumes that there is an equivalence between RecordDecl* and
RecordType*. This was true before because we only created one RecordDecl* for
a given RecordType*, but it is no longer true. I believe this shouldn't be too
hard to change, but the patch was big enough as it is.
I have tested this patch on both the clang test suite, and by running the static analyzer over Postgresql and a large Apple-internal project (mix of Objective-C and C).
llvm-svn: 55839
2008-09-06 01:16:31 +08:00
|
|
|
C.getTypeDeclType(R, PrevDecl);
|
|
|
|
return R;
|
2008-09-03 05:12:32 +08:00
|
|
|
}
|
|
|
|
|
2008-08-08 22:08:55 +08:00
|
|
|
RecordDecl::~RecordDecl() {
|
|
|
|
}
|
|
|
|
|
|
|
|
void RecordDecl::Destroy(ASTContext& C) {
|
|
|
|
TagDecl::Destroy(C);
|
|
|
|
}
|
|
|
|
|
2009-03-25 23:59:44 +08:00
|
|
|
bool RecordDecl::isInjectedClassName() const {
|
|
|
|
return isImplicit() && getDeclName() && getDeclContext()->isRecord() &&
|
|
|
|
cast<RecordDecl>(getDeclContext())->getDeclName() == getDeclName();
|
|
|
|
}
|
|
|
|
|
2008-12-12 00:49:14 +08:00
|
|
|
/// completeDefinition - Notes that the definition of this type is now
|
|
|
|
/// complete.
|
|
|
|
void RecordDecl::completeDefinition(ASTContext& C) {
|
2007-01-25 12:52:46 +08:00
|
|
|
assert(!isDefinition() && "Cannot redefine record!");
|
2009-01-17 08:42:38 +08:00
|
|
|
TagDecl::completeDefinition();
|
2007-01-25 12:52:46 +08:00
|
|
|
}
|
2007-03-27 07:09:51 +08:00
|
|
|
|
2008-10-09 01:01:13 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// 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);
|
2009-03-14 07:17:24 +08:00
|
|
|
|
|
|
|
C.Deallocate(ParamInfo);
|
2008-10-09 01:01:13 +08:00
|
|
|
Decl::Destroy(C);
|
|
|
|
}
|
2009-03-14 00:56:44 +08:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|