[cfe-commits] r74301 - in /cfe/trunk: lib/Sema/SemaTemplateDeduction.cpp test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p2.cpp test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p3.cpp

Douglas Gregor dgregor at apple.com
Fri Jun 26 11:27:22 PDT 2009


Author: dgregor
Date: Fri Jun 26 13:27:22 2009
New Revision: 74301

URL: http://llvm.org/viewvc/llvm-project?rev=74301&view=rev
Log:
Improve template argument deduction for reference parameters when
deducing template arguments from a function call. Plus, add a bunch of
tests.


Added:
    cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p2.cpp
    cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p3.cpp
Modified:
    cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp

Modified: cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp?rev=74301&r1=74300&r2=74301&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp Fri Jun 26 13:27:22 2009
@@ -156,17 +156,49 @@
   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 @@
     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 @@
   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 @@
     // 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

Added: cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p2.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p2.cpp?rev=74301&view=auto

==============================================================================
--- cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p2.cpp (added)
+++ cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p2.cpp Fri Jun 26 13:27:22 2009
@@ -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());
+}

Added: cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p3.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p3.cpp?rev=74301&view=auto

==============================================================================
--- cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p3.cpp (added)
+++ cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p3.cpp Fri Jun 26 13:27:22 2009
@@ -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





More information about the cfe-commits mailing list