From: Eli Friedman Date: Fri, 15 Feb 2008 18:16:39 +0000 (+0000) Subject: Split out incomplete arrays from VariableArrayType into X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=c5773c4b8ce1ed6ed5c7112c9020c954a47dce96;p=clang Split out incomplete arrays from VariableArrayType into IncompleteArrayType. This should make code dealing with both incomplete and variable length arrays much more readable, plus it allows properly making the distinction between isVariableArrayType() and isVariablyModifiedType(). The patch is a little big, but it's strightforward. so I don't think there should be any issues. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@47165 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/AST/ASTContext.cpp b/AST/ASTContext.cpp index d4a689cb2d..608858b55f 100644 --- a/AST/ASTContext.cpp +++ b/AST/ASTContext.cpp @@ -532,49 +532,49 @@ QualType ASTContext::getConstantArrayType(QualType EltTy, QualType ASTContext::getVariableArrayType(QualType EltTy, Expr *NumElts, ArrayType::ArraySizeModifier ASM, unsigned EltTypeQuals) { - if (NumElts) { - // Since we don't unique expressions, it isn't possible to unique VLA's - // that have an expression provided for their size. - - VariableArrayType *New = new VariableArrayType(EltTy, QualType(), NumElts, - ASM, EltTypeQuals); - - CompleteVariableArrayTypes.push_back(New); - Types.push_back(New); - return QualType(New, 0); - } - else { - // No size is provided for the VLA. These we can unique. - llvm::FoldingSetNodeID ID; - VariableArrayType::Profile(ID, EltTy); - - void *InsertPos = 0; - if (VariableArrayType *ATP = - IncompleteVariableArrayTypes.FindNodeOrInsertPos(ID, InsertPos)) - return QualType(ATP, 0); - - // If the element type isn't canonical, this won't be a canonical type - // either, so fill in the canonical type field. - QualType Canonical; - - if (!EltTy->isCanonical()) { - Canonical = getVariableArrayType(EltTy.getCanonicalType(), NumElts, + // Since we don't unique expressions, it isn't possible to unique VLA's + // that have an expression provided for their size. + + VariableArrayType *New = new VariableArrayType(EltTy, QualType(), NumElts, + ASM, EltTypeQuals); + + VariableArrayTypes.push_back(New); + Types.push_back(New); + return QualType(New, 0); +} + +QualType ASTContext::getIncompleteArrayType(QualType EltTy, + ArrayType::ArraySizeModifier ASM, + unsigned EltTypeQuals) { + llvm::FoldingSetNodeID ID; + IncompleteArrayType::Profile(ID, EltTy); + + void *InsertPos = 0; + if (IncompleteArrayType *ATP = + IncompleteArrayTypes.FindNodeOrInsertPos(ID, InsertPos)) + return QualType(ATP, 0); + + // If the element type isn't canonical, this won't be a canonical type + // either, so fill in the canonical type field. + QualType Canonical; + + if (!EltTy->isCanonical()) { + Canonical = getIncompleteArrayType(EltTy.getCanonicalType(), ASM, EltTypeQuals); - - // Get the new insert position for the node we care about. - VariableArrayType *NewIP = - IncompleteVariableArrayTypes.FindNodeOrInsertPos(ID, InsertPos); - - assert(NewIP == 0 && "Shouldn't be in the map!"); - } - - VariableArrayType *New = new VariableArrayType(EltTy, QualType(), NumElts, - ASM, EltTypeQuals); - - IncompleteVariableArrayTypes.InsertNode(New, InsertPos); - Types.push_back(New); - return QualType(New, 0); + + // Get the new insert position for the node we care about. + IncompleteArrayType *NewIP = + IncompleteArrayTypes.FindNodeOrInsertPos(ID, InsertPos); + + assert(NewIP == 0 && "Shouldn't be in the map!"); } + + IncompleteArrayType *New = new IncompleteArrayType(EltTy, Canonical, + ASM, EltTypeQuals); + + IncompleteArrayTypes.InsertNode(New, InsertPos); + Types.push_back(New); + return QualType(New, 0); } /// getVectorType - Return the unique reference to a vector type of @@ -1690,6 +1690,8 @@ bool ASTContext::typesAreCompatible(QualType lhs, QualType rhs) { // Same as above for arrays if (LHSClass == Type::VariableArray) LHSClass = Type::ConstantArray; if (RHSClass == Type::VariableArray) RHSClass = Type::ConstantArray; + if (LHSClass == Type::IncompleteArray) LHSClass = Type::ConstantArray; + if (RHSClass == Type::IncompleteArray) RHSClass = Type::ConstantArray; // If the canonical type classes don't match... if (LHSClass != RHSClass) { @@ -1719,6 +1721,7 @@ bool ASTContext::typesAreCompatible(QualType lhs, QualType rhs) { return pointerTypesAreCompatible(lcanon, rcanon); case Type::ConstantArray: case Type::VariableArray: + case Type::IncompleteArray: return arrayTypesAreCompatible(lcanon, rcanon); case Type::FunctionNoProto: return functionTypesAreCompatible(lcanon, rcanon); diff --git a/AST/Type.cpp b/AST/Type.cpp index 1ce5059777..13ffb0e220 100644 --- a/AST/Type.cpp +++ b/AST/Type.cpp @@ -46,6 +46,7 @@ bool Type::isDerivedType() const { case Pointer: case VariableArray: case ConstantArray: + case IncompleteArray: case FunctionProto: case FunctionNoProto: case Reference: @@ -255,28 +256,26 @@ bool Type::isVariablyModifiedType() const { return false; } -const VariableArrayType *Type::getAsVariablyModifiedType() const { - if (const VariableArrayType *VAT = getAsVariableArrayType()) { - if (VAT->getSizeExpr()) - return VAT; - } - return 0; -} - bool Type::isIncompleteArrayType() const { - if (const VariableArrayType *VAT = getAsVariableArrayType()) { - if (!VAT->getSizeExpr()) - return true; - } - return false; + return isa(CanonicalType); } -const VariableArrayType *Type::getAsIncompleteArrayType() const { - if (const VariableArrayType *VAT = getAsVariableArrayType()) { - if (!VAT->getSizeExpr()) - return VAT; +const IncompleteArrayType *Type::getAsIncompleteArrayType() const { + // If this is directly a variable array type, return it. + if (const IncompleteArrayType *ATy = dyn_cast(this)) + return ATy; + + // If the canonical form of this type isn't the right kind, reject it. + if (!isa(CanonicalType)) { + // Look through type qualifiers + if (isa(CanonicalType.getUnqualifiedType())) + return CanonicalType.getUnqualifiedType()->getAsIncompleteArrayType(); + return 0; } - return 0; + + // If this is a typedef for a variable array type, strip the typedef off + // without losing all typedef information. + return getDesugaredType()->getAsIncompleteArrayType(); } const RecordType *Type::getAsRecordType() const { @@ -563,8 +562,7 @@ bool Type::isAggregateType() const { } if (const ASQualType *ASQT = dyn_cast(CanonicalType)) return ASQT->getBaseType()->isAggregateType(); - return CanonicalType->getTypeClass() == ConstantArray || - CanonicalType->getTypeClass() == VariableArray; + return isa(CanonicalType); } /// isConstantSizeType - Return true if this is not a variable sized type, @@ -594,9 +592,9 @@ bool Type::isIncompleteType() const { // A tagged type (struct/union/enum/class) is incomplete if the decl is a // forward declaration, but not a full definition (C99 6.2.5p22). return !cast(CanonicalType)->getDecl()->isDefinition(); - case VariableArray: + case IncompleteArray: // An array of unknown size is an incomplete type (C99 6.2.5p22). - return cast(CanonicalType)->getSizeExpr() == 0; + return true; } } @@ -804,6 +802,12 @@ void ConstantArrayType::getAsStringInternal(std::string &S) const { getElementType().getAsStringInternal(S); } +void IncompleteArrayType::getAsStringInternal(std::string &S) const { + S += "[]"; + + getElementType().getAsStringInternal(S); +} + void VariableArrayType::getAsStringInternal(std::string &S) const { S += '['; diff --git a/AST/TypeSerialization.cpp b/AST/TypeSerialization.cpp index 7583a07475..e2ccd3c55e 100644 --- a/AST/TypeSerialization.cpp +++ b/AST/TypeSerialization.cpp @@ -91,6 +91,10 @@ void Type::Create(ASTContext& Context, unsigned i, Deserializer& D) { D.RegisterPtr(PtrID,FunctionTypeProto::CreateImpl(Context,D)); break; + case Type::IncompleteArray: + D.RegisterPtr(PtrID,IncompleteArrayType::CreateImpl(Context,D)); + break; + case Type::Pointer: D.RegisterPtr(PtrID,PointerType::CreateImpl(Context,D)); break; @@ -269,3 +273,21 @@ Type* VariableArrayType::CreateImpl(ASTContext& Context, Deserializer& D) { return Context.getVariableArrayType(ElTy,SizeExpr,am,ITQ).getTypePtr(); } + +//===----------------------------------------------------------------------===// +// IncompleteArrayType +//===----------------------------------------------------------------------===// + +void IncompleteArrayType::EmitImpl(Serializer& S) const { + S.Emit(getElementType()); + S.EmitInt(getSizeModifier()); + S.EmitInt(getIndexTypeQualifier()); +} + +Type* IncompleteArrayType::CreateImpl(ASTContext& Context, Deserializer& D) { + QualType ElTy = QualType::ReadVal(D); + ArraySizeModifier am = static_cast(D.ReadInt()); + unsigned ITQ = D.ReadInt(); + + return Context.getIncompleteArrayType(ElTy,am,ITQ).getTypePtr(); +} diff --git a/CodeGen/CodeGenTypes.cpp b/CodeGen/CodeGenTypes.cpp index d293b4f081..96bccfc6ec 100644 --- a/CodeGen/CodeGenTypes.cpp +++ b/CodeGen/CodeGenTypes.cpp @@ -207,15 +207,18 @@ const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) { case Type::VariableArray: { const VariableArrayType &A = cast(Ty); - assert(A.getSizeModifier() == ArrayType::Normal && - A.getIndexTypeQualifier() == 0 && + assert(A.getIndexTypeQualifier() == 0 && "FIXME: We only handle trivial array types so far!"); - if (A.getSizeExpr() == 0) { - // int X[] -> [0 x int] - return llvm::ArrayType::get(ConvertType(A.getElementType()), 0); - } else { - assert(0 && "FIXME: VLAs not implemented yet!"); - } + // VLAs resolve to the innermost element type; this matches + // the return of alloca, and there isn't any obviously better choice. + return ConvertType(A.getElementType()); + } + case Type::IncompleteArray: { + const IncompleteArrayType &A = cast(Ty); + assert(A.getIndexTypeQualifier() == 0 && + "FIXME: We only handle trivial array types so far!"); + // int X[] -> [0 x int] + return llvm::ArrayType::get(ConvertType(A.getElementType()), 0); } case Type::ConstantArray: { const ConstantArrayType &A = cast(Ty); diff --git a/Sema/SemaDecl.cpp b/Sema/SemaDecl.cpp index 2358bdf391..81d4c9e0f7 100644 --- a/Sema/SemaDecl.cpp +++ b/Sema/SemaDecl.cpp @@ -412,13 +412,13 @@ bool Sema::CheckInitExpr(Expr *expr, InitListExpr *IList, unsigned slot, } bool Sema::CheckStringLiteralInit(StringLiteral *strLiteral, QualType &DeclT) { - if (const VariableArrayType *VAT = DeclT->getAsIncompleteArrayType()) { + if (const IncompleteArrayType *IAT = DeclT->getAsIncompleteArrayType()) { // C99 6.7.8p14. We have an array of character type with unknown size // being initialized to a string literal. llvm::APSInt ConstVal(32); ConstVal = strLiteral->getByteLength() + 1; // Return a new array type (C99 6.7.8p22). - DeclT = Context.getConstantArrayType(VAT->getElementType(), ConstVal, + DeclT = Context.getConstantArrayType(IAT->getElementType(), ConstVal, ArrayType::Normal, 0); } else if (const ConstantArrayType *CAT = DeclT->getAsConstantArrayType()) { // C99 6.7.8p14. We have an array of character type with known size. @@ -564,17 +564,18 @@ bool Sema::CheckInitializerListTypes(InitListExpr*& IList, QualType &DeclType, } } int maxElements; - if (const VariableArrayType *VAT = DeclType->getAsVariableArrayType()) { + if (DeclType->isIncompleteArrayType()) { // FIXME: use a proper constant maxElements = 0x7FFFFFFF; + } else if (const VariableArrayType *VAT = DeclType->getAsVariableArrayType()) { // Check for VLAs; in standard C it would be possible to check this // earlier, but I don't know where clang accepts VLAs (gcc accepts // them in all sorts of strange places). - if (const Expr *expr = VAT->getSizeExpr()) { - Diag(expr->getLocStart(), diag::err_variable_object_no_init, - expr->getSourceRange()); - hadError = true; - } + Diag(VAT->getSizeExpr()->getLocStart(), + diag::err_variable_object_no_init, + VAT->getSizeExpr()->getSourceRange()); + hadError = true; + maxElements = 0x7FFFFFFF; } else { const ConstantArrayType *CAT = DeclType->getAsConstantArrayType(); maxElements = static_cast(CAT->getSize().getZExtValue()); @@ -638,7 +639,7 @@ bool Sema::CheckInitializerListTypes(InitListExpr*& IList, QualType &DeclType, bool Sema::CheckInitializerTypes(Expr *&Init, QualType &DeclType) { // C99 6.7.8p3: The type of the entity to be initialized shall be an array // of unknown size ("[]") or an object type that is not a variable array type. - if (const VariableArrayType *VAT = DeclType->getAsVariablyModifiedType()) + if (const VariableArrayType *VAT = DeclType->getAsVariableArrayType()) return Diag(VAT->getSizeExpr()->getLocStart(), diag::err_variable_object_no_init, VAT->getSizeExpr()->getSourceRange()); @@ -897,10 +898,8 @@ Sema::DeclTy *Sema::FinalizeDeclaratorGroup(Scope *S, DeclTy *group) { // static storage duration, it shall not have a variable length array. if ((FVD || BVD) && IDecl->getStorageClass() == VarDecl::Static) { if (const VariableArrayType *VLA = T->getAsVariableArrayType()) { - if (VLA->getSizeExpr()) { - Diag(IDecl->getLocation(), diag::err_typecheck_illegal_vla); - IDecl->setInvalidDecl(); - } + Diag(IDecl->getLocation(), diag::err_typecheck_illegal_vla); + IDecl->setInvalidDecl(); } } // Block scope. C99 6.7p7: If an identifier for an object is declared with diff --git a/Sema/SemaType.cpp b/Sema/SemaType.cpp index 5ba25863db..58d7019e6d 100644 --- a/Sema/SemaType.cpp +++ b/Sema/SemaType.cpp @@ -231,9 +231,11 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S) { } llvm::APSInt ConstVal(32); // If no expression was provided, we consider it a VLA. - if (!ArraySize || !ArraySize->isIntegerConstantExpr(ConstVal, Context)) + if (!ArraySize) { + T = Context.getIncompleteArrayType(T, ASM, ATI.TypeQuals); + } else if (!ArraySize->isIntegerConstantExpr(ConstVal, Context)) { T = Context.getVariableArrayType(T, ArraySize, ASM, ATI.TypeQuals); - else { + } else { // C99 6.7.5.2p1: If the expression is a constant expression, it shall // have a value greater than zero. if (ConstVal.isSigned()) { diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index e55790ea4a..40e1f72bb6 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -37,8 +37,8 @@ class ASTContext { llvm::FoldingSet PointerTypes; llvm::FoldingSet ReferenceTypes; llvm::FoldingSet ConstantArrayTypes; - llvm::FoldingSet IncompleteVariableArrayTypes; - std::vector CompleteVariableArrayTypes; + llvm::FoldingSet IncompleteArrayTypes; + std::vector VariableArrayTypes; llvm::FoldingSet VectorTypes; llvm::FoldingSet FunctionTypeNoProtos; llvm::FoldingSet FunctionTypeProtos; @@ -143,6 +143,12 @@ public: ArrayType::ArraySizeModifier ASM, unsigned EltTypeQuals); + /// getIncompleteArrayType - Returns a unique reference to the type for a + /// incomplete array of the specified element type. + QualType getIncompleteArrayType(QualType EltTy, + ArrayType::ArraySizeModifier ASM, + unsigned EltTypeQuals); + /// getConstantArrayType - Return the unique reference to the type for a /// constant array of the specified element type. QualType getConstantArrayType(QualType EltTy, const llvm::APInt &ArySize, diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index 9ff76ef666..b77d23b813 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -44,6 +44,7 @@ namespace clang { class ArrayType; class ConstantArrayType; class VariableArrayType; + class IncompleteArrayType; class RecordType; class ComplexType; class TagType; @@ -217,7 +218,7 @@ class Type { public: enum TypeClass { Builtin, Complex, Pointer, Reference, - ConstantArray, VariableArray, + ConstantArray, VariableArray, IncompleteArray, Vector, OCUVector, FunctionNoProto, FunctionProto, TypeName, Tagged, ASQual, @@ -319,8 +320,7 @@ public: const ArrayType *getAsArrayType() const; const ConstantArrayType *getAsConstantArrayType() const; const VariableArrayType *getAsVariableArrayType() const; - const VariableArrayType *getAsIncompleteArrayType() const; - const VariableArrayType *getAsVariablyModifiedType() const; + const IncompleteArrayType *getAsIncompleteArrayType() const; const RecordType *getAsRecordType() const; const RecordType *getAsStructureType() const; const RecordType *getAsUnionType() const; @@ -576,7 +576,8 @@ public: } static bool classof(const Type *T) { return T->getTypeClass() == ConstantArray || - T->getTypeClass() == VariableArray; + T->getTypeClass() == VariableArray || + T->getTypeClass() == IncompleteArray; } static bool classof(const ArrayType *) { return true; } }; @@ -623,6 +624,36 @@ protected: friend class Type; }; +class IncompleteArrayType : public ArrayType { + IncompleteArrayType(QualType et, QualType can, + ArraySizeModifier sm, unsigned tq) + : ArrayType(IncompleteArray, et, can, sm, tq) {} + friend class ASTContext; // ASTContext creates these. +public: + + virtual void getAsStringInternal(std::string &InnerString) const; + + static bool classof(const Type *T) { + return T->getTypeClass() == IncompleteArray; + } + static bool classof(const IncompleteArrayType *) { return true; } + + friend class StmtIteratorBase; + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getElementType()); + } + + static void Profile(llvm::FoldingSetNodeID &ID, QualType ET) { + ID.AddPointer(ET.getAsOpaquePtr()); + } + +protected: + virtual void EmitImpl(llvm::Serializer& S) const; + static Type* CreateImpl(ASTContext& Context,llvm::Deserializer& D); + friend class Type; +}; + // FIXME: VariableArrayType's aren't uniqued (since expressions aren't). class VariableArrayType : public ArrayType { /// SizeExpr - An assignment expression. VLA's are only permitted within @@ -647,14 +678,7 @@ public: friend class StmtIteratorBase; void Profile(llvm::FoldingSetNodeID &ID) { - assert (SizeExpr == NULL - && "Can only unique VariableArrayTypes with no specified size."); - - Profile(ID, getElementType()); - } - - static void Profile(llvm::FoldingSetNodeID &ID, QualType ET) { - ID.AddPointer(ET.getAsOpaquePtr()); + assert (0 && "Cannnot unique VariableArrayTypes."); } protected: