Index: include/clang/AST/ASTContext.h
===================================================================
--- include/clang/AST/ASTContext.h	(revision 73189)
+++ include/clang/AST/ASTContext.h	(working copy)
@@ -274,6 +274,7 @@
   /// 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,
+                                Expr *Original_ArySize,
                                 ArrayType::ArraySizeModifier ASM,
                                 unsigned EltTypeQuals);
                         
@@ -771,6 +772,12 @@
   void InitBuiltinTypes();
   void InitBuiltinType(QualType &R, BuiltinType::Kind K);
   
+  /// isCanonicalArraySize - Returns true if and only if the argument
+  /// expression is a "canonical" way of expressing a constant array size.
+  /// Namely, if it is an integer literal whose type is signed and whose
+  /// token is a decimal constant with no suffix.
+  bool isCanonicalArraySize(Expr *ArySizeExpr);
+  
   // Return the ObjC type encoding for a given type.
   void getObjCEncodingForTypeImpl(QualType t, std::string &S, 
                                   bool ExpandPointedToStructures,
Index: include/clang/AST/Type.h
===================================================================
--- include/clang/AST/Type.h	(revision 73189)
+++ include/clang/AST/Type.h	(working copy)
@@ -843,27 +843,34 @@
 /// size.  For example 'int A[100]' has ConstantArrayType where the element type
 /// is 'int' and the size is 100.
 class ConstantArrayType : public ArrayType {
-  llvm::APInt Size; // Allows us to unique the type.
-  
+  llvm::APInt Size; // Allows us to unique the type if OrigSizeExpr == 0.
+
+  // The original expression for the constant array size; it is 0 if the
+  // expression was "canonical", i.e., a single token decimal integer.
+  Expr *OrigSizeExpr;
+
   ConstantArrayType(QualType et, QualType can, const llvm::APInt &size,
-                    ArraySizeModifier sm, unsigned tq)
-    : ArrayType(ConstantArray, et, can, sm, tq), Size(size) {}
+                    Expr *orig_size, ArraySizeModifier sm, unsigned tq)
+    : ArrayType(ConstantArray, et, can, sm, tq), Size(size),
+      OrigSizeExpr(orig_size) {}
   friend class ASTContext;  // ASTContext creates these.
 public:
   const llvm::APInt &getSize() const { return Size; }
+  Expr *getOriginalSizeExpr() const { return OrigSizeExpr; }
   virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const;
   
   void Profile(llvm::FoldingSetNodeID &ID) {
-    Profile(ID, getElementType(), getSize(), 
+    Profile(ID, getElementType(), getSize(), getOriginalSizeExpr(),
             getSizeModifier(), getIndexTypeQualifier());
   }
   static void Profile(llvm::FoldingSetNodeID &ID, QualType ET,
-                      const llvm::APInt &ArraySize, ArraySizeModifier SizeMod,
-                      unsigned TypeQuals) {
+                      const llvm::APInt &ArraySize, const Expr *Orig_ArraySize,
+                      ArraySizeModifier SizeMod, unsigned TypeQuals) {
     ID.AddPointer(ET.getAsOpaquePtr());
     ID.AddInteger(ArraySize.getZExtValue());
     ID.AddInteger(SizeMod);
     ID.AddInteger(TypeQuals);
+    ID.AddPointer(Orig_ArraySize);
   }
   static bool classof(const Type *T) { 
     return T->getTypeClass() == ConstantArray; 
Index: lib/Frontend/PCHWriter.cpp
===================================================================
--- lib/Frontend/PCHWriter.cpp	(revision 73189)
+++ lib/Frontend/PCHWriter.cpp	(working copy)
@@ -121,6 +121,7 @@
 void PCHTypeWriter::VisitConstantArrayType(const ConstantArrayType *T) {
   VisitArrayType(T);
   Writer.AddAPInt(T->getSize(), Record);
+  Writer.AddStmt(T->getOriginalSizeExpr());
   Code = pch::TYPE_CONSTANT_ARRAY;
 }
 
Index: lib/Frontend/PCHReader.cpp
===================================================================
--- lib/Frontend/PCHReader.cpp	(revision 73189)
+++ lib/Frontend/PCHReader.cpp	(working copy)
@@ -1613,7 +1613,8 @@
     unsigned IndexTypeQuals = Record[2];
     unsigned Idx = 3;
     llvm::APInt Size = ReadAPInt(Record, Idx);
-    return Context->getConstantArrayType(ElementType, Size, ASM,IndexTypeQuals);
+    return Context->getConstantArrayType(ElementType, Size, ReadTypeExpr(),
+                                         ASM, IndexTypeQuals);
   }
 
   case pch::TYPE_INCOMPLETE_ARRAY: {
Index: lib/CodeGen/CGObjC.cpp
===================================================================
--- lib/CodeGen/CGObjC.cpp	(revision 73189)
+++ lib/CodeGen/CGObjC.cpp	(working copy)
@@ -458,7 +458,7 @@
   QualType ItemsTy =
     getContext().getConstantArrayType(getContext().getObjCIdType(),
                                       llvm::APInt(32, NumItems), 
-                                      ArrayType::Normal, 0);
+                                      0, ArrayType::Normal, 0);
   llvm::Value *ItemsPtr = CreateTempAlloca(ConvertType(ItemsTy), "items.ptr");
   
   llvm::Value *Collection = EmitScalarExpr(S.getCollection());
Index: lib/CodeGen/CGDebugInfo.cpp
===================================================================
--- lib/CodeGen/CGDebugInfo.cpp	(revision 73189)
+++ lib/CodeGen/CGDebugInfo.cpp	(working copy)
@@ -946,7 +946,7 @@
     QualType ET = M->getContext().getAsArrayType(T)->getElementType();
     
     T = M->getContext().getConstantArrayType(ET, ConstVal, 
-                                           ArrayType::Normal, 0);
+                                             0, ArrayType::Normal, 0);
   }
 
   DebugFactory.CreateGlobalVariable(Unit, Name, Name, "", Unit, LineNo,
@@ -976,7 +976,7 @@
     QualType ET = M->getContext().getAsArrayType(T)->getElementType();
     
     T = M->getContext().getConstantArrayType(ET, ConstVal, 
-                                           ArrayType::Normal, 0);
+                                             0, ArrayType::Normal, 0);
   }
 
   DebugFactory.CreateGlobalVariable(Unit, Name, Name, "", Unit, LineNo,
Index: lib/CodeGen/CGBlocks.cpp
===================================================================
--- lib/CodeGen/CGBlocks.cpp	(revision 73189)
+++ lib/CodeGen/CGBlocks.cpp	(working copy)
@@ -690,7 +690,7 @@
     llvm::ArrayType::get(llvm::Type::Int8Ty, Pad);
     QualType PadTy = getContext().getConstantArrayType(getContext().CharTy,
                                                        llvm::APInt(32, Pad),
-                                                       ArrayType::Normal, 0);
+                                                       0, ArrayType::Normal, 0);
     ValueDecl *PadDecl = VarDecl::Create(getContext(), 0, SourceLocation(),
                                          0, QualType(PadTy), VarDecl::None,
                                          SourceLocation());
