Implement core issue 1164, which concerns the partial ordering of

f(T&) and f(T&&).

llvm-svn: 123981
This commit is contained in:
Douglas Gregor 2011-01-21 17:29:42 +00:00
parent bf2f961a35
commit 6381402fe1
2 changed files with 97 additions and 47 deletions

View File

@ -84,14 +84,29 @@ DeduceTemplateArguments(Sema &S,
TemplateDeductionInfo &Info,
llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced);
/// \brief Stores the result of comparing the qualifiers of two types, used
/// when
/// \brief Whether template argument deduction for two reference parameters
/// resulted in the argument type, parameter type, or neither type being more
/// qualified than the other.
enum DeductionQualifierComparison {
NeitherMoreQualified = 0,
ParamMoreQualified,
ArgMoreQualified
};
/// \brief Stores the result of comparing two reference parameters while
/// performing template argument deduction for partial ordering of function
/// templates.
struct RefParamPartialOrderingComparison {
/// \brief Whether the parameter type is an rvalue reference type.
bool ParamIsRvalueRef;
/// \brief Whether the argument type is an rvalue reference type.
bool ArgIsRvalueRef;
/// \brief Whether the parameter or argument (or neither) is more qualified.
DeductionQualifierComparison Qualifiers;
};
static Sema::TemplateDeductionResult
DeduceTemplateArguments(Sema &S,
@ -102,8 +117,8 @@ DeduceTemplateArguments(Sema &S,
llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced,
unsigned TDF,
bool PartialOrdering = false,
llvm::SmallVectorImpl<DeductionQualifierComparison> *
QualifierComparisons = 0);
llvm::SmallVectorImpl<RefParamPartialOrderingComparison> *
RefParamComparisons = 0);
static Sema::TemplateDeductionResult
DeduceTemplateArguments(Sema &S,
@ -638,7 +653,7 @@ FinishArgumentPackDeduction(Sema &S,
/// deduction for during partial ordering for a call
/// (C++0x [temp.deduct.partial]).
///
/// \param QualifierComparisons If we're performing template argument deduction
/// \param RefParamComparisons If we're performing template argument deduction
/// in the context of partial ordering, the set of qualifier comparisons.
///
/// \returns the result of template argument deduction so far. Note that a
@ -653,8 +668,8 @@ DeduceTemplateArguments(Sema &S,
llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced,
unsigned TDF,
bool PartialOrdering = false,
llvm::SmallVectorImpl<DeductionQualifierComparison> *
QualifierComparisons = 0) {
llvm::SmallVectorImpl<RefParamPartialOrderingComparison> *
RefParamComparisons = 0) {
// Fast-path check to see if we have too many/too few arguments.
if (NumParams != NumArgs &&
!(NumParams && isa<PackExpansionType>(Params[NumParams - 1])) &&
@ -692,7 +707,7 @@ DeduceTemplateArguments(Sema &S,
Args[ArgIdx],
Info, Deduced, TDF,
PartialOrdering,
QualifierComparisons))
RefParamComparisons))
return Result;
++ArgIdx;
@ -750,7 +765,7 @@ DeduceTemplateArguments(Sema &S,
if (Sema::TemplateDeductionResult Result
= DeduceTemplateArguments(S, TemplateParams, Pattern, Args[ArgIdx],
Info, Deduced, PartialOrdering,
QualifierComparisons))
RefParamComparisons))
return Result;
// Capture the deduced template arguments for each parameter pack expanded
@ -802,7 +817,7 @@ DeduceTemplateArguments(Sema &S,
/// \param PartialOrdering Whether we're performing template argument deduction
/// in the context of partial ordering (C++0x [temp.deduct.partial]).
///
/// \param QualifierComparisons If we're performing template argument deduction
/// \param RefParamComparisons If we're performing template argument deduction
/// in the context of partial ordering, the set of qualifier comparisons.
///
/// \returns the result of template argument deduction so far. Note that a
@ -816,7 +831,7 @@ DeduceTemplateArguments(Sema &S,
llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced,
unsigned TDF,
bool PartialOrdering,
llvm::SmallVectorImpl<DeductionQualifierComparison> *QualifierComparisons) {
llvm::SmallVectorImpl<RefParamPartialOrderingComparison> *RefParamComparisons) {
// We only want to look at the canonical types, since typedefs and
// sugar are not part of template argument deduction.
QualType Param = S.Context.getCanonicalType(ParamIn);
@ -842,7 +857,7 @@ DeduceTemplateArguments(Sema &S,
if (ArgRef)
Arg = ArgRef->getPointeeType();
if (QualifierComparisons && ParamRef && ArgRef) {
if (RefParamComparisons && ParamRef && ArgRef) {
// C++0x [temp.deduct.partial]p6:
// If both P and A were reference types (before being replaced with the
// type referred to above), determine which of the two types (if any) is
@ -852,12 +867,15 @@ DeduceTemplateArguments(Sema &S,
//
// We save this information for later, using it only when deduction
// succeeds in both directions.
DeductionQualifierComparison QualifierResult = NeitherMoreQualified;
RefParamPartialOrderingComparison Comparison;
Comparison.ParamIsRvalueRef = ParamRef->getAs<RValueReferenceType>();
Comparison.ArgIsRvalueRef = ArgRef->getAs<RValueReferenceType>();
Comparison.Qualifiers = NeitherMoreQualified;
if (Param.isMoreQualifiedThan(Arg))
QualifierResult = ParamMoreQualified;
Comparison.Qualifiers = ParamMoreQualified;
else if (Arg.isMoreQualifiedThan(Param))
QualifierResult = ArgMoreQualified;
QualifierComparisons->push_back(QualifierResult);
Comparison.Qualifiers = ArgMoreQualified;
RefParamComparisons->push_back(Comparison);
}
// C++0x [temp.deduct.partial]p7:
@ -2937,8 +2955,8 @@ static bool isAtLeastAsSpecializedAs(Sema &S,
FunctionTemplateDecl *FT1,
FunctionTemplateDecl *FT2,
TemplatePartialOrderingContext TPOC,
unsigned NumCallArguments,
llvm::SmallVectorImpl<DeductionQualifierComparison> *QualifierComparisons) {
unsigned NumCallArguments,
llvm::SmallVectorImpl<RefParamPartialOrderingComparison> *RefParamComparisons) {
FunctionDecl *FD1 = FT1->getTemplatedDecl();
FunctionDecl *FD2 = FT2->getTemplatedDecl();
const FunctionProtoType *Proto1 = FD1->getType()->getAs<FunctionProtoType>();
@ -3004,7 +3022,7 @@ static bool isAtLeastAsSpecializedAs(Sema &S,
if (DeduceTemplateArguments(S, TemplateParams, Args2.data(), Args2.size(),
Args1.data(), Args1.size(), Info, Deduced,
TDF_None, /*PartialOrdering=*/true,
QualifierComparisons))
RefParamComparisons))
return false;
break;
@ -3016,7 +3034,7 @@ static bool isAtLeastAsSpecializedAs(Sema &S,
if (DeduceTemplateArguments(S, TemplateParams, Proto2->getResultType(),
Proto1->getResultType(), Info, Deduced,
TDF_None, /*PartialOrdering=*/true,
QualifierComparisons))
RefParamComparisons))
return false;
break;
@ -3027,7 +3045,7 @@ static bool isAtLeastAsSpecializedAs(Sema &S,
// types?
if (DeduceTemplateArguments(S, TemplateParams, FD2->getType(),
FD1->getType(), Info, Deduced, TDF_None,
/*PartialOrdering=*/true, QualifierComparisons))
/*PartialOrdering=*/true, RefParamComparisons))
return false;
break;
}
@ -3131,12 +3149,12 @@ Sema::getMoreSpecializedTemplate(FunctionTemplateDecl *FT1,
SourceLocation Loc,
TemplatePartialOrderingContext TPOC,
unsigned NumCallArguments) {
llvm::SmallVector<DeductionQualifierComparison, 4> QualifierComparisons;
llvm::SmallVector<RefParamPartialOrderingComparison, 4> RefParamComparisons;
bool Better1 = isAtLeastAsSpecializedAs(*this, Loc, FT1, FT2, TPOC,
NumCallArguments, 0);
bool Better2 = isAtLeastAsSpecializedAs(*this, Loc, FT2, FT1, TPOC,
NumCallArguments,
&QualifierComparisons);
&RefParamComparisons);
if (Better1 != Better2) // We have a clear winner
return Better1? FT1 : FT2;
@ -3144,7 +3162,6 @@ Sema::getMoreSpecializedTemplate(FunctionTemplateDecl *FT1,
if (!Better1 && !Better2) // Neither is better than the other
return 0;
// C++0x [temp.deduct.partial]p10:
// If for each type being considered a given template is at least as
// specialized for all types and more specialized for some set of types and
@ -3154,30 +3171,53 @@ Sema::getMoreSpecializedTemplate(FunctionTemplateDecl *FT1,
// specialized than the other.
Better1 = false;
Better2 = false;
for (unsigned I = 0, N = QualifierComparisons.size(); I != N; ++I) {
for (unsigned I = 0, N = RefParamComparisons.size(); I != N; ++I) {
// C++0x [temp.deduct.partial]p9:
// If, for a given type, deduction succeeds in both directions (i.e., the
// types are identical after the transformations above) and if the type
// from the argument template is more cv-qualified than the type from the
// parameter template (as described above) that type is considered to be
// more specialized than the other. If neither type is more cv-qualified
// than the other then neither type is more specialized than the other.
switch (QualifierComparisons[I]) {
case NeitherMoreQualified:
break;
case ParamMoreQualified:
Better1 = true;
if (Better2)
return 0;
break;
case ArgMoreQualified:
Better2 = true;
if (Better1)
return 0;
break;
// types are identical after the transformations above) and both P and A
// were reference types (before being replaced with the type referred to
// above):
// -- if the type from the argument template was an lvalue reference
// and the type from the parameter template was not, the argument
// type is considered to be more specialized than the other;
// otherwise,
if (!RefParamComparisons[I].ArgIsRvalueRef &&
RefParamComparisons[I].ParamIsRvalueRef) {
Better2 = true;
if (Better1)
return 0;
continue;
} else if (!RefParamComparisons[I].ParamIsRvalueRef &&
RefParamComparisons[I].ArgIsRvalueRef) {
Better1 = true;
if (Better2)
return 0;
continue;
}
// -- if the type from the argument template is more cv-qualified than
// the type from the parameter template (as described above), the
// argument type is considered to be more specialized than the
// other; otherwise,
switch (RefParamComparisons[I].Qualifiers) {
case NeitherMoreQualified:
break;
case ParamMoreQualified:
Better1 = true;
if (Better2)
return 0;
continue;
case ArgMoreQualified:
Better2 = true;
if (Better1)
return 0;
continue;
}
// -- neither type is more specialized than the other.
}
assert(!(Better1 && Better2) && "Should have broken out in the loop above");
@ -3364,7 +3404,7 @@ Sema::getMoreSpecializedPartialSpecialization(
bool Better1 = !::DeduceTemplateArguments(*this, PS2->getTemplateParameters(),
PT2, PT1, Info, Deduced, TDF_None,
/*PartialOrdering=*/true,
/*QualifierComparisons=*/0);
/*RefParamComparisons=*/0);
if (Better1) {
InstantiatingTemplate Inst(*this, PS2->getLocation(), PS2,
Deduced.data(), Deduced.size(), Info);
@ -3379,7 +3419,7 @@ Sema::getMoreSpecializedPartialSpecialization(
bool Better2 = !::DeduceTemplateArguments(*this, PS1->getTemplateParameters(),
PT1, PT2, Info, Deduced, TDF_None,
/*PartialOrdering=*/true,
/*QualifierComparisons=*/0);
/*RefParamComparisons=*/0);
if (Better2) {
InstantiatingTemplate Inst(*this, PS1->getLocation(), PS1,
Deduced.data(), Deduced.size(), Info);

View File

@ -0,0 +1,10 @@
// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
template<typename T> int &f0(T&);
template<typename T> float &f0(T&&);
// Core issue 1164
void test_f0(int i) {
int &ir0 = f0(i);
float &fr0 = f0(5);
}