Index: include/clang/Frontend/PCHBitCodes.h
===================================================================
--- include/clang/Frontend/PCHBitCodes.h	(revision 73484)
+++ include/clang/Frontend/PCHBitCodes.h	(working copy)
@@ -387,7 +387,11 @@
       /// \brief An ObjCQualifiedInterfaceType record.
       TYPE_OBJC_QUALIFIED_INTERFACE = 22,
       /// \brief An ObjCQualifiedIdType record.
-      TYPE_OBJC_QUALIFIED_ID        = 23
+      TYPE_OBJC_QUALIFIED_ID        = 23,
+      /// \brief A ConstantArrayWithExprType record.
+      TYPE_CONSTANT_ARRAY_WITH_EXPR = 24,
+      /// \brief A ConstantArrayWithoutExprType record.
+      TYPE_CONSTANT_ARRAY_WITHOUT_EXPR = 25
     };
 
     /// \brief The type IDs for special types constructed by semantic
Index: include/clang/AST/PrettyPrinter.h
===================================================================
--- include/clang/AST/PrettyPrinter.h	(revision 73484)
+++ include/clang/AST/PrettyPrinter.h	(working copy)
@@ -35,7 +35,8 @@
   /// \brief Create a default printing policy for C.
   PrintingPolicy() 
     : Indentation(2), CPlusPlus(false), SuppressSpecifiers(false),
-      SuppressTag(false), SuppressTagKind(false), Dump(false) { }
+      SuppressTag(false), SuppressTagKind(false), Dump(false),
+      ConstantArraySizeAsWritten(false) { }
 
   /// \brief The number of spaces to use to indent each line.
   unsigned Indentation : 8;
@@ -79,6 +80,24 @@
   /// and pretty-printing involves printing something similar to
   /// source code.
   bool Dump : 1;
+
+  /// \brief Whether we should print the sizes of constant array expressions
+  /// as written in the sources.
+  ///
+  /// This flag is determines whether arrays types declared as
+  ///
+  /// \code
+  /// int a[4+10*10];
+  /// char a[] = "A string";
+  /// \endcode
+  ///
+  /// will be printed as written or as follows:
+  ///
+  /// \code
+  /// int a[104];
+  /// char a[9] = "A string";
+  /// \endcode
+  bool ConstantArraySizeAsWritten : 1;
 };
 
 } // end namespace clang
Index: include/clang/AST/TypeNodes.def
===================================================================
--- include/clang/AST/TypeNodes.def	(revision 73484)
+++ include/clang/AST/TypeNodes.def	(working copy)
@@ -57,6 +57,8 @@
 TYPE(MemberPointer, Type)
 ABSTRACT_TYPE(Array, Type)
 TYPE(ConstantArray, ArrayType)
+NON_CANONICAL_TYPE(ConstantArrayWithExpr, ConstantArrayType)
+NON_CANONICAL_TYPE(ConstantArrayWithoutExpr, ConstantArrayType)
 TYPE(IncompleteArray, ArrayType)
 TYPE(VariableArray, ArrayType)
 DEPENDENT_TYPE(DependentSizedArray, ArrayType)
Index: include/clang/AST/ASTContext.h
===================================================================
--- include/clang/AST/ASTContext.h	(revision 73484)
+++ include/clang/AST/ASTContext.h	(working copy)
@@ -267,7 +267,22 @@
   QualType getConstantArrayType(QualType EltTy, const llvm::APInt &ArySize,
                                 ArrayType::ArraySizeModifier ASM,
                                 unsigned EltTypeQuals);
