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
This commit is contained in:
Chandler Carruth 2009-12-29 07:16:59 +00:00
parent 5d3b077111
commit 607f38e05f
6 changed files with 93 additions and 60 deletions

View 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

View 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();

View 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;

View 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)) {

View 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;

View 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}}
}