[cfe-commits] r74323 - in /cfe/trunk: include/clang/AST/DeclTemplate.h lib/Sema/SemaTemplateDeduction.cpp test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/basic.cpp

Douglas Gregor dgregor at apple.com
Fri Jun 26 13:57:09 PDT 2009


Author: dgregor
Date: Fri Jun 26 15:57:09 2009
New Revision: 74323

URL: http://llvm.org/viewvc/llvm-project?rev=74323&view=rev
Log:
Template argument deduction is no longer responsible for checking
non-dependent parameter types. Instead, class template partial
specializations perform a final check of all of the instantiated
arguments. This model is cleaner, and works better for function
templates where the "final check" occurs during overload resolution.

Also, cope with cv-qualifiers when the parameter type was originally a
reference type, so that the deduced argument can be more qualified
than the transformed argument.


Modified:
    cfe/trunk/include/clang/AST/DeclTemplate.h
    cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
    cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/basic.cpp

Modified: cfe/trunk/include/clang/AST/DeclTemplate.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclTemplate.h?rev=74323&r1=74322&r2=74323&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/DeclTemplate.h (original)
+++ cfe/trunk/include/clang/AST/DeclTemplate.h Fri Jun 26 15:57:09 2009
@@ -580,6 +580,30 @@
     return reinterpret_cast<Expr *>(TypeOrValue);
   }
 
+  /// \brief Iterator that traverses the elements of a template argument pack.
+  typedef const TemplateArgument * pack_iterator;
+  
+  /// \brief Iterator referencing the first argument of a template argument 
+  /// pack.
+  pack_iterator pack_begin() const {
+    assert(Kind == Pack);
+    return Args.Args;
+  }
+
+  /// \brief Iterator referencing one past the last argument of a template
+  /// argument pack.
+  pack_iterator pack_end() const {
+    assert(Kind == Pack);
+    return Args.Args + Args.NumArgs;
+  }
+  
+  /// \brief The number of template arguments in the given template argument
+  /// pack.
+  unsigned pack_size() const {
+    assert(Kind == Pack);
+    return Args.NumArgs;
+  }
+  
   /// \brief Retrieve the location where the template argument starts.
   SourceLocation getLocation() const { return StartLoc; }
 

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp Fri Jun 26 15:57:09 2009
@@ -199,16 +199,9 @@
     Param.setCVRQualifiers(Param.getCVRQualifiers() & ~ExtraQualsOnParam);
   }
   
-  // If the parameter type is not dependent, just compare the types
-  // directly.
-  if (!Param->isDependentType()) {
-    if (Param == Arg)
-      return Sema::TDK_Success;
-
-    Info.FirstArg = TemplateArgument(SourceLocation(), ParamIn);
-    Info.SecondArg = TemplateArgument(SourceLocation(), ArgIn);
-    return Sema::TDK_NonDeducedMismatch;
-  }
+  // If the parameter type is not dependent, there is nothing to deduce.
+  if (!Param->isDependentType())
+    return Sema::TDK_Success;
 
   // C++ [temp.deduct.type]p9:
   //   A template type argument T, a template template argument TT or a 
@@ -259,7 +252,9 @@
   Info.FirstArg = TemplateArgument(SourceLocation(), ParamIn);
   Info.SecondArg = TemplateArgument(SourceLocation(), ArgIn);
 
-  if (Param.getCVRQualifiers() != Arg.getCVRQualifiers())
+  if ((ParamTypeWasReference && Param.isMoreQualifiedThan(Arg)) ||
+      (!ParamTypeWasReference && 
+       (Param.getCVRQualifiers() != Arg.getCVRQualifiers())))
     return Sema::TDK_NonDeducedMismatch;
 
   switch (Param->getTypeClass()) {
@@ -419,7 +414,7 @@
       return Sema::TDK_Success;
     }
      
-    //     template-name<T> (wheretemplate-name refers to a class template)
+    //     template-name<T> (where template-name refers to a class template)
     //     template-name<i>
     //     TT<T> (TODO)
     //     TT<i> (TODO)
@@ -559,7 +554,7 @@
   }
 
   // FIXME: Many more cases to go (to go).
-  return Sema::TDK_NonDeducedMismatch;
+  return Sema::TDK_Success;
 }
 
 static Sema::TemplateDeductionResult
@@ -656,6 +651,62 @@
   return Sema::TDK_Success;
 }
 
