diff options
-rw-r--r-- | AST/ASTContext.cpp | 85 | ||||
-rw-r--r-- | AST/Type.cpp | 48 | ||||
-rw-r--r-- | AST/TypeSerialization.cpp | 22 | ||||
-rw-r--r-- | CodeGen/CodeGenTypes.cpp | 19 | ||||
-rw-r--r-- | Sema/SemaDecl.cpp | 25 | ||||
-rw-r--r-- | Sema/SemaType.cpp | 6 | ||||
-rw-r--r-- | include/clang/AST/ASTContext.h | 10 | ||||
-rw-r--r-- | include/clang/AST/Type.h | 48 |
8 files changed, 163 insertions, 100 deletions
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<IncompleteArrayType>(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<IncompleteArrayType>(this)) + return ATy; + + // If the canonical form of this type isn't the right kind, reject it. + if (!isa<IncompleteArrayType>(CanonicalType)) { + // Look through type qualifiers + if (isa<IncompleteArrayType>(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<ASQualType>(CanonicalType)) return ASQT->getBaseType()->isAggregateType(); - return CanonicalType->getTypeClass() == ConstantArray || - CanonicalType->getTypeClass() == VariableArray; + return isa<ArrayType>(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<TagType>(CanonicalType)->getDecl()->isDefinition(); - case VariableArray: + case IncompleteArray: // An array of unknown size is an incomplete type (C99 6.2.5p22). - return cast<VariableArrayType>(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<ArraySizeModifier>(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<VariableArrayType>(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<IncompleteArrayType>(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<ConstantArrayType>(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<int>(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<PointerType> PointerTypes; llvm::FoldingSet<ReferenceType> ReferenceTypes; llvm::FoldingSet<ConstantArrayType> ConstantArrayTypes; - llvm::FoldingSet<VariableArrayType> IncompleteVariableArrayTypes; - std::vector<VariableArrayType*> CompleteVariableArrayTypes; + llvm::FoldingSet<IncompleteArrayType> IncompleteArrayTypes; + std::vector<VariableArrayType*> VariableArrayTypes; llvm::FoldingSet<VectorType> VectorTypes; llvm::FoldingSet<FunctionTypeNoProto> FunctionTypeNoProtos; llvm::FoldingSet<FunctionTypeProto> 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: |