Correctly refer to element CVR qualifications when determining if a type is
more or less cv-qualified than another during implicit conversion and overload
resolution ([basic.type.qualifier] p5). Factors the logic out of template
deduction and into the ASTContext so it can be shared.

This fixes several aspects of PR5542, but not all of them.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@92248 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 4bfea24..fe96280 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -2372,6 +2372,36 @@
                                                      VAT->getBracketsRange()));
 }
 
+QualType ASTContext::getUnqualifiedArrayType(QualType T,
+                                             Qualifiers &Quals) {
+  assert(T.isCanonical() && "Only operates on canonical types");
+  if (!isa<ArrayType>(T)) {
+    Quals = T.getLocalQualifiers();
+    return T.getLocalUnqualifiedType();
+  }
+
+  assert(!T.hasQualifiers() && "canonical array type has qualifiers!");
+  const ArrayType *AT = cast<ArrayType>(T);
+  QualType Elt = AT->getElementType();
+  QualType UnqualElt = getUnqualifiedArrayType(Elt, Quals);
+  if (Elt == UnqualElt)
+    return T;
+
+  if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(T)) {
+    return getConstantArrayType(UnqualElt, CAT->getSize(),
+                                CAT->getSizeModifier(), 0);
+  }
+
+  if (const IncompleteArrayType *IAT = dyn_cast<IncompleteArrayType>(T)) {
+    return getIncompleteArrayType(UnqualElt, IAT->getSizeModifier(), 0);
+  }
+
+  const DependentSizedArrayType *DSAT = cast<DependentSizedArrayType>(T);
+  return getDependentSizedArrayType(UnqualElt, DSAT->getSizeExpr()->Retain(),
+                                    DSAT->getSizeModifier(), 0,
+                                    SourceRange());
+}
+
 DeclarationName ASTContext::getNameForTemplate(TemplateName Name) {
   if (TemplateDecl *TD = Name.getAsTemplateDecl())
     return TD->getDeclName();
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index a180075..ab90a80 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -4206,7 +4206,7 @@
 /// type, and the first type (T1) is the pointee type of the reference
 /// type being initialized.
 Sema::ReferenceCompareResult
-Sema::CompareReferenceRelationship(SourceLocation Loc, 
+Sema::CompareReferenceRelationship(SourceLocation Loc,
                                    QualType OrigT1, QualType OrigT2,
                                    bool& DerivedToBase) {
   assert(!OrigT1->isReferenceType() &&
@@ -4215,8 +4215,9 @@
 
   QualType T1 = Context.getCanonicalType(OrigT1);
   QualType T2 = Context.getCanonicalType(OrigT2);
-  QualType UnqualT1 = T1.getLocalUnqualifiedType();
-  QualType UnqualT2 = T2.getLocalUnqualifiedType();
+  Qualifiers T1Quals, T2Quals;
+  QualType UnqualT1 = Context.getUnqualifiedArrayType(T1, T1Quals);
+  QualType UnqualT2 = Context.getUnqualifiedArrayType(T2, T2Quals);
 
   // C++ [dcl.init.ref]p4:
   //   Given types "cv1 T1" and "cv2 T2," "cv1 T1" is
@@ -4234,6 +4235,13 @@
   // At this point, we know that T1 and T2 are reference-related (at
   // least).
 
+  // If the type is an array type, promote the element qualifiers to the type
+  // for comparison.
+  if (isa<ArrayType>(T1) && T1Quals)
+    T1 = Context.getQualifiedType(UnqualT1, T1Quals);
+  if (isa<ArrayType>(T2) && T2Quals)
+    T2 = Context.getQualifiedType(UnqualT2, T2Quals);
+
   // C++ [dcl.init.ref]p4:
   //   "cv1 T1" is reference-compatible with "cv2 T2" if T1 is
   //   reference-related to T2 and cv1 is the same cv-qualification
@@ -4241,7 +4249,7 @@
   //   overload resolution, cases for which cv1 is greater
   //   cv-qualification than cv2 are identified as
   //   reference-compatible with added qualification (see 13.3.3.2).
-  if (T1.getCVRQualifiers() == T2.getCVRQualifiers())
+  if (T1Quals.getCVRQualifiers() == T2Quals.getCVRQualifiers())
     return Ref_Compatible;
   else if (T1.isMoreQualifiedThan(T2))
     return Ref_Compatible_With_Added_Qualification;
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index 72a85cc..99dbaba 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -1802,7 +1802,16 @@
     QualType T2 = QualType::getFromOpaquePtr(SCS2.ToTypePtr);
     T1 = Context.getCanonicalType(T1);
     T2 = Context.getCanonicalType(T2);
-    if (Context.hasSameUnqualifiedType(T1, T2)) {
+    Qualifiers T1Quals, T2Quals;
+    QualType UnqualT1 = Context.getUnqualifiedArrayType(T1, T1Quals);
+    QualType UnqualT2 = Context.getUnqualifiedArrayType(T2, T2Quals);
+    if (UnqualT1 == UnqualT2) {
+      // If the type is an array type, promote the element qualifiers to the type
+      // for comparison.
+      if (isa<ArrayType>(T1) && T1Quals)
+        T1 = Context.getQualifiedType(UnqualT1, T1Quals);
+      if (isa<ArrayType>(T2) && T2Quals)
+        T2 = Context.getQualifiedType(UnqualT2, T2Quals);
       if (T2.isMoreQualifiedThan(T1))
         return ImplicitConversionSequence::Better;
       else if (T1.isMoreQualifiedThan(T2))
@@ -1835,12 +1844,22 @@
   QualType T2 = QualType::getFromOpaquePtr(SCS2.ToTypePtr);
   T1 = Context.getCanonicalType(T1);
   T2 = Context.getCanonicalType(T2);
+  Qualifiers T1Quals, T2Quals;
+  QualType UnqualT1 = Context.getUnqualifiedArrayType(T1, T1Quals);
+  QualType UnqualT2 = Context.getUnqualifiedArrayType(T2, T2Quals);
 
   // If the types are the same, we won't learn anything by unwrapped
   // them.
-  if (Context.hasSameUnqualifiedType(T1, T2))
+  if (UnqualT1 == UnqualT2)
     return ImplicitConversionSequence::Indistinguishable;
 
+  // If the type is an array type, promote the element qualifiers to the type
+  // for comparison.
+  if (isa<ArrayType>(T1) && T1Quals)
+    T1 = Context.getQualifiedType(UnqualT1, T1Quals);
+  if (isa<ArrayType>(T2) && T2Quals)
+    T2 = Context.getQualifiedType(UnqualT2, T2Quals);
+
   ImplicitConversionSequence::CompareKind Result
     = ImplicitConversionSequence::Indistinguishable;
   while (UnwrapSimilarPointerTypes(T1, T2)) {
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp
index 590a751..e31c05c 100644
--- a/lib/Sema/SemaTemplateDeduction.cpp
+++ b/lib/Sema/SemaTemplateDeduction.cpp
@@ -337,58 +337,6 @@
   return Sema::TDK_Success;
 }
 
-/// \brief Returns a completely-unqualified array type, capturing the
-/// qualifiers in Quals.
-///
-/// \param Context the AST context in which the array type was built.
-///
-/// \param T a canonical type that may be an array type.
-///
-/// \param Quals will receive the full set of qualifiers that were
-/// applied to the element type of the array.
-///
-/// \returns if \p T is an array type, the completely unqualified array type
-/// that corresponds to T. Otherwise, returns T.
-static QualType getUnqualifiedArrayType(ASTContext &Context, QualType T,
-                                        Qualifiers &Quals) {
-  assert(T.isCanonical() && "Only operates on canonical types");
-  if (!isa<ArrayType>(T)) {
-    Quals = T.getLocalQualifiers();
-    return T.getLocalUnqualifiedType();
-  }
-
-  assert(!T.hasQualifiers() && "canonical array type has qualifiers!");
-
-  if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(T)) {
-    QualType Elt = getUnqualifiedArrayType(Context, CAT->getElementType(),
-                                           Quals);
-    if (Elt == CAT->getElementType())
-      return T;
-
-    return Context.getConstantArrayType(Elt, CAT->getSize(),
-                                        CAT->getSizeModifier(), 0);
-  }
-
-  if (const IncompleteArrayType *IAT = dyn_cast<IncompleteArrayType>(T)) {
-    QualType Elt = getUnqualifiedArrayType(Context, IAT->getElementType(),
-                                           Quals);
-    if (Elt == IAT->getElementType())
-      return T;
-
-    return Context.getIncompleteArrayType(Elt, IAT->getSizeModifier(), 0);
-  }
-
-  const DependentSizedArrayType *DSAT = cast<DependentSizedArrayType>(T);
-  QualType Elt = getUnqualifiedArrayType(Context, DSAT->getElementType(),
-                                         Quals);
-  if (Elt == DSAT->getElementType())
-    return T;
-
-  return Context.getDependentSizedArrayType(Elt, DSAT->getSizeExpr()->Retain(),
-                                            DSAT->getSizeModifier(), 0,
-                                            SourceRange());
-}
-
 /// \brief Deduce the template arguments by comparing the parameter type and
 /// the argument type (C++ [temp.deduct.type]).
 ///
@@ -459,7 +407,7 @@
     // FIXME: address spaces, ObjC GC qualifiers
     if (isa<ArrayType>(Arg)) {
       Qualifiers Quals;
-      Arg = getUnqualifiedArrayType(Context, Arg, Quals);
+      Arg = Context.getUnqualifiedArrayType(Arg, Quals);
       if (Quals) {
         Arg = Context.getQualifiedType(Arg, Quals);
         RecanonicalizeArg = true;