diff options
Diffstat (limited to 'lib/AST/DeclCXX.cpp')
-rw-r--r-- | lib/AST/DeclCXX.cpp | 462 |
1 files changed, 462 insertions, 0 deletions
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp new file mode 100644 index 0000000..19f8958 --- /dev/null +++ b/lib/AST/DeclCXX.cpp @@ -0,0 +1,462 @@ +//===--- 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/DeclTemplate.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Expr.h" +#include "clang/Basic/IdentifierTable.h" +#include "llvm/ADT/STLExtras.h" +using namespace clang; + +//===----------------------------------------------------------------------===// +// Decl Allocation/Deallocation Method Implementations +//===----------------------------------------------------------------------===// + +CXXRecordDecl::CXXRecordDecl(Kind K, TagKind TK, DeclContext *DC, + SourceLocation L, IdentifierInfo *Id) + : RecordDecl(K, TK, DC, L, Id), + UserDeclaredConstructor(false), UserDeclaredCopyConstructor(false), + UserDeclaredCopyAssignment(false), UserDeclaredDestructor(false), + Aggregate(true), PlainOldData(true), Polymorphic(false), Abstract(false), + HasTrivialConstructor(true), HasTrivialDestructor(true), + Bases(0), NumBases(0), Conversions(DC, DeclarationName()), + TemplateOrInstantiation() { } + +CXXRecordDecl *CXXRecordDecl::Create(ASTContext &C, TagKind TK, DeclContext *DC, + SourceLocation L, IdentifierInfo *Id, + CXXRecordDecl* PrevDecl, + bool DelayTypeCreation) { + CXXRecordDecl* R = new (C) CXXRecordDecl(CXXRecord, TK, DC, L, Id); + if (!DelayTypeCreation) + C.getTypeDeclType(R, PrevDecl); + return R; +} + +CXXRecordDecl::~CXXRecordDecl() { + delete [] Bases; +} + +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; + + // FIXME: allocate using the ASTContext + 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 { + QualType ClassType + = Context.getTypeDeclType(const_cast<CXXRecordDecl*>(this)); + DeclarationName ConstructorName + = Context.DeclarationNames.getCXXConstructorName( + Context.getCanonicalType(ClassType)); + unsigned TypeQuals; + DeclContext::lookup_const_iterator Con, ConEnd; + for (llvm::tie(Con, ConEnd) = this->lookup(Context, ConstructorName); + Con != ConEnd; ++Con) { + if (cast<CXXConstructorDecl>(*Con)->isCopyConstructor(Context, TypeQuals) && + (TypeQuals & QualType::Const) != 0) + return true; + } + + return false; +} + +bool CXXRecordDecl::hasConstCopyAssignment(ASTContext &Context) const { + QualType ClassType = Context.getCanonicalType(Context.getTypeDeclType( + const_cast<CXXRecordDecl*>(this))); + DeclarationName OpName =Context.DeclarationNames.getCXXOperatorName(OO_Equal); + + DeclContext::lookup_const_iterator Op, OpEnd; + for (llvm::tie(Op, OpEnd) = this->lookup(Context, OpName); + Op != OpEnd; ++Op) { + // C++ [class.copy]p9: + // A user-declared copy assignment operator is a non-static non-template + // member function of class X with exactly one parameter of type X, X&, + // const X&, volatile X& or const volatile X&. + const CXXMethodDecl* Method = cast<CXXMethodDecl>(*Op); + if (Method->isStatic()) + continue; + // TODO: Skip templates? Or is this implicitly done due to parameter types? + const FunctionProtoType *FnType = + Method->getType()->getAsFunctionProtoType(); + assert(FnType && "Overloaded operator has no prototype."); + // Don't assert on this; an invalid decl might have been left in the AST. + if (FnType->getNumArgs() != 1 || FnType->isVariadic()) + continue; + bool AcceptsConst = true; + QualType ArgType = FnType->getArgType(0); + if (const LValueReferenceType *Ref = ArgType->getAsLValueReferenceType()) { + ArgType = Ref->getPointeeType(); + // Is it a non-const lvalue reference? + if (!ArgType.isConstQualified()) + AcceptsConst = false; + } + if (Context.getCanonicalType(ArgType).getUnqualifiedType() != ClassType) + continue; + + // We have a single argument of type cv X or cv X&, i.e. we've found the + // copy assignment operator. Return whether it accepts const arguments. + return AcceptsConst; + } + assert(isInvalidDecl() && + "No copy assignment operator declared in valid code."); + return false; +} + +void +CXXRecordDecl::addedConstructor(ASTContext &Context, + CXXConstructorDecl *ConDecl) { + if (!ConDecl->isImplicit()) { + // 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; + + // C++ [class]p4: + // A POD-struct is an aggregate class [...] + PlainOldData = false; + + // C++ [class.ctor]p5: + // A constructor is trivial if it is an implicitly-declared default + // constructor. + HasTrivialConstructor = 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; + } +} + +void CXXRecordDecl::addedAssignmentOperator(ASTContext &Context, + CXXMethodDecl *OpDecl) { + // We're interested specifically in copy assignment operators. + // Unlike addedConstructor, this method is not called for implicit + // declarations. + const FunctionProtoType *FnType = OpDecl->getType()->getAsFunctionProtoType(); + assert(FnType && "Overloaded operator has no proto function type."); + assert(FnType->getNumArgs() == 1 && !FnType->isVariadic()); + QualType ArgType = FnType->getArgType(0); + if (const LValueReferenceType *Ref = ArgType->getAsLValueReferenceType()) + ArgType = Ref->getPointeeType(); + + ArgType = ArgType.getUnqualifiedType(); + QualType ClassType = Context.getCanonicalType(Context.getTypeDeclType( + const_cast<CXXRecordDecl*>(this))); + + if (ClassType != Context.getCanonicalType(ArgType)) + return; + + // This is a copy assignment operator. + // Suppress the implicit declaration of a copy constructor. + UserDeclaredCopyAssignment = true; + + // C++ [class]p4: + // A POD-struct is an aggregate class that [...] has no user-defined copy + // assignment operator [...]. + PlainOldData = false; +} + +void CXXRecordDecl::addConversionFunction(ASTContext &Context, + CXXConversionDecl *ConvDecl) { + Conversions.addOverload(ConvDecl); +} + +const CXXDestructorDecl * +CXXRecordDecl::getDestructor(ASTContext &Context) { + QualType ClassType = Context.getTypeDeclType(this); + + DeclarationName Name + = Context.DeclarationNames.getCXXDestructorName(ClassType); + + DeclContext::lookup_iterator I, E; + llvm::tie(I, E) = lookup(Context, Name); + assert(I != E && "Did not find a destructor!"); + + const CXXDestructorDecl *Dtor = cast<CXXDestructorDecl>(*I); + assert(++I == E && "Found more than one destructor!"); + + return Dtor; +} + +CXXMethodDecl * +CXXMethodDecl::Create(ASTContext &C, CXXRecordDecl *RD, + SourceLocation L, DeclarationName N, + QualType T, bool isStatic, bool isInline) { + return new (C) CXXMethodDecl(CXXMethod, RD, L, N, T, isStatic, isInline); +} + + +typedef llvm::DenseMap<const CXXMethodDecl*, + std::vector<const CXXMethodDecl *> *> + OverriddenMethodsMapTy; + +static OverriddenMethodsMapTy *OverriddenMethods = 0; + +void CXXMethodDecl::addOverriddenMethod(const CXXMethodDecl *MD) { + // FIXME: The CXXMethodDecl dtor needs to remove and free the entry. + + if (!OverriddenMethods) + OverriddenMethods = new OverriddenMethodsMapTy(); + + std::vector<const CXXMethodDecl *> *&Methods = (*OverriddenMethods)[this]; + if (!Methods) + Methods = new std::vector<const CXXMethodDecl *>; + + Methods->push_back(MD); +} + +CXXMethodDecl::method_iterator CXXMethodDecl::begin_overridden_methods() const { + if (!OverriddenMethods) + return 0; + + OverriddenMethodsMapTy::iterator it = OverriddenMethods->find(this); + if (it == OverriddenMethods->end()) + return 0; + return &(*it->second)[0]; +} + +CXXMethodDecl::method_iterator CXXMethodDecl::end_overridden_methods() const { + if (!OverriddenMethods) + return 0; + + OverriddenMethodsMapTy::iterator it = OverriddenMethods->find(this); + if (it == OverriddenMethods->end()) + return 0; + + return &(*it->second)[it->second->size()]; +} + +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<CXXRecordDecl*>(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<uintptr_t>(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(FieldDecl *Member, Expr **Args, unsigned NumArgs) + : Args(0), NumArgs(0) { + BaseOrMember = reinterpret_cast<uintptr_t>(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"); + return new (C) 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? Rvalue references don't count. + const LValueReferenceType *ParamRefType = + Param->getType()->getAsLValueReferenceType(); + if (!ParamRefType) + return false; + + // Is it a reference to our class type? + QualType PointeeType + = Context.getCanonicalType(ParamRefType->getPointeeType()); + QualType ClassTy + = Context.getTagDeclType(const_cast<CXXRecordDecl*>(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()->getAsFunctionProtoType()->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"); + return new (C) 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"); + return new (C) CXXConversionDecl(RD, L, N, T, isInline, isExplicit); +} + +OverloadedFunctionDecl * +OverloadedFunctionDecl::Create(ASTContext &C, DeclContext *DC, + DeclarationName N) { + return new (C) OverloadedFunctionDecl(DC, N); +} + +LinkageSpecDecl *LinkageSpecDecl::Create(ASTContext &C, + DeclContext *DC, + SourceLocation L, + LanguageIDs Lang, bool Braces) { + return new (C) LinkageSpecDecl(DC, L, Lang, Braces); +} + +UsingDirectiveDecl *UsingDirectiveDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation L, + SourceLocation NamespaceLoc, + SourceRange QualifierRange, + NestedNameSpecifier *Qualifier, + SourceLocation IdentLoc, + NamespaceDecl *Used, + DeclContext *CommonAncestor) { + return new (C) UsingDirectiveDecl(DC, L, NamespaceLoc, QualifierRange, + Qualifier, IdentLoc, Used, CommonAncestor); +} + +NamespaceAliasDecl *NamespaceAliasDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation L, + SourceLocation AliasLoc, + IdentifierInfo *Alias, + SourceRange QualifierRange, + NestedNameSpecifier *Qualifier, + SourceLocation IdentLoc, + NamedDecl *Namespace) { + return new (C) NamespaceAliasDecl(DC, L, AliasLoc, Alias, QualifierRange, + Qualifier, IdentLoc, Namespace); +} + +StaticAssertDecl *StaticAssertDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation L, Expr *AssertExpr, + StringLiteral *Message) { + return new (C) StaticAssertDecl(DC, L, AssertExpr, Message); +} + +void StaticAssertDecl::Destroy(ASTContext& C) { + AssertExpr->Destroy(C); + Message->Destroy(C); + this->~StaticAssertDecl(); + C.Deallocate((void *)this); +} + +StaticAssertDecl::~StaticAssertDecl() { +} + +static const char *getAccessName(AccessSpecifier AS) { + switch (AS) { + default: + case AS_none: + assert("Invalid access specifier!"); + return 0; + case AS_public: + return "public"; + case AS_private: + return "private"; + case AS_protected: + return "protected"; + } +} + +const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB, + AccessSpecifier AS) { + return DB << getAccessName(AS); +} + + |