+/// \brief Determine whether two template arguments are the same.
+static bool isSameTemplateArg(ASTContext &Context, 
+                              const TemplateArgument &X,
+                              const TemplateArgument &Y) {
+  if (X.getKind() != Y.getKind())
+    return false;
+  
+  switch (X.getKind()) {
+    case TemplateArgument::Null:
+      assert(false && "Comparing NULL template argument");
+      break;
+      
+    case TemplateArgument::Type:
+      return Context.getCanonicalType(X.getAsType()) ==
+             Context.getCanonicalType(Y.getAsType());
+      
+    case TemplateArgument::Declaration:
+      return Context.getCanonicalDecl(X.getAsDecl()) ==
+             Context.getCanonicalDecl(Y.getAsDecl());
+      
+    case TemplateArgument::Integral:
+      return *X.getAsIntegral() == *Y.getAsIntegral();
+      
+    case TemplateArgument::Expression:
+      // FIXME: We assume that all expressions are distinct, but we should
+      // really check their canonical forms.
+      return false;
+      
+    case TemplateArgument::Pack:
+      if (X.pack_size() != Y.pack_size())
+        return false;
+      
+      for (TemplateArgument::pack_iterator XP = X.pack_begin(), 
+                                        XPEnd = X.pack_end(), 
+                                           YP = Y.pack_begin();
+           XP != XPEnd; ++XP, ++YP) 
+        if (!isSameTemplateArg(Context, *XP, *YP))
+          return false;
+
+      return true;
+  }
+
+  return false;
+}
+
+/// \brief Helper function to build a TemplateParameter when we don't
+/// know its type statically.
+static TemplateParameter makeTemplateParameter(Decl *D) {
+  if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(D))
+    return TemplateParameter(TTP);
+  else if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(D))
+    return TemplateParameter(NTTP);
+  
+  return TemplateParameter(cast<TemplateTemplateParmDecl>(D));
+}
+
 /// \brief Perform template argument deduction to determine whether
 /// the given template arguments match the given class template
 /// partial specialization per C++ [temp.class.spec.match].
@@ -720,27 +771,44 @@
   for (unsigned I = 0, N = PartialTemplateArgs.flat_size(); I != N; ++I) {
     Decl *Param = const_cast<Decl *>(
                     ClassTemplate->getTemplateParameters()->getParam(I));
-    if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Param)) {
-      TemplateArgument InstArg = Instantiate(PartialTemplateArgs[I],
-                                             *DeducedArgumentList);
-      if (InstArg.getKind() != TemplateArgument::Type) {
-        Info.Param = TTP;
-        Info.FirstArg = PartialTemplateArgs[I];
-        return TDK_SubstitutionFailure;
-      }
-
-      if (Context.getCanonicalType(InstArg.getAsType())
-            != Context.getCanonicalType(TemplateArgs[I].getAsType())) {
-        Info.Param = TTP;
-        Info.FirstArg = TemplateArgs[I];
-        Info.SecondArg = InstArg;
-        return TDK_NonDeducedMismatch;
+    TemplateArgument InstArg = Instantiate(PartialTemplateArgs[I],
+                                           *DeducedArgumentList);
+    if (InstArg.isNull()) {
+      Info.Param = makeTemplateParameter(Param);
+      Info.FirstArg = PartialTemplateArgs[I];
+      return TDK_SubstitutionFailure;      
+    }
+    
+    if (InstArg.getKind() == TemplateArgument::Expression) {
+      // When the argument is an expression, check the expression result 
+      // against the actual template parameter to get down to the canonical
+      // template argument.
+      Expr *InstExpr = InstArg.getAsExpr();
+      if (NonTypeTemplateParmDecl *NTTP 
+            = dyn_cast<NonTypeTemplateParmDecl>(Param)) {
+        if (CheckTemplateArgument(NTTP, NTTP->getType(), InstExpr, InstArg)) {
+          Info.Param = makeTemplateParameter(Param);
+          Info.FirstArg = PartialTemplateArgs[I];
+          return TDK_SubstitutionFailure;      
+        }
+      } else if (TemplateTemplateParmDecl *TTP 
+                   = dyn_cast<TemplateTemplateParmDecl>(Param)) {
+        // FIXME: template template arguments should really resolve to decls
+        DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(InstExpr);
+        if (!DRE || CheckTemplateArgument(TTP, DRE)) {
+          Info.Param = makeTemplateParameter(Param);
+          Info.FirstArg = PartialTemplateArgs[I];
+          return TDK_SubstitutionFailure;      
+        }
       }
-
-      continue;
     }
-
-    // FIXME: Check template template arguments?
+    
+    if (!isSameTemplateArg(Context, TemplateArgs[I], InstArg)) {
+      Info.Param = makeTemplateParameter(Param);
+      Info.FirstArg = TemplateArgs[I];
+      Info.SecondArg = InstArg;
+      return TDK_NonDeducedMismatch;
+    }
   }
 
   if (Trap.hasErrorOccurred())

Modified: cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/basic.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/basic.cpp?rev=74323&r1=74322&r2=74323&view=diff

==============================================================================
--- cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/basic.cpp (original)
+++ cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/basic.cpp Fri Jun 26 15:57:09 2009
@@ -1,4 +1,4 @@
-// RUN: clang-cc -fsyntax-only %s
+// RUN: clang-cc -fsyntax-only -verify %s
 
 template<typename T> struct A { };
 
@@ -9,3 +9,20 @@
   A<const float> a1 = f0(cfp);
 }
 
+template<typename T> void f1(T*, int);
+
+void test_f1(int *ip, float fv) {
+  f1(ip, fv);
+}
+
+template<typename T> void f2(T*, T*);
+
+struct ConvToIntPtr {
+  operator int*() const;
+};
+
+void test_f2(int *ip, float *fp) {
+  f2(ip, ConvToIntPtr()); // expected-error{{no matching function}}
+  f2(ip, ip); // okay
+  f2(ip, fp); // expected-error{{no matching function}}
+}





More information about the cfe-commits mailing list