-                        
+
+  /// getConstantArrayWithExprType - Return a reference to the type for a
+  /// constant array of the specified element type.
+  QualType getConstantArrayWithExprType(QualType EltTy,
+                                        const llvm::APInt &ArySize,
+                                        Expr *ArySizeExpr,
+                                        ArrayType::ArraySizeModifier ASM,
+                                        unsigned EltTypeQuals);
+
+  /// getConstantArrayWithoutExprType - Return a reference to the type
+  /// for a constant array of the specified element type.
+  QualType getConstantArrayWithoutExprType(QualType EltTy,
+                                           const llvm::APInt &ArySize,
+                                           ArrayType::ArraySizeModifier ASM,
+                                           unsigned EltTypeQuals);
+
   /// getVectorType - Return the unique reference to a vector type of
   /// the specified element type and size. VectorType must be a built-in type.
   QualType getVectorType(QualType VectorType, unsigned NumElts);
Index: include/clang/AST/Type.h
===================================================================
--- include/clang/AST/Type.h	(revision 73484)
+++ include/clang/AST/Type.h	(working copy)
@@ -832,6 +832,8 @@
   
   static bool classof(const Type *T) {
     return T->getTypeClass() == ConstantArray ||
+           T->getTypeClass() == ConstantArrayWithExpr ||
+           T->getTypeClass() == ConstantArrayWithoutExpr ||
            T->getTypeClass() == VariableArray ||
            T->getTypeClass() == IncompleteArray ||
            T->getTypeClass() == DependentSizedArray;
@@ -839,15 +841,20 @@
   static bool classof(const ArrayType *) { return true; }
 };
 
-/// ConstantArrayType - This class represents C arrays with a specified constant
-/// size.  For example 'int A[100]' has ConstantArrayType where the element type
-/// is 'int' and the size is 100.
+/// ConstantArrayType - This class represents the canonical version of
+/// C arrays with a specified constant size.  For example, the canonical
+/// type for 'int A[4 + 4*100]' is a ConstantArrayType where the element
+/// type is 'int' and the size is 404.
 class ConstantArrayType : public ArrayType {
   llvm::APInt Size; // Allows us to unique the type.
   
   ConstantArrayType(QualType et, QualType can, const llvm::APInt &size,
                     ArraySizeModifier sm, unsigned tq)
     : ArrayType(ConstantArray, et, can, sm, tq), Size(size) {}
+protected:
+  ConstantArrayType(TypeClass tc, QualType et, QualType can,
+                    const llvm::APInt &size, ArraySizeModifier sm, unsigned tq)
+    : ArrayType(tc, et, can, sm, tq), Size(size) {}
   friend class ASTContext;  // ASTContext creates these.
 public:
   const llvm::APInt &getSize() const { return Size; }
@@ -865,12 +872,73 @@
     ID.AddInteger(SizeMod);
     ID.AddInteger(TypeQuals);
   }
-  static bool classof(const Type *T) { 
-    return T->getTypeClass() == ConstantArray; 
+  static bool classof(const Type *T) {
+    return T->getTypeClass() == ConstantArray ||
+           T->getTypeClass() == ConstantArrayWithExpr ||
+           T->getTypeClass() == ConstantArrayWithoutExpr;
   }
   static bool classof(const ConstantArrayType *) { return true; }
 };
 
