[cfe-commits] r73237 - in /cfe/trunk: include/clang/AST/DeclTemplate.h lib/Sema/Sema.h lib/Sema/SemaTemplateDeduction.cpp lib/Sema/SemaTemplateInstantiate.cpp

Douglas Gregor dgregor at apple.com
Fri Jun 12 11:26:58 PDT 2009


Author: dgregor
Date: Fri Jun 12 13:26:56 2009
New Revision: 73237

URL: http://llvm.org/viewvc/llvm-project?rev=73237&view=rev
Log:
Improve template argument deduction to keep track of why template
argument deduction failed. For example, given

  template<typename T> struct is_same<T, T> { ... };

template argument deduction will fail for is_same<int, float>, and now
reports enough information

Right now, we don't do anything with this extra information, but it
can be used for informative diagnostics that say, e.g., "template
argument deduction failed because T was deduced to 'int' in one
context and 'float' in another".


Modified:
    cfe/trunk/include/clang/AST/DeclTemplate.h
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
    cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp

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

==============================================================================
--- cfe/trunk/include/clang/AST/DeclTemplate.h (original)
+++ cfe/trunk/include/clang/AST/DeclTemplate.h Fri Jun 12 13:26:56 2009
@@ -17,6 +17,7 @@
 #include "clang/AST/DeclCXX.h"
 #include "llvm/ADT/APSInt.h"
 #include "llvm/ADT/FoldingSet.h"
+#include "llvm/ADT/PointerUnion.h"
 
 namespace clang {
 
@@ -29,6 +30,10 @@
 class NonTypeTemplateParmDecl;
 class TemplateTemplateParmDecl;
 
+/// \brief Stores a template parameter of any kind.
+typedef llvm::PointerUnion3<TemplateTypeParmDecl*, NonTypeTemplateParmDecl*,
+                            TemplateTemplateParmDecl*> TemplateParameter;
+
 /// TemplateParameterList - Stores a list of template parameters for a
 /// TemplateDecl and its derived classes.
 class TemplateParameterList {
@@ -69,6 +74,11 @@
 
   unsigned size() const { return NumParams; }
 
+  Decl* getParam(unsigned Idx) {
+    assert(Idx < size() && "Template parameter index out-of-range");
+    return begin()[Idx];
+  }
+
   const Decl* getParam(unsigned Idx) const {
     assert(Idx < size() && "Template parameter index out-of-range");
     return begin()[Idx];

Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=73237&r1=73236&r2=73237&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Fri Jun 12 13:26:56 2009
@@ -2040,9 +2040,118 @@
                              const IdentifierInfo &II,
                              SourceRange Range);
 
-  TemplateArgumentList *
+  /// \brief Describes the result of template argument deduction.
+  ///
+  /// The TemplateDeductionResult enumeration describes the result of
+  /// template argument deduction, as returned from
+  /// DeduceTemplateArguments(). The separate TemplateDeductionInfo
+  /// structure provides additional information about the results of
+  /// template argument deduction, e.g., the deduced template argument
+  /// list (if successful) or the specific template parameters or
+  /// deduced arguments that were involved in the failure.
+  enum TemplateDeductionResult {
+    /// \brief Template argument deduction was successful.
+    TDK_Success = 0,
+    /// \brief Template argument deduction exceeded the maximum template
+    /// instantiation depth (which has already been diagnosed).
+    TDK_InstantiationDepth,
+    /// \brief Template argument deduction did not deduce a value
+    /// for every template parameter.
+    TDK_Incomplete,
+    /// \brief Template argument deduction produced inconsistent
+    /// deduced values for the given template parameter.
+    TDK_Inconsistent,
+    /// \brief Template argument deduction failed due to inconsistent
+    /// cv-qualifiers on a template parameter type that would
+    /// otherwise be deduced, e.g., we tried to deduce T in "const T"
+    /// but were given a non-const "X".
+    TDK_InconsistentQuals,
+    /// \brief Substitution of the deduced template argument values
+    /// resulted in an error.
+    TDK_SubstitutionFailure,
+    /// \brief Substitution of the deduced template argument values
+    /// into a non-deduced context produced a type or value that
+    /// produces a type that does not match the original template
+    /// arguments provided.
+    TDK_NonDeducedMismatch
+  };
+
+  /// \brief Provides information about an attempted template argument
+  /// deduction, whose success or failure was described by a
+  /// TemplateDeductionResult value.
+  class TemplateDeductionInfo {
+    /// \brief The context in which the template arguments are stored.
+    ASTContext &Context;
+
+    /// \brief The deduced template argument list.
+    ///
+    TemplateArgumentList *Deduced;
+
+    // do not implement these
+    TemplateDeductionInfo(const TemplateDeductionInfo&);
+    TemplateDeductionInfo &operator=(const TemplateDeductionInfo&);
+
+  public:
+    TemplateDeductionInfo(ASTContext &Context) : Context(Context), Deduced(0) { }
+
+    ~TemplateDeductionInfo() {
+      // FIXME: if (Deduced) Deduced->Destroy(Context);
+    }
+
+    /// \brief Take ownership of the deduced template argument list.
+    TemplateArgumentList *take() { 
+      TemplateArgumentList *Result = Deduced;
+      Deduced = 0;
+      return Result;
+    }
+
+    /// \brief Provide a new template argument list that contains the
+    /// results of template argument deduction.
+    void reset(TemplateArgumentList *NewDeduced) {
+      // FIXME: if (Deduced) Deduced->Destroy(Context);
+      Deduced = NewDeduced;
+    }
+
+    /// \brief The template parameter to which a template argument
+    /// deduction failure refers.
+    ///
+    /// Depending on the result of template argument deduction, this
+    /// template parameter may have different meanings:
+    ///
+    ///   TDK_Incomplete: this is the first template parameter whose
+    ///   corresponding template argument was not deduced.
+    ///
+    ///   TDK_Inconsistent: this is the template parameter for which
+    ///   two different template argument values were deduced.
+    TemplateParameter Param;
+
+    /// \brief The first template argument to which the template
+    /// argument deduction failure refers.
+    ///
+    /// Depending on the result of the template argument deduction,
+    /// this template argument may have different meanings:
+    ///
+    ///   TDK_Inconsistent: this argument is the first value deduced
+    ///   for the corresponding template parameter.
+    ///
+    ///   TDK_SubstitutionFailure: this argument is the template
+    ///   argument we were instantiating when we encountered an error.
+    ///
+    ///   TDK_NonDeducedMismatch: this is the template argument
+    ///   provided in the source code.
+    TemplateArgument FirstArg;
+
+    /// \brief The second template argument to which the template
+    /// argument deduction failure refers.
+    ///
+    /// FIXME: Finish documenting this.
+    TemplateArgument SecondArg;
+  };
+
+  TemplateDeductionResult
   DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
-                          const TemplateArgumentList &TemplateArgs);
+                          const TemplateArgumentList &TemplateArgs,
+                          TemplateDeductionInfo &Info);
                              
   //===--------------------------------------------------------------------===//
   // C++ Template Instantiation

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp Fri Jun 12 13:26:56 2009
@@ -20,9 +20,12 @@
 #include "llvm/Support/Compiler.h"
 using namespace clang;
 
