//===--- DeclCXX.cpp - C++ Declaration AST Node Implementation ------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file implements the C++ related Decl classes. // //===----------------------------------------------------------------------===// #include "clang/AST/DeclCXX.h" #include "clang/AST/ASTContext.h" #include "clang/Basic/IdentifierTable.h" using namespace clang; //===----------------------------------------------------------------------===// // Decl Allocation/Deallocation Method Implementations //===----------------------------------------------------------------------===// CXXFieldDecl *CXXFieldDecl::Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation L, IdentifierInfo *Id, QualType T, bool Mut, Expr *BW) { void *Mem = C.getAllocator().Allocate(); return new (Mem) CXXFieldDecl(RD, L, Id, T, Mut, BW); } CXXRecordDecl::CXXRecordDecl(TagKind TK, DeclContext *DC, SourceLocation L, IdentifierInfo *Id) : RecordDecl(CXXRecord, TK, DC, L, Id), DeclContext(CXXRecord), UserDeclaredConstructor(false), UserDeclaredCopyConstructor(false), Aggregate(true), Polymorphic(false), Bases(0), NumBases(0), Constructors(DC, DeclarationName()), Destructor(0), Conversions(DC, DeclarationName()) { } CXXRecordDecl *CXXRecordDecl::Create(ASTContext &C, TagKind TK, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, CXXRecordDecl* PrevDecl) { void *Mem = C.getAllocator().Allocate(); CXXRecordDecl* R = new (Mem) CXXRecordDecl(TK, DC, L, Id); C.getTypeDeclType(R, PrevDecl); return R; } CXXRecordDecl::~CXXRecordDecl() { delete [] Bases; } void CXXRecordDecl::Destroy(ASTContext &C) { for (OverloadedFunctionDecl::function_iterator func = Constructors.function_begin(); func != Constructors.function_end(); ++func) (*func)->Destroy(C); if (isDefinition()) Destructor->Destroy(C); for (OverloadedFunctionDecl::function_iterator func = Conversions.function_begin(); func != Conversions.function_end(); ++func) (*func)->Destroy(C); RecordDecl::Destroy(C); } void CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, unsigned NumBases) { // C++ [dcl.init.aggr]p1: // An aggregate is an array or a class (clause 9) with [...] // no base classes [...]. Aggregate = false; if (this->Bases) delete [] this->Bases; this->Bases = new CXXBaseSpecifier[NumBases]; this->NumBases = NumBases; for (unsigned i = 0; i < NumBases; ++i) this->Bases[i] = *Bases[i]; } bool CXXRecordDecl::hasConstCopyConstructor(ASTContext &Context) const { for (OverloadedFunctionDecl::function_const_iterator Con = Constructors.function_begin(); Con != Constructors.function_end(); ++Con) { unsigned TypeQuals; if (cast(*Con)->isCopyConstructor(Context, TypeQuals) && (TypeQuals & QualType::Const != 0)) return true; } return false; } void CXXRecordDecl::addConstructor(ASTContext &Context, CXXConstructorDecl *ConDecl) { if (!ConDecl->isImplicitlyDeclared()) { // Note that we have a user-declared constructor. UserDeclaredConstructor = true; // C++ [dcl.init.aggr]p1: // An aggregate is an array or a class (clause 9) with no // user-declared constructors (12.1) [...]. Aggregate = false; // Note when we have a user-declared copy constructor, which will // suppress the implicit declaration of a copy constructor. if (ConDecl->isCopyConstructor(Context)) UserDeclaredCopyConstructor = true; } Constructors.addOverload(ConDecl); } void CXXRecordDecl::addConversionFunction(ASTContext &Context, CXXConversionDecl *ConvDecl) { Conversions.addOverload(ConvDecl); } CXXMethodDecl * CXXMethodDecl::Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation L, DeclarationName N, QualType T, bool isStatic, bool isInline, ScopedDecl *PrevDecl) { void *Mem = C.getAllocator().Allocate(); return new (Mem) CXXMethodDecl(CXXMethod, RD, L, N, T, isStatic, isInline, PrevDecl); } QualType CXXMethodDecl::getThisType(ASTContext &C) const { // C++ 9.3.2p1: The type of this in a member function of a class X is X*. // If the member function is declared const, the type of this is const X*, // if the member function is declared volatile, the type of this is // volatile X*, and if the member function is declared const volatile, // the type of this is const volatile X*. assert(isInstance() && "No 'this' for static methods!"); QualType ClassTy = C.getTagDeclType(const_cast(getParent())); ClassTy = ClassTy.getWithAdditionalQualifiers(getTypeQualifiers()); return C.getPointerType(ClassTy).withConst(); } CXXBaseOrMemberInitializer:: CXXBaseOrMemberInitializer(QualType BaseType, Expr **Args, unsigned NumArgs) : Args(0), NumArgs(0) { BaseOrMember = reinterpret_cast(BaseType.getTypePtr()); assert((BaseOrMember & 0x01) == 0 && "Invalid base class type pointer"); BaseOrMember |= 0x01; if (NumArgs > 0) { this->NumArgs = NumArgs; this->Args = new Expr*[NumArgs]; for (unsigned Idx = 0; Idx < NumArgs; ++Idx) this->Args[Idx] = Args[Idx]; } } CXXBaseOrMemberInitializer:: CXXBaseOrMemberInitializer(CXXFieldDecl *Member, Expr **Args, unsigned NumArgs) : Args(0), NumArgs(0) { BaseOrMember = reinterpret_cast(Member); assert((BaseOrMember & 0x01) == 0 && "Invalid member pointer"); if (NumArgs > 0) { this->NumArgs = NumArgs; this->Args = new Expr*[NumArgs]; for (unsigned Idx = 0; Idx < NumArgs; ++Idx) this->Args[Idx] = Args[Idx]; } } CXXBaseOrMemberInitializer::~CXXBaseOrMemberInitializer() { delete [] Args; } CXXConstructorDecl * CXXConstructorDecl::Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation L, DeclarationName N, QualType T, bool isExplicit, bool isInline, bool isImplicitlyDeclared) { assert(N.getNameKind() == DeclarationName::CXXConstructorName && "Name must refer to a constructor"); void *Mem = C.getAllocator().Allocate(); return new (Mem) CXXConstructorDecl(RD, L, N, T, isExplicit, isInline, isImplicitlyDeclared); } bool CXXConstructorDecl::isDefaultConstructor() const { // C++ [class.ctor]p5: // A default constructor for a class X is a constructor of class // X that can be called without an argument. return (getNumParams() == 0) || (getNumParams() > 0 && getParamDecl(0)->getDefaultArg() != 0); } bool CXXConstructorDecl::isCopyConstructor(ASTContext &Context, unsigned &TypeQuals) const { // C++ [class.copy]p2: // A non-template constructor for class X is a copy constructor // if its first parameter is of type X&, const X&, volatile X& or // const volatile X&, and either there are no other parameters // or else all other parameters have default arguments (8.3.6). if ((getNumParams() < 1) || (getNumParams() > 1 && getParamDecl(1)->getDefaultArg() == 0)) return false; const ParmVarDecl *Param = getParamDecl(0); // Do we have a reference type? const ReferenceType *ParamRefType = Param->getType()->getAsReferenceType(); if (!ParamRefType) return false; // Is it a reference to our class type? QualType PointeeType = Context.getCanonicalType(ParamRefType->getPointeeType()); QualType ClassTy = Context.getTagDeclType(const_cast(getParent())); if (PointeeType.getUnqualifiedType() != ClassTy) return false; // We have a copy constructor. TypeQuals = PointeeType.getCVRQualifiers(); return true; } bool CXXConstructorDecl::isConvertingConstructor() const { // C++ [class.conv.ctor]p1: // A constructor declared without the function-specifier explicit // that can be called with a single parameter specifies a // conversion from the type of its first parameter to the type of // its class. Such a constructor is called a converting // constructor. if (isExplicit()) return false; return (getNumParams() == 0 && getType()->getAsFunctionTypeProto()->isVariadic()) || (getNumParams() == 1) || (getNumParams() > 1 && getParamDecl(1)->getDefaultArg() != 0); } CXXDestructorDecl * CXXDestructorDecl::Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation L, DeclarationName N, QualType T, bool isInline, bool isImplicitlyDeclared) { assert(N.getNameKind() == DeclarationName::CXXDestructorName && "Name must refer to a destructor"); void *Mem = C.getAllocator().Allocate(); return new (Mem) CXXDestructorDecl(RD, L, N, T, isInline, isImplicitlyDeclared); } CXXConversionDecl * CXXConversionDecl::Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation L, DeclarationName N, QualType T, bool isInline, bool isExplicit) { assert(N.getNameKind() == DeclarationName::CXXConversionFunctionName && "Name must refer to a conversion function"); void *Mem = C.getAllocator().Allocate(); return new (Mem) CXXConversionDecl(RD, L, N, T, isInline, isExplicit); } CXXClassVarDecl *CXXClassVarDecl::Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation L, IdentifierInfo *Id, QualType T, ScopedDecl *PrevDecl) { void *Mem = C.getAllocator().Allocate(); return new (Mem) CXXClassVarDecl(RD, L, Id, T, PrevDecl); } OverloadedFunctionDecl * OverloadedFunctionDecl::Create(ASTContext &C, DeclContext *DC, DeclarationName N) { void *Mem = C.getAllocator().Allocate(); return new (Mem) OverloadedFunctionDecl(DC, N); } LinkageSpecDecl *LinkageSpecDecl::Create(ASTContext &C, SourceLocation L, LanguageIDs Lang, Decl *D) { void *Mem = C.getAllocator().Allocate(); return new (Mem) LinkageSpecDecl(L, Lang, D); }