+/// ConstantArrayWithExprType - This class represents C arrays with a
+/// constant size specified by means of an integer constant expression.
+/// For example 'int A[sizeof(int)]' has ConstantArrayWithExprType where
+/// the element type is 'int' and the size expression is 'sizeof(int)'.
+/// These types are non-canonical.
+class ConstantArrayWithExprType : public ConstantArrayType {
+  /// SizeExpr - The ICE occurring in the concrete syntax.
+  Expr *SizeExpr;
+
+  ConstantArrayWithExprType(QualType et, QualType can, const llvm::APInt &size,
+                            Expr *e, ArraySizeModifier sm, unsigned tq)
+    : ConstantArrayType(ConstantArrayWithExpr, et, can, size, sm, tq),
+      SizeExpr(e) {}
+  friend class ASTContext;  // ASTContext creates these.
+  virtual void Destroy(ASTContext& C);
+
+public:
+  Expr *getSizeExpr() const { return SizeExpr; }
+
+  virtual void getAsStringInternal(std::string &InnerString,
+                                   const PrintingPolicy &Policy) const;
+
+  static bool classof(const Type *T) {
+    return T->getTypeClass() == ConstantArrayWithExpr;
+  }
+  static bool classof(const ConstantArrayWithExprType *) { return true; }
+
+  void Profile(llvm::FoldingSetNodeID &ID) {
+    assert(0 && "Cannot unique ConstantArrayWithExprTypes.");
+  }
+};
+
+/// ConstantArrayWithoutExprType - This class represents C arrays with a
+/// constant size that was not specified by an integer constant expression,
+/// but inferred by static semantics.
+/// For example 'int A[] = { 0, 1, 2 }' has ConstantArrayWithoutExprType.
+/// These types are non-canonical: the corresponding canonical type,
+/// having the size specified in an APInt object, is a ConstantArrayType.
+class ConstantArrayWithoutExprType : public ConstantArrayType {
+  ConstantArrayWithoutExprType(QualType et, QualType can,
+                               const llvm::APInt &size,
+                               ArraySizeModifier sm, unsigned tq)
+    : ConstantArrayType(ConstantArrayWithoutExpr, et, can, size, sm, tq) {}
+  friend class ASTContext;  // ASTContext creates these.
+
+public:
+  virtual void getAsStringInternal(std::string &InnerString,
+                                   const PrintingPolicy &Policy) const;
+
+  static bool classof(const Type *T) {
+    return T->getTypeClass() == ConstantArrayWithoutExpr;
+  }
+  static bool classof(const ConstantArrayWithoutExprType *) { return true; }
+
+  void Profile(llvm::FoldingSetNodeID &ID) {
+    assert(0 && "Cannot unique ConstantArrayWithoutExprTypes.");
+  }
+};
+
 /// IncompleteArrayType - This class represents C arrays with an unspecified
 /// size.  For example 'int A[]' has an IncompleteArrayType where the element
 /// type is 'int' and the size is unspecified.
Index: lib/Frontend/PCHWriter.cpp
===================================================================
--- lib/Frontend/PCHWriter.cpp	(revision 73484)
+++ lib/Frontend/PCHWriter.cpp	(working copy)
@@ -124,6 +124,21 @@
   Code = pch::TYPE_CONSTANT_ARRAY;
 }
 
+void PCHTypeWriter
+::VisitConstantArrayWithExprType(const ConstantArrayWithExprType *T) {
+  VisitArrayType(T);
+  Writer.AddAPInt(T->getSize(), Record);
+  Writer.AddStmt(T->getSizeExpr());
+  Code = pch::TYPE_CONSTANT_ARRAY_WITH_EXPR;
+}
+
+void PCHTypeWriter
+::VisitConstantArrayWithoutExprType(const ConstantArrayWithoutExprType *T) {
+  VisitArrayType(T);
+  Writer.AddAPInt(T->getSize(), Record);
+  Code = pch::TYPE_CONSTANT_ARRAY_WITHOUT_EXPR;
+}
+
 void PCHTypeWriter::VisitIncompleteArrayType(const IncompleteArrayType *T) {
   VisitArrayType(T);
   Code = pch::TYPE_INCOMPLETE_ARRAY;
Index: lib/Frontend/PCHReader.cpp
===================================================================
--- lib/Frontend/PCHReader.cpp	(revision 73484)
+++ lib/Frontend/PCHReader.cpp	(working copy)
@@ -1623,6 +1623,27 @@
     return Context->getConstantArrayType(ElementType, Size, ASM,IndexTypeQuals);
   }
 