-static bool
-DeduceTemplateArguments(ASTContext &Context, const TemplateArgument &Param,
+static Sema::TemplateDeductionResult
+DeduceTemplateArguments(ASTContext &Context, 
+                        TemplateParameterList *TemplateParams,
+                        const TemplateArgument &Param,
                         const TemplateArgument &Arg,
+                        Sema::TemplateDeductionInfo &Info,
                         llvm::SmallVectorImpl<TemplateArgument> &Deduced);
 
 /// \brief If the given expression is of a form that permits the deduction
@@ -40,12 +43,12 @@
 
 /// \brief Deduce the value of the given non-type template parameter 
 /// from the given constant.
-///
-/// \returns true if deduction succeeded, false otherwise.
-static bool DeduceNonTypeTemplateArgument(ASTContext &Context, 
-                                          NonTypeTemplateParmDecl *NTTP, 
-                                          llvm::APInt Value,
-                             llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
+static Sema::TemplateDeductionResult
+DeduceNonTypeTemplateArgument(ASTContext &Context, 
+                              NonTypeTemplateParmDecl *NTTP, 
+                              llvm::APInt Value,
+                              Sema::TemplateDeductionInfo &Info,
+                              llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
   assert(NTTP->getDepth() == 0 && 
          "Cannot deduce non-type template argument with depth > 0");
   
@@ -53,25 +56,41 @@
     Deduced[NTTP->getIndex()] = TemplateArgument(SourceLocation(), 
                                                  llvm::APSInt(Value),
                                                  NTTP->getType());
-    return true;
+    return Sema::TDK_Success;
   }
   
-  if (Deduced[NTTP->getIndex()].getKind() != TemplateArgument::Integral)
-    return false;
+  assert(Deduced[NTTP->getIndex()].getKind() == TemplateArgument::Integral);
   
   // If the template argument was previously deduced to a negative value, 
   // then our deduction fails.
   const llvm::APSInt *PrevValuePtr = Deduced[NTTP->getIndex()].getAsIntegral();
-  assert(PrevValuePtr && "Not an integral template argument?");
-  if (PrevValuePtr->isSigned() && PrevValuePtr->isNegative())
-    return false;
-  
+  if (PrevValuePtr->isSigned() && PrevValuePtr->isNegative()) {
+    // FIXME: This is wacky; we should be dealing with APSInts and
+    // checking the actual signs.
+    Info.Param = NTTP;
+    Info.FirstArg = Deduced[NTTP->getIndex()];
+    Info.SecondArg = TemplateArgument(SourceLocation(), 
+                                      llvm::APSInt(Value),
+                                      NTTP->getType());
+    return Sema::TDK_Inconsistent;
+  }
+
   llvm::APInt PrevValue = *PrevValuePtr;
   if (Value.getBitWidth() > PrevValue.getBitWidth())
     PrevValue.zext(Value.getBitWidth());
   else if (Value.getBitWidth() < PrevValue.getBitWidth())
     Value.zext(PrevValue.getBitWidth());
-  return Value == PrevValue;
+
+  if (Value != PrevValue) {
+    Info.Param = NTTP;
+    Info.FirstArg = Deduced[NTTP->getIndex()];
+    Info.SecondArg = TemplateArgument(SourceLocation(), 
+                                      llvm::APSInt(Value),
+                                      NTTP->getType());
+    return Sema::TDK_Inconsistent;
+  }
+
+  return Sema::TDK_Success;
 }
 
 /// \brief Deduce the value of the given non-type template parameter 
@@ -79,10 +98,12 @@
 ///
 /// \returns true if deduction succeeded, false otherwise.
 
-static bool DeduceNonTypeTemplateArgument(ASTContext &Context, 
-                                          NonTypeTemplateParmDecl *NTTP,
-                                          Expr *Value,
-                            llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
+static Sema::TemplateDeductionResult
+DeduceNonTypeTemplateArgument(ASTContext &Context, 
+                              NonTypeTemplateParmDecl *NTTP,
+                              Expr *Value,
+                              Sema::TemplateDeductionInfo &Info,
+                           llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
   assert(NTTP->getDepth() == 0 && 
          "Cannot deduce non-type template argument with depth > 0");
   assert((Value->isTypeDependent() || Value->isValueDependent()) &&
@@ -91,53 +112,73 @@
   if (Deduced[NTTP->getIndex()].isNull()) {
     // FIXME: Clone the Value?
     Deduced[NTTP->getIndex()] = TemplateArgument(Value);
-    return true;
+    return Sema::TDK_Success;
   }
   
   if (Deduced[NTTP->getIndex()].getKind() == TemplateArgument::Integral) {
     // Okay, we deduced a constant in one case and a dependent expression 
     // in another case. FIXME: Later, we will check that instantiating the 
     // dependent expression gives us the constant value.
-    return true;
+    return Sema::TDK_Success;
   }
   
   // FIXME: Compare the expressions for equality!
-  return true;
+  return Sema::TDK_Success;
 }
 
-static bool DeduceTemplateArguments(ASTContext &Context,
-                                    TemplateName Param,
-                                    TemplateName Arg,
-                             llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
+static Sema::TemplateDeductionResult
+DeduceTemplateArguments(ASTContext &Context,
+                        TemplateName Param,
+                        TemplateName Arg,
+                        Sema::TemplateDeductionInfo &Info,
+                        llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
   // FIXME: Implement template argument deduction for template
   // template parameters.
 
+  // FIXME: this routine does not have enough information to produce
+  // good diagnostics.
+
   TemplateDecl *ParamDecl = Param.getAsTemplateDecl();
   TemplateDecl *ArgDecl = Arg.getAsTemplateDecl();
   
-  if (!ParamDecl || !ArgDecl)
-    return false;
+  if (!ParamDecl || !ArgDecl) {
+    // FIXME: fill in Info.Param/Info.FirstArg
+    return Sema::TDK_Inconsistent;
+  }
 
   ParamDecl = cast<TemplateDecl>(Context.getCanonicalDecl(ParamDecl));
   ArgDecl = cast<TemplateDecl>(Context.getCanonicalDecl(ArgDecl));
-  return ParamDecl == ArgDecl;
+  if (ParamDecl != ArgDecl) {
+    // FIXME: fill in Info.Param/Info.FirstArg
+    return Sema::TDK_Inconsistent;
+  }
+
+  return Sema::TDK_Success;
 }
 
-static bool DeduceTemplateArguments(ASTContext &Context, QualType Param, 
-                                    QualType Arg,
-                             llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
+static Sema::TemplateDeductionResult
+DeduceTemplateArguments(ASTContext &Context, 
+                        TemplateParameterList *TemplateParams,
+                        QualType ParamIn, QualType ArgIn,
+                        Sema::TemplateDeductionInfo &Info,
+                        llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
   // We only want to look at the canonical types, since typedefs and
   // sugar are not part of template argument deduction.
-  Param = Context.getCanonicalType(Param);
-  Arg = Context.getCanonicalType(Arg);
+  QualType Param = Context.getCanonicalType(ParamIn);
+  QualType Arg = Context.getCanonicalType(ArgIn);
 
   // If the parameter type is not dependent, just compare the types
   // directly.
-  if (!Param->isDependentType())
-    return Param == Arg;
+  if (!Param->isDependentType()) {
+    if (Param == Arg)
+      return Sema::TDK_Success;
+
+    Info.FirstArg = TemplateArgument(SourceLocation(), ParamIn);
+    Info.SecondArg = TemplateArgument(SourceLocation(), ArgIn);
+    return Sema::TDK_NonDeducedMismatch;
+  }
 
   // C++ [temp.deduct.type]p9:
-  //
   //   A template type argument T, a template template argument TT or a 
   //   template non-type argument i can be deduced if P and A have one of 
   //   the following forms:
@@ -146,16 +187,21 @@
   //     cv-list T
   if (const TemplateTypeParmType *TemplateTypeParm 
         = Param->getAsTemplateTypeParmType()) {
+    unsigned Index = TemplateTypeParm->getIndex();
+
     // The argument type can not be less qualified than the parameter
     // type.
-    if (Param.isMoreQualifiedThan(Arg))
-      return false;
+    if (Param.isMoreQualifiedThan(Arg)) {
+      Info.Param = cast<TemplateTypeParmDecl>(TemplateParams->getParam(Index));
+      Info.FirstArg = Deduced[Index];
+      Info.SecondArg = TemplateArgument(SourceLocation(), Arg);
+      return Sema::TDK_InconsistentQuals;
+    }
 
     assert(TemplateTypeParm->getDepth() == 0 && "Can't deduce with depth > 0");
 	  
     unsigned Quals = Arg.getCVRQualifiers() & ~Param.getCVRQualifiers();
     QualType DeducedType = Arg.getQualifiedType(Quals);
-	  unsigned Index = TemplateTypeParm->getIndex();
 
     if (Deduced[Index].isNull())
       Deduced[Index] = TemplateArgument(SourceLocation(), DeducedType);
@@ -166,55 +212,63 @@
       //   deduced values, or if different pairs yield different deduced 
       //   values, or if any template argument remains neither deduced nor 
       //   explicitly specified, template argument deduction fails.
-      if (Deduced[Index].getAsType() != DeducedType)
-        return false;
+      if (Deduced[Index].getAsType() != DeducedType) {
+        Info.Param 
+          = cast<TemplateTypeParmDecl>(TemplateParams->getParam(Index));
+        Info.FirstArg = Deduced[Index];
+        Info.SecondArg = TemplateArgument(SourceLocation(), Arg);
+        return Sema::TDK_Inconsistent;
+      }
     }
-    return true;
+    return Sema::TDK_Success;
   }
 
+  // Set up the template argument deduction information for a failure.
+  Info.FirstArg = TemplateArgument(SourceLocation(), ParamIn);
+  Info.SecondArg = TemplateArgument(SourceLocation(), ArgIn);
+
   if (Param.getCVRQualifiers() != Arg.getCVRQualifiers())
-    return false;
+    return Sema::TDK_NonDeducedMismatch;
 
   switch (Param->getTypeClass()) {
     // No deduction possible for these types
     case Type::Builtin:
-      return false;
-      
+      return Sema::TDK_NonDeducedMismatch;
       
     //     T *
     case Type::Pointer: {
       const PointerType *PointerArg = Arg->getAsPointerType();
       if (!PointerArg)
-        return false;
+        return Sema::TDK_NonDeducedMismatch;
       
-      return DeduceTemplateArguments(Context,
+      return DeduceTemplateArguments(Context, TemplateParams,
                                    cast<PointerType>(Param)->getPointeeType(),
                                      PointerArg->getPointeeType(),
-                                     Deduced);
+                                     Info, Deduced);
     }
       
     //     T &
     case Type::LValueReference: {
       const LValueReferenceType *ReferenceArg = Arg->getAsLValueReferenceType();
       if (!ReferenceArg)
-        return false;
+        return Sema::TDK_NonDeducedMismatch;
       
-      return DeduceTemplateArguments(Context,
+      return DeduceTemplateArguments(Context, TemplateParams,
                            cast<LValueReferenceType>(Param)->getPointeeType(),
                                      ReferenceArg->getPointeeType(),
-                                     Deduced);
+                                     Info, Deduced);
     }
 
     //     T && [C++0x]
     case Type::RValueReference: {
       const RValueReferenceType *ReferenceArg = Arg->getAsRValueReferenceType();
       if (!ReferenceArg)
-        return false;
+        return Sema::TDK_NonDeducedMismatch;
       
-      return DeduceTemplateArguments(Context,
+      return DeduceTemplateArguments(Context, TemplateParams,
                            cast<RValueReferenceType>(Param)->getPointeeType(),
                                      ReferenceArg->getPointeeType(),
-                                     Deduced);
+                                     Info, Deduced);
     }
       
     //     T [] (implied, but not stated explicitly)
@@ -222,12 +276,12 @@
       const IncompleteArrayType *IncompleteArrayArg = 
         Context.getAsIncompleteArrayType(Arg);
       if (!IncompleteArrayArg)
-        return false;
+        return Sema::TDK_NonDeducedMismatch;
       
-      return DeduceTemplateArguments(Context,
+      return DeduceTemplateArguments(Context, TemplateParams,
                      Context.getAsIncompleteArrayType(Param)->getElementType(),
                                      IncompleteArrayArg->getElementType(),
-                                     Deduced);
+                                     Info, Deduced);
     }
 
     //     T [integer-constant]
@@ -235,39 +289,40 @@
       const ConstantArrayType *ConstantArrayArg = 
         Context.getAsConstantArrayType(Arg);
       if (!ConstantArrayArg)
-        return false;
+        return Sema::TDK_NonDeducedMismatch;
       
       const ConstantArrayType *ConstantArrayParm = 
         Context.getAsConstantArrayType(Param);
       if (ConstantArrayArg->getSize() != ConstantArrayParm->getSize())
-        return false;
+        return Sema::TDK_NonDeducedMismatch;
       
-      return DeduceTemplateArguments(Context,
+      return DeduceTemplateArguments(Context, TemplateParams,
                                      ConstantArrayParm->getElementType(),
                                      ConstantArrayArg->getElementType(),
-                                     Deduced);
+                                     Info, Deduced);
     }
 
     //     type [i]
     case Type::DependentSizedArray: {
       const ArrayType *ArrayArg = dyn_cast<ArrayType>(Arg);
       if (!ArrayArg)
-        return false;
+        return Sema::TDK_NonDeducedMismatch;
       
       // Check the element type of the arrays
       const DependentSizedArrayType *DependentArrayParm
         = cast<DependentSizedArrayType>(Param);
-      if (!DeduceTemplateArguments(Context,
-                                   DependentArrayParm->getElementType(),
-                                   ArrayArg->getElementType(),
-                                   Deduced))
-        return false;
+      if (Sema::TemplateDeductionResult Result
+            = DeduceTemplateArguments(Context, TemplateParams,
+                                      DependentArrayParm->getElementType(),
+                                      ArrayArg->getElementType(),
+                                      Info, Deduced))
+        return Result;
           
       // Determine the array bound is something we can deduce.
       NonTypeTemplateParmDecl *NTTP 
         = getDeducedParameterFromExpr(DependentArrayParm->getSizeExpr());
       if (!NTTP)
-        return true;
+        return Sema::TDK_Success;
       
       // We can perform template argument deduction for the given non-type 
       // template parameter.
@@ -277,15 +332,15 @@
             = dyn_cast<ConstantArrayType>(ArrayArg))
         return DeduceNonTypeTemplateArgument(Context, NTTP, 
                                              ConstantArrayArg->getSize(),
-                                             Deduced);
+                                             Info, Deduced);
       if (const DependentSizedArrayType *DependentArrayArg
             = dyn_cast<DependentSizedArrayType>(ArrayArg))
         return DeduceNonTypeTemplateArgument(Context, NTTP,
                                              DependentArrayArg->getSizeExpr(),
-                                             Deduced);
+                                             Info, Deduced);
       
       // Incomplete type does not match a dependently-sized array type
-      return false;
+      return Sema::TDK_NonDeducedMismatch;
     }
       
     //     type(*)(T) 
@@ -295,38 +350,40 @@
       const FunctionProtoType *FunctionProtoArg = 
         dyn_cast<FunctionProtoType>(Arg);
       if (!FunctionProtoArg)
-        return false;
+        return Sema::TDK_NonDeducedMismatch;
       
       const FunctionProtoType *FunctionProtoParam = 
         cast<FunctionProtoType>(Param);
 
       if (FunctionProtoParam->getTypeQuals() != 
           FunctionProtoArg->getTypeQuals())
-        return false;
+        return Sema::TDK_NonDeducedMismatch;
       
       if (FunctionProtoParam->getNumArgs() != FunctionProtoArg->getNumArgs())
-        return false;
+        return Sema::TDK_NonDeducedMismatch;
       
       if (FunctionProtoParam->isVariadic() != FunctionProtoArg->isVariadic())
-        return false;
+        return Sema::TDK_NonDeducedMismatch;
 
       // Check return types.
-      if (!DeduceTemplateArguments(Context,
-                                   FunctionProtoParam->getResultType(),
-                                   FunctionProtoArg->getResultType(),
-                                   Deduced))
-        return false;
+      if (Sema::TemplateDeductionResult Result
+            = DeduceTemplateArguments(Context, TemplateParams,
+                                      FunctionProtoParam->getResultType(),
+                                      FunctionProtoArg->getResultType(),
+                                      Info, Deduced))
+        return Result;
       
       for (unsigned I = 0, N = FunctionProtoParam->getNumArgs(); I != N; ++I) {
         // Check argument types.
-        if (!DeduceTemplateArguments(Context,
-                                     FunctionProtoParam->getArgType(I),
-                                     FunctionProtoArg->getArgType(I),
-                                     Deduced))
-          return false;
+        if (Sema::TemplateDeductionResult Result
+              = DeduceTemplateArguments(Context, TemplateParams,
+                                        FunctionProtoParam->getArgType(I),
+                                        FunctionProtoArg->getArgType(I),
+                                        Info, Deduced))
+          return Result;
       }
       
-      return true;
+      return Sema::TDK_Success;
     }
      
     //     template-name<T> (wheretemplate-name refers to a class template)
