llvm-project/clang/lib/AST/DeclCXX.cpp
Douglas Gregor deaad8cc34 Create a new TypeNodes.def file that enumerates all of the types,
giving them rough classifications (normal types, never-canonical
types, always-dependent types, abstract type representations) and
making it far easier to make sure that we've hit all of the cases when
decoding types. 

Switched some switch() statements on the type class over to using this
mechanism, and filtering out those things we don't care about. For
example, CodeGen should never see always-dependent or non-canonical
types, while debug info generation should never see always-dependent
types. More switch() statements on the type class need to be moved 
over to using this approach, so that we'll get warnings when we add a
new type then fail to account for it somewhere in the compiler.

As part of this, some types have been renamed:

  TypeOfExpr -> TypeOfExprType
  FunctionTypeProto -> FunctionProtoType
  FunctionTypeNoProto -> FunctionNoProtoType

There shouldn't be any functionality change...

llvm-svn: 65591
2009-02-26 23:50:07 +00:00

347 lines
13 KiB
C++

//===--- 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"
#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), Bases(0),
NumBases(0), Conversions(DC, DeclarationName()) { }
CXXRecordDecl *CXXRecordDecl::Create(ASTContext &C, TagKind TK, DeclContext *DC,
SourceLocation L, IdentifierInfo *Id,
CXXRecordDecl* PrevDecl) {
CXXRecordDecl* R = new (C) CXXRecordDecl(CXXRecord, TK, DC, L, Id);
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;
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(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(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 ReferenceType *Ref = ArgType->getAsReferenceType()) {
ArgType = Ref->getPointeeType();
// Is it a non-const 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;
// 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 ReferenceType *Ref = ArgType->getAsReferenceType())
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);
}
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);
}
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?
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<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);
}
CXXClassVarDecl *CXXClassVarDecl::Create(ASTContext &C, CXXRecordDecl *RD,
SourceLocation L, IdentifierInfo *Id,
QualType T) {
return new (C) CXXClassVarDecl(RD, L, Id, T);
}
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,
SourceLocation IdentLoc,
NamespaceDecl *Used,
DeclContext *CommonAncestor) {
return new (C) UsingDirectiveDecl(DC, L, NamespaceLoc, IdentLoc,
Used, CommonAncestor);
}