+  case pch::TYPE_CONSTANT_ARRAY_WITH_EXPR: {
+    QualType ElementType = GetType(Record[0]);
+    ArrayType::ArraySizeModifier ASM = (ArrayType::ArraySizeModifier)Record[1];
+    unsigned IndexTypeQuals = Record[2];
+    unsigned Idx = 3;
+    llvm::APInt Size = ReadAPInt(Record, Idx);
+    return Context->getConstantArrayWithExprType(ElementType,
+                                                 Size, ReadTypeExpr(),
+                                                 ASM, IndexTypeQuals);
+  }
+
+  case pch::TYPE_CONSTANT_ARRAY_WITHOUT_EXPR: {
+    QualType ElementType = GetType(Record[0]);
+    ArrayType::ArraySizeModifier ASM = (ArrayType::ArraySizeModifier)Record[1];
+    unsigned IndexTypeQuals = Record[2];
+    unsigned Idx = 3;
+    llvm::APInt Size = ReadAPInt(Record, Idx);
+    return Context->getConstantArrayWithoutExprType(ElementType, Size,
+                                                    ASM, IndexTypeQuals);
+  }
+
   case pch::TYPE_INCOMPLETE_ARRAY: {
     QualType ElementType = GetType(Record[0]);
     ArrayType::ArraySizeModifier ASM = (ArrayType::ArraySizeModifier)Record[1];
Index: lib/CodeGen/CGDebugInfo.cpp
===================================================================
--- lib/CodeGen/CGDebugInfo.cpp	(revision 73484)
+++ lib/CodeGen/CGDebugInfo.cpp	(working copy)
@@ -781,6 +781,8 @@
     return Slot = CreateType(cast<FunctionType>(Ty), Unit);
     
   case Type::ConstantArray:
+  case Type::ConstantArrayWithExpr:
+  case Type::ConstantArrayWithoutExpr:
   case Type::VariableArray:
   case Type::IncompleteArray:
     return Slot = CreateType(cast<ArrayType>(Ty), Unit);
Index: lib/Sema/SemaInit.cpp
===================================================================
--- lib/Sema/SemaInit.cpp	(revision 73484)
+++ lib/Sema/SemaInit.cpp	(working copy)
@@ -97,8 +97,9 @@
     llvm::APSInt ConstVal(32);
     ConstVal = StrLength;
     // Return a new array type (C99 6.7.8p22).
-    DeclT = S.Context.getConstantArrayType(IAT->getElementType(), ConstVal, 
-                                           ArrayType::Normal, 0);
+    DeclT = S.Context.getConstantArrayWithoutExprType(IAT->getElementType(),
+                                                      ConstVal,
+                                                      ArrayType::Normal, 0);
     return;
   }
   
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp	(revision 73484)
+++ lib/Sema/SemaDecl.cpp	(working copy)
@@ -1533,9 +1533,17 @@
     return QualType();
 
   llvm::APSInt &Res = EvalResult.Val.getInt();
-  if (Res >= llvm::APSInt(Res.getBitWidth(), Res.isUnsigned()))
-    return Context.getConstantArrayType(VLATy->getElementType(),
-                                        Res, ArrayType::Normal, 0);
+  if (Res >= llvm::APSInt(Res.getBitWidth(), Res.isUnsigned())) {
+    Expr* ArySizeExpr = VLATy->getSizeExpr();
+    // FIXME: here we could "steal" (how?) ArySizeExpr from the VLA,
+    // so as to transfer ownership to the ConstantArrayWithExpr.
+    // Alternatively, we could "clone" it (how?).
+    // Since we don't know how to do things above, we just use the
+    // very same Expr*.
+    return Context.getConstantArrayWithExprType(VLATy->getElementType(),
+                                                Res, ArySizeExpr,
+                                                ArrayType::Normal, 0);
+  }
 
   SizeIsNegative = true;
   return QualType();
Index: lib/Sema/SemaType.cpp
===================================================================
--- lib/Sema/SemaType.cpp	(revision 73484)
+++ lib/Sema/SemaType.cpp	(working copy)
@@ -529,7 +529,8 @@
           << ArraySize->getSourceRange();
       }
     } 