@@ -344,11 +401,12 @@
       if (const TemplateSpecializationType *SpecArg 
             = dyn_cast<TemplateSpecializationType>(Arg)) {
         // Perform template argument deduction for the template name.
-        if (!DeduceTemplateArguments(Context,
-                                     SpecParam->getTemplateName(),
-                                     SpecArg->getTemplateName(),
-                                     Deduced))
-          return false;
+        if (Sema::TemplateDeductionResult Result
+              = DeduceTemplateArguments(Context,
+                                        SpecParam->getTemplateName(),
+                                        SpecArg->getTemplateName(),
+                                        Info, Deduced))
+          return Result;
             
         unsigned NumArgs = SpecParam->getNumArgs();
 
@@ -359,18 +417,19 @@
         // issue may be resolved elsewhere, because we may want to
         // instantiate default template arguments when
         if (SpecArg->getNumArgs() != NumArgs)
-          return false;
+          return Sema::TDK_NonDeducedMismatch;
 
         // Perform template argument deduction on each template
         // argument.
         for (unsigned I = 0; I != NumArgs; ++I)
-          if (!DeduceTemplateArguments(Context,
-                                       SpecParam->getArg(I),
-                                       SpecArg->getArg(I),
-                                       Deduced))
-            return false;
+          if (Sema::TemplateDeductionResult Result
+                = DeduceTemplateArguments(Context, TemplateParams,
+                                          SpecParam->getArg(I),
+                                          SpecArg->getArg(I),
+                                          Info, Deduced))
+            return Result;
 
-        return true;
+        return Sema::TDK_Success;
       } 
 
       // If the argument type is a class template specialization, we