Index: lib/Sema/SemaInit.cpp
===================================================================
--- lib/Sema/SemaInit.cpp	(revision 73189)
+++ lib/Sema/SemaInit.cpp	(working copy)
@@ -98,7 +98,7 @@
     ConstVal = StrLength;
     // Return a new array type (C99 6.7.8p22).
     DeclT = S.Context.getConstantArrayType(IAT->getElementType(), ConstVal, 
-                                           ArrayType::Normal, 0);
+                                           0, ArrayType::Normal, 0);
     return;
   }
   
@@ -923,7 +923,7 @@
     }
 
     DeclType = SemaRef.Context.getConstantArrayType(elementType, maxElements, 
-                                                     ArrayType::Normal, 0);
+                                                    0, ArrayType::Normal, 0);
   }
 }
 
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp	(revision 73189)
+++ lib/Sema/SemaDecl.cpp	(working copy)
@@ -1535,7 +1535,8 @@
   llvm::APSInt &Res = EvalResult.Val.getInt();
   if (Res >= llvm::APSInt(Res.getBitWidth(), Res.isUnsigned()))
     return Context.getConstantArrayType(VLATy->getElementType(),
-                                        Res, ArrayType::Normal, 0);
+                                        Res, VLATy->getSizeExpr(),
+                                        ArrayType::Normal, 0);
 
   SizeIsNegative = true;
   return QualType();
