From 518da18d70005f7986be131ac9292615d0f47fb2 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Wed, 13 Oct 2010 16:58:14 +0000 Subject: [PATCH] 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 --- clang/include/clang/AST/Type.h | 123 +++++++++++++++++--------------- clang/include/clang/Sema/Sema.h | 3 +- clang/lib/AST/Type.cpp | 93 ++++++++++++------------ 3 files changed, 115 insertions(+), 104 deletions(-) diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index 6358ab80aaca..c5a34716f918 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -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(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(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(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(D)) { assert(!isa(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(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(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. diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index dcad3b2c9c74..144c58d1bb06 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -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; diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index d924135ac65d..6698e50eba85 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -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()) - return PT->getPointeeType()->isVariablyModifiedType(); - if (const ReferenceType *RT = getAs()) - return RT->getPointeeType()->isVariablyModifiedType(); - if (const MemberPointerType *PT = getAs()) - 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()) - 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(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(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(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(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