From: Chris Lattner Date: Mon, 4 Aug 2008 07:31:14 +0000 (+0000) Subject: Finally fix PR2189. This makes a fairly invasive but important change to X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=c63a1f276f7b324fd9a4be82098b1c8f7bf30733;p=clang Finally fix PR2189. This makes a fairly invasive but important change to move getAsArrayType into ASTContext instead of being a method on type. This is required because getAsArrayType(const AT), where AT is a typedef for "int[10]" needs to return ArrayType(const int, 10). Fixing this greatly simplifies getArrayDecayedType, which is a good sign. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@54317 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index 0def988140..2c1e1e4ec6 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -253,7 +253,7 @@ public: // Return the ObjC type encoding for a given type. void getObjCEncodingForType(QualType t, std::string &S, - llvm::SmallVector &RT) const; + llvm::SmallVector &RT) const; // Put the string version of type qualifiers into S. void getObjCEncodingForTypeQualifier(Decl::ObjCDeclQualifier QT, @@ -339,6 +339,21 @@ public: /// for exact equality with a simple pointer comparison. QualType getCanonicalType(QualType T); + /// Type Query functions. If the type is an instance of the specified class, + /// return the Type pointer for the underlying maximally pretty type. This + /// is a member of ASTContext because this may need to do some amount of + /// canonicalization, e.g. to move type qualifiers into the element type. + const ArrayType *getAsArrayType(QualType T); + const ConstantArrayType *getAsConstantArrayType(QualType T) { + return dyn_cast_or_null(getAsArrayType(T)); + } + const VariableArrayType *getAsVariableArrayType(QualType T) { + return dyn_cast_or_null(getAsArrayType(T)); + } + const IncompleteArrayType *getAsIncompleteArrayType(QualType T) { + return dyn_cast_or_null(getAsArrayType(T)); + } + /// getArrayDecayedType - Return the properly qualified result of decaying the /// specified array type to a pointer. This operation is non-trivial when /// handling typedefs etc. The canonical type of "T" must be an array type, diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index 5d764894c2..4b349f4d10 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -143,6 +143,9 @@ public: QualType getQualifiedType(unsigned TQs) const { return QualType(getTypePtr(), TQs); } + QualType getWithAdditionalQualifiers(unsigned TQs) const { + return QualType(getTypePtr(), TQs|getCVRQualifiers()); + } inline QualType getUnqualifiedType() const; @@ -285,10 +288,6 @@ public: /// types that have a non-constant expression. This does not include "[]". bool isVariablyModifiedType() const; - /// isIncompleteArrayType (C99 6.2.5p22) - Return true for variable array - /// types that don't have any expression ("[]"). - bool isIncompleteArrayType() const; - /// Helper methods to distinguish type categories. All type predicates /// operate on the canonical type, ignoring typedefs and qualifiers. @@ -322,6 +321,9 @@ public: bool isReferenceType() const; bool isFunctionPointerType() const; bool isArrayType() const; + bool isConstantArrayType() const; + bool isIncompleteArrayType() const; + bool isVariableArrayType() const; bool isRecordType() const; bool isClassType() const; bool isStructureType() const; @@ -342,12 +344,9 @@ public: const PointerLikeType *getAsPointerLikeType() const; // Pointer or Reference. const PointerType *getAsPointerType() const; const ReferenceType *getAsReferenceType() const; - const ArrayType *getAsArrayType() const; - const ConstantArrayType *getAsConstantArrayType() const; - const VariableArrayType *getAsVariableArrayType() const; - const IncompleteArrayType *getAsIncompleteArrayType() const; const RecordType *getAsRecordType() const; const RecordType *getAsStructureType() const; + /// NOTE: getAsArrayType* are methods on ASTContext. const TypedefType *getAsTypedefType() const; const RecordType *getAsUnionType() const; const EnumType *getAsEnumType() const; @@ -358,11 +357,17 @@ public: const ObjCInterfaceType *getAsObjCInterfaceType() const; const ObjCQualifiedInterfaceType *getAsObjCQualifiedInterfaceType() const; const ObjCQualifiedIdType *getAsObjCQualifiedIdType() const; - + /// getAsPointerToObjCInterfaceType - If this is a pointer to an ObjC /// interface, return the interface type, otherwise return null. const ObjCInterfaceType *getAsPointerToObjCInterfaceType() const; + /// getArrayElementTypeNoTypeQual - If this is an array type, return the + /// element type of the array, potentially with type qualifiers missing. + /// This method should never be used when type qualifiers are meaningful. + const Type *getArrayElementTypeNoTypeQual() const; + + /// getDesugaredType - Return the specified type with any "sugar" removed from /// the type. This takes off typedefs, typeof's etc. If the outer level of @@ -370,7 +375,7 @@ public: /// to getting the canonical type, but it doesn't remove *all* typedefs. For /// example, it returns "T*" as "T*", (not as "int*"), because the pointer is /// concrete. - const Type *getDesugaredType() const; + QualType getDesugaredType() const; /// More type predicates useful for type checking/promotion bool isPromotableIntegerType() const; // C99 6.3.1.1p2 @@ -391,11 +396,8 @@ public: /// according to the rules of C99 6.7.5p3. It is not legal to call this on /// incomplete types. bool isConstantSizeType() const; -private: + QualType getCanonicalTypeInternal() const { return CanonicalType; } - friend class QualType; - friend class TypedefType; -public: void dump() const; virtual void getAsStringInternal(std::string &InnerString) const = 0; static bool classof(const Type *) { return true; } @@ -619,14 +621,6 @@ public: } unsigned getIndexTypeQualifier() const { return IndexTypeQuals; } - QualType getBaseType() const { - const ArrayType *AT; - QualType ElmtType = getElementType(); - // If we have a multi-dimensional array, navigate to the base type. - while ((AT = ElmtType->getAsArrayType())) - ElmtType = AT->getElementType(); - return ElmtType; - } static bool classof(const Type *T) { return T->getTypeClass() == ConstantArray || T->getTypeClass() == VariableArray || @@ -646,19 +640,7 @@ class ConstantArrayType : public ArrayType { : ArrayType(ConstantArray, et, can, sm, tq), Size(sz) {} friend class ASTContext; // ASTContext creates these. public: - llvm::APInt getSize() const { return Size; } - int getMaximumElements() const { - QualType ElmtType = getElementType(); - int maxElements = static_cast(getSize().getZExtValue()); - - const ConstantArrayType *CAT; - // If we have a multi-dimensional array, include it's elements. - while ((CAT = ElmtType->getAsConstantArrayType())) { - ElmtType = CAT->getElementType(); - maxElements *= static_cast(CAT->getSize().getZExtValue()); - } - return maxElements; - } + const llvm::APInt &getSize() const { return Size; } virtual void getAsStringInternal(std::string &InnerString) const; void Profile(llvm::FoldingSetNodeID &ID) { @@ -740,7 +722,7 @@ class VariableArrayType : public ArrayType { virtual void Destroy(ASTContext& C); public: - const Expr *getSizeExpr() const { + Expr *getSizeExpr() const { // We use C-style casts instead of cast<> here because we do not wish // to have a dependency of Type.h on Stmt.h/Expr.h. return (Expr*) SizeExpr; @@ -1274,7 +1256,7 @@ inline QualType QualType::getUnqualifiedType() const { inline unsigned QualType::getAddressSpace() const { QualType CT = getTypePtr()->getCanonicalTypeInternal(); if (const ArrayType *AT = dyn_cast(CT)) - return AT->getBaseType().getAddressSpace(); + return AT->getElementType().getAddressSpace(); if (const RecordType *RT = dyn_cast(CT)) return RT->getAddressSpace(); if (const ASQualType *ASQT = dyn_cast(CT)) @@ -1291,7 +1273,8 @@ inline const ObjCInterfaceType *Type::getAsPointerToObjCInterfaceType() const { return 0; } - +// NOTE: All of these methods use "getUnqualifiedType" to strip off address +// space qualifiers if present. inline bool Type::isFunctionType() const { return isa(CanonicalType.getUnqualifiedType()); } @@ -1313,11 +1296,20 @@ inline bool Type::isFunctionPointerType() const { inline bool Type::isArrayType() const { return isa(CanonicalType.getUnqualifiedType()); } +inline bool Type::isConstantArrayType() const { + return isa(CanonicalType.getUnqualifiedType()); +} +inline bool Type::isIncompleteArrayType() const { + return isa(CanonicalType.getUnqualifiedType()); +} +inline bool Type::isVariableArrayType() const { + return isa(CanonicalType.getUnqualifiedType()); +} inline bool Type::isRecordType() const { return isa(CanonicalType.getUnqualifiedType()); } inline bool Type::isAnyComplexType() const { - return isa(CanonicalType); + return isa(CanonicalType.getUnqualifiedType()); } inline bool Type::isVectorType() const { return isa(CanonicalType.getUnqualifiedType()); @@ -1326,13 +1318,13 @@ inline bool Type::isExtVectorType() const { return isa(CanonicalType.getUnqualifiedType()); } inline bool Type::isObjCInterfaceType() const { - return isa(CanonicalType); + return isa(CanonicalType.getUnqualifiedType()); } inline bool Type::isObjCQualifiedInterfaceType() const { - return isa(CanonicalType); + return isa(CanonicalType.getUnqualifiedType()); } inline bool Type::isObjCQualifiedIdType() const { - return isa(CanonicalType); + return isa(CanonicalType.getUnqualifiedType()); } } // end namespace clang diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 47a3e3ac67..002a51f877 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -375,7 +375,7 @@ void ASTRecordLayout::LayoutField(const FieldDecl *FD, unsigned FieldNo, // Flexible array members don't have any size, but they // have to be aligned appropriately for their element type. FieldSize = 0; - const ArrayType* ATy = FD->getType()->getAsArrayType(); + const ArrayType* ATy = Context.getAsArrayType(FD->getType()); FieldAlign = Context.getTypeAlign(ATy->getElementType()); } else { std::pair FieldInfo = @@ -1018,8 +1018,107 @@ QualType ASTContext::getPointerDiffType() const { /// for exact equality with a simple pointer comparison. QualType ASTContext::getCanonicalType(QualType T) { QualType CanType = T.getTypePtr()->getCanonicalTypeInternal(); - return QualType(CanType.getTypePtr(), - T.getCVRQualifiers() | CanType.getCVRQualifiers()); + + // If the result has type qualifiers, make sure to canonicalize them as well. + unsigned TypeQuals = T.getCVRQualifiers() | CanType.getCVRQualifiers(); + if (TypeQuals == 0) return CanType; + + // If the type qualifiers are on an array type, get the canonical type of the + // array with the qualifiers applied to the element type. + ArrayType *AT = dyn_cast(CanType); + if (!AT) + return CanType.getQualifiedType(TypeQuals); + + // Get the canonical version of the element with the extra qualifiers on it. + // This can recursively sink qualifiers through multiple levels of arrays. + QualType NewEltTy=AT->getElementType().getWithAdditionalQualifiers(TypeQuals); + NewEltTy = getCanonicalType(NewEltTy); + + if (ConstantArrayType *CAT = dyn_cast(AT)) + return getConstantArrayType(NewEltTy, CAT->getSize(),CAT->getSizeModifier(), + CAT->getIndexTypeQualifier()); + if (IncompleteArrayType *IAT = dyn_cast(AT)) + return getIncompleteArrayType(NewEltTy, IAT->getSizeModifier(), + IAT->getIndexTypeQualifier()); + + // FIXME: What is the ownership of size expressions in VLAs? + VariableArrayType *VAT = cast(AT); + return getVariableArrayType(NewEltTy, VAT->getSizeExpr(), + VAT->getSizeModifier(), + VAT->getIndexTypeQualifier()); +} + + +const ArrayType *ASTContext::getAsArrayType(QualType T) { + // Handle the non-qualified case efficiently. + if (T.getCVRQualifiers() == 0) { + // Handle the common positive case fast. + if (const ArrayType *AT = dyn_cast(T)) + return AT; + } + + // Handle the common negative case fast, ignoring CVR qualifiers. + QualType CType = T->getCanonicalTypeInternal(); + + // Make sure to look through type qualifiers (like ASQuals) for the negative + // test. + if (!isa(CType) && + !isa(CType.getUnqualifiedType())) + return 0; + + // Apply any CVR qualifiers from the array type to the element type. This + // implements C99 6.7.3p8: "If the specification of an array type includes + // any type qualifiers, the element type is so qualified, not the array type." + + // If we get here, we either have type qualifiers on the type, or we have + // sugar such as a typedef in the way. If we have type qualifiers on the type + // we must propagate them down into the elemeng type. + unsigned CVRQuals = T.getCVRQualifiers(); + unsigned AddrSpace = 0; + Type *Ty = T.getTypePtr(); + + // Rip through ASQualType's and typedefs to get to a concrete type. + while (1) { + if (const ASQualType *ASQT = dyn_cast(Ty)) { + AddrSpace = ASQT->getAddressSpace(); + Ty = ASQT->getBaseType(); + } else { + T = Ty->getDesugaredType(); + if (T.getTypePtr() == Ty && T.getCVRQualifiers() == 0) + break; + CVRQuals |= T.getCVRQualifiers(); + Ty = T.getTypePtr(); + } + } + + // If we have a simple case, just return now. + const ArrayType *ATy = dyn_cast(Ty); + if (ATy == 0 || (AddrSpace == 0 && CVRQuals == 0)) + return ATy; + + // Otherwise, we have an array and we have qualifiers on it. Push the + // qualifiers into the array element type and return a new array type. + // Get the canonical version of the element with the extra qualifiers on it. + // This can recursively sink qualifiers through multiple levels of arrays. + QualType NewEltTy = ATy->getElementType(); + if (AddrSpace) + NewEltTy = getASQualType(NewEltTy, AddrSpace); + NewEltTy = NewEltTy.getWithAdditionalQualifiers(CVRQuals); + + if (const ConstantArrayType *CAT = dyn_cast(ATy)) + return cast(getConstantArrayType(NewEltTy, CAT->getSize(), + CAT->getSizeModifier(), + CAT->getIndexTypeQualifier())); + if (const IncompleteArrayType *IAT = dyn_cast(ATy)) + return cast(getIncompleteArrayType(NewEltTy, + IAT->getSizeModifier(), + IAT->getIndexTypeQualifier())); + + // FIXME: What is the ownership of size expressions in VLAs? + const VariableArrayType *VAT = cast(ATy); + return cast(getVariableArrayType(NewEltTy, VAT->getSizeExpr(), + VAT->getSizeModifier(), + VAT->getIndexTypeQualifier())); } @@ -1030,60 +1129,17 @@ QualType ASTContext::getCanonicalType(QualType T) { /// /// See C99 6.7.5.3p7 and C99 6.3.2.1p3. QualType ASTContext::getArrayDecayedType(QualType Ty) { - // Handle the common case where typedefs are not involved directly. - QualType EltTy; - unsigned ArrayQuals = 0; - unsigned PointerQuals = 0; - if (ArrayType *AT = dyn_cast(Ty)) { - // Since T "isa" an array type, it could not have had an address space - // qualifier, just CVR qualifiers. The properly qualified element pointer - // gets the union of the CVR qualifiers from the element and the array, and - // keeps any address space qualifier on the element type if present. - EltTy = AT->getElementType(); - ArrayQuals = Ty.getCVRQualifiers(); - PointerQuals = AT->getIndexTypeQualifier(); - } else { - // Otherwise, we have an ASQualType or a typedef, etc. Make sure we don't - // lose qualifiers when dealing with typedefs. Example: - // typedef int arr[10]; - // void test2() { - // const arr b; - // b[4] = 1; - // } - // - // The decayed type of b is "const int*" even though the element type of the - // array is "int". - QualType CanTy = getCanonicalType(Ty); - const ArrayType *PrettyArrayType = Ty->getAsArrayType(); - assert(PrettyArrayType && "Not an array type!"); - - // Get the element type with 'getAsArrayType' so that we don't lose any - // typedefs in the element type of the array. - EltTy = PrettyArrayType->getElementType(); - - // If the array was address-space qualifier, make sure to ASQual the element - // type. We can just grab the address space from the canonical type. - if (unsigned AS = CanTy.getAddressSpace()) - EltTy = getASQualType(EltTy, AS); - - // To properly handle [multiple levels of] typedefs, typeof's etc, we take - // the CVR qualifiers directly from the canonical type, which is guaranteed - // to have the full set unioned together. - ArrayQuals = CanTy.getCVRQualifiers(); - PointerQuals = PrettyArrayType->getIndexTypeQualifier(); - } + // Get the element type with 'getAsArrayType' so that we don't lose any + // typedefs in the element type of the array. This also handles propagation + // of type qualifiers from the array type into the element type if present + // (C99 6.7.3p8). + const ArrayType *PrettyArrayType = getAsArrayType(Ty); + assert(PrettyArrayType && "Not an array type!"); - // Apply any CVR qualifiers from the array type to the element type. This - // implements C99 6.7.3p8: "If the specification of an array type includes - // any type qualifiers, the element type is so qualified, not the array type." - EltTy = EltTy.getQualifiedType(ArrayQuals | EltTy.getCVRQualifiers()); - - QualType PtrTy = getPointerType(EltTy); + QualType PtrTy = getPointerType(PrettyArrayType->getElementType()); // int x[restrict 4] -> int *restrict - PtrTy = PtrTy.getQualifiedType(PointerQuals); - - return PtrTy; + return PtrTy.getQualifiedType(PrettyArrayType->getIndexTypeQualifier()); } /// getFloatingRank - Return a relative rank for floating point types. @@ -1308,8 +1364,7 @@ void ASTContext::getObjCEncodingForMethodDecl(ObjCMethodDecl *Decl, } void ASTContext::getObjCEncodingForType(QualType T, std::string& S, - llvm::SmallVector &ERType) const -{ + llvm::SmallVector &ERType) const { // FIXME: This currently doesn't encode: // @ An object (whether statically typed or typed id) // # A class object (Class) @@ -1372,7 +1427,9 @@ void ASTContext::getObjCEncodingForType(QualType T, std::string& S, S += '^'; getObjCEncodingForType(PT->getPointeeType(), S, ERType); - } else if (const ArrayType *AT = T->getAsArrayType()) { + } else if (const ArrayType *AT = + // Ignore type qualifiers etc. + dyn_cast(T->getCanonicalTypeInternal())) { S += '['; if (const ConstantArrayType *CAT = dyn_cast(AT)) diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 60b762f66d..21f2b07d13 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -466,14 +466,17 @@ Expr::isModifiableLvalueResult Expr::isModifiableLvalue(ASTContext &Ctx) const { case LV_DuplicateVectorComponents: return MLV_DuplicateVectorComponents; case LV_InvalidExpression: return MLV_InvalidExpression; } - if (TR.isConstQualified()) + + QualType CT = Ctx.getCanonicalType(getType()); + + if (CT.isConstQualified()) return MLV_ConstQualified; - if (TR->isArrayType()) + if (CT->isArrayType()) return MLV_ArrayType; - if (TR->isIncompleteType()) + if (CT->isIncompleteType()) return MLV_IncompleteType; - if (const RecordType *r = TR->getAsRecordType()) { + if (const RecordType *r = CT->getAsRecordType()) { if (r->hasConstFields()) return MLV_ConstQualified; } diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index d32f963acb..f9f6ecac07 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -35,6 +35,45 @@ void VariableArrayType::Destroy(ASTContext& C) { delete this; } + +/// getArrayElementTypeNoTypeQual - If this is an array type, return the +/// element type of the array, potentially with type qualifiers missing. +/// This method should never be used when type qualifiers are meaningful. +const Type *Type::getArrayElementTypeNoTypeQual() const { + // If this is directly an array type, return it. + if (const ArrayType *ATy = dyn_cast(this)) + return ATy->getElementType().getTypePtr(); + + // If the canonical form of this type isn't the right kind, reject it. + if (!isa(CanonicalType)) { + // Look through type qualifiers + if (ArrayType *AT = dyn_cast(CanonicalType.getUnqualifiedType())) + return AT->getElementType().getTypePtr(); + return 0; + } + + // If this is a typedef for an array type, strip the typedef off without + // losing all typedef information. + return getDesugaredType()->getArrayElementTypeNoTypeQual(); +} + +/// getDesugaredType - Return the specified type with any "sugar" removed from +/// type type. This takes off typedefs, typeof's etc. If the outer level of +/// the type is already concrete, it returns it unmodified. This is similar +/// to getting the canonical type, but it doesn't remove *all* typedefs. For +/// example, it return "T*" as "T*", (not as "int*"), because the pointer is +/// concrete. +QualType Type::getDesugaredType() const { + if (const TypedefType *TDT = dyn_cast(this)) + return TDT->LookThroughTypedefs(); + if (const TypeOfExpr *TOE = dyn_cast(this)) + return TOE->getUnderlyingExpr()->getType(); + if (const TypeOfType *TOT = dyn_cast(this)) + return TOT->getUnderlyingType(); + // FIXME: remove this cast. + return QualType(const_cast(this), 0); +} + /// isVoidType - Helper method to determine if this is the 'void' type. bool Type::isVoidType() const { if (const BuiltinType *BT = dyn_cast(CanonicalType)) @@ -118,23 +157,6 @@ const ComplexType *Type::getAsComplexIntegerType() const { return getDesugaredType()->getAsComplexIntegerType(); } -/// getDesugaredType - Return the specified type with any "sugar" removed from -/// type type. This takes off typedefs, typeof's etc. If the outer level of -/// the type is already concrete, it returns it unmodified. This is similar -/// to getting the canonical type, but it doesn't remove *all* typedefs. For -/// example, it return "T*" as "T*", (not as "int*"), because the pointer is -/// concrete. -const Type *Type::getDesugaredType() const { - if (const TypedefType *TDT = dyn_cast(this)) - return TDT->LookThroughTypedefs().getTypePtr(); - if (const TypeOfExpr *TOE = dyn_cast(this)) - return TOE->getUnderlyingExpr()->getType().getTypePtr(); - if (const TypeOfType *TOT = dyn_cast(this)) - return TOT->getUnderlyingType().getTypePtr(); - return this; -} - - const BuiltinType *Type::getAsBuiltinType() const { // If this is directly a builtin type, return it. if (const BuiltinType *BTy = dyn_cast(this)) @@ -230,71 +252,17 @@ const ReferenceType *Type::getAsReferenceType() const { return getDesugaredType()->getAsReferenceType(); } -const ArrayType *Type::getAsArrayType() const { - // If this is directly an array type, return it. - if (const ArrayType *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()->getAsArrayType(); - return 0; - } - - // If this is a typedef for an array type, strip the typedef off without - // losing all typedef information. - return getDesugaredType()->getAsArrayType(); -} - -const ConstantArrayType *Type::getAsConstantArrayType() const { - // If this is directly a constant array type, return it. - if (const ConstantArrayType *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()->getAsConstantArrayType(); - return 0; - } - - // If this is a typedef for a constant array type, strip the typedef off - // without losing all typedef information. - return getDesugaredType()->getAsConstantArrayType(); -} - -const VariableArrayType *Type::getAsVariableArrayType() const { - // If this is directly a variable array type, return it. - if (const VariableArrayType *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()->getAsVariableArrayType(); - return 0; - } - - // If this is a typedef for a variable array type, strip the typedef off - // without losing all typedef information. - return getDesugaredType()->getAsVariableArrayType(); -} - /// 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 { - // A VLA is a veriably modified type - if (getAsVariableArrayType()) + // A VLA is a variably modified type. + if (isVariableArrayType()) return true; // An array can contain a variably modified type - if (const ArrayType* AT = getAsArrayType()) - return AT->getElementType()->isVariablyModifiedType(); + if (const Type *T = getArrayElementTypeNoTypeQual()) + return T->isVariablyModifiedType(); // A pointer can point to a variably modified type if (const PointerType* PT = getAsPointerType()) @@ -310,28 +278,6 @@ bool Type::isVariablyModifiedType() const { return false; } -bool Type::isIncompleteArrayType() const { - return isa(CanonicalType); -} - -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; - } - - // 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 { // If this is directly a reference type, return it. if (const RecordType *RTy = dyn_cast(this)) diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp index d232fd9560..0b63463d1f 100644 --- a/lib/CodeGen/CGDebugInfo.cpp +++ b/lib/CodeGen/CGDebugInfo.cpp @@ -108,10 +108,8 @@ CGDebugInfo::~CGDebugInfo() delete GlobalVariableAnchor; } -void CGDebugInfo::setLocation(SourceLocation loc) -{ - SourceManager &SM = M->getContext().getSourceManager(); - CurLoc = SM.getLogicalLoc(loc); +void CGDebugInfo::setLocation(SourceLocation loc) { + CurLoc = M->getContext().getSourceManager().getLogicalLoc(loc); } /// getCastValueFor - Return a llvm representation for a given debug information @@ -481,20 +479,20 @@ CGDebugInfo::getOrCreateArrayType(QualType type, llvm::CompileUnitDesc *Unit) // Add the dimensions of the array. std::vector &Elements = ArrayTy->getElements(); do { + const ArrayType *AT = M->getContext().getAsArrayType(type); llvm::SubrangeDesc *Subrange = new llvm::SubrangeDesc(); // push it back on the subrange desc list so that we can free it later. SubrangeDescList.push_back(Subrange); uint64_t Upper = 0; - if (type->getTypeClass() == Type::ConstantArray) { - const ConstantArrayType *ConstArrTy = type->getAsConstantArrayType(); + if (const ConstantArrayType *ConstArrTy = dyn_cast(AT)) { Upper = ConstArrTy->getSize().getZExtValue() - 1; } Subrange->setLo(0); Subrange->setHi(Upper); Elements.push_back(Subrange); - type = type->getAsArrayType()->getElementType(); + type = AT->getElementType(); } while (type->isArrayType()); ArrayTy->setFromType(getOrCreateType(type, Unit)); diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index 1fd616c648..ca52b070dd 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -429,7 +429,8 @@ LValue CodeGenFunction::EmitStringLiteralLValue(const StringLiteral *E) { std::string StringLiteral(StrData, StrData+Len); // Resize the string to the right size - const ConstantArrayType *CAT = E->getType()->getAsConstantArrayType(); + const ConstantArrayType *CAT = + getContext().getAsConstantArrayType(E->getType()); uint64_t RealLen = CAT->getSize().getZExtValue(); StringLiteral.resize(RealLen, '\0'); diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp index 815e296e79..df90ee09f5 100644 --- a/lib/CodeGen/CGExprAgg.cpp +++ b/lib/CodeGen/CGExprAgg.cpp @@ -393,11 +393,10 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) { } uint64_t NumArrayElements = AType->getNumElements(); - QualType ElementType = E->getType()->getAsArrayType()->getElementType(); + QualType ElementType = CGF.getContext().getCanonicalType(E->getType()); + ElementType =CGF.getContext().getAsArrayType(ElementType)->getElementType(); - unsigned CVRqualifier = - CGF.getContext().getCanonicalType(E->getType())->getAsArrayType() - ->getElementType().getCVRQualifiers(); + unsigned CVRqualifier = ElementType.getCVRQualifiers(); for (uint64_t i = 0; i != NumArrayElements; ++i) { llvm::Value *NextVal = Builder.CreateStructGEP(DestPtr, i, ".array"); diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp index 681993a5d4..d58d004607 100644 --- a/lib/CodeGen/CGExprConstant.cpp +++ b/lib/CodeGen/CGExprConstant.cpp @@ -85,7 +85,7 @@ public: unsigned NumInitElements = ILE->getNumInits(); // FIXME: Check for wide strings if (NumInitElements > 0 && isa(ILE->getInit(0)) && - ILE->getType()->getAsArrayType()->getElementType()->isCharType()) + ILE->getType()->getArrayElementTypeNoTypeQual()->isCharType()) return Visit(ILE->getInit(0)); const llvm::Type *ElemTy = AType->getElementType(); unsigned NumElements = AType->getNumElements(); @@ -332,9 +332,7 @@ public: llvm::Constant *Idx0 = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0); llvm::Constant *Ops[] = {Idx0, Idx0}; C = llvm::ConstantExpr::getGetElementPtr(C, Ops, 2); - - QualType ElemType = SType->getAsArrayType()->getElementType(); - T = CGM.getContext().getPointerType(ElemType); + T = CGM.getContext().getArrayDecayedType(SType); } else if (SType->isFunctionType()) { // Function types decay to a pointer to the function C = EmitLValue(SExpr); @@ -357,7 +355,8 @@ public: // Otherwise this must be a string initializing an array in a static // initializer. Don't emit it as the address of the string, emit the string // data itself as an inline array. - const ConstantArrayType *CAT = E->getType()->getAsConstantArrayType(); + const ConstantArrayType *CAT = + CGM.getContext().getAsConstantArrayType(E->getType()); assert(CAT && "String isn't pointer or array!"); std::string Str(StrData, StrData + Len); diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index b531616b13..5d85b7a70f 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -632,7 +632,8 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) { // FIXME: This is silly; getTypeAlign should just work for incomplete arrays unsigned Align; - if (const IncompleteArrayType* IAT = D->getType()->getAsIncompleteArrayType()) + if (const IncompleteArrayType* IAT = + Context.getAsIncompleteArrayType(D->getType())) Align = Context.getTypeAlign(IAT->getElementType()); else Align = Context.getTypeAlign(D->getType()); diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index f8835ffa8c..e9343e3989 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -386,8 +386,8 @@ Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, bool &Redeclaration) { /// definition that would be otherwise equivalent. static bool areEquivalentArrayTypes(QualType NewQType, QualType OldQType, ASTContext &Context) { - const ArrayType *NewAT = NewQType->getAsArrayType(); - const ArrayType *OldAT = OldQType->getAsArrayType(); + const ArrayType *NewAT = Context.getAsArrayType(NewQType); + const ArrayType *OldAT = Context.getAsArrayType(OldQType); if (!NewAT || !OldAT) return false; @@ -549,7 +549,9 @@ bool Sema::CheckSingleInitializer(Expr *&Init, QualType DeclType) { } bool Sema::CheckStringLiteralInit(StringLiteral *strLiteral, QualType &DeclT) { - if (const IncompleteArrayType *IAT = DeclT->getAsIncompleteArrayType()) { + const ArrayType *AT = Context.getAsArrayType(DeclT); + + if (const IncompleteArrayType *IAT = dyn_cast(AT)) { // C99 6.7.8p14. We have an array of character type with unknown size // being initialized to a string literal. llvm::APSInt ConstVal(32); @@ -557,14 +559,14 @@ bool Sema::CheckStringLiteralInit(StringLiteral *strLiteral, QualType &DeclT) { // Return a new array type (C99 6.7.8p22). DeclT = Context.getConstantArrayType(IAT->getElementType(), ConstVal, ArrayType::Normal, 0); - } else if (const ConstantArrayType *CAT = DeclT->getAsConstantArrayType()) { + } else { + const ConstantArrayType *CAT = cast(AT); // C99 6.7.8p14. We have an array of character type with known size. - if (strLiteral->getByteLength() > (unsigned)CAT->getMaximumElements()) + // FIXME: Avoid truncation for 64-bit length strings. + if (strLiteral->getByteLength() > (unsigned)CAT->getSize().getZExtValue()) Diag(strLiteral->getSourceRange().getBegin(), diag::warn_initializer_string_for_char_array_too_long, strLiteral->getSourceRange()); - } else { - assert(0 && "HandleStringLiteralInit(): Invalid array type"); } // Set type from "char *" to "constant array of char". strLiteral->setType(DeclT); @@ -573,7 +575,7 @@ bool Sema::CheckStringLiteralInit(StringLiteral *strLiteral, QualType &DeclT) { } StringLiteral *Sema::IsStringLiteralInit(Expr *Init, QualType DeclType) { - const ArrayType *AT = DeclType->getAsArrayType(); + const ArrayType *AT = Context.getAsArrayType(DeclType); if (AT && AT->getElementType()->isCharType()) { return dyn_cast(Init); } @@ -583,7 +585,7 @@ StringLiteral *Sema::IsStringLiteralInit(Expr *Init, 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->getAsVariableArrayType()) + if (const VariableArrayType *VAT = Context.getAsVariableArrayType(DeclType)) return Diag(VAT->getSizeExpr()->getLocStart(), diag::err_variable_object_no_init, VAT->getSizeExpr()->getSourceRange()); @@ -1393,7 +1395,7 @@ Sema::DeclTy *Sema::FinalizeDeclaratorGroup(Scope *S, DeclTy *group) { // static storage duration, it shall not have a variable length array. if ((IDecl->isFileVarDecl() || IDecl->isBlockVarDecl()) && IDecl->getStorageClass() == VarDecl::Static) { - if (T->getAsVariableArrayType()) { + if (T->isVariableArrayType()) { Diag(IDecl->getLocation(), diag::err_typecheck_illegal_vla); IDecl->setInvalidDecl(); } diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 56632d1d77..6c6d6e2610 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -1055,7 +1055,7 @@ ActOnCompoundLiteral(SourceLocation LParenLoc, TypeTy *Ty, Expr *literalExpr = static_cast(InitExpr); if (literalType->isArrayType()) { - if (literalType->getAsVariableArrayType()) + if (literalType->isVariableArrayType()) return Diag(LParenLoc, diag::err_variable_object_no_init, SourceRange(LParenLoc, @@ -2381,7 +2381,7 @@ Sema::ExprResult Sema::ActOnBuiltinOffsetOf(SourceLocation BuiltinLoc, const OffsetOfComponent &OC = CompPtr[i]; if (OC.isBrackets) { // Offset of an array sub-field. TODO: Should we allow vector elements? - const ArrayType *AT = Res->getType()->getAsArrayType(); + const ArrayType *AT = Context.getAsArrayType(Res->getType()); if (!AT) { delete Res; return Diag(OC.LocEnd, diag::err_offsetof_array_type, diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 0078cc149c..1889bafacb 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -30,7 +30,8 @@ InitListChecker::InitListChecker(Sema *S, InitListExpr *IL, QualType &T) { int InitListChecker::numArrayElements(QualType DeclType) { // FIXME: use a proper constant int maxElements = 0x7FFFFFFF; - if (const ConstantArrayType *CAT = DeclType->getAsConstantArrayType()) { + if (const ConstantArrayType *CAT = + SemaRef->Context.getAsConstantArrayType(DeclType)) { maxElements = static_cast(CAT->getSize().getZExtValue()); } return maxElements; @@ -231,7 +232,8 @@ void InitListChecker::CheckArrayType(InitListExpr *IList, QualType &DeclType, return; } } - if (const VariableArrayType *VAT = DeclType->getAsVariableArrayType()) { + if (const VariableArrayType *VAT = + SemaRef->Context.getAsVariableArrayType(DeclType)) { // 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). @@ -243,7 +245,8 @@ void InitListChecker::CheckArrayType(InitListExpr *IList, QualType &DeclType, } int maxElements = numArrayElements(DeclType); - QualType elementType = DeclType->getAsArrayType()->getElementType(); + QualType elementType = SemaRef->Context.getAsArrayType(DeclType) + ->getElementType(); int numElements = 0; for (int i = 0; i < maxElements; ++i, ++numElements) { // Don't attempt to go past the end of the init list diff --git a/test/Sema/typedef-retain.c b/test/Sema/typedef-retain.c index 5e4c978c3a..861e0771cc 100644 --- a/test/Sema/typedef-retain.c +++ b/test/Sema/typedef-retain.c @@ -14,13 +14,25 @@ void test2(float4 a, int4p result, int i) { // PR2039 typedef int a[5]; -void z() { +void test3() { typedef const a b; b r; r[0]=10; // expected-error {{read-only variable is not assignable}} } -int e(const a y) { +int test4(const a y) { y[0] = 10; // expected-error {{read-only variable is not assignable}} } +// PR2189 +int test5() { + const int s[5]; int t[5]; + return &s == &t; // expected-warning {{comparison of distinct pointer types}} +} + +int test6() { + const a s; + a t; + return &s == &t; // expected-warning {{comparison of distinct pointer types}} +} +