@@ -378,34 +437,36 @@
       // arguments.
       const RecordType *RecordArg = dyn_cast<RecordType>(Arg);
       if (!RecordArg)
-        return false;
+        return Sema::TDK_NonDeducedMismatch;
 
       ClassTemplateSpecializationDecl *SpecArg 
         = dyn_cast<ClassTemplateSpecializationDecl>(RecordArg->getDecl());
       if (!SpecArg)
-        return false;
+        return Sema::TDK_NonDeducedMismatch;
 
       // Perform template argument deduction for the template name.
-      if (!DeduceTemplateArguments(Context,
-                                   SpecParam->getTemplateName(),
-                                   TemplateName(SpecArg->getSpecializedTemplate()),
-                                   Deduced))
-          return false;
+      if (Sema::TemplateDeductionResult Result
+            = DeduceTemplateArguments(Context, 
+                                      SpecParam->getTemplateName(),
+                              TemplateName(SpecArg->getSpecializedTemplate()),
+                                      Info, Deduced))
+          return Result;
 
       // FIXME: Can the # of arguments in the parameter and the argument differ?
       unsigned NumArgs = SpecParam->getNumArgs();
       const TemplateArgumentList &ArgArgs = SpecArg->getTemplateArgs();
       if (NumArgs != ArgArgs.size())
