More fixes to the handling of CVR-comparisons on array types. Adds a method to
QualType to get CVR-qualifiers through array types, and switches the primary
comparison methods to use it. This may allow simplifying some of the callers of
getUnqualifiedArrayType.

Also fix the normalizing of CV-qualification during template deduction to
normalize through arrays and allow a more qualified deduced array type. This
fixes PR5911.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@92289 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h
index a27c4d7..9b0cdc3 100644
--- a/include/clang/AST/Type.h
+++ b/include/clang/AST/Type.h
@@ -531,7 +531,12 @@
   /// \brief Retrieve the set of CVR (const-volatile-restrict) qualifiers 
   /// applied to this type.
   unsigned getCVRQualifiers() const;
-  
+
+  /// \brief Retrieve the set of CVR (const-volatile-restrict) qualifiers
+  /// applied to this type, looking through any number of unqualified array
+  /// types to their element types' qualifiers.
+  unsigned getCVRQualifiersThroughArrayTypes() const;
+
   bool isConstant(ASTContext& Ctx) const {
     return QualType::isConstant(*this, Ctx);
   }
@@ -2686,7 +2691,20 @@
   return getLocalCVRQualifiers() | 
               getTypePtr()->getCanonicalTypeInternal().getLocalCVRQualifiers();
 }
-  
+
+/// getCVRQualifiersThroughArrayTypes - If there are CVR qualifiers for this
+/// type, returns them. Otherwise, if this is an array type, recurses
+/// on the element type until some qualifiers have been found or a non-array
+/// type reached.
+inline unsigned QualType::getCVRQualifiersThroughArrayTypes() const {
+  if (unsigned Quals = getCVRQualifiers())
+    return Quals;
+  QualType CT = getTypePtr()->getCanonicalTypeInternal();
+  if (const ArrayType *AT = dyn_cast<ArrayType>(CT))
+    return AT->getElementType().getCVRQualifiersThroughArrayTypes();
+  return 0;
+}
+
 inline void QualType::removeConst() {
   removeFastQualifiers(Qualifiers::Const);
 }
@@ -2786,8 +2804,8 @@
 /// int".
 inline bool QualType::isMoreQualifiedThan(QualType Other) const {
   // FIXME: work on arbitrary qualifiers
-  unsigned MyQuals = this->getCVRQualifiers();
-  unsigned OtherQuals = Other.getCVRQualifiers();
+  unsigned MyQuals = this->getCVRQualifiersThroughArrayTypes();
+  unsigned OtherQuals = Other.getCVRQualifiersThroughArrayTypes();
   if (getAddressSpace() != Other.getAddressSpace())
     return false;
   return MyQuals != OtherQuals && (MyQuals | OtherQuals) == MyQuals;
@@ -2799,8 +2817,8 @@
 /// "int", and "const volatile int".
 inline bool QualType::isAtLeastAsQualifiedAs(QualType Other) const {
   // FIXME: work on arbitrary qualifiers
-  unsigned MyQuals = this->getCVRQualifiers();
-  unsigned OtherQuals = Other.getCVRQualifiers();
+  unsigned MyQuals = this->getCVRQualifiersThroughArrayTypes();
+  unsigned OtherQuals = Other.getCVRQualifiersThroughArrayTypes();
   if (getAddressSpace() != Other.getAddressSpace())
     return false;
   return (MyQuals | OtherQuals) == MyQuals;
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp
index e31c05c..21f7996 100644
--- a/lib/Sema/SemaTemplateDeduction.cpp
+++ b/lib/Sema/SemaTemplateDeduction.cpp
@@ -375,9 +375,11 @@
   //     referred to by the reference) can be more cv-qualified than the
   //     transformed A.
   if (TDF & TDF_ParamWithReferenceType) {
-    Qualifiers Quals = Param.getQualifiers();
-    Quals.setCVRQualifiers(Quals.getCVRQualifiers() & Arg.getCVRQualifiers());
-    Param = Context.getQualifiedType(Param.getUnqualifiedType(), Quals);
+    Qualifiers Quals;
+    QualType UnqualParam = Context.getUnqualifiedArrayType(Param, Quals);
+    Quals.setCVRQualifiers(Quals.getCVRQualifiers() &
+                           Arg.getCVRQualifiersThroughArrayTypes());
+    Param = Context.getQualifiedType(UnqualParam, Quals);
   }
 
   // If the parameter type is not dependent, there is nothing to deduce.
diff --git a/test/SemaTemplate/deduction.cpp b/test/SemaTemplate/deduction.cpp
index 887535b..375d199 100644
--- a/test/SemaTemplate/deduction.cpp
+++ b/test/SemaTemplate/deduction.cpp
@@ -81,3 +81,8 @@
 int array2[is_same<Replace<vector<_1>, int, float>::type, vector<int> >::value? 1 : -1];
 int array3[is_same<Replace<vector<const _1>, int, float>::type, vector<const int> >::value? 1 : -1];
 int array4[is_same<Replace<vector<int, _2>, double, float>::type, vector<int, float> >::value? 1 : -1];
+
+// PR5911
+template <typename T, int N> void f(const T (&a)[N]);
+int iarr[] = { 1 };
+void test_PR5911() { f(iarr); }