diff options
author | Douglas Gregor <dgregor@apple.com> | 2009-06-26 18:27:22 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2009-06-26 18:27:22 +0000 |
commit | 500d331eade2f5070b66ba51d777224f9fda6e1d (patch) | |
tree | 1bde7f5dd9d27f271a9f3e8eae3d9fcbf93ed381 | |
parent | e8c9e9218f215ec6089f12b076c7b9d310fd5194 (diff) |
Improve template argument deduction for reference parameters when
deducing template arguments from a function call. Plus, add a bunch of
tests.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@74301 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | lib/Sema/SemaTemplateDeduction.cpp | 46 | ||||
-rw-r--r-- | test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p2.cpp | 31 | ||||
-rw-r--r-- | test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p3.cpp | 44 |
3 files changed, 117 insertions, 4 deletions
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index 03466f02a2..66e12fefe6 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -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 diff --git a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p2.cpp b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p2.cpp new file mode 100644 index 0000000000..6f27d36368 --- /dev/null +++ b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p2.cpp @@ -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()); +} diff --git a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p3.cpp b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p3.cpp new file mode 100644 index 0000000000..18023523a9 --- /dev/null +++ b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p3.cpp @@ -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.
\ No newline at end of file |