-    T = Context.getConstantArrayType(T, ConstVal, ASM, Quals);
+    T = Context.getConstantArrayWithExprType(T, ConstVal, ArraySize,
+                                             ASM, Quals);
   }
   // If this is not C99, extwarn about VLA's and C99 array size modifiers.
   if (!getLangOptions().C99) {
Index: lib/Sema/SemaTemplateInstantiate.cpp
===================================================================
--- lib/Sema/SemaTemplateInstantiate.cpp	(revision 73484)
+++ lib/Sema/SemaTemplateInstantiate.cpp	(working copy)
@@ -383,6 +383,24 @@
 
 QualType 
 TemplateTypeInstantiator::
+InstantiateConstantArrayWithExprType(const ConstantArrayWithExprType *T, 
+                                     unsigned Quals) const {
+  const ConstantArrayType *CAT
+    = (const ConstantArrayType*)(T->getCanonicalTypeInternal().getTypePtr());
+  return InstantiateConstantArrayType(CAT, Quals);
+}
+
+QualType 
+TemplateTypeInstantiator::
+InstantiateConstantArrayWithoutExprType(const ConstantArrayWithoutExprType *T, 
+                                        unsigned Quals) const {
+  const ConstantArrayType *CAT
+    = (const ConstantArrayType*)(T->getCanonicalTypeInternal().getTypePtr());
+  return InstantiateConstantArrayType(CAT, Quals);
+}
+
+QualType 
+TemplateTypeInstantiator::
 InstantiateIncompleteArrayType(const IncompleteArrayType *T,
                                unsigned Quals) const {
   QualType ElementType = Instantiate(T->getElementType());
Index: lib/Sema/Sema.cpp
===================================================================
--- lib/Sema/Sema.cpp	(revision 73484)
+++ lib/Sema/Sema.cpp	(working copy)
@@ -270,8 +270,8 @@
         llvm::APInt One(Context.getTypeSize(Context.getSizeType()), 
                         true);
         QualType T 
-          = Context.getConstantArrayType(ArrayT->getElementType(),
-                                         One, ArrayType::Normal, 0);
+          = Context.getConstantArrayWithoutExprType(ArrayT->getElementType(),
+                                                    One, ArrayType::Normal, 0);
         VD->setType(T);
       }
     } else if (RequireCompleteType(VD->getLocation(), VD->getType(), 
Index: lib/AST/Type.cpp
===================================================================
--- lib/AST/Type.cpp	(revision 73484)
+++ lib/AST/Type.cpp	(working copy)
@@ -37,6 +37,18 @@
   C.Deallocate(this);
 }
 
+void ConstantArrayWithExprType::Destroy(ASTContext& C) {
+  // FIXME: destruction of SizeExpr commented out due to resource contention.
+  // SizeExpr->Destroy(C);
+  // See FIXME in SemaDecl.cpp:1536: if we were able to either steal
+  // or clone the SizeExpr there, then here we could freely delete it.
+  // Since we do not know how to steal or clone, we keep a pointer to
+  // a shared resource, but we cannot free it.
+  // (There probably is a trivial solution ... for people knowing clang!).
+  this->~ConstantArrayWithExprType();
+  C.Deallocate(this);
+}
+
 void VariableArrayType::Destroy(ASTContext& C) {
   if (SizeExpr)
     SizeExpr->Destroy(C);
@@ -154,6 +166,8 @@
   case Pointer:
   case VariableArray:
   case ConstantArray:
+  case ConstantArrayWithExpr:
+  case ConstantArrayWithoutExpr:
   case IncompleteArray:
   case FunctionProto:
   case FunctionNoProto:
@@ -1302,6 +1316,29 @@
   getElementType().getAsStringInternal(S, Policy);
 }
 
+void ConstantArrayWithExprType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const {
+  if (Policy.ConstantArraySizeAsWritten) {
+    std::string SStr;
+    llvm::raw_string_ostream s(SStr);
+    getSizeExpr()->printPretty(s, 0, Policy);
+    S += '[';
+    S += s.str();
+    S += ']';
+    getElementType().getAsStringInternal(S, Policy);
+  }
+  else
+    ConstantArrayType::getAsStringInternal(S, Policy);
+}
+
+void ConstantArrayWithoutExprType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const {
+  if (Policy.ConstantArraySizeAsWritten) {
+    S += "[]";
+    getElementType().getAsStringInternal(S, Policy);
+  }
+  else
+    ConstantArrayType::getAsStringInternal(S, Policy);
+}
+
 void IncompleteArrayType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const {
   S += "[]";
 
Index: lib/AST/ASTContext.cpp
===================================================================
--- lib/AST/ASTContext.cpp	(revision 73484)
+++ lib/AST/ASTContext.cpp	(working copy)
@@ -270,6 +270,10 @@
     Align = getTypeAlign(cast<ArrayType>(T)->getElementType());
     break;
 
+  case Type::ConstantArrayWithExpr:
+  case Type::ConstantArrayWithoutExpr:
+    T = T->getCanonicalTypeInternal().getTypePtr();
+    // Intentionally falling through next case.
   case Type::ConstantArray: {
     const ConstantArrayType *CAT = cast<ConstantArrayType>(T);
     
@@ -1136,6 +1140,54 @@
   return QualType(New, 0);
 }
 
+/// getConstantArrayWithExprType - Return a reference to the type for
+/// an array of the specified element type.
+QualType
+ASTContext::getConstantArrayWithExprType(QualType EltTy,
+                                         const llvm::APInt &ArySizeIn,
+                                         Expr *ArySizeExpr,
+                                         ArrayType::ArraySizeModifier ASM,
+                                         unsigned EltTypeQuals) {
+  // Convert the array size into a canonical width matching the pointer
+  // size for the target.
+  llvm::APInt ArySize(ArySizeIn);
+  ArySize.zextOrTrunc(Target.getPointerWidth(EltTy.getAddressSpace()));
+
+  // Compute the canonical ConstantArrayType.
+  QualType Canonical = getConstantArrayType(getCanonicalType(EltTy),
+                                            ArySize, ASM, EltTypeQuals);
+  // Since we don't unique expressions, it isn't possible to unique VLA's
+  // that have an expression provided for their size.
+  ConstantArrayWithExprType *New =
+    new(*this,8)ConstantArrayWithExprType(EltTy, Canonical,
+                                          ArySize, ArySizeExpr,
+                                          ASM, EltTypeQuals);
+  Types.push_back(New);
+  return QualType(New, 0);
+}
+
+/// getConstantArrayWithoutExprType - Return a reference to the type for
+/// an array of the specified element type.
+QualType
+ASTContext::getConstantArrayWithoutExprType(QualType EltTy,
+                                            const llvm::APInt &ArySizeIn,
+                                            ArrayType::ArraySizeModifier ASM,
+                                            unsigned EltTypeQuals) {
+  // Convert the array size into a canonical width matching the pointer
+  // size for the target.
+  llvm::APInt ArySize(ArySizeIn);
+  ArySize.zextOrTrunc(Target.getPointerWidth(EltTy.getAddressSpace()));
+
+  // Compute the canonical ConstantArrayType.
+  QualType Canonical = getConstantArrayType(getCanonicalType(EltTy),
+                                            ArySize, ASM, EltTypeQuals);
+  ConstantArrayWithoutExprType *New =
+    new(*this,8)ConstantArrayWithoutExprType(EltTy, Canonical, ArySize,
+                                             ASM, EltTypeQuals);
+  Types.push_back(New);
+  return QualType(New, 0);
+}
+
 /// getVariableArrayType - Returns a non-unique reference to the type for a
 /// variable array of the specified element type.
 QualType ASTContext::getVariableArrayType(QualType EltTy, Expr *NumElts,
