[cfe-commits] r73274 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.td lib/Sema/Sema.h lib/Sema/SemaTemplate.cpp lib/Sema/SemaTemplateDeduction.cpp test/SemaTemplate/temp_class_spec_neg.cpp

Douglas Gregor dgregor at apple.com
Fri Jun 12 17:26:55 PDT 2009


Author: dgregor
Date: Fri Jun 12 19:26:55 2009
New Revision: 73274

URL: http://llvm.org/viewvc/llvm-project?rev=73274&view=rev
Log:
When some template parameters of a class template partial
specialization cannot be deduced, produce a warning noting that the
affected class template partial specialization will never be used.

Modified:
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaTemplate.cpp
    cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
    cfe/trunk/test/SemaTemplate/temp_class_spec_neg.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=73274&r1=73273&r2=73274&view=diff

==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Fri Jun 12 19:26:55 2009
@@ -770,6 +770,12 @@
     "class template partial specialization does not specialize any template "
     "argument; to %select{declare|define}0 the primary template, remove the "
     "template argument list">; 
+def warn_partial_specs_not_deducible : Warning<
+    "class template partial specialization contains "
+    "%select{a template parameter|template parameters}0 that can not be "
+    "deduced; this partial specialization will never be used">;
+def note_partial_spec_unused_parameter : Note<
+    "non-deducible template parameter %0">;
 def unsup_template_partial_spec_ordering : Error<
   "partial ordering of class template partial specializations is not yet "
   "supported">;

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

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Fri Jun 12 19:26:55 2009
@@ -2163,7 +2163,10 @@
   DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
                           const TemplateArgumentList &TemplateArgs,
                           TemplateDeductionInfo &Info);
-                             
+                   
+  void MarkDeducedTemplateParameters(const TemplateArgumentList &TemplateArgs,
+                                     llvm::SmallVectorImpl<bool> &Deduced);
+          
   //===--------------------------------------------------------------------===//
   // C++ Template Instantiation
   //

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Fri Jun 12 19:26:55 2009
@@ -2328,8 +2328,6 @@
     Specialization->setLocation(TemplateNameLoc);
     PrevDecl = 0;
   } else if (isPartialSpecialization) {
-    // FIXME: extra checking for partial specializations
-
     // Create a new class template partial specialization declaration node.
     TemplateParameterList *TemplateParams 
       = static_cast<TemplateParameterList*>(*TemplateParameterLists.get());
@@ -2351,6 +2349,38 @@
       ClassTemplate->getPartialSpecializations().InsertNode(Partial, InsertPos);
     }
     Specialization = Partial;
+
+    // Check that all of the template parameters of the class template
+    // partial specialization are deducible from the template
+    // arguments. If not, this class template partial specialization
+    // will never be used.
+    llvm::SmallVector<bool, 8> DeducibleParams;
+    DeducibleParams.resize(TemplateParams->size());
+    MarkDeducedTemplateParameters(Partial->getTemplateArgs(), DeducibleParams);
+    unsigned NumNonDeducible = 0;
+    for (unsigned I = 0, N = DeducibleParams.size(); I != N; ++I)
+      if (!DeducibleParams[I])
+        ++NumNonDeducible;
+
+    if (NumNonDeducible) {
+      Diag(TemplateNameLoc, diag::warn_partial_specs_not_deducible)
+        << (NumNonDeducible > 1)
+        << SourceRange(TemplateNameLoc, RAngleLoc);
+      for (unsigned I = 0, N = DeducibleParams.size(); I != N; ++I) {
+        if (!DeducibleParams[I]) {
+          NamedDecl *Param = cast<NamedDecl>(TemplateParams->getParam(I));
+          if (Param->getDeclName())
+            Diag(Param->getLocation(), 
+                 diag::note_partial_spec_unused_parameter)
+              << Param->getDeclName();
+          else
+            Diag(Param->getLocation(), 
+                 diag::note_partial_spec_unused_parameter)
+              << std::string("<anonymous>");
+        }
+      }
+    }
+
   } else {
     // Create a new class template specialization declaration node for
     // this explicit specialization.

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp Fri Jun 12 19:26:55 2009
@@ -881,3 +881,178 @@
 
   return TDK_Success;
 }
