From 607f38e05fac37a6a4972199eb646d8f1d2ff878 Mon Sep 17 00:00:00 2001 From: Chandler Carruth Date: Tue, 29 Dec 2009 07:16:59 +0000 Subject: [PATCH] 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. llvm-svn: 92248 --- clang/include/clang/AST/ASTContext.h | 19 ++++++- clang/lib/AST/ASTContext.cpp | 30 +++++++++++ clang/lib/Sema/SemaDeclCXX.cpp | 16 ++++-- clang/lib/Sema/SemaOverload.cpp | 23 +++++++- clang/lib/Sema/SemaTemplateDeduction.cpp | 54 +------------------ .../test/SemaCXX/qualification-conversion.cpp | 11 ++++ 6 files changed, 93 insertions(+), 60 deletions(-) diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index 2d4123eb173c..bcab46d0f5ed 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -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 diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 4bfea2421cbc..fe9628060917 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -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(T)) { + Quals = T.getLocalQualifiers(); + return T.getLocalUnqualifiedType(); + } + + assert(!T.hasQualifiers() && "canonical array type has qualifiers!"); + const ArrayType *AT = cast(T); + QualType Elt = AT->getElementType(); + QualType UnqualElt = getUnqualifiedArrayType(Elt, Quals); + if (Elt == UnqualElt) + return T; + + if (const ConstantArrayType *CAT = dyn_cast(T)) { + return getConstantArrayType(UnqualElt, CAT->getSize(), + CAT->getSizeModifier(), 0); + } + + if (const IncompleteArrayType *IAT = dyn_cast(T)) { + return getIncompleteArrayType(UnqualElt, IAT->getSizeModifier(), 0); + } + + const DependentSizedArrayType *DSAT = cast(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/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index a1800755bdcf..ab90a80cabb9 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -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(T1) && T1Quals) + T1 = Context.getQualifiedType(UnqualT1, T1Quals); + if (isa(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; diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 72a85cc968d9..99dbaba37be7 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -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(T1) && T1Quals) + T1 = Context.getQualifiedType(UnqualT1, T1Quals); + if (isa(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(T1) && T1Quals) + T1 = Context.getQualifiedType(UnqualT1, T1Quals); + if (isa(T2) && T2Quals) + T2 = Context.getQualifiedType(UnqualT2, T2Quals); + ImplicitConversionSequence::CompareKind Result = ImplicitConversionSequence::Indistinguishable; while (UnwrapSimilarPointerTypes(T1, T2)) { diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index 590a75174bf3..e31c05cf2af3 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -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(T)) { - Quals = T.getLocalQualifiers(); - return T.getLocalUnqualifiedType(); - } - - assert(!T.hasQualifiers() && "canonical array type has qualifiers!"); - - if (const ConstantArrayType *CAT = dyn_cast(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(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(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(Arg)) { Qualifiers Quals; - Arg = getUnqualifiedArrayType(Context, Arg, Quals); + Arg = Context.getUnqualifiedArrayType(Arg, Quals); if (Quals) { Arg = Context.getQualifiedType(Arg, Quals); RecanonicalizeArg = true; diff --git a/clang/test/SemaCXX/qualification-conversion.cpp b/clang/test/SemaCXX/qualification-conversion.cpp index cb9bbbd986ef..f1af5bf2852d 100644 --- a/clang/test/SemaCXX/qualification-conversion.cpp +++ b/clang/test/SemaCXX/qualification-conversion.cpp @@ -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}} +}