Compute whether a type is variably modified as we build the type,

rather than walking the type's structure every time we request this
information. Performance optimization; no functionality change.

llvm-svn: 116409
This commit is contained in:
Douglas Gregor 2010-10-13 16:58:14 +00:00
parent 26d1e2b370
commit 518da18d70
3 changed files with 115 additions and 104 deletions

View File

@ -793,6 +793,9 @@ private:
/// subclasses can pack their bitfields into the same word.
bool Dependent : 1;
/// \brief Whether this type is a variably-modified type (C99 6.7.5).
bool VariablyModified : 1;
/// \brief Whether the linkage of this type is already known.
mutable bool LinkageKnown : 1;
@ -808,20 +811,25 @@ private:
}
protected:
/// \brief Compute the linkage of this type.
/// \brief Compute the linkage of this type along with the presence of
/// any local or unnamed types.
virtual Linkage getLinkageImpl() const;
enum { BitsRemainingInType = 19 };
// silence VC++ warning C4355: 'this' : used in base member initializer list
Type *this_() { return this; }
Type(TypeClass tc, QualType Canonical, bool dependent)
Type(TypeClass tc, QualType Canonical, bool Dependent, bool VariablyModified)
: CanonicalType(Canonical.isNull() ? QualType(this_(), 0) : Canonical),
TC(tc), Dependent(dependent), LinkageKnown(false),
TC(tc), Dependent(Dependent), VariablyModified(VariablyModified),
LinkageKnown(false),
CachedLinkage(NoLinkage), FromAST(false) {}
virtual ~Type();
friend class ASTContext;
void setDependent(bool D = true) { Dependent = D; }
void setVariablyModified(bool VM = true) { VariablyModified = VM; }
public:
TypeClass getTypeClass() const { return static_cast<TypeClass>(TC); }
@ -854,10 +862,6 @@ public:
/// (C++0x [basic.types]p10)
bool isLiteralType() const;
/// isVariablyModifiedType (C99 6.7.5.2p2) - Return true for variable array
/// types that have a non-constant expression. This does not include "[]".
bool isVariablyModifiedType() const;
/// Helper methods to distinguish type categories. All type predicates
/// operate on the canonical type, ignoring typedefs and qualifiers.
@ -951,6 +955,10 @@ public:
/// that its definition somehow depends on a template parameter
/// (C++ [temp.dep.type]).
bool isDependentType() const { return Dependent; }
/// \brief Whether this type is a variably-modified type (C99 6.7.5).
bool isVariablyModifiedType() const { return VariablyModified; }
bool isOverloadableType() const;
/// \brief Determine wither this type is a C++ elaborated-type-specifier.
@ -1142,7 +1150,8 @@ protected:
public:
BuiltinType(Kind K)
: Type(Builtin, QualType(), /*Dependent=*/(K == Dependent)),
: Type(Builtin, QualType(), /*Dependent=*/(K == Dependent),
/*VariablyModified=*/false),
TypeKind(K) {}
Kind getKind() const { return TypeKind; }
@ -1185,7 +1194,8 @@ public:
class ComplexType : public Type, public llvm::FoldingSetNode {
QualType ElementType;
ComplexType(QualType Element, QualType CanonicalPtr) :
Type(Complex, CanonicalPtr, Element->isDependentType()),
Type(Complex, CanonicalPtr, Element->isDependentType(),
Element->isVariablyModifiedType()),
ElementType(Element) {
}
friend class ASTContext; // ASTContext creates these.
@ -1216,7 +1226,9 @@ class PointerType : public Type, public llvm::FoldingSetNode {
QualType PointeeType;
PointerType(QualType Pointee, QualType CanonicalPtr) :
Type(Pointer, CanonicalPtr, Pointee->isDependentType()), PointeeType(Pointee) {
Type(Pointer, CanonicalPtr, Pointee->isDependentType(),
Pointee->isVariablyModifiedType()),
PointeeType(Pointee) {
}
friend class ASTContext; // ASTContext creates these.
@ -1248,7 +1260,8 @@ public:
class BlockPointerType : public Type, public llvm::FoldingSetNode {
QualType PointeeType; // Block is some kind of pointer type
BlockPointerType(QualType Pointee, QualType CanonicalCls) :
Type(BlockPointer, CanonicalCls, Pointee->isDependentType()),
Type(BlockPointer, CanonicalCls, Pointee->isDependentType(),
Pointee->isVariablyModifiedType()),
PointeeType(Pointee) {
}
friend class ASTContext; // ASTContext creates these.
@ -1302,7 +1315,8 @@ class ReferenceType : public Type, public llvm::FoldingSetNode {
protected:
ReferenceType(TypeClass tc, QualType Referencee, QualType CanonicalRef,
bool SpelledAsLValue) :
Type(tc, CanonicalRef, Referencee->isDependentType()),
Type(tc, CanonicalRef, Referencee->isDependentType(),
Referencee->isVariablyModifiedType()),
PointeeType(Referencee), SpelledAsLValue(SpelledAsLValue),
InnerRef(Referencee->isReferenceType()) {
}
@ -1384,7 +1398,8 @@ class MemberPointerType : public Type, public llvm::FoldingSetNode {
MemberPointerType(QualType Pointee, const Type *Cls, QualType CanonicalPtr) :
Type(MemberPointer, CanonicalPtr,
Cls->isDependentType() || Pointee->isDependentType()),
Cls->isDependentType() || Pointee->isDependentType(),
Pointee->isVariablyModifiedType()),
PointeeType(Pointee), Class(Cls) {
}
friend class ASTContext; // ASTContext creates these.
@ -1458,7 +1473,8 @@ protected:
// value-dependent,
ArrayType(TypeClass tc, QualType et, QualType can,
ArraySizeModifier sm, unsigned tq)
: Type(tc, can, et->isDependentType() || tc == DependentSizedArray),
: Type(tc, can, et->isDependentType() || tc == DependentSizedArray,
(tc == VariableArray || et->isVariablyModifiedType())),
ElementType(et), SizeModifier(sm), IndexTypeQuals(tq) {}
friend class ASTContext; // ASTContext creates these.
@ -1702,7 +1718,8 @@ class DependentSizedExtVectorType : public Type, public llvm::FoldingSetNode {
DependentSizedExtVectorType(ASTContext &Context, QualType ElementType,
QualType can, Expr *SizeExpr, SourceLocation loc)
: Type (DependentSizedExtVector, can, true),
: Type(DependentSizedExtVector, can, /*Dependent=*/true,
ElementType->isVariablyModifiedType()),
Context(Context), SizeExpr(SizeExpr), ElementType(ElementType),
loc(loc) {}
friend class ASTContext;
@ -1753,11 +1770,15 @@ protected:
VectorType(QualType vecType, unsigned nElements, QualType canonType,
AltiVecSpecific altiVecSpec) :
Type(Vector, canonType, vecType->isDependentType()),
Type(Vector, canonType, vecType->isDependentType(),
vecType->isVariablyModifiedType()),
ElementType(vecType), NumElements(nElements), AltiVecSpec(altiVecSpec) {}
VectorType(TypeClass tc, QualType vecType, unsigned nElements,
QualType canonType, AltiVecSpecific altiVecSpec)
: Type(tc, canonType, vecType->isDependentType()), ElementType(vecType),
: Type(tc, canonType, vecType->isDependentType(),
vecType->isVariablyModifiedType()),
ElementType(vecType),
NumElements(nElements), AltiVecSpec(altiVecSpec) {}
friend class ASTContext; // ASTContext creates these.
@ -1958,8 +1979,8 @@ class FunctionType : public Type {
protected:
FunctionType(TypeClass tc, QualType res, bool SubclassInfo,
unsigned typeQuals, QualType Canonical, bool Dependent,
const ExtInfo &Info)
: Type(tc, Canonical, Dependent),
bool VariablyModified, const ExtInfo &Info)
: Type(tc, Canonical, Dependent, VariablyModified),
SubClassData(SubclassInfo), TypeQuals(typeQuals),
NoReturn(Info.getNoReturn()),
RegParm(Info.getRegParm()), CallConv(Info.getCC()), ResultType(res) {}
@ -1997,7 +2018,8 @@ class FunctionNoProtoType : public FunctionType, public llvm::FoldingSetNode {
FunctionNoProtoType(QualType Result, QualType Canonical,
const ExtInfo &Info)
: FunctionType(FunctionNoProto, Result, false, 0, Canonical,
/*Dependent=*/false, Info) {}
/*Dependent=*/false, Result->isVariablyModifiedType(),
Info) {}
friend class ASTContext; // ASTContext creates these.
protected:
@ -2032,36 +2054,11 @@ public:
/// exception specification, but this specification is not part of the canonical
/// type.
class FunctionProtoType : public FunctionType, public llvm::FoldingSetNode {
/// hasAnyDependentType - Determine whether there are any dependent
/// types within the arguments passed in.
static bool hasAnyDependentType(const QualType *ArgArray, unsigned numArgs) {
for (unsigned Idx = 0; Idx < numArgs; ++Idx)
if (ArgArray[Idx]->isDependentType())
return true;
return false;
}
FunctionProtoType(QualType Result, const QualType *ArgArray, unsigned numArgs,
bool isVariadic, unsigned typeQuals, bool hasExs,
bool hasAnyExs, const QualType *ExArray,
unsigned numExs, QualType Canonical,
const ExtInfo &Info)
: FunctionType(FunctionProto, Result, isVariadic, typeQuals, Canonical,
(Result->isDependentType() ||
hasAnyDependentType(ArgArray, numArgs)),
Info),
NumArgs(numArgs), NumExceptions(numExs), HasExceptionSpec(hasExs),
AnyExceptionSpec(hasAnyExs) {
// Fill in the trailing argument array.
QualType *ArgInfo = reinterpret_cast<QualType*>(this+1);
for (unsigned i = 0; i != numArgs; ++i)
ArgInfo[i] = ArgArray[i];
// Fill in the exception array.
QualType *Ex = ArgInfo + numArgs;
for (unsigned i = 0; i != numExs; ++i)
Ex[i] = ExArray[i];
}
const ExtInfo &Info);
/// NumArgs - The number of arguments this function has, not counting '...'.
unsigned NumArgs : 20;
@ -2149,7 +2146,7 @@ class UnresolvedUsingType : public Type {
UnresolvedUsingTypenameDecl *Decl;
UnresolvedUsingType(const UnresolvedUsingTypenameDecl *D)
: Type(UnresolvedUsing, QualType(), true),
: Type(UnresolvedUsing, QualType(), true, false),
Decl(const_cast<UnresolvedUsingTypenameDecl*>(D)) {}
friend class ASTContext; // ASTContext creates these.
public:
@ -2178,7 +2175,7 @@ class TypedefType : public Type {
TypedefDecl *Decl;
protected:
TypedefType(TypeClass tc, const TypedefDecl *D, QualType can)
: Type(tc, can, can->isDependentType()),
: Type(tc, can, can->isDependentType(), can->isVariablyModifiedType()),
Decl(const_cast<TypedefDecl*>(D)) {
assert(!isa<TypedefType>(can) && "Invalid canonical type");
}
@ -2251,7 +2248,8 @@ public:
class TypeOfType : public Type {
QualType TOType;
TypeOfType(QualType T, QualType can)
: Type(TypeOf, can, T->isDependentType()), TOType(T) {
: Type(TypeOf, can, T->isDependentType(), T->isVariablyModifiedType()),
TOType(T) {
assert(!isa<TypedefType>(can) && "Invalid canonical type");
}
friend class ASTContext; // ASTContext creates these.
@ -2406,11 +2404,13 @@ class TemplateTypeParmType : public Type, public llvm::FoldingSetNode {
TemplateTypeParmType(unsigned D, unsigned I, bool PP, IdentifierInfo *N,
QualType Canon)
: Type(TemplateTypeParm, Canon, /*Dependent=*/true),
: Type(TemplateTypeParm, Canon, /*Dependent=*/true,
/*VariablyModified=*/false),
Depth(D), Index(I), ParameterPack(PP), Name(N) { }
TemplateTypeParmType(unsigned D, unsigned I, bool PP)
: Type(TemplateTypeParm, QualType(this, 0), /*Dependent=*/true),
: Type(TemplateTypeParm, QualType(this, 0), /*Dependent=*/true,
/*VariablyModified=*/false),
Depth(D), Index(I), ParameterPack(PP), Name(0) { }
friend class ASTContext; // ASTContext creates these
@ -2455,7 +2455,8 @@ class SubstTemplateTypeParmType : public Type, public llvm::FoldingSetNode {
const TemplateTypeParmType *Replaced;
SubstTemplateTypeParmType(const TemplateTypeParmType *Param, QualType Canon)
: Type(SubstTemplateTypeParm, Canon, Canon->isDependentType()),
: Type(SubstTemplateTypeParm, Canon, Canon->isDependentType(),
Canon->isVariablyModifiedType()),
Replaced(Param) { }
friend class ASTContext;
@ -2629,7 +2630,8 @@ class InjectedClassNameType : public Type {
// currently suitable for AST reading, too much
// interdependencies.
InjectedClassNameType(CXXRecordDecl *D, QualType TST)
: Type(InjectedClassName, QualType(), true),
: Type(InjectedClassName, QualType(), /*Dependent=*/true,
/*VariablyModified=*/false),
Decl(D), InjectedType(TST) {
assert(isa<TemplateSpecializationType>(TST));
assert(!TST.hasQualifiers());
@ -2693,8 +2695,9 @@ class TypeWithKeyword : public Type {
protected:
TypeWithKeyword(ElaboratedTypeKeyword Keyword, TypeClass tc,
QualType Canonical, bool dependent)
: Type(tc, Canonical, dependent), Keyword(Keyword) {}
QualType Canonical, bool Dependent, bool VariablyModified)
: Type(tc, Canonical, Dependent, VariablyModified),
Keyword(Keyword) {}
public:
virtual ~TypeWithKeyword(); // pin vtable to Type.cpp
@ -2752,7 +2755,8 @@ class ElaboratedType : public TypeWithKeyword, public llvm::FoldingSetNode {
ElaboratedType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS,
QualType NamedType, QualType CanonType)
: TypeWithKeyword(Keyword, Elaborated, CanonType,
NamedType->isDependentType()),
NamedType->isDependentType(),
NamedType->isVariablyModifiedType()),
NNS(NNS), NamedType(NamedType) {
assert(!(Keyword == ETK_None && NNS == 0) &&
"ElaboratedType cannot have elaborated type keyword "
@ -2812,7 +2816,8 @@ class DependentNameType : public TypeWithKeyword, public llvm::FoldingSetNode {
DependentNameType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS,
const IdentifierInfo *Name, QualType CanonType)
: TypeWithKeyword(Keyword, DependentName, CanonType, true),
: TypeWithKeyword(Keyword, DependentName, CanonType, /*Dependent=*/true,
/*VariablyModified=*/false),
NNS(NNS), Name(Name) {
assert(NNS->isDependent() &&
"DependentNameType requires a dependent nested-name-specifier");
@ -2981,7 +2986,7 @@ protected:
enum Nonce_ObjCInterface { Nonce_ObjCInterface };
ObjCObjectType(enum Nonce_ObjCInterface)
: Type(ObjCInterface, QualType(), false),
: Type(ObjCInterface, QualType(), false, false),
NumProtocols(0),
BaseType(QualType(this_(), 0)) {}
@ -3139,7 +3144,7 @@ class ObjCObjectPointerType : public Type, public llvm::FoldingSetNode {
QualType PointeeType;
ObjCObjectPointerType(QualType Canonical, QualType Pointee)
: Type(ObjCObjectPointer, Canonical, false),
: Type(ObjCObjectPointer, Canonical, false, false),
PointeeType(Pointee) {}
friend class ASTContext; // ASTContext creates these.

View File

@ -165,7 +165,8 @@ class LocInfoType : public Type {
TypeSourceInfo *DeclInfo;
LocInfoType(QualType ty, TypeSourceInfo *TInfo)
: Type((TypeClass)LocInfo, ty, ty->isDependentType()), DeclInfo(TInfo) {
: Type((TypeClass)LocInfo, ty, ty->isDependentType(),
ty->isVariablyModifiedType()), DeclInfo(TInfo) {
assert(getTypeClass() == (TypeClass)LocInfo && "LocInfo didn't fit in TC?");
}
friend class Sema;

View File

@ -268,42 +268,6 @@ QualType Type::getPointeeType() const {
return QualType();
}
/// isVariablyModifiedType (C99 6.7.5p3) - Return true for variable length
/// array types and types that contain variable array types in their
/// declarator
bool Type::isVariablyModifiedType() const {
// FIXME: We should really keep a "variably modified" bit in Type, rather
// than walking the type hierarchy to recompute it.
// A VLA is a variably modified type.
if (isVariableArrayType())
return true;
// An array can contain a variably modified type
if (const Type *T = getArrayElementTypeNoTypeQual())
return T->isVariablyModifiedType();
// A pointer can point to a variably modified type.
// Also, C++ references and member pointers can point to a variably modified
// type, where VLAs appear as an extension to C++, and should be treated
// correctly.
if (const PointerType *PT = getAs<PointerType>())
return PT->getPointeeType()->isVariablyModifiedType();
if (const ReferenceType *RT = getAs<ReferenceType>())
return RT->getPointeeType()->isVariablyModifiedType();
if (const MemberPointerType *PT = getAs<MemberPointerType>())
return PT->getPointeeType()->isVariablyModifiedType();
// A function can return a variably modified type
// This one isn't completely obvious, but it follows from the
// definition in C99 6.7.5p3. Because of this rule, it's
// illegal to declare a function returning a variably modified type.
if (const FunctionType *FT = getAs<FunctionType>())
return FT->getResultType()->isVariablyModifiedType();
return false;
}
const RecordType *Type::getAsStructureType() const {
// If this is directly a structure type, return it.
if (const RecordType *RT = dyn_cast<RecordType>(this)) {
@ -346,7 +310,7 @@ const RecordType *Type::getAsUnionType() const {
ObjCObjectType::ObjCObjectType(QualType Canonical, QualType Base,
ObjCProtocolDecl * const *Protocols,
unsigned NumProtocols)
: Type(ObjCObject, Canonical, false),
: Type(ObjCObject, Canonical, false, false),
NumProtocols(NumProtocols),
BaseType(Base) {
assert(this->NumProtocols == NumProtocols &&
@ -913,7 +877,8 @@ DependentTemplateSpecializationType::DependentTemplateSpecializationType(
NestedNameSpecifier *NNS, const IdentifierInfo *Name,
unsigned NumArgs, const TemplateArgument *Args,
QualType Canon)
: TypeWithKeyword(Keyword, DependentTemplateSpecialization, Canon, true),
: TypeWithKeyword(Keyword, DependentTemplateSpecialization, Canon, true,
false),
NNS(NNS), Name(Name), NumArgs(NumArgs) {
assert(NNS && NNS->isDependent() &&
"DependentTemplateSpecializatonType requires dependent qualifier");
@ -1026,6 +991,35 @@ llvm::StringRef FunctionType::getNameForCallConv(CallingConv CC) {
}
}
FunctionProtoType::FunctionProtoType(QualType Result, const QualType *ArgArray,
unsigned numArgs, bool isVariadic,
unsigned typeQuals, bool hasExs,
bool hasAnyExs, const QualType *ExArray,
unsigned numExs, QualType Canonical,
const ExtInfo &Info)
: FunctionType(FunctionProto, Result, isVariadic, typeQuals, Canonical,
Result->isDependentType(),
Result->isVariablyModifiedType(),
Info),
NumArgs(numArgs), NumExceptions(numExs), HasExceptionSpec(hasExs),
AnyExceptionSpec(hasAnyExs)
{
// Fill in the trailing argument array.
QualType *ArgInfo = reinterpret_cast<QualType*>(this+1);
for (unsigned i = 0; i != numArgs; ++i) {
if (ArgArray[i]->isDependentType())
setDependent();
ArgInfo[i] = ArgArray[i];
}
// Fill in the exception array.
QualType *Ex = ArgInfo + numArgs;
for (unsigned i = 0; i != numExs; ++i)
Ex[i] = ExArray[i];
}
void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result,
arg_type_iterator ArgTys,
unsigned NumArgs, bool isVariadic,
@ -1087,7 +1081,8 @@ QualType TypedefType::desugar() const {
}
TypeOfExprType::TypeOfExprType(Expr *E, QualType can)
: Type(TypeOfExpr, can, E->isTypeDependent()), TOExpr(E) {
: Type(TypeOfExpr, can, E->isTypeDependent(),
E->getType()->isVariablyModifiedType()), TOExpr(E) {
}
QualType TypeOfExprType::desugar() const {
@ -1100,7 +1095,8 @@ void DependentTypeOfExprType::Profile(llvm::FoldingSetNodeID &ID,
}
DecltypeType::DecltypeType(Expr *E, QualType underlyingType, QualType can)
: Type(Decltype, can, E->isTypeDependent()), E(E),
: Type(Decltype, can, E->isTypeDependent(),
E->getType()->isVariablyModifiedType()), E(E),
UnderlyingType(underlyingType) {
}
@ -1113,7 +1109,7 @@ void DependentDecltypeType::Profile(llvm::FoldingSetNodeID &ID,
}
TagType::TagType(TypeClass TC, const TagDecl *D, QualType can)
: Type(TC, can, D->isDependentType()),
: Type(TC, can, D->isDependentType(), /*VariablyModified=*/false),
decl(const_cast<TagDecl*>(D)) {}
static TagDecl *getInterestingTagDecl(TagDecl *decl) {
@ -1213,16 +1209,25 @@ TemplateSpecializationType(TemplateName T,
unsigned NumArgs, QualType Canon)
: Type(TemplateSpecialization,
Canon.isNull()? QualType(this, 0) : Canon,
T.isDependent() || anyDependentTemplateArguments(Args, NumArgs)),
Template(T), NumArgs(NumArgs) {
T.isDependent(), false),
Template(T), NumArgs(NumArgs)
{
assert((!Canon.isNull() ||
T.isDependent() || anyDependentTemplateArguments(Args, NumArgs)) &&
"No canonical type for non-dependent class template specialization");
TemplateArgument *TemplateArgs
= reinterpret_cast<TemplateArgument *>(this + 1);
for (unsigned Arg = 0; Arg < NumArgs; ++Arg)
for (unsigned Arg = 0; Arg < NumArgs; ++Arg) {
// Update dependent and variably-modified bits.
if (isDependent(Args[Arg]))
setDependent();
if (Args[Arg].getKind() == TemplateArgument::Type &&
Args[Arg].getAsType()->isVariablyModifiedType())
setVariablyModified();
new (&TemplateArgs[Arg]) TemplateArgument(Args[Arg]);
}
}
void