-        return false;
+        return Sema::TDK_NonDeducedMismatch;
 
       for (unsigned I = 0; I != NumArgs; ++I)
-        if (!DeduceTemplateArguments(Context,
-                                     SpecParam->getArg(I),
-                                     ArgArgs.get(I),
-                                     Deduced))
-          return false;
+        if (Sema::TemplateDeductionResult Result
+              = DeduceTemplateArguments(Context, TemplateParams,
+                                        SpecParam->getArg(I),
+                                        ArgArgs.get(I),
+                                        Info, Deduced))
+          return Result;
       
-      return true;
+      return Sema::TDK_Success;
     }
 
     //     T type::*
@@ -421,16 +482,19 @@
       const MemberPointerType *MemPtrParam = cast<MemberPointerType>(Param);
       const MemberPointerType *MemPtrArg = dyn_cast<MemberPointerType>(Arg);
       if (!MemPtrArg)
-        return false;
+        return Sema::TDK_NonDeducedMismatch;
 
-      return DeduceTemplateArguments(Context,
-                                     MemPtrParam->getPointeeType(),
-                                     MemPtrArg->getPointeeType(),
-                                     Deduced) &&
-        DeduceTemplateArguments(Context,
-                                QualType(MemPtrParam->getClass(), 0),
-                                QualType(MemPtrArg->getClass(), 0),
-                                Deduced);
+      if (Sema::TemplateDeductionResult Result
+            = DeduceTemplateArguments(Context, TemplateParams,
+                                      MemPtrParam->getPointeeType(),
+                                      MemPtrArg->getPointeeType(),
+                                      Info, Deduced))
+        return Result;
+
+      return DeduceTemplateArguments(Context, TemplateParams,
+                                     QualType(MemPtrParam->getClass(), 0),
+                                     QualType(MemPtrArg->getClass(), 0),
+                                     Info, Deduced);
     }
 
     //     type(^)(T) 
