2006-10-15 22:34:45 +00:00
|
|
|
//===--- Decl.cpp - Declaration AST Node Implementation -------------------===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
2007-12-29 19:59:25 +00:00
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
2006-10-15 22:34:45 +00:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
2008-06-04 13:04:04 +00:00
|
|
|
// This file implements the Decl subclasses.
|
2006-10-15 22:34:45 +00:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "clang/AST/Decl.h"
|
2009-02-03 19:21:40 +00:00
|
|
|
#include "clang/AST/DeclCXX.h"
|
2009-02-22 19:35:57 +00:00
|
|
|
#include "clang/AST/DeclObjC.h"
|
2009-05-10 22:57:19 +00:00
|
|
|
#include "clang/AST/DeclTemplate.h"
|
2008-03-15 06:12:44 +00:00
|
|
|
#include "clang/AST/ASTContext.h"
|
2009-08-19 01:27:32 +00:00
|
|
|
#include "clang/AST/TypeLoc.h"
|
2008-08-11 04:54:23 +00:00
|
|
|
#include "clang/AST/Stmt.h"
|
2008-12-17 23:39:55 +00:00
|
|
|
#include "clang/AST/Expr.h"
|
2009-05-29 20:38:28 +00:00
|
|
|
#include "clang/AST/PrettyPrinter.h"
|
2009-06-14 01:54:56 +00:00
|
|
|
#include "clang/Basic/Builtins.h"
|
2008-08-11 04:54:23 +00:00
|
|
|
#include "clang/Basic/IdentifierTable.h"
|
2009-09-04 01:14:41 +00:00
|
|
|
#include "clang/Parse/DeclSpec.h"
|
|
|
|
#include "llvm/Support/ErrorHandling.h"
|
2009-02-04 17:27:36 +00:00
|
|
|
#include <vector>
|
2008-05-20 00:43:19 +00:00
|
|
|
|
2006-10-25 05:11:20 +00:00
|
|
|
using namespace clang;
|
2006-10-15 22:34:45 +00:00
|
|
|
|
2009-03-04 06:34:08 +00:00
|
|
|
void Attr::Destroy(ASTContext &C) {
|
|
|
|
if (Next) {
|
|
|
|
Next->Destroy(C);
|
|
|
|
Next = 0;
|
|
|
|
}
|
|
|
|
this->~Attr();
|
|
|
|
C.Deallocate((void*)this);
|
|
|
|
}
|
|
|
|
|
2009-08-19 01:27:32 +00:00
|
|
|
/// \brief Return the TypeLoc wrapper for the type source info.
|
2009-12-07 02:54:59 +00:00
|
|
|
TypeLoc TypeSourceInfo::getTypeLoc() const {
|
2009-09-29 19:40:20 +00:00
|
|
|
return TypeLoc(Ty, (void*)(this + 1));
|
2009-08-19 01:27:32 +00:00
|
|
|
}
|
2009-03-04 06:34:08 +00:00
|
|
|
|
2008-03-15 06:12:44 +00:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Decl Allocation/Deallocation Method Implementations
|
|
|
|
//===----------------------------------------------------------------------===//
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-03-04 06:34:08 +00:00
|
|
|
|
2008-04-17 14:40:12 +00:00
|
|
|
TranslationUnitDecl *TranslationUnitDecl::Create(ASTContext &C) {
|
2009-06-29 17:38:40 +00:00
|
|
|
return new (C) TranslationUnitDecl(C);
|
2008-04-17 14:40:12 +00:00
|
|
|
}
|
|
|
|
|
2008-04-27 13:50:30 +00:00
|
|
|
NamespaceDecl *NamespaceDecl::Create(ASTContext &C, DeclContext *DC,
|
|
|
|
SourceLocation L, IdentifierInfo *Id) {
|
2009-01-27 21:25:57 +00:00
|
|
|
return new (C) NamespaceDecl(DC, L, Id);
|
2008-04-27 13:50:30 +00:00
|
|
|
}
|
|
|
|
|
2008-05-20 04:49:55 +00:00
|
|
|
void NamespaceDecl::Destroy(ASTContext& C) {
|
|
|
|
// NamespaceDecl uses "NextDeclarator" to chain namespace declarations
|
|
|
|
// together. They are all top-level Decls.
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2008-05-24 15:09:56 +00:00
|
|
|
this->~NamespaceDecl();
|
2009-01-27 21:25:57 +00:00
|
|
|
C.Deallocate((void *)this);
|
2008-05-20 04:49:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-06-17 18:05:57 +00:00
|
|
|
ImplicitParamDecl *ImplicitParamDecl::Create(ASTContext &C, DeclContext *DC,
|
2009-01-20 01:17:11 +00:00
|
|
|
SourceLocation L, IdentifierInfo *Id, QualType T) {
|
2009-01-27 21:25:57 +00:00
|
|
|
return new (C) ImplicitParamDecl(ImplicitParam, DC, L, Id, T);
|
2008-06-17 18:05:57 +00:00
|
|
|
}
|
|
|
|
|
2009-04-14 02:08:49 +00: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;
|
2009-09-09 15:08:12 +00:00
|
|
|
case VarDecl::PrivateExtern: return "__private_extern__"; break;
|
2009-04-14 02:08:49 +00:00
|
|
|
case VarDecl::Register: return "register"; break;
|
2009-09-09 15:08:12 +00:00
|
|
|
case VarDecl::Static: return "static"; break;
|
2009-04-14 02:08:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
assert(0 && "Invalid storage class");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-04-22 18:39:57 +00:00
|
|
|
ParmVarDecl *ParmVarDecl::Create(ASTContext &C, DeclContext *DC,
|
2008-04-04 06:12:32 +00:00
|
|
|
SourceLocation L, IdentifierInfo *Id,
|
2009-12-07 02:54:59 +00:00
|
|
|
QualType T, TypeSourceInfo *TInfo,
|
2009-08-19 01:27:57 +00:00
|
|
|
StorageClass S, Expr *DefArg) {
|
2009-12-07 02:54:59 +00:00
|
|
|
return new (C) ParmVarDecl(ParmVar, DC, L, Id, T, TInfo, S, DefArg);
|
2008-12-20 23:29:59 +00:00
|
|
|
}
|
|
|
|
|
2009-09-11 18:44:32 +00:00
|
|
|
SourceRange ParmVarDecl::getDefaultArgRange() const {
|
|
|
|
if (const Expr *E = getInit())
|
|
|
|
return E->getSourceRange();
|
|
|
|
|
2009-12-13 17:53:43 +00:00
|
|
|
if (hasUninstantiatedDefaultArg())
|
|
|
|
return getUninstantiatedDefaultArg()->getSourceRange();
|
2009-09-11 18:44:32 +00:00
|
|
|
|
|
|
|
return SourceRange();
|
|
|
|
}
|
2009-05-26 18:54:04 +00:00
|
|
|
|
2009-09-11 18:44:32 +00:00
|
|
|
void VarDecl::setInit(ASTContext &C, Expr *I) {
|
|
|
|
if (EvaluatedStmt *Eval = Init.dyn_cast<EvaluatedStmt *>()) {
|
|
|
|
Eval->~EvaluatedStmt();
|
|
|
|
C.Deallocate(Eval);
|
2009-05-26 18:54:04 +00:00
|
|
|
}
|
|
|
|
|
2009-09-11 18:44:32 +00:00
|
|
|
Init = I;
|
|
|
|
}
|
|
|
|
|
2009-09-12 00:17:51 +00:00
|
|
|
bool VarDecl::isExternC() const {
|
|
|
|
ASTContext &Context = getASTContext();
|
2009-03-02 00:19:53 +00:00
|
|
|
if (!Context.getLangOptions().CPlusPlus)
|
2009-09-09 15:08:12 +00:00
|
|
|
return (getDeclContext()->isTranslationUnit() &&
|
2009-03-02 00:19:53 +00:00
|
|
|
getStorageClass() != Static) ||
|
|
|
|
(getDeclContext()->isFunctionOrMethod() && hasExternalStorage());
|
|
|
|
|
2009-09-09 15:08:12 +00:00
|
|
|
for (const DeclContext *DC = getDeclContext(); !DC->isTranslationUnit();
|
2009-03-02 00:19:53 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2008-04-22 18:39:57 +00:00
|
|
|
FunctionDecl *FunctionDecl::Create(ASTContext &C, DeclContext *DC,
|
2009-09-09 15:08:12 +00:00
|
|
|
SourceLocation L,
|
2009-08-19 01:27:57 +00:00
|
|
|
DeclarationName N, QualType T,
|
2009-12-07 02:54:59 +00:00
|
|
|
TypeSourceInfo *TInfo,
|
2009-09-09 15:08:12 +00:00
|
|
|
StorageClass S, bool isInline,
|
2009-08-21 00:31:54 +00:00
|
|
|
bool hasWrittenPrototype) {
|
2009-09-09 15:08:12 +00:00
|
|
|
FunctionDecl *New
|
2009-12-07 02:54:59 +00:00
|
|
|
= new (C) FunctionDecl(Function, DC, L, N, T, TInfo, S, isInline);
|
2009-05-14 21:46:00 +00:00
|
|
|
New->HasWrittenPrototype = hasWrittenPrototype;
|
2009-02-25 16:33:18 +00:00
|
|
|
return New;
|
2008-03-15 21:24:04 +00:00
|
|
|
}
|
|
|
|
|
2008-10-10 01:28:17 +00:00
|
|
|
BlockDecl *BlockDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L) {
|
2009-01-27 21:25:57 +00:00
|
|
|
return new (C) BlockDecl(DC, L);
|
2008-10-08 17:01:13 +00:00
|
|
|
}
|
|
|
|
|
2008-12-11 16:49:14 +00:00
|
|
|
FieldDecl *FieldDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L,
|
2009-08-19 01:27:57 +00:00
|
|
|
IdentifierInfo *Id, QualType T,
|
2009-12-07 02:54:59 +00:00
|
|
|
TypeSourceInfo *TInfo, Expr *BW, bool Mutable) {
|
|
|
|
return new (C) FieldDecl(Decl::Field, DC, L, Id, T, TInfo, BW, Mutable);
|
2008-03-16 00:16:02 +00:00
|
|
|
}
|
|
|
|
|
2009-01-07 19:46:03 +00:00
|
|
|
bool FieldDecl::isAnonymousStructOrUnion() const {
|
|
|
|
if (!isImplicit() || getDeclName())
|
|
|
|
return false;
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-07-29 21:53:49 +00:00
|
|
|
if (const RecordType *Record = getType()->getAs<RecordType>())
|
2009-01-07 19:46:03 +00:00
|
|
|
return Record->getDecl()->isAnonymousStructOrUnion();
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
2008-03-15 21:24:04 +00:00
|
|
|
|
2008-04-04 06:12:32 +00:00
|
|
|
EnumConstantDecl *EnumConstantDecl::Create(ASTContext &C, EnumDecl *CD,
|
|
|
|
SourceLocation L,
|
2008-03-15 21:32:50 +00:00
|
|
|
IdentifierInfo *Id, QualType T,
|
2009-01-20 01:17:11 +00:00
|
|
|
Expr *E, const llvm::APSInt &V) {
|
2009-01-27 21:25:57 +00:00
|
|
|
return new (C) EnumConstantDecl(CD, L, Id, T, E, V);
|
2008-03-15 06:12:44 +00:00
|
|
|
}
|
|
|
|
|
2008-05-20 04:49:55 +00:00
|
|
|
void EnumConstantDecl::Destroy(ASTContext& C) {
|
|
|
|
if (Init) Init->Destroy(C);
|
|
|
|
Decl::Destroy(C);
|
|
|
|
}
|
|
|
|
|
2008-04-22 18:39:57 +00:00
|
|
|
TypedefDecl *TypedefDecl::Create(ASTContext &C, DeclContext *DC,
|
2009-10-24 08:00:42 +00:00
|
|
|
SourceLocation L, IdentifierInfo *Id,
|
2009-12-07 02:54:59 +00:00
|
|
|
TypeSourceInfo *TInfo) {
|
|
|
|
return new (C) TypedefDecl(DC, L, Id, TInfo);
|
2008-03-15 06:12:44 +00:00
|
|
|
}
|
|
|
|
|
2008-04-22 18:39:57 +00:00
|
|
|
EnumDecl *EnumDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L,
|
2009-07-21 14:46:17 +00:00
|
|
|
IdentifierInfo *Id, SourceLocation TKL,
|
2008-12-15 16:32:14 +00:00
|
|
|
EnumDecl *PrevDecl) {
|
2009-07-29 23:36:44 +00:00
|
|
|
EnumDecl *Enum = new (C) EnumDecl(DC, L, Id, PrevDecl, TKL);
|
2008-12-15 16:32:14 +00:00
|
|
|
C.getTypeDeclType(Enum, PrevDecl);
|
|
|
|
return Enum;
|
2008-03-15 06:12:44 +00:00
|
|
|
}
|
|
|
|
|
2008-09-02 20:13:32 +00:00
|
|
|
void EnumDecl::Destroy(ASTContext& C) {
|
|
|
|
Decl::Destroy(C);
|
|
|
|
}
|
|
|
|
|
2009-12-09 09:09:27 +00:00
|
|
|
void EnumDecl::completeDefinition(ASTContext &C,
|
|
|
|
QualType NewType,
|
|
|
|
QualType NewPromotionType) {
|
2008-12-11 16:49:14 +00:00
|
|
|
assert(!isDefinition() && "Cannot redefine enums!");
|
|
|
|
IntegerType = NewType;
|
2009-12-09 09:09:27 +00:00
|
|
|
PromotionType = NewPromotionType;
|
2009-01-17 00:42:38 +00:00
|
|
|
TagDecl::completeDefinition();
|
2008-12-11 16:49:14 +00:00
|
|
|
}
|
|
|
|
|
2009-01-20 01:17:11 +00:00
|
|
|
FileScopeAsmDecl *FileScopeAsmDecl::Create(ASTContext &C, DeclContext *DC,
|
2008-04-04 06:12:32 +00:00
|
|
|
SourceLocation L,
|
2008-03-16 00:16:02 +00:00
|
|
|
StringLiteral *Str) {
|
2009-01-27 21:25:57 +00:00
|
|
|
return new (C) FileScopeAsmDecl(DC, L, Str);
|
2008-03-16 00:16:02 +00:00
|
|
|
}
|
|
|
|
|
2008-03-31 00:36:02 +00:00
|
|
|
//===----------------------------------------------------------------------===//
|
2009-01-20 01:17:11 +00:00
|
|
|
// NamedDecl Implementation
|
2008-11-09 23:41:00 +00:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2009-11-25 22:24:25 +00:00
|
|
|
static NamedDecl::Linkage getLinkageForNamespaceScopeDecl(const NamedDecl *D) {
|
|
|
|
assert(D->getDeclContext()->getLookupContext()->isFileContext() &&
|
|
|
|
"Not a name having namespace scope");
|
|
|
|
ASTContext &Context = D->getASTContext();
|
|
|
|
|
|
|
|
// C++ [basic.link]p3:
|
|
|
|
// A name having namespace scope (3.3.6) has internal linkage if it
|
|
|
|
// is the name of
|
|
|
|
// - an object, reference, function or function template that is
|
|
|
|
// explicitly declared static; or,
|
|
|
|
// (This bullet corresponds to C99 6.2.2p3.)
|
|
|
|
if (const VarDecl *Var = dyn_cast<VarDecl>(D)) {
|
|
|
|
// Explicitly declared static.
|
|
|
|
if (Var->getStorageClass() == VarDecl::Static)
|
|
|
|
return NamedDecl::InternalLinkage;
|
|
|
|
|
|
|
|
// - an object or reference that is explicitly declared const
|
|
|
|
// and neither explicitly declared extern nor previously
|
|
|
|
// declared to have external linkage; or
|
|
|
|
// (there is no equivalent in C99)
|
|
|
|
if (Context.getLangOptions().CPlusPlus &&
|
2009-11-26 03:04:01 +00:00
|
|
|
Var->getType().isConstant(Context) &&
|
2009-11-25 22:24:25 +00:00
|
|
|
Var->getStorageClass() != VarDecl::Extern &&
|
|
|
|
Var->getStorageClass() != VarDecl::PrivateExtern) {
|
|
|
|
bool FoundExtern = false;
|
|
|
|
for (const VarDecl *PrevVar = Var->getPreviousDeclaration();
|
|
|
|
PrevVar && !FoundExtern;
|
|
|
|
PrevVar = PrevVar->getPreviousDeclaration())
|
|
|
|
if (PrevVar->getLinkage() == NamedDecl::ExternalLinkage)
|
|
|
|
FoundExtern = true;
|
|
|
|
|
|
|
|
if (!FoundExtern)
|
|
|
|
return NamedDecl::InternalLinkage;
|
|
|
|
}
|
|
|
|
} else if (isa<FunctionDecl>(D) || isa<FunctionTemplateDecl>(D)) {
|
|
|
|
const FunctionDecl *Function = 0;
|
|
|
|
if (const FunctionTemplateDecl *FunTmpl
|
|
|
|
= dyn_cast<FunctionTemplateDecl>(D))
|
|
|
|
Function = FunTmpl->getTemplatedDecl();
|
|
|
|
else
|
|
|
|
Function = cast<FunctionDecl>(D);
|
|
|
|
|
|
|
|
// Explicitly declared static.
|
|
|
|
if (Function->getStorageClass() == FunctionDecl::Static)
|
|
|
|
return NamedDecl::InternalLinkage;
|
|
|
|
} else if (const FieldDecl *Field = dyn_cast<FieldDecl>(D)) {
|
|
|
|
// - a data member of an anonymous union.
|
|
|
|
if (cast<RecordDecl>(Field->getDeclContext())->isAnonymousStructOrUnion())
|
|
|
|
return NamedDecl::InternalLinkage;
|
|
|
|
}
|
|
|
|
|
|
|
|
// C++ [basic.link]p4:
|
|
|
|
|
|
|
|
// A name having namespace scope has external linkage if it is the
|
|
|
|
// name of
|
|
|
|
//
|
|
|
|
// - an object or reference, unless it has internal linkage; or
|
|
|
|
if (const VarDecl *Var = dyn_cast<VarDecl>(D)) {
|
|
|
|
if (!Context.getLangOptions().CPlusPlus &&
|
|
|
|
(Var->getStorageClass() == VarDecl::Extern ||
|
|
|
|
Var->getStorageClass() == VarDecl::PrivateExtern)) {
|
|
|
|
// C99 6.2.2p4:
|
|
|
|
// For an identifier declared with the storage-class specifier
|
|
|
|
// extern in a scope in which a prior declaration of that
|
|
|
|
// identifier is visible, if the prior declaration specifies
|
|
|
|
// internal or external linkage, the linkage of the identifier
|
|
|
|
// at the later declaration is the same as the linkage
|
|
|
|
// specified at the prior declaration. If no prior declaration
|
|
|
|
// is visible, or if the prior declaration specifies no
|
|
|
|
// linkage, then the identifier has external linkage.
|
|
|
|
if (const VarDecl *PrevVar = Var->getPreviousDeclaration()) {
|
|
|
|
if (NamedDecl::Linkage L = PrevVar->getLinkage())
|
|
|
|
return L;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// C99 6.2.2p5:
|
|
|
|
// If the declaration of an identifier for an object has file
|
|
|
|
// scope and no storage-class specifier, its linkage is
|
|
|
|
// external.
|
|
|
|
return NamedDecl::ExternalLinkage;
|
|
|
|
}
|
|
|
|
|
|
|
|
// - a function, unless it has internal linkage; or
|
|
|
|
if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) {
|
|
|
|
// C99 6.2.2p5:
|
|
|
|
// If the declaration of an identifier for a function has no
|
|
|
|
// storage-class specifier, its linkage is determined exactly
|
|
|
|
// as if it were declared with the storage-class specifier
|
|
|
|
// extern.
|
|
|
|
if (!Context.getLangOptions().CPlusPlus &&
|
|
|
|
(Function->getStorageClass() == FunctionDecl::Extern ||
|
|
|
|
Function->getStorageClass() == FunctionDecl::PrivateExtern ||
|
|
|
|
Function->getStorageClass() == FunctionDecl::None)) {
|
|
|
|
// C99 6.2.2p4:
|
|
|
|
// For an identifier declared with the storage-class specifier
|
|
|
|
// extern in a scope in which a prior declaration of that
|
|
|
|
// identifier is visible, if the prior declaration specifies
|
|
|
|
// internal or external linkage, the linkage of the identifier
|
|
|
|
// at the later declaration is the same as the linkage
|
|
|
|
// specified at the prior declaration. If no prior declaration
|
|
|
|
// is visible, or if the prior declaration specifies no
|
|
|
|
// linkage, then the identifier has external linkage.
|
|
|
|
if (const FunctionDecl *PrevFunc = Function->getPreviousDeclaration()) {
|
|
|
|
if (NamedDecl::Linkage L = PrevFunc->getLinkage())
|
|
|
|
return L;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NamedDecl::ExternalLinkage;
|
|
|
|
}
|
|
|
|
|
|
|
|
// - a named class (Clause 9), or an unnamed class defined in a
|
|
|
|
// typedef declaration in which the class has the typedef name
|
|
|
|
// for linkage purposes (7.1.3); or
|
|
|
|
// - a named enumeration (7.2), or an unnamed enumeration
|
|
|
|
// defined in a typedef declaration in which the enumeration
|
|
|
|
// has the typedef name for linkage purposes (7.1.3); or
|
|
|
|
if (const TagDecl *Tag = dyn_cast<TagDecl>(D))
|
|
|
|
if (Tag->getDeclName() || Tag->getTypedefForAnonDecl())
|
|
|
|
return NamedDecl::ExternalLinkage;
|
|
|
|
|
|
|
|
// - an enumerator belonging to an enumeration with external linkage;
|
|
|
|
if (isa<EnumConstantDecl>(D))
|
|
|
|
if (cast<NamedDecl>(D->getDeclContext())->getLinkage()
|
|
|
|
== NamedDecl::ExternalLinkage)
|
|
|
|
return NamedDecl::ExternalLinkage;
|
|
|
|
|
|
|
|
// - a template, unless it is a function template that has
|
|
|
|
// internal linkage (Clause 14);
|
|
|
|
if (isa<TemplateDecl>(D))
|
|
|
|
return NamedDecl::ExternalLinkage;
|
|
|
|
|
|
|
|
// - a namespace (7.3), unless it is declared within an unnamed
|
|
|
|
// namespace.
|
|
|
|
if (isa<NamespaceDecl>(D) && !D->isInAnonymousNamespace())
|
|
|
|
return NamedDecl::ExternalLinkage;
|
|
|
|
|
|
|
|
return NamedDecl::NoLinkage;
|
|
|
|
}
|
|
|
|
|
|
|
|
NamedDecl::Linkage NamedDecl::getLinkage() const {
|
|
|
|
// Handle linkage for namespace-scope names.
|
|
|
|
if (getDeclContext()->getLookupContext()->isFileContext())
|
|
|
|
if (Linkage L = getLinkageForNamespaceScopeDecl(this))
|
|
|
|
return L;
|
|
|
|
|
|
|
|
// C++ [basic.link]p5:
|
|
|
|
// In addition, a member function, static data member, a named
|
|
|
|
// class or enumeration of class scope, or an unnamed class or
|
|
|
|
// enumeration defined in a class-scope typedef declaration such
|
|
|
|
// that the class or enumeration has the typedef name for linkage
|
|
|
|
// purposes (7.1.3), has external linkage if the name of the class
|
|
|
|
// has external linkage.
|
|
|
|
if (getDeclContext()->isRecord() &&
|
|
|
|
(isa<CXXMethodDecl>(this) || isa<VarDecl>(this) ||
|
|
|
|
(isa<TagDecl>(this) &&
|
|
|
|
(getDeclName() || cast<TagDecl>(this)->getTypedefForAnonDecl()))) &&
|
|
|
|
cast<RecordDecl>(getDeclContext())->getLinkage() == ExternalLinkage)
|
|
|
|
return ExternalLinkage;
|
|
|
|
|
|
|
|
// C++ [basic.link]p6:
|
|
|
|
// The name of a function declared in block scope and the name of
|
|
|
|
// an object declared by a block scope extern declaration have
|
|
|
|
// linkage. If there is a visible declaration of an entity with
|
|
|
|
// linkage having the same name and type, ignoring entities
|
|
|
|
// declared outside the innermost enclosing namespace scope, the
|
|
|
|
// block scope declaration declares that same entity and receives
|
|
|
|
// the linkage of the previous declaration. If there is more than
|
|
|
|
// one such matching entity, the program is ill-formed. Otherwise,
|
|
|
|
// if no matching entity is found, the block scope entity receives
|
|
|
|
// external linkage.
|
|
|
|
if (getLexicalDeclContext()->isFunctionOrMethod()) {
|
|
|
|
if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(this)) {
|
|
|
|
if (Function->getPreviousDeclaration())
|
|
|
|
if (Linkage L = Function->getPreviousDeclaration()->getLinkage())
|
|
|
|
return L;
|
|
|
|
|
|
|
|
return ExternalLinkage;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (const VarDecl *Var = dyn_cast<VarDecl>(this))
|
|
|
|
if (Var->getStorageClass() == VarDecl::Extern ||
|
|
|
|
Var->getStorageClass() == VarDecl::PrivateExtern) {
|
|
|
|
if (Var->getPreviousDeclaration())
|
|
|
|
if (Linkage L = Var->getPreviousDeclaration()->getLinkage())
|
|
|
|
return L;
|
|
|
|
|
|
|
|
return ExternalLinkage;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// C++ [basic.link]p6:
|
|
|
|
// Names not covered by these rules have no linkage.
|
|
|
|
return NoLinkage;
|
|
|
|
}
|
|
|
|
|
2009-02-04 17:27:36 +00:00
|
|
|
std::string NamedDecl::getQualifiedNameAsString() const {
|
2009-09-08 18:24:21 +00:00
|
|
|
return getQualifiedNameAsString(getASTContext().getLangOptions());
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string NamedDecl::getQualifiedNameAsString(const PrintingPolicy &P) const {
|
2009-10-18 20:26:12 +00:00
|
|
|
// FIXME: Collect contexts, then accumulate names to avoid unnecessary
|
|
|
|
// std::string thrashing.
|
2009-02-04 17:27:36 +00:00
|
|
|
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-09-09 15:08:12 +00:00
|
|
|
if (const ClassTemplateSpecializationDecl *Spec
|
2009-05-18 17:01:57 +00:00
|
|
|
= dyn_cast<ClassTemplateSpecializationDecl>(Ctx)) {
|
|
|
|
const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs();
|
|
|
|
std::string TemplateArgsStr
|
|
|
|
= TemplateSpecializationType::PrintTemplateArgumentList(
|
|
|
|
TemplateArgs.getFlatArgumentList(),
|
2009-05-29 20:38:28 +00:00
|
|
|
TemplateArgs.flat_size(),
|
2009-09-08 18:24:21 +00:00
|
|
|
P);
|
2009-10-18 20:26:12 +00:00
|
|
|
Names.push_back(Spec->getIdentifier()->getNameStart() + TemplateArgsStr);
|
2009-05-18 17:01:57 +00:00
|
|
|
} else if (const NamedDecl *ND = dyn_cast<NamedDecl>(Ctx))
|
2009-02-04 17:27:36 +00: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 01:17:11 +00:00
|
|
|
bool NamedDecl::declarationReplaces(NamedDecl *OldD) const {
|
2008-12-23 21:05:05 +00:00
|
|
|
assert(getDeclName() == OldD->getDeclName() && "Declaration name mismatch");
|
|
|
|
|
2009-02-03 19:21:40 +00: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();
|
|
|
|
}
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2008-12-23 21:05:05 +00:00
|
|
|
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(this))
|
|
|
|
// For function declarations, we keep track of redeclarations.
|
|
|
|
return FD->getPreviousDeclaration() == OldD;
|
|
|
|
|
2009-06-25 22:08:12 +00: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-09-09 15:08:12 +00:00
|
|
|
|
2009-02-22 19:35:57 +00:00
|
|
|
// For method declarations, we keep track of redeclarations.
|
|
|
|
if (isa<ObjCMethodDecl>(this))
|
|
|
|
return false;
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-10-09 21:13:30 +00:00
|
|
|
if (isa<ObjCInterfaceDecl>(this) && isa<ObjCCompatibleAliasDecl>(OldD))
|
|
|
|
return true;
|
|
|
|
|
2009-11-17 05:59:44 +00:00
|
|
|
if (isa<UsingShadowDecl>(this) && isa<UsingShadowDecl>(OldD))
|
|
|
|
return cast<UsingShadowDecl>(this)->getTargetDecl() ==
|
|
|
|
cast<UsingShadowDecl>(OldD)->getTargetDecl();
|
|
|
|
|
2008-12-23 21:05:05 +00: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-24 20:03:32 +00:00
|
|
|
bool NamedDecl::hasLinkage() const {
|
2009-11-25 22:24:25 +00:00
|
|
|
return getLinkage() != NoLinkage;
|
2009-02-24 20:03:32 +00:00
|
|
|
}
|
2009-01-20 01:17:11 +00:00
|
|
|
|
2009-06-26 06:29:23 +00:00
|
|
|
NamedDecl *NamedDecl::getUnderlyingDecl() {
|
|
|
|
NamedDecl *ND = this;
|
|
|
|
while (true) {
|
2009-11-17 05:59:44 +00:00
|
|
|
if (UsingShadowDecl *UD = dyn_cast<UsingShadowDecl>(ND))
|
2009-06-26 06:29:23 +00:00
|
|
|
ND = UD->getTargetDecl();
|
|
|
|
else if (ObjCCompatibleAliasDecl *AD
|
|
|
|
= dyn_cast<ObjCCompatibleAliasDecl>(ND))
|
|
|
|
return AD->getClassInterface();
|
|
|
|
else
|
|
|
|
return ND;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-08-21 00:31:54 +00:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// DeclaratorDecl Implementation
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
SourceLocation DeclaratorDecl::getTypeSpecStartLoc() const {
|
2009-10-18 01:05:36 +00:00
|
|
|
if (DeclInfo) {
|
|
|
|
TypeLoc TL = DeclInfo->getTypeLoc();
|
|
|
|
while (true) {
|
|
|
|
TypeLoc NextTL = TL.getNextTypeLoc();
|
|
|
|
if (!NextTL)
|
|
|
|
return TL.getSourceRange().getBegin();
|
|
|
|
TL = NextTL;
|
|
|
|
}
|
|
|
|
}
|
2009-08-21 00:31:54 +00:00
|
|
|
return SourceLocation();
|
|
|
|
}
|
|
|
|
|
2008-12-17 23:39:55 +00:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// VarDecl Implementation
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2009-01-20 01:17:11 +00:00
|
|
|
VarDecl *VarDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L,
|
2009-12-07 02:54:59 +00:00
|
|
|
IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo,
|
2009-08-21 00:31:54 +00:00
|
|
|
StorageClass S) {
|
2009-12-07 02:54:59 +00:00
|
|
|
return new (C) VarDecl(Var, DC, L, Id, T, TInfo, S);
|
2008-12-17 23:39:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void VarDecl::Destroy(ASTContext& C) {
|
2009-02-05 15:12:41 +00:00
|
|
|
Expr *Init = getInit();
|
2009-05-26 18:54:04 +00:00
|
|
|
if (Init) {
|
2009-02-05 15:12:41 +00:00
|
|
|
Init->Destroy(C);
|
2009-05-26 18:54:04 +00:00
|
|
|
if (EvaluatedStmt *Eval = this->Init.dyn_cast<EvaluatedStmt *>()) {
|
|
|
|
Eval->~EvaluatedStmt();
|
|
|
|
C.Deallocate(Eval);
|
|
|
|
}
|
|
|
|
}
|
2008-12-17 23:39:55 +00:00
|
|
|
this->~VarDecl();
|
2009-01-27 21:25:57 +00:00
|
|
|
C.Deallocate((void *)this);
|
2008-12-17 23:39:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
VarDecl::~VarDecl() {
|
|
|
|
}
|
|
|
|
|
2009-06-20 08:09:14 +00:00
|
|
|
SourceRange VarDecl::getSourceRange() const {
|
|
|
|
if (getInit())
|
|
|
|
return SourceRange(getLocation(), getInit()->getLocEnd());
|
|
|
|
return SourceRange(getLocation(), getLocation());
|
|
|
|
}
|
|
|
|
|
2009-10-14 21:29:40 +00:00
|
|
|
bool VarDecl::isOutOfLine() const {
|
|
|
|
if (!isStaticDataMember())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (Decl::isOutOfLine())
|
|
|
|
return true;
|
|
|
|
|
|
|
|
// If this static data member was instantiated from a static data member of
|
|
|
|
// a class template, check whether that static data member was defined
|
|
|
|
// out-of-line.
|
|
|
|
if (VarDecl *VD = getInstantiatedFromStaticDataMember())
|
|
|
|
return VD->isOutOfLine();
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2009-10-27 18:42:08 +00:00
|
|
|
VarDecl *VarDecl::getOutOfLineDefinition() {
|
|
|
|
if (!isStaticDataMember())
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
for (VarDecl::redecl_iterator RD = redecls_begin(), RDEnd = redecls_end();
|
|
|
|
RD != RDEnd; ++RD) {
|
|
|
|
if (RD->getLexicalDeclContext()->isFileContext())
|
|
|
|
return *RD;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-10-14 21:29:40 +00:00
|
|
|
VarDecl *VarDecl::getInstantiatedFromStaticDataMember() const {
|
2009-10-12 20:18:28 +00:00
|
|
|
if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo())
|
2009-10-08 07:24:58 +00:00
|
|
|
return cast<VarDecl>(MSI->getInstantiatedFrom());
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-10-14 20:14:33 +00:00
|
|
|
TemplateSpecializationKind VarDecl::getTemplateSpecializationKind() const {
|
2009-10-08 07:24:58 +00:00
|
|
|
if (MemberSpecializationInfo *MSI
|
|
|
|
= getASTContext().getInstantiatedFromStaticDataMember(this))
|
|
|
|
return MSI->getTemplateSpecializationKind();
|
|
|
|
|
|
|
|
return TSK_Undeclared;
|
|
|
|
}
|
|
|
|
|
2009-10-14 21:29:40 +00:00
|
|
|
MemberSpecializationInfo *VarDecl::getMemberSpecializationInfo() const {
|
2009-10-12 20:18:28 +00:00
|
|
|
return getASTContext().getInstantiatedFromStaticDataMember(this);
|
|
|
|
}
|
|
|
|
|
2009-10-15 17:21:20 +00:00
|
|
|
void VarDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK,
|
|
|
|
SourceLocation PointOfInstantiation) {
|
2009-10-12 20:18:28 +00:00
|
|
|
MemberSpecializationInfo *MSI = getMemberSpecializationInfo();
|
2009-10-08 07:24:58 +00:00
|
|
|
assert(MSI && "Not an instantiated static data member?");
|
|
|
|
MSI->setTemplateSpecializationKind(TSK);
|
2009-10-15 17:21:20 +00:00
|
|
|
if (TSK != TSK_ExplicitSpecialization &&
|
|
|
|
PointOfInstantiation.isValid() &&
|
|
|
|
MSI->getPointOfInstantiation().isInvalid())
|
|
|
|
MSI->setPointOfInstantiation(PointOfInstantiation);
|
2009-07-24 20:34:43 +00:00
|
|
|
}
|
|
|
|
|
2009-03-10 23:43:53 +00:00
|
|
|
bool VarDecl::isTentativeDefinition(ASTContext &Context) const {
|
|
|
|
if (!isFileVarDecl() || Context.getLangOptions().CPlusPlus)
|
|
|
|
return false;
|
|
|
|
|
2009-04-21 17:11:58 +00:00
|
|
|
const VarDecl *Def = 0;
|
|
|
|
return (!getDefinition(Def) &&
|
2009-03-10 23:43:53 +00:00
|
|
|
(getStorageClass() == None || getStorageClass() == Static));
|
|
|
|
}
|
|
|
|
|
2009-03-20 21:35:28 +00:00
|
|
|
const Expr *VarDecl::getDefinition(const VarDecl *&Def) const {
|
2009-07-14 03:20:21 +00:00
|
|
|
redecl_iterator I = redecls_begin(), E = redecls_end();
|
|
|
|
while (I != E && !I->getInit())
|
|
|
|
++I;
|
2009-03-10 23:43:53 +00:00
|
|
|
|
2009-07-14 03:20:21 +00:00
|
|
|
if (I != E) {
|
|
|
|
Def = *I;
|
|
|
|
return I->getInit();
|
|
|
|
}
|
|
|
|
return 0;
|
2009-03-10 23:43:53 +00:00
|
|
|
}
|
|
|
|
|
2009-07-18 00:34:07 +00:00
|
|
|
VarDecl *VarDecl::getCanonicalDecl() {
|
2009-07-18 08:50:13 +00:00
|
|
|
return getFirstDeclaration();
|
2009-07-05 22:21:56 +00:00
|
|
|
}
|
|
|
|
|
2008-11-09 23:41:00 +00:00
|
|
|
//===----------------------------------------------------------------------===//
|
2008-03-31 00:36:02 +00:00
|
|
|
// FunctionDecl Implementation
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2008-05-20 00:43:19 +00:00
|
|
|
void FunctionDecl::Destroy(ASTContext& C) {
|
2009-04-18 00:07:54 +00:00
|
|
|
if (Body && Body.isOffset())
|
|
|
|
Body.get(C.getExternalSource())->Destroy(C);
|
2008-05-20 03:56:00 +00:00
|
|
|
|
|
|
|
for (param_iterator I=param_begin(), E=param_end(); I!=E; ++I)
|
|
|
|
(*I)->Destroy(C);
|
2009-01-18 19:57:27 +00:00
|
|
|
|
2009-10-07 23:56:10 +00:00
|
|
|
FunctionTemplateSpecializationInfo *FTSInfo
|
|
|
|
= TemplateOrSpecialization.dyn_cast<FunctionTemplateSpecializationInfo*>();
|
|
|
|
if (FTSInfo)
|
|
|
|
C.Deallocate(FTSInfo);
|
|
|
|
|
|
|
|
MemberSpecializationInfo *MSInfo
|
|
|
|
= TemplateOrSpecialization.dyn_cast<MemberSpecializationInfo*>();
|
|
|
|
if (MSInfo)
|
|
|
|
C.Deallocate(MSInfo);
|
|
|
|
|
2009-01-27 21:25:57 +00:00
|
|
|
C.Deallocate(ParamInfo);
|
2009-01-18 19:57:27 +00:00
|
|
|
|
2008-05-20 00:43:19 +00:00
|
|
|
Decl::Destroy(C);
|
|
|
|
}
|
|
|
|
|
2009-09-11 06:45:03 +00:00
|
|
|
void FunctionDecl::getNameForDiagnostic(std::string &S,
|
|
|
|
const PrintingPolicy &Policy,
|
|
|
|
bool Qualified) const {
|
|
|
|
NamedDecl::getNameForDiagnostic(S, Policy, Qualified);
|
|
|
|
const TemplateArgumentList *TemplateArgs = getTemplateSpecializationArgs();
|
|
|
|
if (TemplateArgs)
|
|
|
|
S += TemplateSpecializationType::PrintTemplateArgumentList(
|
|
|
|
TemplateArgs->getFlatArgumentList(),
|
|
|
|
TemplateArgs->flat_size(),
|
|
|
|
Policy);
|
|
|
|
|
|
|
|
}
|
2008-05-20 00:43:19 +00:00
|
|
|
|
2009-06-30 02:35:26 +00:00
|
|
|
Stmt *FunctionDecl::getBody(const FunctionDecl *&Definition) const {
|
2009-07-14 03:20:21 +00:00
|
|
|
for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I) {
|
|
|
|
if (I->Body) {
|
|
|
|
Definition = *I;
|
|
|
|
return I->Body.get(getASTContext().getExternalSource());
|
2008-04-21 02:02:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
2007-01-21 07:42:07 +00:00
|
|
|
}
|
|
|
|
|
2009-06-20 08:09:14 +00:00
|
|
|
void FunctionDecl::setBody(Stmt *B) {
|
|
|
|
Body = B;
|
2009-06-22 17:13:31 +00:00
|
|
|
if (B)
|
2009-06-20 08:09:14 +00:00
|
|
|
EndRangeLoc = B->getLocEnd();
|
|
|
|
}
|
|
|
|
|
2009-09-12 00:17:51 +00:00
|
|
|
bool FunctionDecl::isMain() const {
|
|
|
|
ASTContext &Context = getASTContext();
|
2009-08-15 02:09:25 +00:00
|
|
|
return !Context.getLangOptions().Freestanding &&
|
|
|
|
getDeclContext()->getLookupContext()->isTranslationUnit() &&
|
2009-02-24 01:23:02 +00:00
|
|
|
getIdentifier() && getIdentifier()->isStr("main");
|
|
|
|
}
|
|
|
|
|
2009-09-12 00:17:51 +00:00
|
|
|
bool FunctionDecl::isExternC() const {
|
|
|
|
ASTContext &Context = getASTContext();
|
2009-03-02 00:19:53 +00:00
|
|
|
// In C, any non-static, non-overloadable function has external
|
|
|
|
// linkage.
|
|
|
|
if (!Context.getLangOptions().CPlusPlus)
|
2009-06-30 02:34:44 +00:00
|
|
|
return getStorageClass() != Static && !getAttr<OverloadableAttr>();
|
2009-03-02 00:19:53 +00:00
|
|
|
|
2009-09-09 15:08:12 +00:00
|
|
|
for (const DeclContext *DC = getDeclContext(); !DC->isTranslationUnit();
|
2009-03-02 00:19:53 +00:00
|
|
|
DC = DC->getParent()) {
|
|
|
|
if (const LinkageSpecDecl *Linkage = dyn_cast<LinkageSpecDecl>(DC)) {
|
|
|
|
if (Linkage->getLanguage() == LinkageSpecDecl::lang_c)
|
2009-09-09 15:08:12 +00:00
|
|
|
return getStorageClass() != Static &&
|
2009-06-30 02:34:44 +00:00
|
|
|
!getAttr<OverloadableAttr>();
|
2009-03-02 00:19:53 +00:00
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2009-03-31 16:35:03 +00:00
|
|
|
bool FunctionDecl::isGlobal() const {
|
|
|
|
if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(this))
|
|
|
|
return Method->isStatic();
|
|
|
|
|
|
|
|
if (getStorageClass() == Static)
|
|
|
|
return false;
|
|
|
|
|
2009-09-09 15:08:12 +00:00
|
|
|
for (const DeclContext *DC = getDeclContext();
|
2009-03-31 16:35:03 +00:00
|
|
|
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-13 23:20:09 +00: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
|
2009-09-09 15:08:12 +00:00
|
|
|
/// value of type \c Builtin::ID if in the target-independent range
|
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-13 23:20:09 +00:00
|
|
|
/// \c [1,Builtin::First), or a target-specific builtin value.
|
2009-09-12 00:22:50 +00:00
|
|
|
unsigned FunctionDecl::getBuiltinID() const {
|
|
|
|
ASTContext &Context = getASTContext();
|
2009-02-14 18:57:46 +00:00
|
|
|
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 03:23:10 +00:00
|
|
|
// If this is a static function, it's not a builtin.
|
|
|
|
if (getStorageClass() == Static)
|
|
|
|
return 0;
|
|
|
|
|
2009-02-14 18:57:46 +00: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()) &&
|
2009-09-09 15:08:12 +00:00
|
|
|
cast<LinkageSpecDecl>(getDeclContext())->getLanguage()
|
2009-02-14 18:57:46 +00:00
|
|
|
== LinkageSpecDecl::lang_c &&
|
2009-06-30 02:34:44 +00:00
|
|
|
!getAttr<OverloadableAttr>())
|
2009-02-14 18:57:46 +00: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-13 23:20:09 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-04-25 06:03:53 +00:00
|
|
|
/// getNumParams - Return the number of parameters this function must have
|
2009-04-25 06:12:16 +00:00
|
|
|
/// based on its FunctionType. This is the length of the PararmInfo array
|
2009-04-25 06:03:53 +00:00
|
|
|
/// after it has been created.
|
|
|
|
unsigned FunctionDecl::getNumParams() const {
|
2009-09-21 23:43:11 +00:00
|
|
|
const FunctionType *FT = getType()->getAs<FunctionType>();
|
2009-02-26 23:50:07 +00:00
|
|
|
if (isa<FunctionNoProtoType>(FT))
|
2008-03-15 05:43:15 +00:00
|
|
|
return 0;
|
2009-02-26 23:50:07 +00:00
|
|
|
return cast<FunctionProtoType>(FT)->getNumArgs();
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2007-01-21 07:42:07 +00:00
|
|
|
}
|
|
|
|
|
2009-01-14 00:42:25 +00:00
|
|
|
void FunctionDecl::setParams(ASTContext& C, ParmVarDecl **NewParamInfo,
|
|
|
|
unsigned NumParams) {
|
2007-01-21 07:42:07 +00:00
|
|
|
assert(ParamInfo == 0 && "Already has param info!");
|
2009-04-25 06:12:16 +00:00
|
|
|
assert(NumParams == getNumParams() && "Parameter count mismatch!");
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2007-01-21 19:04:10 +00:00
|
|
|
// Zero params -> null pointer.
|
|
|
|
if (NumParams) {
|
2009-01-27 23:20:32 +00:00
|
|
|
void *Mem = C.Allocate(sizeof(ParmVarDecl*)*NumParams);
|
2009-01-14 00:42:25 +00:00
|
|
|
ParamInfo = new (Mem) ParmVarDecl*[NumParams];
|
2007-06-13 20:44:40 +00:00
|
|
|
memcpy(ParamInfo, NewParamInfo, sizeof(ParmVarDecl*)*NumParams);
|
2009-06-20 08:09:14 +00:00
|
|
|
|
2009-06-23 00:42:00 +00:00
|
|
|
// Update source range. The check below allows us to set EndRangeLoc before
|
|
|
|
// setting the parameters.
|
2009-06-23 00:42:15 +00:00
|
|
|
if (EndRangeLoc.isInvalid() || EndRangeLoc == getLocation())
|
2009-06-20 08:09:14 +00:00
|
|
|
EndRangeLoc = NewParamInfo[NumParams-1]->getLocEnd();
|
2007-01-21 19:04:10 +00:00
|
|
|
}
|
2007-01-21 07:42:07 +00:00
|
|
|
}
|
2007-01-25 04:52:46 +00:00
|
|
|
|
2008-04-10 02:22:51 +00: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-12 23:52:44 +00:00
|
|
|
/// arguments (in C++).
|
2008-04-10 02:22:51 +00:00
|
|
|
unsigned FunctionDecl::getMinRequiredArguments() const {
|
|
|
|
unsigned NumRequiredArgs = getNumParams();
|
|
|
|
while (NumRequiredArgs > 0
|
2009-06-06 04:14:07 +00:00
|
|
|
&& getParamDecl(NumRequiredArgs-1)->hasDefaultArg())
|
2008-04-10 02:22:51 +00:00
|
|
|
--NumRequiredArgs;
|
|
|
|
|
|
|
|
return NumRequiredArgs;
|
|
|
|
}
|
|
|
|
|
2009-10-27 21:11:48 +00:00
|
|
|
bool FunctionDecl::isInlined() const {
|
2009-12-04 22:35:50 +00:00
|
|
|
// FIXME: This is not enough. Consider:
|
|
|
|
//
|
|
|
|
// inline void f();
|
|
|
|
// void f() { }
|
|
|
|
//
|
|
|
|
// f is inlined, but does not have inline specified.
|
|
|
|
// To fix this we should add an 'inline' flag to FunctionDecl.
|
|
|
|
if (isInlineSpecified())
|
2009-10-27 23:26:40 +00:00
|
|
|
return true;
|
2009-12-04 22:35:50 +00:00
|
|
|
|
|
|
|
if (isa<CXXMethodDecl>(this)) {
|
|
|
|
if (!isOutOfLine() || getCanonicalDecl()->isInlineSpecified())
|
|
|
|
return true;
|
|
|
|
}
|
2009-10-27 23:26:40 +00:00
|
|
|
|
|
|
|
switch (getTemplateSpecializationKind()) {
|
|
|
|
case TSK_Undeclared:
|
|
|
|
case TSK_ExplicitSpecialization:
|
|
|
|
return false;
|
|
|
|
|
|
|
|
case TSK_ImplicitInstantiation:
|
|
|
|
case TSK_ExplicitInstantiationDeclaration:
|
|
|
|
case TSK_ExplicitInstantiationDefinition:
|
|
|
|
// Handle below.
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
const FunctionDecl *PatternDecl = getTemplateInstantiationPattern();
|
|
|
|
Stmt *Pattern = 0;
|
|
|
|
if (PatternDecl)
|
|
|
|
Pattern = PatternDecl->getBody(PatternDecl);
|
|
|
|
|
|
|
|
if (Pattern && PatternDecl)
|
|
|
|
return PatternDecl->isInlined();
|
|
|
|
|
|
|
|
return false;
|
2009-10-27 21:11:48 +00:00
|
|
|
}
|
|
|
|
|
2009-10-27 23:26:40 +00:00
|
|
|
/// \brief For an inline function definition in C or C++, determine whether the
|
2009-09-13 07:46:26 +00:00
|
|
|
/// definition will be externally visible.
|
|
|
|
///
|
|
|
|
/// Inline function definitions are always available for inlining optimizations.
|
|
|
|
/// However, depending on the language dialect, declaration specifiers, and
|
|
|
|
/// attributes, the definition of an inline function may or may not be
|
|
|
|
/// "externally" visible to other translation units in the program.
|
|
|
|
///
|
|
|
|
/// In C99, inline definitions are not externally visible by default. However,
|
|
|
|
/// if even one of the globa-scope declarations is marked "extern inline", the
|
|
|
|
/// inline definition becomes externally visible (C99 6.7.4p6).
|
|
|
|
///
|
|
|
|
/// In GNU89 mode, or if the gnu_inline attribute is attached to the function
|
|
|
|
/// definition, we use the GNU semantics for inline, which are nearly the
|
|
|
|
/// opposite of C99 semantics. In particular, "inline" by itself will create
|
|
|
|
/// an externally visible symbol, but "extern inline" will not create an
|
|
|
|
/// externally visible symbol.
|
|
|
|
bool FunctionDecl::isInlineDefinitionExternallyVisible() const {
|
|
|
|
assert(isThisDeclarationADefinition() && "Must have the function definition");
|
2009-10-27 21:11:48 +00:00
|
|
|
assert(isInlined() && "Function must be inline");
|
2009-10-27 23:26:40 +00:00
|
|
|
ASTContext &Context = getASTContext();
|
2009-09-13 07:46:26 +00:00
|
|
|
|
2009-10-27 23:26:40 +00:00
|
|
|
if (!Context.getLangOptions().C99 || hasAttr<GNUInlineAttr>()) {
|
2009-09-13 07:46:26 +00:00
|
|
|
// GNU inline semantics. Based on a number of examples, we came up with the
|
|
|
|
// following heuristic: if the "inline" keyword is present on a
|
|
|
|
// declaration of the function but "extern" is not present on that
|
|
|
|
// declaration, then the symbol is externally visible. Otherwise, the GNU
|
|
|
|
// "extern inline" semantics applies and the symbol is not externally
|
|
|
|
// visible.
|
|
|
|
for (redecl_iterator Redecl = redecls_begin(), RedeclEnd = redecls_end();
|
|
|
|
Redecl != RedeclEnd;
|
|
|
|
++Redecl) {
|
2009-10-27 21:01:01 +00:00
|
|
|
if (Redecl->isInlineSpecified() && Redecl->getStorageClass() != Extern)
|
2009-09-13 07:46:26 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// GNU "extern inline" semantics; no externally visible symbol.
|
2009-04-28 06:37:30 +00:00
|
|
|
return false;
|
2009-09-13 07:46:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// C99 6.7.4p6:
|
|
|
|
// [...] If all of the file scope declarations for a function in a
|
|
|
|
// translation unit include the inline function specifier without extern,
|
|
|
|
// then the definition in that translation unit is an inline definition.
|
|
|
|
for (redecl_iterator Redecl = redecls_begin(), RedeclEnd = redecls_end();
|
|
|
|
Redecl != RedeclEnd;
|
|
|
|
++Redecl) {
|
|
|
|
// Only consider file-scope declarations in this test.
|
|
|
|
if (!Redecl->getLexicalDeclContext()->isTranslationUnit())
|
|
|
|
continue;
|
|
|
|
|
2009-10-27 21:01:01 +00:00
|
|
|
if (!Redecl->isInlineSpecified() || Redecl->getStorageClass() == Extern)
|
2009-09-13 07:46:26 +00:00
|
|
|
return true; // Not an inline definition
|
|
|
|
}
|
|
|
|
|
|
|
|
// C99 6.7.4p6:
|
|
|
|
// An inline definition does not provide an external definition for the
|
|
|
|
// function, and does not forbid an external definition in another
|
|
|
|
// translation unit.
|
2009-04-28 06:37:30 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2009-09-09 15:08:12 +00:00
|
|
|
void
|
2009-06-29 20:59:39 +00:00
|
|
|
FunctionDecl::setPreviousDeclaration(FunctionDecl *PrevDecl) {
|
2009-07-18 08:50:35 +00:00
|
|
|
redeclarable_base::setPreviousDeclaration(PrevDecl);
|
2009-07-18 08:50:13 +00:00
|
|
|
|
2009-06-29 20:59:39 +00:00
|
|
|
if (FunctionTemplateDecl *FunTmpl = getDescribedFunctionTemplate()) {
|
2009-09-09 15:08:12 +00:00
|
|
|
FunctionTemplateDecl *PrevFunTmpl
|
2009-06-29 20:59:39 +00:00
|
|
|
= PrevDecl? PrevDecl->getDescribedFunctionTemplate() : 0;
|
|
|
|
assert((!PrevDecl || PrevFunTmpl) && "Function/function template mismatch");
|
|
|
|
FunTmpl->setPreviousDeclaration(PrevFunTmpl);
|
|
|
|
}
|
2009-09-29 00:50:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
const FunctionDecl *FunctionDecl::getCanonicalDecl() const {
|
|
|
|
return getFirstDeclaration();
|
2009-06-29 20:59:39 +00:00
|
|
|
}
|
|
|
|
|
2009-07-18 00:34:07 +00:00
|
|
|
FunctionDecl *FunctionDecl::getCanonicalDecl() {
|
2009-07-18 08:50:13 +00:00
|
|
|
return getFirstDeclaration();
|
2009-07-05 22:21:56 +00:00
|
|
|
}
|
|
|
|
|
2008-11-06 22:13:31 +00: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 14:39:36 +00:00
|
|
|
if (getDeclName().getNameKind() == DeclarationName::CXXOperatorName)
|
|
|
|
return getDeclName().getCXXOverloadedOperator();
|
2008-11-06 22:13:31 +00:00
|
|
|
else
|
|
|
|
return OO_None;
|
|
|
|
}
|
|
|
|
|
2009-10-07 23:56:10 +00:00
|
|
|
FunctionDecl *FunctionDecl::getInstantiatedFromMemberFunction() const {
|
2009-10-12 20:18:28 +00:00
|
|
|
if (MemberSpecializationInfo *Info = getMemberSpecializationInfo())
|
2009-10-07 23:56:10 +00:00
|
|
|
return cast<FunctionDecl>(Info->getInstantiatedFrom());
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-10-12 20:18:28 +00:00
|
|
|
MemberSpecializationInfo *FunctionDecl::getMemberSpecializationInfo() const {
|
|
|
|
return TemplateOrSpecialization.dyn_cast<MemberSpecializationInfo*>();
|
|
|
|
}
|
|
|
|
|
2009-10-07 23:56:10 +00:00
|
|
|
void
|
|
|
|
FunctionDecl::setInstantiationOfMemberFunction(FunctionDecl *FD,
|
|
|
|
TemplateSpecializationKind TSK) {
|
|
|
|
assert(TemplateOrSpecialization.isNull() &&
|
|
|
|
"Member function is already a specialization");
|
|
|
|
MemberSpecializationInfo *Info
|
|
|
|
= new (getASTContext()) MemberSpecializationInfo(FD, TSK);
|
|
|
|
TemplateOrSpecialization = Info;
|
|
|
|
}
|
|
|
|
|
2009-10-27 20:53:28 +00:00
|
|
|
bool FunctionDecl::isImplicitlyInstantiable() const {
|
|
|
|
// If this function already has a definition or is invalid, it can't be
|
|
|
|
// implicitly instantiated.
|
|
|
|
if (isInvalidDecl() || getBody())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
switch (getTemplateSpecializationKind()) {
|
|
|
|
case TSK_Undeclared:
|
|
|
|
case TSK_ExplicitSpecialization:
|
|
|
|
case TSK_ExplicitInstantiationDefinition:
|
|
|
|
return false;
|
|
|
|
|
|
|
|
case TSK_ImplicitInstantiation:
|
|
|
|
return true;
|
|
|
|
|
|
|
|
case TSK_ExplicitInstantiationDeclaration:
|
|
|
|
// Handled below.
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Find the actual template from which we will instantiate.
|
|
|
|
const FunctionDecl *PatternDecl = getTemplateInstantiationPattern();
|
|
|
|
Stmt *Pattern = 0;
|
|
|
|
if (PatternDecl)
|
|
|
|
Pattern = PatternDecl->getBody(PatternDecl);
|
|
|
|
|
|
|
|
// C++0x [temp.explicit]p9:
|
|
|
|
// Except for inline functions, other explicit instantiation declarations
|
|
|
|
// have the effect of suppressing the implicit instantiation of the entity
|
|
|
|
// to which they refer.
|
|
|
|
if (!Pattern || !PatternDecl)
|
|
|
|
return true;
|
|
|
|
|
2009-10-27 21:11:48 +00:00
|
|
|
return PatternDecl->isInlined();
|
2009-10-27 20:53:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
FunctionDecl *FunctionDecl::getTemplateInstantiationPattern() const {
|
|
|
|
if (FunctionTemplateDecl *Primary = getPrimaryTemplate()) {
|
|
|
|
while (Primary->getInstantiatedFromMemberTemplate()) {
|
|
|
|
// If we have hit a point where the user provided a specialization of
|
|
|
|
// this template, we're done looking.
|
|
|
|
if (Primary->isMemberSpecialization())
|
|
|
|
break;
|
|
|
|
|
|
|
|
Primary = Primary->getInstantiatedFromMemberTemplate();
|
|
|
|
}
|
|
|
|
|
|
|
|
return Primary->getTemplatedDecl();
|
|
|
|
}
|
|
|
|
|
|
|
|
return getInstantiatedFromMemberFunction();
|
|
|
|
}
|
|
|
|
|
2009-06-29 17:30:29 +00:00
|
|
|
FunctionTemplateDecl *FunctionDecl::getPrimaryTemplate() const {
|
2009-09-09 15:08:12 +00:00
|
|
|
if (FunctionTemplateSpecializationInfo *Info
|
2009-06-29 17:30:29 +00:00
|
|
|
= TemplateOrSpecialization
|
|
|
|
.dyn_cast<FunctionTemplateSpecializationInfo*>()) {
|
2009-06-29 22:39:32 +00:00
|
|
|
return Info->Template.getPointer();
|
2009-06-29 17:30:29 +00:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
const TemplateArgumentList *
|
|
|
|
FunctionDecl::getTemplateSpecializationArgs() const {
|
2009-09-09 15:08:12 +00:00
|
|
|
if (FunctionTemplateSpecializationInfo *Info
|
2009-10-13 16:30:37 +00:00
|
|
|
= TemplateOrSpecialization
|
|
|
|
.dyn_cast<FunctionTemplateSpecializationInfo*>()) {
|
2009-06-29 17:30:29 +00:00
|
|
|
return Info->TemplateArguments;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-09-09 15:08:12 +00:00
|
|
|
void
|
2009-06-26 00:10:03 +00:00
|
|
|
FunctionDecl::setFunctionTemplateSpecialization(ASTContext &Context,
|
|
|
|
FunctionTemplateDecl *Template,
|
2009-06-29 20:59:39 +00:00
|
|
|
const TemplateArgumentList *TemplateArgs,
|
2009-09-24 23:14:47 +00:00
|
|
|
void *InsertPos,
|
|
|
|
TemplateSpecializationKind TSK) {
|
|
|
|
assert(TSK != TSK_Undeclared &&
|
|
|
|
"Must specify the type of function template specialization");
|
2009-09-09 15:08:12 +00:00
|
|
|
FunctionTemplateSpecializationInfo *Info
|
2009-06-29 17:30:29 +00:00
|
|
|
= TemplateOrSpecialization.dyn_cast<FunctionTemplateSpecializationInfo*>();
|
2009-06-26 00:10:03 +00:00
|
|
|
if (!Info)
|
2009-06-29 17:30:29 +00:00
|
|
|
Info = new (Context) FunctionTemplateSpecializationInfo;
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-06-29 20:59:39 +00:00
|
|
|
Info->Function = this;
|
2009-06-29 22:39:32 +00:00
|
|
|
Info->Template.setPointer(Template);
|
2009-09-24 23:14:47 +00:00
|
|
|
Info->Template.setInt(TSK - 1);
|
2009-06-26 00:10:03 +00:00
|
|
|
Info->TemplateArguments = TemplateArgs;
|
|
|
|
TemplateOrSpecialization = Info;
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-06-29 20:59:39 +00:00
|
|
|
// Insert this function template specialization into the set of known
|
2009-09-24 23:14:47 +00:00
|
|
|
// function template specializations.
|
|
|
|
if (InsertPos)
|
|
|
|
Template->getSpecializations().InsertNode(Info, InsertPos);
|
|
|
|
else {
|
|
|
|
// Try to insert the new node. If there is an existing node, remove it
|
|
|
|
// first.
|
|
|
|
FunctionTemplateSpecializationInfo *Existing
|
|
|
|
= Template->getSpecializations().GetOrInsertNode(Info);
|
|
|
|
if (Existing) {
|
|
|
|
Template->getSpecializations().RemoveNode(Existing);
|
|
|
|
Template->getSpecializations().GetOrInsertNode(Info);
|
|
|
|
}
|
|
|
|
}
|
2009-06-26 00:10:03 +00:00
|
|
|
}
|
|
|
|
|
2009-09-04 22:48:11 +00:00
|
|
|
TemplateSpecializationKind FunctionDecl::getTemplateSpecializationKind() const {
|
2009-09-09 15:08:12 +00:00
|
|
|
// For a function template specialization, query the specialization
|
2009-09-04 22:48:11 +00:00
|
|
|
// information object.
|
2009-10-07 23:56:10 +00:00
|
|
|
FunctionTemplateSpecializationInfo *FTSInfo
|
2009-06-29 22:39:32 +00:00
|
|
|
= TemplateOrSpecialization.dyn_cast<FunctionTemplateSpecializationInfo*>();
|
2009-10-07 23:56:10 +00:00
|
|
|
if (FTSInfo)
|
|
|
|
return FTSInfo->getTemplateSpecializationKind();
|
2009-09-04 22:48:11 +00:00
|
|
|
|
2009-10-07 23:56:10 +00:00
|
|
|
MemberSpecializationInfo *MSInfo
|
|
|
|
= TemplateOrSpecialization.dyn_cast<MemberSpecializationInfo*>();
|
|
|
|
if (MSInfo)
|
|
|
|
return MSInfo->getTemplateSpecializationKind();
|
|
|
|
|
|
|
|
return TSK_Undeclared;
|
2009-06-29 22:39:32 +00:00
|
|
|
}
|
|
|
|
|
2009-09-09 15:08:12 +00:00
|
|
|
void
|
2009-10-15 17:21:20 +00:00
|
|
|
FunctionDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK,
|
|
|
|
SourceLocation PointOfInstantiation) {
|
2009-10-07 23:56:10 +00:00
|
|
|
if (FunctionTemplateSpecializationInfo *FTSInfo
|
|
|
|
= TemplateOrSpecialization.dyn_cast<
|
2009-10-15 17:21:20 +00:00
|
|
|
FunctionTemplateSpecializationInfo*>()) {
|
2009-10-07 23:56:10 +00:00
|
|
|
FTSInfo->setTemplateSpecializationKind(TSK);
|
2009-10-15 17:21:20 +00:00
|
|
|
if (TSK != TSK_ExplicitSpecialization &&
|
|
|
|
PointOfInstantiation.isValid() &&
|
|
|
|
FTSInfo->getPointOfInstantiation().isInvalid())
|
|
|
|
FTSInfo->setPointOfInstantiation(PointOfInstantiation);
|
|
|
|
} else if (MemberSpecializationInfo *MSInfo
|
|
|
|
= TemplateOrSpecialization.dyn_cast<MemberSpecializationInfo*>()) {
|
2009-10-07 23:56:10 +00:00
|
|
|
MSInfo->setTemplateSpecializationKind(TSK);
|
2009-10-15 17:21:20 +00:00
|
|
|
if (TSK != TSK_ExplicitSpecialization &&
|
|
|
|
PointOfInstantiation.isValid() &&
|
|
|
|
MSInfo->getPointOfInstantiation().isInvalid())
|
|
|
|
MSInfo->setPointOfInstantiation(PointOfInstantiation);
|
|
|
|
} else
|
2009-10-07 23:56:10 +00:00
|
|
|
assert(false && "Function cannot have a template specialization kind");
|
2009-06-29 22:39:32 +00:00
|
|
|
}
|
|
|
|
|
2009-10-15 17:21:20 +00:00
|
|
|
SourceLocation FunctionDecl::getPointOfInstantiation() const {
|
|
|
|
if (FunctionTemplateSpecializationInfo *FTSInfo
|
|
|
|
= TemplateOrSpecialization.dyn_cast<
|
|
|
|
FunctionTemplateSpecializationInfo*>())
|
|
|
|
return FTSInfo->getPointOfInstantiation();
|
|
|
|
else if (MemberSpecializationInfo *MSInfo
|
|
|
|
= TemplateOrSpecialization.dyn_cast<MemberSpecializationInfo*>())
|
|
|
|
return MSInfo->getPointOfInstantiation();
|
|
|
|
|
|
|
|
return SourceLocation();
|
|
|
|
}
|
|
|
|
|
2009-09-11 20:15:17 +00:00
|
|
|
bool FunctionDecl::isOutOfLine() const {
|
|
|
|
if (Decl::isOutOfLine())
|
|
|
|
return true;
|
|
|
|
|
|
|
|
// If this function was instantiated from a member function of a
|
|
|
|
// class template, check whether that member function was defined out-of-line.
|
|
|
|
if (FunctionDecl *FD = getInstantiatedFromMemberFunction()) {
|
|
|
|
const FunctionDecl *Definition;
|
|
|
|
if (FD->getBody(Definition))
|
|
|
|
return Definition->isOutOfLine();
|
|
|
|
}
|
|
|
|
|
|
|
|
// If this function was instantiated from a function template,
|
|
|
|
// check whether that function template was defined out-of-line.
|
|
|
|
if (FunctionTemplateDecl *FunTmpl = getPrimaryTemplate()) {
|
|
|
|
const FunctionDecl *Definition;
|
|
|
|
if (FunTmpl->getTemplatedDecl()->getBody(Definition))
|
|
|
|
return Definition->isOutOfLine();
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
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-05 17:16:31 +00:00
|
|
|
//===----------------------------------------------------------------------===//
|
2009-01-07 00:43:41 +00: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-05 17:16:31 +00:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2009-07-14 03:17:17 +00:00
|
|
|
SourceRange TagDecl::getSourceRange() const {
|
|
|
|
SourceLocation E = RBraceLoc.isValid() ? RBraceLoc : getLocation();
|
2009-07-21 14:46:17 +00:00
|
|
|
return SourceRange(TagKeywordLoc, E);
|
2009-07-14 03:17:17 +00:00
|
|
|
}
|
|
|
|
|
2009-07-18 00:34:07 +00:00
|
|
|
TagDecl* TagDecl::getCanonicalDecl() {
|
2009-07-29 23:36:44 +00:00
|
|
|
return getFirstDeclaration();
|
2009-07-18 00:34:07 +00:00
|
|
|
}
|
|
|
|
|
2009-01-17 00:42:38 +00:00
|
|
|
void TagDecl::startDefinition() {
|
2009-07-29 23:36:44 +00:00
|
|
|
if (TagType *TagT = const_cast<TagType *>(TypeForDecl->getAs<TagType>())) {
|
|
|
|
TagT->decl.setPointer(this);
|
|
|
|
TagT->decl.setInt(1);
|
|
|
|
}
|
2009-01-17 00:42:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void TagDecl::completeDefinition() {
|
|
|
|
IsDefinition = true;
|
2009-07-29 23:36:44 +00:00
|
|
|
if (TagType *TagT = const_cast<TagType *>(TypeForDecl->getAs<TagType>())) {
|
|
|
|
assert(TagT->decl.getPointer() == this &&
|
|
|
|
"Attempt to redefine a tag definition?");
|
|
|
|
TagT->decl.setInt(0);
|
|
|
|
}
|
2009-01-17 00:42:38 +00: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-05 17:16:31 +00:00
|
|
|
TagDecl* TagDecl::getDefinition(ASTContext& C) const {
|
2009-07-29 23:36:44 +00:00
|
|
|
if (isDefinition())
|
|
|
|
return const_cast<TagDecl *>(this);
|
2009-09-09 15:08:12 +00:00
|
|
|
|
|
|
|
for (redecl_iterator R = redecls_begin(), REnd = redecls_end();
|
2009-07-29 23:36:44 +00:00
|
|
|
R != REnd; ++R)
|
|
|
|
if (R->isDefinition())
|
|
|
|
return *R;
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-07-29 23:36:44 +00:00
|
|
|
return 0;
|
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-05 17:16:31 +00:00
|
|
|
}
|
|
|
|
|
2009-09-04 01:14:41 +00:00
|
|
|
TagDecl::TagKind TagDecl::getTagKindForTypeSpec(unsigned TypeSpec) {
|
|
|
|
switch (TypeSpec) {
|
2009-12-12 05:05:38 +00:00
|
|
|
default: llvm_unreachable("unexpected type specifier");
|
2009-09-04 01:14:41 +00:00
|
|
|
case DeclSpec::TST_struct: return TK_struct;
|
|
|
|
case DeclSpec::TST_class: return TK_class;
|
|
|
|
case DeclSpec::TST_union: return TK_union;
|
|
|
|
case DeclSpec::TST_enum: return TK_enum;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-03-31 00:36:02 +00:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// RecordDecl Implementation
|
|
|
|
//===----------------------------------------------------------------------===//
|
2007-01-25 04:52:46 +00:00
|
|
|
|
2008-10-15 00:42:39 +00:00
|
|
|
RecordDecl::RecordDecl(Kind DK, TagKind TK, DeclContext *DC, SourceLocation L,
|
2009-07-29 23:36:44 +00:00
|
|
|
IdentifierInfo *Id, RecordDecl *PrevDecl,
|
|
|
|
SourceLocation TKL)
|
|
|
|
: TagDecl(DK, TK, DC, L, Id, PrevDecl, TKL) {
|
2008-09-02 21:12:32 +00:00
|
|
|
HasFlexibleArrayMember = false;
|
2009-01-07 00:43:41 +00:00
|
|
|
AnonymousStructOrUnion = false;
|
2009-07-08 01:18:33 +00:00
|
|
|
HasObjectMember = false;
|
2008-09-02 21:12:32 +00: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-05 17:16:31 +00:00
|
|
|
SourceLocation L, IdentifierInfo *Id,
|
2009-07-21 14:46:17 +00:00
|
|
|
SourceLocation TKL, RecordDecl* PrevDecl) {
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-07-29 23:36:44 +00:00
|
|
|
RecordDecl* R = new (C) RecordDecl(Record, TK, DC, L, Id, PrevDecl, TKL);
|
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-05 17:16:31 +00:00
|
|
|
C.getTypeDeclType(R, PrevDecl);
|
|
|
|
return R;
|
2008-09-02 21:12:32 +00:00
|
|
|
}
|
|
|
|
|
2008-08-08 14:08:55 +00:00
|
|
|
RecordDecl::~RecordDecl() {
|
|
|
|
}
|
|
|
|
|
|
|
|
void RecordDecl::Destroy(ASTContext& C) {
|
|
|
|
TagDecl::Destroy(C);
|
|
|
|
}
|
|
|
|
|
2009-03-25 15:59:44 +00:00
|
|
|
bool RecordDecl::isInjectedClassName() const {
|
2009-09-09 15:08:12 +00:00
|
|
|
return isImplicit() && getDeclName() && getDeclContext()->isRecord() &&
|
2009-03-25 15:59:44 +00:00
|
|
|
cast<RecordDecl>(getDeclContext())->getDeclName() == getDeclName();
|
|
|
|
}
|
|
|
|
|
2008-12-11 16:49:14 +00:00
|
|
|
/// completeDefinition - Notes that the definition of this type is now
|
|
|
|
/// complete.
|
|
|
|
void RecordDecl::completeDefinition(ASTContext& C) {
|
2007-01-25 04:52:46 +00:00
|
|
|
assert(!isDefinition() && "Cannot redefine record!");
|
2009-01-17 00:42:38 +00:00
|
|
|
TagDecl::completeDefinition();
|
2007-01-25 04:52:46 +00:00
|
|
|
}
|
2007-03-26 23:09:51 +00:00
|
|
|
|
2008-10-08 17:01:13 +00: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-09-09 15:08:12 +00:00
|
|
|
|
|
|
|
C.Deallocate(ParamInfo);
|
2008-10-08 17:01:13 +00:00
|
|
|
Decl::Destroy(C);
|
|
|
|
}
|
2009-03-13 16:56:44 +00:00
|
|
|
|
|
|
|
void BlockDecl::setParams(ASTContext& C, ParmVarDecl **NewParamInfo,
|
|
|
|
unsigned NParms) {
|
|
|
|
assert(ParamInfo == 0 && "Already has param info!");
|
2009-09-09 15:08:12 +00:00
|
|
|
|
2009-03-13 16:56:44 +00:00
|
|
|
// 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;
|
|
|
|
}
|