[cfe-commits] r72819 - in /cfe/trunk: include/clang/AST/DeclTemplate.h lib/Sema/CMakeLists.txt lib/Sema/Sema.h lib/Sema/SemaTemplate.cpp lib/Sema/SemaTemplateDeduction.cpp lib/Sema/SemaTemplateInstantiate.cpp test/SemaTemplate/temp_class_spec.cpp

Douglas Gregor dgregor at apple.com
Wed Jun 3 17:03:09 PDT 2009


Author: dgregor
Date: Wed Jun  3 19:03:07 2009
New Revision: 72819

URL: http://llvm.org/viewvc/llvm-project?rev=72819&view=rev
Log:
When performing template argument deduction, ensure that multiple
deductions of the same template parameter are equivalent. This allows
us to implement the is_same type trait (!).

Also, move template argument deduction into its own file and update a
few build systems with this change (grrrr).


Added:
    cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
Modified:
    cfe/trunk/include/clang/AST/DeclTemplate.h
    cfe/trunk/lib/Sema/CMakeLists.txt
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaTemplate.cpp
    cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
    cfe/trunk/test/SemaTemplate/temp_class_spec.cpp

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

==============================================================================
--- cfe/trunk/include/clang/AST/DeclTemplate.h (original)
+++ cfe/trunk/include/clang/AST/DeclTemplate.h Wed Jun  3 19:03:07 2009
@@ -390,20 +390,21 @@
 public:
   /// \brief The type of template argument we're storing.
   enum ArgKind {
+    Null = 0,
     /// The template argument is a type. It's value is stored in the
     /// TypeOrValue field.
-    Type = 0,
+    Type = 1,
     /// The template argument is a declaration
-    Declaration = 1,
+    Declaration = 2,
     /// The template argument is an integral value stored in an llvm::APSInt.
-    Integral = 2,
+    Integral = 3,
     /// The template argument is a value- or type-dependent expression
     /// stored in an Expr*.
-    Expression = 3
+    Expression = 4
   } Kind;
 
   /// \brief Construct an empty, invalid template argument.