@@ -441,30 +505,34 @@
       const BlockPointerType *BlockPtrArg = dyn_cast<BlockPointerType>(Arg);
       
       if (!BlockPtrArg)
-        return false;
+        return Sema::TDK_NonDeducedMismatch;
       
-      return DeduceTemplateArguments(Context,
+      return DeduceTemplateArguments(Context, TemplateParams,
                                      BlockPtrParam->getPointeeType(),
-                                     BlockPtrArg->getPointeeType(), Deduced);
+                                     BlockPtrArg->getPointeeType(), Info,
+                                     Deduced);
     }
 
     case Type::TypeOfExpr:
     case Type::TypeOf:
     case Type::Typename:
       // No template argument deduction for these types
-      return true;
+      return Sema::TDK_Success;
 
     default:
       break;
   }
 
   // FIXME: Many more cases to go (to go).
-  return false;
+  return Sema::TDK_NonDeducedMismatch;
 }
 
-static bool
-DeduceTemplateArguments(ASTContext &Context, const TemplateArgument &Param,
+static Sema::TemplateDeductionResult
+DeduceTemplateArguments(ASTContext &Context, 
+                        TemplateParameterList *TemplateParams,
+                        const TemplateArgument &Param,
                         const TemplateArgument &Arg,
+                        Sema::TemplateDeductionInfo &Info,
                         llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
   switch (Param.getKind()) {
   case TemplateArgument::Null:
@@ -473,24 +541,38 @@
       
   case TemplateArgument::Type: 
     assert(Arg.getKind() == TemplateArgument::Type && "Type/value mismatch");
-    return DeduceTemplateArguments(Context, Param.getAsType(), 
-                                   Arg.getAsType(), Deduced);
+    return DeduceTemplateArguments(Context, TemplateParams,
+                                   Param.getAsType(), 
+                                   Arg.getAsType(), Info, Deduced);
 
   case TemplateArgument::Declaration:
     // FIXME: Implement this check
     assert(false && "Unimplemented template argument deduction case");
-    return false;
+    Info.FirstArg = Param;
+    Info.SecondArg = Arg;
+    return Sema::TDK_NonDeducedMismatch;
       
   case TemplateArgument::Integral:
     if (Arg.getKind() == TemplateArgument::Integral) {
       // FIXME: Zero extension + sign checking here?
-      return *Param.getAsIntegral() == *Arg.getAsIntegral();
+      if (*Param.getAsIntegral() == *Arg.getAsIntegral())
+        return Sema::TDK_Success;
+
+      Info.FirstArg = Param;
+      Info.SecondArg = Arg;
+      return Sema::TDK_NonDeducedMismatch;
+    }
+
+    if (Arg.getKind() == TemplateArgument::Expression) {
+      Info.FirstArg = Param;
+      Info.SecondArg = Arg;
+      return Sema::TDK_NonDeducedMismatch;
     }
-    if (Arg.getKind() == TemplateArgument::Expression)
-      return false;
 
     assert(false && "Type/value mismatch");
-    return false;
+    Info.FirstArg = Param;
+    Info.SecondArg = Arg;
+    return Sema::TDK_NonDeducedMismatch;
       
   case TemplateArgument::Expression: {
     if (NonTypeTemplateParmDecl *NTTP 
@@ -498,62 +580,81 @@
       if (Arg.getKind() == TemplateArgument::Integral)
         // FIXME: Sign problems here
         return DeduceNonTypeTemplateArgument(Context, NTTP, 
-                                             *Arg.getAsIntegral(), Deduced);
+                                             *Arg.getAsIntegral(), 
+                                             Info, Deduced);
       if (Arg.getKind() == TemplateArgument::Expression)
         return DeduceNonTypeTemplateArgument(Context, NTTP, Arg.getAsExpr(),
-                                             Deduced);
+                                             Info, Deduced);
       
       assert(false && "Type/value mismatch");
-      return false;
+      Info.FirstArg = Param;
+      Info.SecondArg = Arg;
+      return Sema::TDK_NonDeducedMismatch;
     }
     
     // Can't deduce anything, but that's okay.
-    return true;
+    return Sema::TDK_Success;
   }
   }
       
-  return true;
+  return Sema::TDK_Success;
 }
 
-static bool 
+static Sema::TemplateDeductionResult 
 DeduceTemplateArguments(ASTContext &Context,
+                        TemplateParameterList *TemplateParams,
                         const TemplateArgumentList &ParamList,
                         const TemplateArgumentList &ArgList,
+                        Sema::TemplateDeductionInfo &Info,
                         llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
   assert(ParamList.size() == ArgList.size());
   for (unsigned I = 0, N = ParamList.size(); I != N; ++I) {
-    if (!DeduceTemplateArguments(Context, ParamList[I], ArgList[I], Deduced))
-      return false;
+    if (Sema::TemplateDeductionResult Result
+          = DeduceTemplateArguments(Context, TemplateParams,
+                                    ParamList[I], ArgList[I], 
+                                    Info, Deduced))
+      return Result;
   }
-  return true;
+  return Sema::TDK_Success;
 }
 
 