+
+static void 
+MarkDeducedTemplateParameters(Sema &SemaRef,
+                              const TemplateArgument &TemplateArg,
+                              llvm::SmallVectorImpl<bool> &Deduced);
+
+/// \brief Mark the template arguments that are deduced by the given
+/// expression.
+static void 
+MarkDeducedTemplateParameters(Expr *E, llvm::SmallVectorImpl<bool> &Deduced) {
+  DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E);
+  if (!E)
+    return;
+
+  NonTypeTemplateParmDecl *NTTP 
+    = dyn_cast<NonTypeTemplateParmDecl>(DRE->getDecl());
+  if (!NTTP)
+    return;
+
+  Deduced[NTTP->getIndex()] = true;
+}
+
+/// \brief Mark the template parameters that are deduced by the given
+/// type.
+static void 
+MarkDeducedTemplateParameters(Sema &SemaRef, QualType T,
+                              llvm::SmallVectorImpl<bool> &Deduced) {
+  // Non-dependent types have nothing deducible
+  if (!T->isDependentType())
+    return;
+
+  T = SemaRef.Context.getCanonicalType(T);
+  switch (T->getTypeClass()) {
+  case Type::ExtQual:
+    MarkDeducedTemplateParameters(SemaRef, 
+                QualType(cast<ExtQualType>(T.getTypePtr())->getBaseType(), 0),
+                                  Deduced);
+    break;
+
+  case Type::Pointer:
+    MarkDeducedTemplateParameters(SemaRef,
+                          cast<PointerType>(T.getTypePtr())->getPointeeType(),
+                                  Deduced);
+    break;
+
+  case Type::BlockPointer:
+    MarkDeducedTemplateParameters(SemaRef,
+                     cast<BlockPointerType>(T.getTypePtr())->getPointeeType(),
+                                  Deduced);
+    break;
+
+  case Type::LValueReference:
+  case Type::RValueReference:
+    MarkDeducedTemplateParameters(SemaRef,
+                        cast<ReferenceType>(T.getTypePtr())->getPointeeType(),
+                                  Deduced);
+    break;
+
+  case Type::MemberPointer: {
+    const MemberPointerType *MemPtr = cast<MemberPointerType>(T.getTypePtr());
+    MarkDeducedTemplateParameters(SemaRef, MemPtr->getPointeeType(), Deduced);
+    MarkDeducedTemplateParameters(SemaRef, QualType(MemPtr->getClass(), 0),
+                                  Deduced);
+    break;
+  }
+
+  case Type::DependentSizedArray:
+    MarkDeducedTemplateParameters(
+                 cast<DependentSizedArrayType>(T.getTypePtr())->getSizeExpr(),
+                                  Deduced);
+    // Fall through to check the element type
+
+  case Type::ConstantArray:
+  case Type::IncompleteArray:
+    MarkDeducedTemplateParameters(SemaRef,
+                            cast<ArrayType>(T.getTypePtr())->getElementType(),
+                                  Deduced);
+    break;
+
+  case Type::Vector:
+  case Type::ExtVector:
+    MarkDeducedTemplateParameters(SemaRef,
+                           cast<VectorType>(T.getTypePtr())->getElementType(),
+                                  Deduced);
+    break;
+
+  case Type::FunctionProto: {
+    const FunctionProtoType *Proto = cast<FunctionProtoType>(T.getTypePtr());
+    MarkDeducedTemplateParameters(SemaRef, Proto->getResultType(), Deduced);
+    for (unsigned I = 0, N = Proto->getNumArgs(); I != N; ++I)
+      MarkDeducedTemplateParameters(SemaRef, Proto->getArgType(I), Deduced);
+    break;
+  }
+
+  case Type::TemplateTypeParm:
+    Deduced[cast<TemplateTypeParmType>(T.getTypePtr())->getIndex()] = true;
+    break;
+
+  case Type::TemplateSpecialization: {
+    const TemplateSpecializationType *Spec 
+      = cast<TemplateSpecializationType>(T.getTypePtr());
+    if (TemplateDecl *Template = Spec->getTemplateName().getAsTemplateDecl())
+      if (TemplateTemplateParmDecl *TTP 
+            = dyn_cast<TemplateTemplateParmDecl>(Template))
+        Deduced[TTP->getIndex()] = true;
+      
+      for (unsigned I = 0, N = Spec->getNumArgs(); I != N; ++I)
+        MarkDeducedTemplateParameters(SemaRef, Spec->getArg(I), Deduced);
+
+    break;
+  }
+
+  // None of these types have any deducible parts.
+  case Type::Builtin:
+  case Type::FixedWidthInt:
+  case Type::Complex:
+  case Type::VariableArray:
+  case Type::FunctionNoProto:
+  case Type::Record:
+  case Type::Enum:
+  case Type::Typename:
+  case Type::ObjCInterface:
+  case Type::ObjCQualifiedInterface:
+  case Type::ObjCQualifiedId:
+#define TYPE(Class, Base)
+#define ABSTRACT_TYPE(Class, Base)
+#define DEPENDENT_TYPE(Class, Base)
+#define NON_CANONICAL_TYPE(Class, Base) case Type::Class:
+#include "clang/AST/TypeNodes.def"
+    break;
+  }
+}
+
+/// \brief Mark the template parameters that are deduced by this
+/// template argument.
+static void 
+MarkDeducedTemplateParameters(Sema &SemaRef,
+                              const TemplateArgument &TemplateArg,
+                              llvm::SmallVectorImpl<bool> &Deduced) {
+  switch (TemplateArg.getKind()) {
+  case TemplateArgument::Null:
+  case TemplateArgument::Integral:
+    break;
+    
+  case TemplateArgument::Type:
+    MarkDeducedTemplateParameters(SemaRef, TemplateArg.getAsType(), Deduced);
+    break;
+
+  case TemplateArgument::Declaration:
+    if (TemplateTemplateParmDecl *TTP 
+        = dyn_cast<TemplateTemplateParmDecl>(TemplateArg.getAsDecl()))
+      Deduced[TTP->getIndex()] = true;
+    break;
+
+  case TemplateArgument::Expression:
+    MarkDeducedTemplateParameters(TemplateArg.getAsExpr(), Deduced);
+    break;
+  }
+}
+
+/// \brief Mark the template parameters can be deduced by the given
+/// template argument list.
+///
+/// \param TemplateArgs the template argument list from which template
+/// parameters will be deduced.
+///
+/// \param Deduced a bit vector whose elements will be set to \c true
+/// to indicate when the corresponding template parameter will be
+/// deduced.
+void 
+Sema::MarkDeducedTemplateParameters(const TemplateArgumentList &TemplateArgs,
+                                    llvm::SmallVectorImpl<bool> &Deduced) {
+  for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I)
+    ::MarkDeducedTemplateParameters(*this, TemplateArgs[I], Deduced);
+}

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

==============================================================================
--- cfe/trunk/test/SemaTemplate/temp_class_spec_neg.cpp (original)
+++ cfe/trunk/test/SemaTemplate/temp_class_spec_neg.cpp Fri Jun 12 19:26:55 2009
@@ -39,3 +39,7 @@
          int N = 17, // expected-error{{default template argument}}
          template<typename X> class TT = ::vector> // expected-error{{default template argument}}
   struct Test0<T*, N, TT> { };
+
+template<typename T> struct Test1;
+template<typename T, typename U>  // expected-note{{non-deducible}}
+  struct Test1<T*> { }; // expected-warning{{never be used}}





More information about the cfe-commits mailing list