]> granicus.if.org Git - clang/commitdiff
Split out incomplete arrays from VariableArrayType into
authorEli Friedman <eli.friedman@gmail.com>
Fri, 15 Feb 2008 18:16:39 +0000 (18:16 +0000)
committerEli Friedman <eli.friedman@gmail.com>
Fri, 15 Feb 2008 18:16:39 +0000 (18:16 +0000)
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

AST/ASTContext.cpp
AST/Type.cpp
AST/TypeSerialization.cpp
CodeGen/CodeGenTypes.cpp
Sema/SemaDecl.cpp
Sema/SemaType.cpp
include/clang/AST/ASTContext.h
include/clang/AST/Type.h

index d4a689cb2d47ee2cd9696158a6e8eb9d2a193bb5..608858b55fd16dbcbd0975572e937dd5e335c222 100644 (file)
@@ -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);
index 1ce5059777454c3ebfad1239491845b68471b96e..13ffb0e220988a2f5cc9531e78df3e1617ee46b1 100644 (file)
@@ -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 += '[';
   
index 7583a07475679f0709f7268167f00064e02f5be5..e2ccd3c55ed354cb19d3ab7d79d0d508d37b5a57 100644 (file)
@@ -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();
+}
index d293b4f081cb741408b06ff03910e3cef59b3b34..96bccfc6ec4cfb65df18cb5215992f8108cecedb 100644 (file)
@@ -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);
index 2358bdf391d705c460fc6e5a3d2445a759734eef..81d4c9e0f7c4be7c42514c19ca36b0e963941e21 100644 (file)
@@ -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
index 5ba25863dbaf3cc2f9e3420d2cdbbdf5ec933cc3..58d7019e6dd3b0033d86a14d0ff4dd2a96be8623 100644 (file)
@@ -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()) {
index e55790ea4a65afcc10984adbc8610e86358fffd4..40e1f72bb6e2252b132944e6dc7c492e23e17120 100644 (file)
@@ -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,
index 9ff76ef666dd599c8d505c81a29e81c6e09dfb30..b77d23b813389fcdaf21e246847c9987141baab1 100644 (file)
@@ -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: