forked from OSchip/llvm-project
Improve template argument deduction for reference parameters when
deducing template arguments from a function call. Plus, add a bunch of tests. llvm-svn: 74301
This commit is contained in:
parent
88efd1fed3
commit
cceb97559e
|
@ -156,17 +156,49 @@ DeduceTemplateArguments(ASTContext &Context,
|
|||
return Sema::TDK_Success;
|
||||
}
|
||||
|
||||
/// \brief Deduce the template arguments by comparing the parameter type and
|
||||
/// the argument type (C++ [temp.deduct.type]).
|
||||
///
|
||||
/// \param Context the AST context in which this deduction occurs.
|
||||
///
|
||||
/// \param TemplateParams the template parameters that we are deducing
|
||||
///
|
||||
/// \param ParamIn the parameter type
|
||||
///
|
||||
/// \param ArgIn the argument type
|
||||
///
|
||||
/// \param Info information about the template argument deduction itself
|
||||
///
|
||||
/// \param Deduced the deduced template arguments
|
||||
///
|
||||
/// \param ParamTypeWasReference if true, the original parameter type was
|
||||
/// a reference type (C++0x [temp.deduct.type]p4 bullet 1).
|
||||
///
|
||||
/// \returns the result of template argument deduction so far. Note that a
|
||||
/// "success" result means that template argument deduction has not yet failed,
|
||||
/// but it may still fail, later, for other reasons.
|
||||
static Sema::TemplateDeductionResult
|
||||
DeduceTemplateArguments(ASTContext &Context,
|
||||
TemplateParameterList *TemplateParams,
|
||||
QualType ParamIn, QualType ArgIn,
|
||||
Sema::TemplateDeductionInfo &Info,
|
||||
llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
|
||||
llvm::SmallVectorImpl<TemplateArgument> &Deduced,
|
||||
bool ParamTypeWasReference = false) {
|
||||
// We only want to look at the canonical types, since typedefs and
|
||||
// sugar are not part of template argument deduction.
|
||||
QualType Param = Context.getCanonicalType(ParamIn);
|
||||
QualType Arg = Context.getCanonicalType(ArgIn);
|
||||
|
||||
// C++0x [temp.deduct.call]p4 bullet 1:
|
||||
// - If the original P is a reference type, the deduced A (i.e., the type
|
||||
// referred to by the reference) can be more cv-qualified than the
|
||||
// transformed A.
|
||||
if (ParamTypeWasReference) {
|
||||
unsigned ExtraQualsOnParam
|
||||
= Param.getCVRQualifiers() & ~Arg.getCVRQualifiers();
|
||||
Param.setCVRQualifiers(Param.getCVRQualifiers() & ~ExtraQualsOnParam);
|
||||
}
|
||||
|
||||
// If the parameter type is not dependent, just compare the types
|
||||
// directly.
|
||||
if (!Param->isDependentType()) {
|
||||
|
@ -761,7 +793,11 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
|
|||
CheckArgs = Function->getNumParams();
|
||||
}
|
||||
|
||||
// Template argument deduction for function templates in a SFINAE context.
|
||||
// Trap any errors that might occur.
|
||||
SFINAETrap Trap(*this);
|
||||
|
||||
// Deduce template arguments from the function parameters.
|
||||
llvm::SmallVector<TemplateArgument, 4> Deduced;
|
||||
Deduced.resize(FunctionTemplate->getTemplateParameters()->size());
|
||||
TemplateParameterList *TemplateParams
|
||||
|
@ -769,11 +805,12 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
|
|||
for (unsigned I = 0; I != CheckArgs; ++I) {
|
||||
QualType ParamType = Function->getParamDecl(I)->getType();
|
||||
QualType ArgType = Args[I]->getType();
|
||||
|
||||
|
||||
// C++ [temp.deduct.call]p2:
|
||||
// If P is not a reference type:
|
||||
QualType CanonParamType = Context.getCanonicalType(ParamType);
|
||||
if (!isa<ReferenceType>(CanonParamType)) {
|
||||
bool ParamWasReference = isa<ReferenceType>(CanonParamType);
|
||||
if (!ParamWasReference) {
|
||||
// - If A is an array type, the pointer type produced by the
|
||||
// array-to-pointer standard conversion (4.2) is used in place of
|
||||
// A for type deduction; otherwise,
|
||||
|
@ -822,7 +859,8 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
|
|||
// arguments from a type.
|
||||
if (TemplateDeductionResult Result
|
||||
= ::DeduceTemplateArguments(Context, TemplateParams,
|
||||
ParamType, ArgType, Info, Deduced))
|
||||
ParamType, ArgType, Info, Deduced,
|
||||
ParamWasReference))
|
||||
return Result;
|
||||
|
||||
// FIXME: C++ [temp.deduct.call] paragraphs 6-9 deal with function
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
// RUN: clang-cc -fsyntax-only -verify %s
|
||||
template<typename T> struct A { };
|
||||
|
||||
// bullet 1
|
||||
template<typename T> A<T> f0(T* ptr);
|
||||
|
||||
void test_f0_bullet1() {
|
||||
int arr0[6];
|
||||
A<int> a0 = f0(arr0);
|
||||
const int arr1[] = { 1, 2, 3, 4, 5 };
|
||||
A<const int> a1 = f0(arr1);
|
||||
}
|
||||
|
||||
// bullet 2
|
||||
int g0(int, int);
|
||||
float g1(float);
|
||||
|
||||
void test_f0_bullet2() {
|
||||
A<int(int, int)> a0 = f0(g0);
|
||||
A<float(float)> a1 = f0(g1);
|
||||
}
|
||||
|
||||
// bullet 3
|
||||
struct X { };
|
||||
const X get_X();
|
||||
|
||||
template<typename T> A<T> f1(T);
|
||||
|
||||
void test_f1_bullet3() {
|
||||
A<X> a0 = f1(get_X());
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
// RUN: clang-cc -fsyntax-only %s
|
||||
|
||||
template<typename T> struct A { };
|
||||
|
||||
// Top-level cv-qualifiers of P's type are ignored for type deduction.
|
||||
template<typename T> A<T> f0(const T);
|
||||
|
||||
void test_f0(int i, const int ci) {
|
||||
A<int> a0 = f0(i);
|
||||
A<int> a1 = f0(ci);
|
||||
}
|
||||
|
||||
// If P is a reference type, the type referred to by P is used for type
|
||||
// deduction.
|
||||
template<typename T> A<T> f1(T&);
|
||||
|
||||
void test_f1(int i, const int ci, volatile int vi) {
|
||||
A<int> a0 = f1(i);
|
||||
A<const int> a1 = f1(ci);
|
||||
A<volatile int> a2 = f1(vi);
|
||||
}
|
||||
|
||||
template<typename T, unsigned N> struct B { };
|
||||
template<typename T, unsigned N> B<T, N> g0(T (&array)[N]);
|
||||
|
||||
void test_g0() {
|
||||
int array0[5];
|
||||
B<int, 5> b0 = g0(array0);
|
||||
const int array1[] = { 1, 2, 3};
|
||||
B<const int, 3> b1 = g0(array1);
|
||||
}
|
||||
|
||||
// - If the original P is a reference type, the deduced A (i.e., the type
|
||||
// referred to by the reference) can be more cv-qualified than the
|
||||
// transformed A.
|
||||
template<typename T> A<T> f2(const T&);
|
||||
|
||||
void test_f2(int i, const int ci, volatile int vi) {
|
||||
A<int> a0 = f2(i);
|
||||
A<int> a1 = f2(ci);
|
||||
A<volatile int> a2 = f2(vi);
|
||||
}
|
||||
|
||||
// FIXME: the next two bullets require a bit of effort.
|
Loading…
Reference in New Issue