]> granicus.if.org Git - clang/commitdiff
Correctly refer to element CVR qualifications when determining if a type is
authorChandler Carruth <chandlerc@gmail.com>
Tue, 29 Dec 2009 07:16:59 +0000 (07:16 +0000)
committerChandler Carruth <chandlerc@gmail.com>
Tue, 29 Dec 2009 07:16:59 +0000 (07:16 +0000)
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

include/clang/AST/ASTContext.h
lib/AST/ASTContext.cpp
lib/Sema/SemaDeclCXX.cpp
lib/Sema/SemaOverload.cpp
lib/Sema/SemaTemplateDeduction.cpp
test/SemaCXX/qualification-conversion.cpp

index 2d4123eb173c04996666f92d8159d372dace8964..bcab46d0f5ed43893d747724f35424f31ff0482f 100644 (file)
@@ -898,12 +898,29 @@ public:
     return getCanonicalType(T1) == getCanonicalType(T2);
   }
 
+  /// \brief Returns this type as a completely-unqualified array type, capturing
+  /// the qualifiers in Quals. This only operates on canonical types in order
+  /// to ensure the ArrayType doesn't itself have qualifiers.
+  ///
+  /// \param T is the canonicalized QualType, which may be an ArrayType
+  ///
+  /// \param Quals will receive the full set of qualifiers that were
+  /// applied to the element type of the array.
+  ///
+  /// \returns if this is an array type, the completely unqualified array type
+  /// that corresponds to it. Otherwise, returns this->getUnqualifiedType().
+  QualType getUnqualifiedArrayType(QualType T, Qualifiers &Quals);
+
   /// \brief Determine whether the given types are equivalent after
   /// cvr-qualifiers have been removed.
   bool hasSameUnqualifiedType(QualType T1, QualType T2) {
     CanQualType CT1 = getCanonicalType(T1);
     CanQualType CT2 = getCanonicalType(T2);
-    return CT1.getUnqualifiedType() == CT2.getUnqualifiedType();
+
+    Qualifiers Quals;
+    QualType UnqualT1 = getUnqualifiedArrayType(CT1, Quals);
+    QualType UnqualT2 = getUnqualifiedArrayType(CT2, Quals);
+    return UnqualT1 == UnqualT2;
   }
 
   /// \brief Retrieves the "canonical" declaration of
index 4bfea2421cbcd4e58d99dcb97a4ec5ee248a626c..fe9628060917a91a978d8c03b103e99cc3f5fa2f 100644 (file)
@@ -2372,6 +2372,36 @@ CanQualType ASTContext::getCanonicalType(QualType T) {
                                                      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();
index a1800755bdcf2a224d252570894dafa7e932d6e0..ab90a80cabb9a2d00c629f075bc0ae0853b740b1 100644 (file)
@@ -4206,7 +4206,7 @@ Sema::CompleteConstructorCall(CXXConstructorDecl *Constructor,
 /// 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 @@ Sema::CompareReferenceRelationship(SourceLocation Loc,
 
   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 @@ Sema::CompareReferenceRelationship(SourceLocation Loc,
   // 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 @@ Sema::CompareReferenceRelationship(SourceLocation Loc,
   //   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;
index 72a85cc968d933a9d29fb2859386fbc610b476dc..99dbaba37be796fcdd21695c8cb3427f9f9ba078 100644 (file)
@@ -1802,7 +1802,16 @@ Sema::CompareStandardConversionSequences(const StandardConversionSequence& SCS1,
     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 @@ Sema::CompareQualificationConversions(const StandardConversionSequence& SCS1,
   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)) {
index 590a75174bf3a31b27a8d03afe85fa43a83230a2..e31c05cf2af30a78e467970873782e91a06a1423 100644 (file)
@@ -337,58 +337,6 @@ DeduceTemplateArguments(ASTContext &Context,
   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 @@ DeduceTemplateArguments(ASTContext &Context,
     // 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;
index cb9bbbd986efdf3886f77726d8b811dfeddb1f88..f1af5bf2852d191a561b8d518f415e97134f3678 100644 (file)
@@ -21,3 +21,14 @@ void test_mquals(int A::*p, int A::* A::*pp, int A::* A::* A::*ppp) {
   mquals2(pp);
   mquals3(ppp); // expected-error {{no matching}}
 }
+
+void aquals1(int const (*p)[1]);
+void aquals2(int * const (*pp)[1]);
+void aquals2a(int const * (*pp2)[1]); // expected-note{{candidate function}}
+
+void test_aquals(int (*p)[1], int * (*pp)[1], int * (*pp2)[1]) {
+  int const (*p2)[1] = p;
+  aquals1(p);
+  aquals2(pp);
+  aquals2a(pp2); // expected-error {{no matching}}
+}