-TemplateArgumentList * 
+Sema::TemplateDeductionResult
 Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
-                              const TemplateArgumentList &TemplateArgs) {
+                              const TemplateArgumentList &TemplateArgs,
+                              TemplateDeductionInfo &Info) {
   // Deduce the template arguments for the partial specialization
   llvm::SmallVector<TemplateArgument, 4> Deduced;
   Deduced.resize(Partial->getTemplateParameters()->size());
-  if (! ::DeduceTemplateArguments(Context, Partial->getTemplateArgs(), 
-                                  TemplateArgs, Deduced))
-    return 0;
-
-  // FIXME: It isn't clear whether we want the diagnostic to point at
-  // the partial specialization itself or at the actual point of
-  // instantiation.
+  if (TemplateDeductionResult Result
+        = ::DeduceTemplateArguments(Context, 
+                                    Partial->getTemplateParameters(),
+                                    Partial->getTemplateArgs(), 
+                                    TemplateArgs, Info, Deduced))
+    return Result;
+
   InstantiatingTemplate Inst(*this, Partial->getLocation(), Partial,
                              Deduced.data(), Deduced.size());
   if (Inst)
-    return 0;
+    return TDK_InstantiationDepth;
 
   // C++ [temp.deduct.type]p2:
   //   [...] or if any template argument remains neither deduced nor
   //   explicitly specified, template argument deduction fails.
   TemplateArgumentListBuilder Builder(Context);
   for (unsigned I = 0, N = Deduced.size(); I != N; ++I) {
-    if (Deduced[I].isNull())
-      return 0;
+    if (Deduced[I].isNull()) {
+      Decl *Param 
+        = const_cast<Decl *>(Partial->getTemplateParameters()->getParam(I));
+      if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Param))
+        Info.Param = TTP;
+      else if (NonTypeTemplateParmDecl *NTTP 
+                 = dyn_cast<NonTypeTemplateParmDecl>(Param))
+        Info.Param = NTTP;
+      else
+        Info.Param = cast<TemplateTemplateParmDecl>(Param);
+      return TDK_Incomplete;
+    }
 
     Builder.push_back(Deduced[I]);
   }
@@ -562,6 +663,7 @@
   TemplateArgumentList *DeducedArgumentList 
     = new (Context) TemplateArgumentList(Context, Builder, /*CopyArgs=*/true,
                                          /*FlattenArgs=*/true);
+  Info.reset(DeducedArgumentList);
 
   // Now that we have all of the deduced template arguments, take
   // another pass through them to convert any integral template
@@ -574,8 +676,11 @@
                                           ->getParam(I));
       QualType T = InstantiateType(Parm->getType(), *DeducedArgumentList,
                                    Parm->getLocation(), Parm->getDeclName());
-      if (T.isNull()) // FIXME: DeducedArgumentList->Destroy(Context);
-        return 0;
+      if (T.isNull()) {
+        Info.Param = const_cast<NonTypeTemplateParmDecl*>(Parm);
+        Info.FirstArg = TemplateArgument(Parm->getLocation(), Parm->getType());
+        return TDK_SubstitutionFailure;
+      }
       
       // FIXME: Make sure we didn't overflow our data type!
       llvm::APSInt &Value = *Arg.getAsIntegral();
@@ -600,8 +705,17 @@
     TemplateArgument InstArg = Instantiate(PartialTemplateArgs[I],
                                            *DeducedArgumentList);
     if (InstArg.isNull()) {
-      // FIXME: DeducedArgumentList->Destroy(Context); (or use RAII)
-      return 0;
+      Decl *Param = const_cast<Decl *>(
+                         ClassTemplate->getTemplateParameters()->getParam(I));
+      if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Param))
+        Info.Param = TTP;
+      else if (NonTypeTemplateParmDecl *NTTP 
+                 = dyn_cast<NonTypeTemplateParmDecl>(Param))
+        Info.Param = NTTP;
+      else
+        Info.Param = cast<TemplateTemplateParmDecl>(Param);
+      Info.FirstArg = PartialTemplateArgs[I];
+      return TDK_SubstitutionFailure;
     }
 
     Decl *Param 
