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
// 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) {
return pointerTypesAreCompatible(lcanon, rcanon);
case Type::ConstantArray:
case Type::VariableArray:
+ case Type::IncompleteArray:
return arrayTypesAreCompatible(lcanon, rcanon);
case Type::FunctionNoProto:
return functionTypesAreCompatible(lcanon, rcanon);
case Pointer:
case VariableArray:
case ConstantArray:
+ case IncompleteArray:
case FunctionProto:
case FunctionNoProto:
case Reference:
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 {
}
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,
// 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;
}
}
getElementType().getAsStringInternal(S);
}
+void IncompleteArrayType::getAsStringInternal(std::string &S) const {
+ S += "[]";
+
+ getElementType().getAsStringInternal(S);
+}
+
void VariableArrayType::getAsStringInternal(std::string &S) const {
S += '[';
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;
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();
+}
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);
}
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.
}
}
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());
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());
// 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
}
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()) {
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;
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,
class ArrayType;
class ConstantArrayType;
class VariableArrayType;
+ class IncompleteArrayType;
class RecordType;
class ComplexType;
class TagType;
public:
enum TypeClass {
Builtin, Complex, Pointer, Reference,
- ConstantArray, VariableArray,
+ ConstantArray, VariableArray, IncompleteArray,
Vector, OCUVector,
FunctionNoProto, FunctionProto,
TypeName, Tagged, ASQual,
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;
}
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; }
};
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
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: