Fix the problems with template argument deduction and array types for

real. It turns out that we need to actually move all of the qualifiers
up to the array type itself, then recanonicalize the deduced template
argument type.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@76788 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Douglas Gregor 2009-07-22 21:30:48 +00:00
Родитель cd0c073cb7
Коммит f290e0db83
2 изменённых файлов: 79 добавлений и 9 удалений

Просмотреть файл

@ -283,6 +283,57 @@ DeduceTemplateArguments(ASTContext &Context,
return Sema::TDK_Success;
}
/// \brief Returns a completely-unqualified array type, capturing the
/// qualifiers in CVRQuals.
///
/// \param Context the AST context in which the array type was built.
///
/// \param T a canonical type that may be an array type.
///
/// \param CVRQuals will receive the set of const/volatile/restrict 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,
unsigned &CVRQuals) {
assert(T->isCanonical() && "Only operates on canonical types");
if (!isa<ArrayType>(T)) {
CVRQuals = T.getCVRQualifiers();
return T.getUnqualifiedType();
}
if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(T)) {
QualType Elt = getUnqualifiedArrayType(Context, CAT->getElementType(),
CVRQuals);
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(),
CVRQuals);
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(),
CVRQuals);
if (Elt == DSAT->getElementType())
return T;
// FIXME: Clone expression!
return Context.getDependentSizedArrayType(Elt, DSAT->getSizeExpr(),
DSAT->getSizeModifier(), 0,
SourceRange());
}
/// \brief Deduce the template arguments by comparing the parameter type and
/// the argument type (C++ [temp.deduct.type]).
///
@ -340,14 +391,19 @@ DeduceTemplateArguments(ASTContext &Context,
if (const TemplateTypeParmType *TemplateTypeParm
= Param->getAsTemplateTypeParmType()) {
unsigned Index = TemplateTypeParm->getIndex();
bool RecanonicalizeArg = false;
// If the argument type is an array type, move the qualifiers up to the
// top level, so they can be matched with the qualifiers on the parameter.
// FIXME: address spaces, ObjC GC qualifiers
QualType ArgElementType = Arg;
while (const ArrayType *ArgArray = ArgElementType->getAs<ArrayType>())
ArgElementType = ArgArray->getElementType();
Arg = Arg.getWithAdditionalQualifiers(ArgElementType.getCVRQualifiers());
if (isa<ArrayType>(Arg)) {
unsigned CVRQuals = 0;
Arg = getUnqualifiedArrayType(Context, Arg, CVRQuals);
if (CVRQuals) {
Arg = Arg.getWithAdditionalQualifiers(CVRQuals);
RecanonicalizeArg = true;
}
}
// The argument type can not be less qualified than the parameter
// type.
@ -361,9 +417,10 @@ DeduceTemplateArguments(ASTContext &Context,
assert(TemplateTypeParm->getDepth() == 0 && "Can't deduce with depth > 0");
unsigned Quals = Arg.getCVRQualifiers() & ~Param.getCVRQualifiers();
QualType DeducedType
= Context.getCanonicalType(Arg.getQualifiedType(Quals));
QualType DeducedType = Arg.getQualifiedType(Quals);
if (RecanonicalizeArg)
DeducedType = Context.getCanonicalType(DeducedType);
if (Deduced[Index].isNull())
Deduced[Index] = TemplateArgument(SourceLocation(), DeducedType);
else {

Просмотреть файл

@ -94,7 +94,20 @@ struct remove_reference<T&> {
int remove_ref0[is_same<remove_reference<int>::type, int>::value? 1 : -1];
int remove_ref1[is_same<remove_reference<int&>::type, int>::value? 1 : -1];
template<typename T>
struct remove_const {
typedef T type;
};
template<typename T>
struct remove_const<const T> {
typedef T type;
};
int remove_const0[is_same<remove_const<const int>::type, int>::value? 1 : -1];
int remove_const1[is_same<remove_const<const int[3]>::type, int[3]>::value? 1 : -1];
template<typename T>
struct is_incomplete_array {
static const bool value = false;