@@ -609,16 +723,22 @@
     if (isa<TemplateTypeParmDecl>(Param)) {
       if (InstArg.getKind() != TemplateArgument::Type ||
           Context.getCanonicalType(InstArg.getAsType())
-            != Context.getCanonicalType(TemplateArgs[I].getAsType()))
-        // FIXME: DeducedArgumentList->Destroy(Context); (or use RAII)
-        return 0;
+            != Context.getCanonicalType(TemplateArgs[I].getAsType())) {
+        Info.Param = cast<TemplateTypeParmDecl>(Param);
+        Info.FirstArg = TemplateArgs[I];
+        Info.SecondArg = InstArg;
+        return TDK_NonDeducedMismatch;
+      }
     } else if (NonTypeTemplateParmDecl *NTTP 
                  = dyn_cast<NonTypeTemplateParmDecl>(Param)) {
       QualType T = InstantiateType(NTTP->getType(), TemplateArgs,
                                    NTTP->getLocation(), NTTP->getDeclName());
-      if (T.isNull())
-        // FIXME: DeducedArgumentList->Destroy(Context); (or use RAII)
-        return 0;
+      if (T.isNull()) {
+        Info.Param = NTTP;
+        Info.FirstArg = TemplateArgs[I];
+        Info.SecondArg = InstArg;
+        return TDK_NonDeducedMismatch;
+      }
 
       if (InstArg.getKind() == TemplateArgument::Declaration ||
           InstArg.getKind() == TemplateArgument::Expression) {
@@ -640,18 +760,26 @@
 
         // Check that the template argument can be used to initialize
         // the corresponding template parameter.
-        if (CheckTemplateArgument(NTTP, T, E, InstArg))
-          return 0;
+        if (CheckTemplateArgument(NTTP, T, E, InstArg)) {
+          // FIXME: This isn't precisely the problem, but since it
+          // can't actually happen in well-formed C++ we don't care at
+          // the moment. Revisit this when we have template argument
+          // deduction for function templates.
+          Info.Param = NTTP;
+          Info.FirstArg = TemplateArgs[I];
+          Info.SecondArg = InstArg;
+          return TDK_NonDeducedMismatch;
+        }
       }
 
       switch (InstArg.getKind()) {
       case TemplateArgument::Null:
         assert(false && "Null template arguments cannot get here");
-        return 0;
+        return TDK_NonDeducedMismatch;
 
       case TemplateArgument::Type:
         assert(false && "Type/value mismatch");
-        return 0;
+        return TDK_NonDeducedMismatch;
 
       case TemplateArgument::Integral: {
         llvm::APSInt &Value = *InstArg.getAsIntegral();
@@ -664,15 +792,23 @@
           // Check that an unsigned parameter does not receive a negative
           // value.
           if (IntegerType->isUnsignedIntegerType()
-              && (Value.isSigned() && Value.isNegative()))
-            return 0;
+              && (Value.isSigned() && Value.isNegative())) {
+            Info.Param = NTTP;
+            Info.FirstArg = TemplateArgs[I];
+            Info.SecondArg = InstArg;
+            return TDK_NonDeducedMismatch;
+          }
 
           // Check for truncation. If the number of bits in the
           // instantiated template argument exceeds what is allowed by
           // the type, template argument deduction fails.
           unsigned AllowedBits = Context.getTypeSize(IntegerType);
-          if (Value.getActiveBits() > AllowedBits)
-            return 0;
+          if (Value.getActiveBits() > AllowedBits) {
+            Info.Param = NTTP;
+            Info.FirstArg = TemplateArgs[I];
+            Info.SecondArg = InstArg;
+            return TDK_NonDeducedMismatch;
+          }
 
           if (Value.getBitWidth() != AllowedBits)
             Value.extOrTrunc(AllowedBits);
@@ -680,28 +816,49 @@
 
           // Check that the instantiated value is the same as the
           // value provided as a template argument.
-          if (Value != *TemplateArgs[I].getAsIntegral())
-            return 0;
+          if (Value != *TemplateArgs[I].getAsIntegral()) {
+            Info.Param = NTTP;
+            Info.FirstArg = TemplateArgs[I];
+            Info.SecondArg = InstArg;
+            return TDK_NonDeducedMismatch;
+          }
         } else if (T->isPointerType() || T->isMemberPointerType()) {
           // Deal with NULL pointers that are used to initialize
           // pointer and pointer-to-member non-type template
           // parameters (C++0x).
-          if (TemplateArgs[I].getAsDecl()) 
-            return 0; // Not a NULL declaration
-
+          if (TemplateArgs[I].getAsDecl()) {
+            // Not a NULL declaration
+            Info.Param = NTTP;
+            Info.FirstArg = TemplateArgs[I];
+            Info.SecondArg = InstArg;
+            return TDK_NonDeducedMismatch;
+          }
           // Check that the integral value is 0, the NULL pointer
           // constant.
-          if (Value != 0)
-            return 0;
-        } else
-          return 0;
+          if (Value != 0) {
+            Info.Param = NTTP;
+            Info.FirstArg = TemplateArgs[I];
+            Info.SecondArg = InstArg;
+            return TDK_NonDeducedMismatch;
+          }
+        } else {
+          Info.Param = NTTP;
+          Info.FirstArg = TemplateArgs[I];
+          Info.SecondArg = InstArg;
+          return TDK_NonDeducedMismatch;
+        }
+
         break;
       }
 
       case TemplateArgument::Declaration:
         if (Context.getCanonicalDecl(InstArg.getAsDecl())
-              != Context.getCanonicalDecl(TemplateArgs[I].getAsDecl()))
-          return 0;
+              != Context.getCanonicalDecl(TemplateArgs[I].getAsDecl())) {
+          Info.Param = NTTP;
+          Info.FirstArg = TemplateArgs[I];
+          Info.SecondArg = InstArg;
+          return TDK_NonDeducedMismatch;
+        }
         break;
 
       case TemplateArgument::Expression:
@@ -714,5 +871,5 @@
     }
   }
 
-  return DeducedArgumentList;
+  return TDK_Success;
 }

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp Fri Jun 12 13:26:56 2009
@@ -864,10 +864,17 @@
          PartialEnd = Template->getPartialSpecializations().end();
        Partial != PartialEnd;
        ++Partial) {
-    if (TemplateArgumentList *Deduced 
+    TemplateDeductionInfo Info(Context);
+    if (TemplateDeductionResult Result
           = DeduceTemplateArguments(&*Partial, 
-                                    ClassTemplateSpec->getTemplateArgs()))
-      Matched.push_back(std::make_pair(&*Partial, Deduced));
+                                    ClassTemplateSpec->getTemplateArgs(),
+                                    Info)) {
+      // FIXME: Store the failed-deduction information for use in
+      // diagnostics, later.
+      (void)Result;
+    } else {
+      Matched.push_back(std::make_pair(&*Partial, Info.take()));
+    }
   }
 
   if (Matched.size() == 1) {





More information about the cfe-commits mailing list