Index: lib/Sema/SemaType.cpp
===================================================================
--- lib/Sema/SemaType.cpp	(revision 73189)
+++ lib/Sema/SemaType.cpp	(working copy)
@@ -529,7 +529,7 @@
           << ArraySize->getSourceRange();
       }
     } 
-    T = Context.getConstantArrayType(T, ConstVal, ASM, Quals);
+    T = Context.getConstantArrayType(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/SemaExprObjC.cpp
===================================================================
--- lib/Sema/SemaExprObjC.cpp	(revision 73189)
+++ lib/Sema/SemaExprObjC.cpp	(working copy)
@@ -109,7 +109,7 @@
     if (getLangOptions().CPlusPlus)
       StrTy.addConst();
     StrTy = Context.getConstantArrayType(StrTy, llvm::APInt(32, Str.size()+1),
-                                         ArrayType::Normal, 0);
+                                         0, ArrayType::Normal, 0);
   }
   
   return new (Context) ObjCEncodeExpr(StrTy, EncodedType, AtLoc, RParenLoc);
Index: lib/Sema/SemaExpr.cpp
===================================================================
--- lib/Sema/SemaExpr.cpp	(revision 73189)
+++ lib/Sema/SemaExpr.cpp	(working copy)
@@ -546,7 +546,7 @@
   // strings.
   StrTy = Context.getConstantArrayType(StrTy,
                                  llvm::APInt(32, Literal.GetNumStringChars()+1),
-                                       ArrayType::Normal, 0);
+                                       0, ArrayType::Normal, 0);
   
   // Pass &StringTokLocs[0], StringTokLocs.size() to factory!
   return Owned(StringLiteral::Create(Context, Literal.GetString(), 
@@ -1216,7 +1216,7 @@
 
   llvm::APInt LengthI(32, Length + 1);
   QualType ResTy = Context.CharTy.getQualifiedType(QualType::Const);
-  ResTy = Context.getConstantArrayType(ResTy, LengthI, ArrayType::Normal, 0);
+  ResTy = Context.getConstantArrayType(ResTy, LengthI, 0, ArrayType::Normal, 0);
   return Owned(new (Context) PredefinedExpr(Loc, ResTy, IT));
 }
 
Index: lib/Sema/Sema.cpp
===================================================================
--- lib/Sema/Sema.cpp	(revision 73189)
+++ lib/Sema/Sema.cpp	(working copy)
@@ -270,7 +270,7 @@
                         true);
         QualType T 
           = Context.getConstantArrayType(ArrayT->getElementType(),
-                                         One, ArrayType::Normal, 0);
+                                         One, 0, ArrayType::Normal, 0);
         VD->setType(T);
       }
     } else if (RequireCompleteType(VD->getLocation(), VD->getType(), 
Index: lib/AST/ASTContext.cpp
===================================================================
--- lib/AST/ASTContext.cpp	(revision 73189)
+++ lib/AST/ASTContext.cpp	(working copy)
@@ -1105,6 +1105,7 @@
 /// array of the specified element type.
 QualType ASTContext::getConstantArrayType(QualType EltTy, 
                                           const llvm::APInt &ArySizeIn,
+                                          Expr *Orig_ArySize,
                                           ArrayType::ArraySizeModifier ASM,
                                           unsigned EltTypeQuals) {
   assert((EltTy->isDependentType() || EltTy->isConstantSizeType()) &&
@@ -1115,20 +1116,25 @@
   llvm::APInt ArySize(ArySizeIn);
   ArySize.zextOrTrunc(Target.getPointerWidth(EltTy.getAddressSpace()));
   
+  // The original array size expression is only used if not "canonical".
+  if (Orig_ArySize && isCanonicalArraySize(Orig_ArySize))
+    Orig_ArySize = 0;
+
   llvm::FoldingSetNodeID ID;
-  ConstantArrayType::Profile(ID, EltTy, ArySize, ASM, EltTypeQuals);
+  ConstantArrayType::Profile(ID, EltTy, ArySize, Orig_ArySize,
+                             ASM, EltTypeQuals);
       
   void *InsertPos = 0;
   if (ConstantArrayType *ATP = 
       ConstantArrayTypes.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.
+  // If element type and size expression are not both canonical, this won't
+  // be a canonical type either, so fill in the canonical type field.
   QualType Canonical;
-  if (!EltTy->isCanonical()) {
-    Canonical = getConstantArrayType(getCanonicalType(EltTy), ArySize, 
-                                     ASM, EltTypeQuals);
+  if (!(EltTy->isCanonical() && Orig_ArySize == 0)) {
+    Canonical = getConstantArrayType(getCanonicalType(EltTy),
+                                     ArySize, 0, ASM, EltTypeQuals);
     // Get the new insert position for the node we care about.
     ConstantArrayType *NewIP = 
       ConstantArrayTypes.FindNodeOrInsertPos(ID, InsertPos);
@@ -1136,12 +1142,39 @@
   }
   
   ConstantArrayType *New =
-    new(*this,8)ConstantArrayType(EltTy, Canonical, ArySize, ASM, EltTypeQuals);
+    new(*this,8)ConstantArrayType(EltTy, Canonical, ArySize, Orig_ArySize,
+                                  ASM, EltTypeQuals);
   ConstantArrayTypes.InsertNode(New, InsertPos);
   Types.push_back(New);
   return QualType(New, 0);
 }
 
+/// isCanonicalArraySize - Returns true if and only if the argument
+/// expression is a "canonical" way of expressing a constant array size.
+/// Namely, if it is an integer literal whose type is signed and whose
+/// token is a decimal constant with no suffix.
+bool ASTContext::isCanonicalArraySize(Expr *ArySizeExpr) {
+  // FIXME: for sure, there are better ways to code this by exploiting
+  // services made available by NumericLiteralParser.
+  if (const IntegerLiteral *IL = dyn_cast<IntegerLiteral>(ArySizeExpr)) {
+    if (!IL->getType()->isSignedIntegerType())
+      // Note: decimal constants are always signed.
+      return false;
+    SourceLocation sloc = SourceMgr.getSpellingLoc(IL->getLocation());
+    const char* s = SourceMgr.getCharacterData(sloc);
+    if (*s == '0')
+      // Not a decimal constant token.
+      return false;
+    while (std::isdigit(*s))
+      ++s;
+    char c = *s;
+    // No (integer) suffix is allowed.
+    return (c != 'u' && c != 'l' && c != 'U' && c != 'L');
+  }
+  // Not an integer literal expression.
+  return false;
+}
+
 /// 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,
@@ -1704,7 +1737,9 @@
   NewEltTy = getCanonicalType(NewEltTy);
   
   if (ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(AT))
-    return getConstantArrayType(NewEltTy, CAT->getSize(),CAT->getSizeModifier(),
+    return getConstantArrayType(NewEltTy, CAT->getSize(),
+                                CAT->getOriginalSizeExpr(),
+                                CAT->getSizeModifier(),
                                 CAT->getIndexTypeQualifier());
   if (IncompleteArrayType *IAT = dyn_cast<IncompleteArrayType>(AT))
     return getIncompleteArrayType(NewEltTy, IAT->getSizeModifier(),
@@ -1862,6 +1897,7 @@
   
   if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(ATy))
     return cast<ArrayType>(getConstantArrayType(NewEltTy, CAT->getSize(),
+                                                CAT->getOriginalSizeExpr(),
                                                 CAT->getSizeModifier(),
                                                 CAT->getIndexTypeQualifier()));
   if (const IncompleteArrayType *IAT = dyn_cast<IncompleteArrayType>(ATy))
@@ -2101,7 +2137,7 @@
       getPointerType(ObjCIdType),
       getPointerType(UnsignedLongTy),
       getConstantArrayType(UnsignedLongTy,
-                           llvm::APInt(32, 5), ArrayType::Normal, 0)
+                           llvm::APInt(32, 5), 0, ArrayType::Normal, 0)
     };
     
     for (size_t i = 0; i < 4; ++i) {
@@ -3233,9 +3269,9 @@
       return LHS;
     if (RCAT && getCanonicalType(RHSElem) == getCanonicalType(ResultType))
       return RHS;
-    if (LCAT) return getConstantArrayType(ResultType, LCAT->getSize(),
+    if (LCAT) return getConstantArrayType(ResultType, LCAT->getSize(), 0,
                                           ArrayType::ArraySizeModifier(), 0);
-    if (RCAT) return getConstantArrayType(ResultType, RCAT->getSize(),
+    if (RCAT) return getConstantArrayType(ResultType, RCAT->getSize(), 0,
                                           ArrayType::ArraySizeModifier(), 0);
     const VariableArrayType* LVAT = getAsVariableArrayType(LHS);
     const VariableArrayType* RVAT = getAsVariableArrayType(RHS);