-  TemplateArgument() : TypeOrValue(0), StartLoc(), Kind(Type) { }
+  TemplateArgument() : TypeOrValue(0), StartLoc(), Kind(Null) { }
 
   /// \brief Construct a template type argument.
   TemplateArgument(SourceLocation Loc, QualType T) : Kind(Type) {
@@ -484,6 +485,9 @@
   /// \brief Return the kind of stored template argument.
   ArgKind getKind() const { return Kind; }
 
+  /// \brief Determine whether this template argument has no value.
+  bool isNull() const { return Kind == Null; }
+  
   /// \brief Retrieve the template argument as a type.
   QualType getAsType() const {
     if (Kind != Type)
@@ -534,6 +538,9 @@
   void Profile(llvm::FoldingSetNodeID &ID) const {
     ID.AddInteger(Kind);
     switch (Kind) {
+    case Null:
+      break;
+        
     case Type:
       getAsType().Profile(ID);
       break;

Modified: cfe/trunk/lib/Sema/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/CMakeLists.txt?rev=72819&r1=72818&r2=72819&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/CMakeLists.txt (original)
+++ cfe/trunk/lib/Sema/CMakeLists.txt Wed Jun  3 19:03:07 2009
@@ -23,6 +23,7 @@
   SemaOverload.cpp
   SemaStmt.cpp
   SemaTemplate.cpp
+  SemaTemplateDeduction.cpp
   SemaTemplateInstantiate.cpp
   SemaTemplateInstantiateDecl.cpp
   SemaTemplateInstantiateExpr.cpp

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

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Wed Jun  3 19:03:07 2009
@@ -2019,14 +2019,6 @@
                              const IdentifierInfo &II,
                              SourceRange Range);
 
-  bool DeduceTemplateArguments(QualType Param, QualType Arg,
-                               llvm::SmallVectorImpl<TemplateArgument> &Deduced);
-  bool DeduceTemplateArguments(const TemplateArgument &Param,
-                               const TemplateArgument &Arg,
-                               llvm::SmallVectorImpl<TemplateArgument> &Deduced);
-  bool DeduceTemplateArguments(const TemplateArgumentList &ParamList,
-                               const TemplateArgumentList &ArgList,
-                               llvm::SmallVectorImpl<TemplateArgument> &Deduced);
   bool DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
                                const TemplateArgumentList &TemplateArgs);
                              

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Wed Jun  3 19:03:07 2009
@@ -750,6 +750,10 @@
   Canonical.reserve(NumTemplateArgs);
   for (unsigned Idx = 0; Idx < NumTemplateArgs; ++Idx) {
     switch (TemplateArgs[Idx].getKind()) {
+    case TemplateArgument::Null:
+      assert(false && "Should never see a NULL template argument here");
+      break;
+        
     case TemplateArgument::Expression:
       // FIXME: Build canonical expression (!)
       Canonical.push_back(TemplateArgs[Idx]);
@@ -765,11 +769,13 @@
       Canonical.push_back(TemplateArgument(SourceLocation(),
                                            *TemplateArgs[Idx].getAsIntegral(),
                                         TemplateArgs[Idx].getIntegralType()));
+      break;
 
     case TemplateArgument::Type: {
       QualType CanonType 
         = Context.getCanonicalType(TemplateArgs[Idx].getAsType());
       Canonical.push_back(TemplateArgument(SourceLocation(), CanonType));
+      break;
     }
     }
   }
@@ -1092,6 +1098,10 @@
       }
 
       switch (Arg.getKind()) {
+      case TemplateArgument::Null:
+        assert(false && "Should never see a NULL template argument here");
+        break;
+          
       case TemplateArgument::Expression: {
         Expr *E = Arg.getAsExpr();
         if (CheckTemplateArgument(NTTP, NTTPType, E, &Converted))
@@ -1131,6 +1141,10 @@
         = cast<TemplateTemplateParmDecl>(*Param);
      
       switch (Arg.getKind()) {
+      case TemplateArgument::Null:
+        assert(false && "Should never see a NULL template argument here");
+        break;
+          
       case TemplateArgument::Expression: {
         Expr *ArgExpr = Arg.getAsExpr();
         if (ArgExpr && isa<DeclRefExpr>(ArgExpr) &&
@@ -2563,89 +2577,3 @@
       << Name;
   return QualType();
 }
-
-// FIXME: Move to SemaTemplateDeduction.cpp
-bool 
-Sema::DeduceTemplateArguments(QualType Param, QualType Arg,
-                             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);
-
-  // If the parameter type is not dependent, just compare the types
-  // directly.
-  if (!Param->isDependentType())
-    return Param == Arg;
-
-  // FIXME: Use a visitor or switch to handle all of the kinds of
-  // types that the parameter may be.
-  if (const TemplateTypeParmType *TemplateTypeParm 
-        = Param->getAsTemplateTypeParmType()) {
-    (void)TemplateTypeParm; // FIXME: use this
-    // The argument type can not be less qualified than the parameter
-    // type.
-    if (Param.isMoreQualifiedThan(Arg))
-      return false;
-
-    unsigned Quals = Arg.getCVRQualifiers() & ~Param.getCVRQualifiers();
-    QualType DeducedType = Arg.getQualifiedType(Quals);
-    // FIXME: actually save the deduced type, and check that this
-    // deduction is consistent.
-    return true;
-  }
-
-  if (Param.getCVRQualifiers() != Arg.getCVRQualifiers())
-    return false;
-
-  if (const PointerType *PointerParam = Param->getAsPointerType()) {
-    const PointerType *PointerArg = Arg->getAsPointerType();
-    if (!PointerArg)
-      return false;
-
-    return DeduceTemplateArguments(PointerParam->getPointeeType(),
-                                   PointerArg->getPointeeType(),
-                                   Deduced);
-  }
-
-  // FIXME: Many more cases to go (to go).
-  return false;
-}
-
-bool
-Sema::DeduceTemplateArguments(const TemplateArgument &Param,
-                              const TemplateArgument &Arg,
-                             llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
-  assert(Param.getKind() == Arg.getKind() &&
-         "Template argument kind mismatch during deduction");
-  switch (Param.getKind()) {
-  case TemplateArgument::Type: 
-    return DeduceTemplateArguments(Param.getAsType(), Arg.getAsType(),
-                                   Deduced);
-
-  default:
-    return false;
-  }
-}
-
-bool 
-Sema::DeduceTemplateArguments(const TemplateArgumentList &ParamList,
-                              const TemplateArgumentList &ArgList,
-                              llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
-  assert(ParamList.size() == ArgList.size());
-  for (unsigned I = 0, N = ParamList.size(); I != N; ++I) {
-    if (!DeduceTemplateArguments(ParamList[I], ArgList[I], Deduced))
-      return false;
-  }
-  return true;
-}
-
-
-bool 
-Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
-                              const TemplateArgumentList &TemplateArgs) {
-  llvm::SmallVector<TemplateArgument, 4> Deduced;
-  Deduced.resize(Partial->getTemplateParameters()->size());
-  return DeduceTemplateArguments(Partial->getTemplateArgs(), TemplateArgs, 
-                                 Deduced);
-}

Added: cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp?rev=72819&view=auto

==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp (added)
+++ cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp Wed Jun  3 19:03:07 2009
@@ -0,0 +1,121 @@
+//===------- SemaTemplateDeduction.cpp - Template Argument Deduction ------===/
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//===----------------------------------------------------------------------===/
+//
+//  This file implements C++ template argument deduction.
+//
+//===----------------------------------------------------------------------===/
+
+#include "Sema.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/StmtVisitor.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/Parse/DeclSpec.h"
+#include "llvm/Support/Compiler.h"
+using namespace clang;
+
+static bool DeduceTemplateArguments(ASTContext &Context, QualType Param, 
+                                    QualType Arg,
+                             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);
+
+  // If the parameter type is not dependent, just compare the types
+  // directly.
+  if (!Param->isDependentType())
+    return Param == Arg;
+
+  // FIXME: Use a visitor or switch to handle all of the kinds of
+  // types that the parameter may be.
+  if (const TemplateTypeParmType *TemplateTypeParm 
+        = Param->getAsTemplateTypeParmType()) {
+    // The argument type can not be less qualified than the parameter
+    // type.
+    if (Param.isMoreQualifiedThan(Arg))
+      return false;
+
+    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);
+    else {
+      // C++ [temp.deduct.type]p2: 
+      //   [...] If type deduction cannot be done for any P/A pair, or if for
+      //   any pair the deduction leads to more than one possible set of 
+      //   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;
+    }
+    return true;
+  }
+
+  if (Param.getCVRQualifiers() != Arg.getCVRQualifiers())
+    return false;
+
+  if (const PointerType *PointerParam = Param->getAsPointerType()) {
+    const PointerType *PointerArg = Arg->getAsPointerType();
+    if (!PointerArg)
+      return false;
+
+    return DeduceTemplateArguments(Context,
+                                   PointerParam->getPointeeType(),
+                                   PointerArg->getPointeeType(),
+                                   Deduced);
+  }
+
+  // FIXME: Many more cases to go (to go).
+  return false;
+}
+
+static bool
+DeduceTemplateArguments(ASTContext &Context, const TemplateArgument &Param,
+                        const TemplateArgument &Arg,
+                        llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
+  assert(Param.getKind() == Arg.getKind() &&
+         "Template argument kind mismatch during deduction");
+  switch (Param.getKind()) {
+  case TemplateArgument::Type: 
+    return DeduceTemplateArguments(Context, Param.getAsType(), 
+                                   Arg.getAsType(), Deduced);
+
+  default:
+    return false;
+  }
+}
+
+static bool 
+DeduceTemplateArguments(ASTContext &Context,
+                        const TemplateArgumentList &ParamList,
+                        const TemplateArgumentList &ArgList,
+                        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;
+  }
+  return true;
+}
+
+
+bool 
+Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
+                              const TemplateArgumentList &TemplateArgs) {
+  llvm::SmallVector<TemplateArgument, 4> Deduced;
+  Deduced.resize(Partial->getTemplateParameters()->size());
+  return ::DeduceTemplateArguments(Context, Partial->getTemplateArgs(), 
+                                  TemplateArgs, Deduced);
+}

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp Wed Jun  3 19:03:07 2009
@@ -503,6 +503,10 @@
   for (TemplateSpecializationType::iterator Arg = T->begin(), ArgEnd = T->end();
        Arg != ArgEnd; ++Arg) {
     switch (Arg->getKind()) {
+    case TemplateArgument::Null:
+      assert(false && "Should never have a NULL template argument");
+      break;
+        
     case TemplateArgument::Type: {
       QualType T = SemaRef.InstantiateType(Arg->getAsType(), 
                                            TemplateArgs, 

Modified: cfe/trunk/test/SemaTemplate/temp_class_spec.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/temp_class_spec.cpp?rev=72819&r1=72818&r2=72819&view=diff

==============================================================================
--- cfe/trunk/test/SemaTemplate/temp_class_spec.cpp (original)
+++ cfe/trunk/test/SemaTemplate/temp_class_spec.cpp Wed Jun  3 19:03:07 2009
@@ -18,3 +18,21 @@
 int array1[is_pointer<int*>::value? 1 : -1];
 int array2[is_pointer<const int*>::value? 1 : -1]; // expected-error{{partial ordering}} \
 // expected-error{{negative}}
+
+template<typename T, typename U>
+struct is_same {
+  static const bool value = false;
+};
+
+template<typename T>
+struct is_same<T, T> {
+  static const bool value = true;
+};
+
+typedef int INT;
+typedef INT* int_ptr;
+
+int is_same0[is_same<int, int>::value? 1 : -1];
+int is_same1[is_same<int, INT>::value? 1 : -1];
+int is_same2[is_same<const int, int>::value? -1 : 1];
+int is_same3[is_same<int_ptr, int>::value? -1 : 1];





More information about the cfe-commits mailing list