[cfe-commits] r99734 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.td lib/Sema/Sema.h lib/Sema/SemaTemplate.cpp lib/Sema/SemaTemplate.h lib/Sema/SemaTemplateDeduction.cpp lib/Sema/SemaTemplateInstantiate.cpp lib/Sema/SemaType.cpp test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p17.cpp test/SemaTemplate/temp_arg_nontype.cpp

Douglas Gregor dgregor at apple.com
Sat Mar 27 19:42:43 PDT 2010


Author: dgregor
Date: Sat Mar 27 21:42:43 2010
New Revision: 99734

URL: http://llvm.org/viewvc/llvm-project?rev=99734&view=rev
Log:
After performing template argument deduction for a function template,
check deduced non-type template arguments and template template
arguments against the template parameters for which they were deduced,
performing conversions as appropriate so that deduced template
arguments get the same treatment as explicitly-specified template
arguments. This is the bulk of PR6723.

Also keep track of whether deduction of a non-type template argument
came from an array bound (vs. anywhere else). With this information,
we enforce C++ [temp.deduct.type]p17, which requires exact type
matches when deduction deduces a non-type template argument from
something that is not an array bound.

Finally, when in a SFINAE context, translate the "zero sized
arrays are an extension" extension diagnostic into a hard error (for
better standard conformance), which was a minor part of PR6723.


Added:
    cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p17.cpp   (with props)
Modified:
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaTemplate.cpp
    cfe/trunk/lib/Sema/SemaTemplate.h
    cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
    cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
    cfe/trunk/lib/Sema/SemaType.cpp
    cfe/trunk/test/SemaTemplate/temp_arg_nontype.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=99734&r1=99733&r2=99734&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Sat Mar 27 21:42:43 2010
@@ -1206,6 +1206,9 @@
 def err_template_arg_not_ice : Error<
   "non-type template argument of type %0 is not an integral constant "
   "expression">;
+def err_deduced_non_type_template_arg_type_mismatch : Error<
+  "deduced non-type template argument does not have the same type as the "
+  "its corresponding template parameter (%0 vs %1)">;
 def err_template_arg_not_convertible : Error<
   "non-type template argument of type %0 cannot be converted to a value "
   "of type %1">;
@@ -1585,6 +1588,8 @@
   "pointer to function type %0 may not be 'restrict' qualified">;
 def ext_typecheck_zero_array_size : Extension<
   "zero size arrays are an extension">;
+def err_typecheck_zero_array_size : Error<
+  "zero-length arrays are not permitted in C++">;
 def err_at_least_one_initializer_needed_to_size_array : Error<
   "at least one initializer value required to size array">;
 def err_array_size_non_int : Error<"size of array has non-integer type %0">;

Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=99734&r1=99733&r2=99734&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Sat Mar 27 21:42:43 2010
@@ -2862,12 +2862,29 @@
                                           Decl *Param,
                                       TemplateArgumentListBuilder &Converted);
 
+  /// \brief Specifies the context in which a particular template
+  /// argument is being checked.
+  enum CheckTemplateArgumentKind {
+    /// \brief The template argument was specified in the code or was
+    /// instantiated with some deduced template arguments.
+    CTAK_Specified,
+
+    /// \brief The template argument was deduced via template argument
+    /// deduction.
+    CTAK_Deduced,
+
+    /// \brief The template argument was deduced from an array bound
+    /// via template argument deduction.
+    CTAK_DeducedFromArrayBound
+  };
+
   bool CheckTemplateArgument(NamedDecl *Param,
                              const TemplateArgumentLoc &Arg,
                              TemplateDecl *Template,
                              SourceLocation TemplateLoc,
                              SourceLocation RAngleLoc,
-                             TemplateArgumentListBuilder &Converted);
+                             TemplateArgumentListBuilder &Converted,
+                             CheckTemplateArgumentKind CTAK = CTAK_Specified);
   
   bool CheckTemplateArgumentList(TemplateDecl *Template,
                                  SourceLocation TemplateLoc,
@@ -2887,9 +2904,18 @@
                                             TemplateArgument &Converted);
   bool CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
                              QualType InstantiatedParamType, Expr *&Arg,
-                             TemplateArgument &Converted);
+                             TemplateArgument &Converted,
+                             CheckTemplateArgumentKind CTAK = CTAK_Specified);
   bool CheckTemplateArgument(TemplateTemplateParmDecl *Param, 
                              const TemplateArgumentLoc &Arg);
+
+  OwningExprResult 
+  BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg,
+                                          QualType ParamType,
+                                          SourceLocation Loc);
+  OwningExprResult 
+  BuildExpressionFromIntegralTemplateArgument(const TemplateArgument &Arg,
+                                              SourceLocation Loc);
   
   /// \brief Enumeration describing how template parameter lists are compared
   /// for equality.
@@ -3112,14 +3138,15 @@
   TemplateDeductionResult
   SubstituteExplicitTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
                         const TemplateArgumentListInfo &ExplicitTemplateArgs,
-                            llvm::SmallVectorImpl<TemplateArgument> &Deduced,
+                      llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced,
                                  llvm::SmallVectorImpl<QualType> &ParamTypes,
                                       QualType *FunctionType,
                                       TemplateDeductionInfo &Info);
 
   TemplateDeductionResult
   FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
-                             llvm::SmallVectorImpl<TemplateArgument> &Deduced,
+                      llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced,
+                                  unsigned NumExplicitlySpecified,
                                   FunctionDecl *&Specialization,
                                   TemplateDeductionInfo &Info);
 

Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=99734&r1=99733&r2=99734&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Sat Mar 27 21:42:43 2010
@@ -1897,7 +1897,8 @@
                                  TemplateDecl *Template,
                                  SourceLocation TemplateLoc,
                                  SourceLocation RAngleLoc,
-                                 TemplateArgumentListBuilder &Converted) {
+                                 TemplateArgumentListBuilder &Converted,
+                                 CheckTemplateArgumentKind CTAK) {
   // Check template type parameters.
   if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Param))
     return CheckTemplateTypeArgument(TTP, Arg, Converted);
@@ -1937,7 +1938,7 @@
     case TemplateArgument::Expression: {
       Expr *E = Arg.getArgument().getAsExpr();
       TemplateArgument Result;
-      if (CheckTemplateArgument(NTTP, NTTPType, E, Result))
+      if (CheckTemplateArgument(NTTP, NTTPType, E, Result, CTAK))
         return true;
       
       Converted.Append(Result);
@@ -2478,7 +2479,8 @@
 /// If no error was detected, Converted receives the converted template argument.
 bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
                                  QualType InstantiatedParamType, Expr *&Arg,
-                                 TemplateArgument &Converted) {
+                                 TemplateArgument &Converted,
+                                 CheckTemplateArgumentKind CTAK) {
   SourceLocation StartLoc = Arg->getSourceRange().getBegin();
 
   // If either the parameter has a dependent type or the argument is
@@ -2525,17 +2527,27 @@
       return true;
     }
 
-    // FIXME: We need some way to more easily get the unqualified form
-    // of the types without going all the way to the
-    // canonical type.
-    if (Context.getCanonicalType(ParamType).getCVRQualifiers())
-      ParamType = Context.getCanonicalType(ParamType).getUnqualifiedType();
-    if (Context.getCanonicalType(ArgType).getCVRQualifiers())
-      ArgType = Context.getCanonicalType(ArgType).getUnqualifiedType();
+    // From here on out, all we care about are the unqualified forms
+    // of the parameter and argument types.
+    ParamType = ParamType.getUnqualifiedType();
+    ArgType = ArgType.getUnqualifiedType();
 
     // Try to convert the argument to the parameter's type.
     if (Context.hasSameType(ParamType, ArgType)) {
       // Okay: no conversion necessary
+    } else if (CTAK == CTAK_Deduced) {
+      // C++ [temp.deduct.type]p17:
+      //   If, in the declaration of a function template with a non-type
+      //   template-parameter, the non-type template- parameter is used
+      //   in an expression in the function parameter-list and, if the
+      //   corresponding template-argument is deduced, the
+      //   template-argument type shall match the type of the
+      //   template-parameter exactly, except that a template-argument
+      //   deduced from an array bound may be of any integral type.
+      Diag(StartLoc, diag::err_deduced_non_type_template_arg_type_mismatch)
+        << ArgType << ParamType;
+      Diag(Param->getLocation(), diag::note_template_param_here);
+      return true;      
     } else if (IsIntegralPromotion(Arg, ArgType, ParamType) ||
                !ParamType->isEnumeralType()) {
       // This is an integral promotion or conversion.
@@ -2838,6 +2850,112 @@
                                          Arg.getLocation());
 }
 
+/// \brief Given a non-type template argument that refers to a
+/// declaration and the type of its corresponding non-type template
+/// parameter, produce an expression that properly refers to that
+/// declaration.
+Sema::OwningExprResult 
+Sema::BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg,
+                                              QualType ParamType,
+                                              SourceLocation Loc) {
+  assert(Arg.getKind() == TemplateArgument::Declaration &&
+         "Only declaration template arguments permitted here");
+  ValueDecl *VD = cast<ValueDecl>(Arg.getAsDecl());
+
+  if (VD->getDeclContext()->isRecord() && 
+      (isa<CXXMethodDecl>(VD) || isa<FieldDecl>(VD))) {
+    // If the value is a class member, we might have a pointer-to-member.
+    // Determine whether the non-type template template parameter is of
+    // pointer-to-member type. If so, we need to build an appropriate
+    // expression for a pointer-to-member, since a "normal" DeclRefExpr
+    // would refer to the member itself.
+    if (ParamType->isMemberPointerType()) {
+      QualType ClassType
+        = Context.getTypeDeclType(cast<RecordDecl>(VD->getDeclContext()));
+      NestedNameSpecifier *Qualifier
+        = NestedNameSpecifier::Create(Context, 0, false, ClassType.getTypePtr());
+      CXXScopeSpec SS;
+      SS.setScopeRep(Qualifier);
+      OwningExprResult RefExpr = BuildDeclRefExpr(VD, 
+                                           VD->getType().getNonReferenceType(), 
+                                                  Loc,
+                                                  &SS);
+      if (RefExpr.isInvalid())
+        return ExprError();
+      
+      RefExpr = CreateBuiltinUnaryOp(Loc, UnaryOperator::AddrOf, move(RefExpr));
+      assert(!RefExpr.isInvalid() &&
+             Context.hasSameType(((Expr*) RefExpr.get())->getType(),
+                                 ParamType));
+      return move(RefExpr);
+    }
+  }
+  
+  QualType T = VD->getType().getNonReferenceType();
+  if (ParamType->isPointerType()) {
+    // C++03 [temp.arg.nontype]p5:
+    //  - For a non-type template-parameter of type pointer to
+    //    object, qualification conversions and the array-to-pointer
+    //    conversion are applied.
+    //  - For a non-type template-parameter of type pointer to
+    //    function, only the function-to-pointer conversion is
+    //    applied.
+    OwningExprResult RefExpr = BuildDeclRefExpr(VD, T, Loc);
+    if (RefExpr.isInvalid())
+      return ExprError();
+    
+    // Decay functions and arrays.
+    Expr *RefE = (Expr *)RefExpr.get();
+    DefaultFunctionArrayConversion(RefE);
+    if (RefE != RefExpr.get()) {
+      RefExpr.release();
+      RefExpr = Owned(RefE);
+    }
+    
+    // Qualification conversions.
+    RefExpr.release();
+    ImpCastExprToType(RefE, ParamType.getUnqualifiedType(), CastExpr::CK_NoOp);
+    return Owned(RefE);
+  }
+
+  // If the non-type template parameter has reference type, qualify the
+  // resulting declaration reference with the extra qualifiers on the
+  // type that the reference refers to.
+  if (const ReferenceType *TargetRef = ParamType->getAs<ReferenceType>())
+    T = Context.getQualifiedType(T, TargetRef->getPointeeType().getQualifiers());
+    
+  return BuildDeclRefExpr(VD, T, Loc);
+}
+
+/// \brief Construct a new expression that refers to the given
+/// integral template argument with the given source-location
+/// information.
+///
+/// This routine takes care of the mapping from an integral template
+/// argument (which may have any integral type) to the appropriate
+/// literal value.
+Sema::OwningExprResult 
+Sema::BuildExpressionFromIntegralTemplateArgument(const TemplateArgument &Arg,
+                                                  SourceLocation Loc) {
+  assert(Arg.getKind() == TemplateArgument::Integral &&
+         "Operation is only value for integral template arguments");
+  QualType T = Arg.getIntegralType();
+  if (T->isCharType() || T->isWideCharType())
+    return Owned(new (Context) CharacterLiteral(
+                                             Arg.getAsIntegral()->getZExtValue(),
+                                             T->isWideCharType(),
+                                             T,
+                                             Loc));
+  if (T->isBooleanType())
+    return Owned(new (Context) CXXBoolLiteralExpr(
+                                            Arg.getAsIntegral()->getBoolValue(),
+                                            T,
+                                            Loc));
+
+  return Owned(new (Context) IntegerLiteral(*Arg.getAsIntegral(), T, Loc));
+}
+
+
 /// \brief Determine whether the given template parameter lists are
 /// equivalent.
 ///

Modified: cfe/trunk/lib/Sema/SemaTemplate.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.h?rev=99734&r1=99733&r2=99734&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.h (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.h Sat Mar 27 21:42:43 2010
@@ -99,6 +99,40 @@
     /// template specialization to a function template.
     TPOC_Other
   };
+
+  /// \brief Captures a template argument whose value has been deduced
+  /// via c++ template argument deduction.
+  class DeducedTemplateArgument : public TemplateArgument {
+    /// \brief For a non-type template argument, whether the value was
+    /// deduced from an array bound.
+    bool DeducedFromArrayBound;
+
+  public:
+    DeducedTemplateArgument()
+      : TemplateArgument(), DeducedFromArrayBound(false) { }
+
+    DeducedTemplateArgument(const TemplateArgument &Arg,
+                            bool DeducedFromArrayBound = false)
+      : TemplateArgument(Arg), DeducedFromArrayBound(DeducedFromArrayBound) { }
+
+    /// \brief Construct an integral non-type template argument that
+    /// has been deduced, possible from an array bound.
+    DeducedTemplateArgument(const llvm::APSInt &Value,
+                            QualType ValueType,
+                            bool DeducedFromArrayBound)
+      : TemplateArgument(Value, ValueType), 
+        DeducedFromArrayBound(DeducedFromArrayBound) { }
+
+    /// \brief For a non-type template argument, determine whether the
+    /// template argument was deduced from an array bound.
+    bool wasDeducedFromArrayBound() const { return DeducedFromArrayBound; }
+
+    /// \brief Specify whether the given non-type template argument
+    /// was deduced from an array bound.
+    void setDeducedFromArrayBound(bool Deduced) {
+      DeducedFromArrayBound = Deduced;
+    }
+  };
 }
 
 #endif // LLVM_CLANG_SEMA_TEMPLATE_H

Modified: cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp?rev=99734&r1=99733&r2=99734&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp Sat Mar 27 21:42:43 2010
@@ -75,7 +75,7 @@
                         const TemplateArgument &Param,
                         const TemplateArgument &Arg,
                         Sema::TemplateDeductionInfo &Info,
-                        llvm::SmallVectorImpl<TemplateArgument> &Deduced);
+                    llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced);
 
 /// \brief If the given expression is of a form that permits the deduction
 /// of a non-type template parameter, return the declaration of that
@@ -96,13 +96,15 @@
 DeduceNonTypeTemplateArgument(Sema &S,
                               NonTypeTemplateParmDecl *NTTP,
                               llvm::APSInt Value, QualType ValueType,
+                              bool DeducedFromArrayBound,
                               Sema::TemplateDeductionInfo &Info,
-                              llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
+                    llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
   assert(NTTP->getDepth() == 0 &&
          "Cannot deduce non-type template argument with depth > 0");
 
   if (Deduced[NTTP->getIndex()].isNull()) {
-    Deduced[NTTP->getIndex()] = TemplateArgument(Value, ValueType);
+    Deduced[NTTP->getIndex()] = DeducedTemplateArgument(Value, ValueType,
+                                                        DeducedFromArrayBound);
     return Sema::TDK_Success;
   }
 
@@ -122,6 +124,9 @@
     return Sema::TDK_Inconsistent;
   }
 
+  if (!DeducedFromArrayBound)
+    Deduced[NTTP->getIndex()].setDeducedFromArrayBound(false);
+
   return Sema::TDK_Success;
 }
 
@@ -134,7 +139,7 @@
                               NonTypeTemplateParmDecl *NTTP,
                               Expr *Value,
                               Sema::TemplateDeductionInfo &Info,
-                           llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
+                    llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
   assert(NTTP->getDepth() == 0 &&
          "Cannot deduce non-type template argument with depth > 0");
   assert((Value->isTypeDependent() || Value->isValueDependent()) &&
@@ -176,7 +181,7 @@
                               NonTypeTemplateParmDecl *NTTP,
                               Decl *D,
                               Sema::TemplateDeductionInfo &Info,
-                              llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
+                    llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
   assert(NTTP->getDepth() == 0 &&
          "Cannot deduce non-type template argument with depth > 0");
   
@@ -210,7 +215,7 @@
                         TemplateName Param,
                         TemplateName Arg,
                         Sema::TemplateDeductionInfo &Info,
-                        llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
+                    llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
   TemplateDecl *ParamDecl = Param.getAsTemplateDecl();
   if (!ParamDecl) {
     // The parameter type is dependent and is not a template template parameter,
@@ -274,7 +279,7 @@
                         const TemplateSpecializationType *Param,
                         QualType Arg,
                         Sema::TemplateDeductionInfo &Info,
-                        llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
+                    llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
   assert(Arg.isCanonical() && "Argument type must be canonical");
 
   // Check whether the template argument is a dependent template-id.
@@ -366,7 +371,7 @@
                         TemplateParameterList *TemplateParams,
                         QualType ParamIn, QualType ArgIn,
                         Sema::TemplateDeductionInfo &Info,
-                        llvm::SmallVectorImpl<TemplateArgument> &Deduced,
+                     llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced,
                         unsigned TDF) {
   // We only want to look at the canonical types, since typedefs and
   // sugar are not part of template argument deduction.
@@ -574,6 +579,7 @@
         llvm::APSInt Size(ConstantArrayArg->getSize());
         return DeduceNonTypeTemplateArgument(S, NTTP, Size, 
                                              S.Context.getSizeType(),
+                                             /*ArrayBound=*/true,
                                              Info, Deduced);
       }
       if (const DependentSizedArrayType *DependentArrayArg
@@ -785,7 +791,7 @@
                         const TemplateArgument &Param,
                         const TemplateArgument &Arg,
                         Sema::TemplateDeductionInfo &Info,
-                        llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
+                    llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
   switch (Param.getKind()) {
   case TemplateArgument::Null:
     assert(false && "Null template argument in parameter list");
@@ -846,6 +852,7 @@
         return DeduceNonTypeTemplateArgument(S, NTTP,
                                              *Arg.getAsIntegral(),
                                              Arg.getIntegralType(),
+                                             /*ArrayBound=*/false,
                                              Info, Deduced);
       if (Arg.getKind() == TemplateArgument::Expression)
         return DeduceNonTypeTemplateArgument(S, NTTP, Arg.getAsExpr(),
@@ -877,7 +884,7 @@
                         const TemplateArgumentList &ParamList,
                         const TemplateArgumentList &ArgList,
                         Sema::TemplateDeductionInfo &Info,
-                        llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
+                    llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
   assert(ParamList.size() == ArgList.size());
   for (unsigned I = 0, N = ParamList.size(); I != N; ++I) {
     if (Sema::TemplateDeductionResult Result
@@ -966,7 +973,7 @@
   //   specialization can be deduced from the actual template argument
   //   list (14.8.2).
   SFINAETrap Trap(*this);
-  llvm::SmallVector<TemplateArgument, 4> Deduced;
+  llvm::SmallVector<DeducedTemplateArgument, 4> Deduced;
   Deduced.resize(Partial->getTemplateParameters()->size());
   if (TemplateDeductionResult Result
         = ::DeduceTemplateArguments(*this,
@@ -1007,6 +1014,8 @@
   // verify that the instantiated template arguments are both valid
   // and are equivalent to the template arguments originally provided
   // to the class template.
+  // FIXME: Do we have to correct the types of deduced non-type template 
+  // arguments (in particular, integral non-type template arguments?).
   Sema::LocalInstantiationScope InstScope(*this);
   ClassTemplateDecl *ClassTemplate = Partial->getSpecializedTemplate();
   const TemplateArgumentLoc *PartialTemplateArgs
@@ -1110,7 +1119,7 @@
 Sema::SubstituteExplicitTemplateArguments(
                                       FunctionTemplateDecl *FunctionTemplate,
                         const TemplateArgumentListInfo &ExplicitTemplateArgs,
-                            llvm::SmallVectorImpl<TemplateArgument> &Deduced,
+                       llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced,
                                  llvm::SmallVectorImpl<QualType> &ParamTypes,
                                           QualType *FunctionType,
                                           TemplateDeductionInfo &Info) {
@@ -1223,12 +1232,67 @@
   return TDK_Success;
 }
 
+/// \brief Allocate a TemplateArgumentLoc where all locations have
+/// been initialized to the given location.
+///
+/// \param S The semantic analysis object.
+///
+/// \param The template argument we are producing template argument
+/// location information for.
+///
+/// \param NTTPType For a declaration template argument, the type of
+/// the non-type template parameter that corresponds to this template
+/// argument.
+///
+/// \param Loc The source location to use for the resulting template
+/// argument.
+static TemplateArgumentLoc 
+getTrivialTemplateArgumentLoc(Sema &S,
+                              const TemplateArgument &Arg, 
+                              QualType NTTPType,
+                              SourceLocation Loc) {
+  switch (Arg.getKind()) {
+  case TemplateArgument::Null:
+    llvm_unreachable("Can't get a NULL template argument here");
+    break;
+
+  case TemplateArgument::Type:
+    return TemplateArgumentLoc(Arg, 
+                    S.Context.getTrivialTypeSourceInfo(Arg.getAsType(), Loc));
+
+  case TemplateArgument::Declaration: {
+    Expr *E
+      = S.BuildExpressionFromDeclTemplateArgument(Arg, NTTPType, Loc)
+                                                              .takeAs<Expr>();
+    return TemplateArgumentLoc(TemplateArgument(E), E);
+  }
+
+  case TemplateArgument::Integral: {
+    Expr *E
+      = S.BuildExpressionFromIntegralTemplateArgument(Arg, Loc).takeAs<Expr>();
+    return TemplateArgumentLoc(TemplateArgument(E), E);
+  }
+
+  case TemplateArgument::Template:
+    return TemplateArgumentLoc(Arg, SourceRange(), Loc);
+
+  case TemplateArgument::Expression:
+    return TemplateArgumentLoc(Arg, Arg.getAsExpr());
+
+  case TemplateArgument::Pack:
+    llvm_unreachable("Template parameter packs are not yet supported");
+  }
+
+  return TemplateArgumentLoc();
+}
+
 /// \brief Finish template argument deduction for a function template,
 /// checking the deduced template arguments for completeness and forming
 /// the function template specialization.
 Sema::TemplateDeductionResult
 Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
-                            llvm::SmallVectorImpl<TemplateArgument> &Deduced,
+                       llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced,
+                                      unsigned NumExplicitlySpecified,
                                       FunctionDecl *&Specialization,
                                       TemplateDeductionInfo &Info) {
   TemplateParameterList *TemplateParams
@@ -1251,13 +1315,71 @@
   //   explicitly specified, template argument deduction fails.
   TemplateArgumentListBuilder Builder(TemplateParams, Deduced.size());
   for (unsigned I = 0, N = Deduced.size(); I != N; ++I) {
+    NamedDecl *Param = FunctionTemplate->getTemplateParameters()->getParam(I);
     if (!Deduced[I].isNull()) {
-      Builder.Append(Deduced[I]);
+      if (I < NumExplicitlySpecified || 
+          Deduced[I].getKind() == TemplateArgument::Type) {
+        // We have already fully type-checked and converted this
+        // argument (because it was explicitly-specified) or no
+        // additional checking is necessary (because it's a template
+        // type parameter). Just record the presence of this
+        // parameter.
+        Builder.Append(Deduced[I]);
+        continue;
+      }
+
+      // We have deduced this argument, so it still needs to be
+      // checked and converted.
+
+      // First, for a non-type template parameter type that is
+      // initialized by a declaration, we need the type of the
+      // corresponding non-type template parameter.
+      QualType NTTPType;
+      if (NonTypeTemplateParmDecl *NTTP 
+                                = dyn_cast<NonTypeTemplateParmDecl>(Param)) { 
+        if (Deduced[I].getKind() == TemplateArgument::Declaration) {
+          NTTPType = NTTP->getType();
+          if (NTTPType->isDependentType()) {
+            TemplateArgumentList TemplateArgs(Context, Builder, 
+                                              /*TakeArgs=*/false);
+            NTTPType = SubstType(NTTPType,
+                                 MultiLevelTemplateArgumentList(TemplateArgs),
+                                 NTTP->getLocation(),
+                                 NTTP->getDeclName());
+            if (NTTPType.isNull()) {
+              Info.Param = makeTemplateParameter(Param);
+              return TDK_SubstitutionFailure;
+            }
+          }
+        }
+      }
+
+      // Convert the deduced template argument into a template
+      // argument that we can check, almost as if the user had written
+      // the template argument explicitly.
+      TemplateArgumentLoc Arg = getTrivialTemplateArgumentLoc(*this,
+                                                              Deduced[I],
+                                                              NTTPType,
+                                                           SourceLocation());
+
+      // Check the template argument, converting it as necessary.
+      if (CheckTemplateArgument(Param, Arg,
+                                FunctionTemplate,
+                                FunctionTemplate->getLocation(),
+                                FunctionTemplate->getSourceRange().getEnd(),
+                                Builder,
+                                Deduced[I].wasDeducedFromArrayBound()
+                                  ? CTAK_DeducedFromArrayBound 
+                                  : CTAK_Deduced)) {
+        Info.Param = makeTemplateParameter(
+                         const_cast<NamedDecl *>(TemplateParams->getParam(I)));
+        return TDK_SubstitutionFailure;
+      }
+
       continue;
     }
 
     // Substitute into the default template argument, if available. 
-    NamedDecl *Param = FunctionTemplate->getTemplateParameters()->getParam(I);
     TemplateArgumentLoc DefArg
       = SubstDefaultTemplateArgumentIfAvailable(FunctionTemplate,
                                               FunctionTemplate->getLocation(),
@@ -1277,7 +1399,8 @@
                               FunctionTemplate,
                               FunctionTemplate->getLocation(),
                               FunctionTemplate->getSourceRange().getEnd(),
-                              Builder)) {
+                              Builder,
+                              CTAK_Deduced)) {
       Info.Param = makeTemplateParameter(
                          const_cast<NamedDecl *>(TemplateParams->getParam(I)));
       return TDK_SubstitutionFailure;
@@ -1388,7 +1511,8 @@
     //   Type deduction is done independently for each P/A pair, and
     //   the deduced template argument values are then combined.
     // So we do not reject deductions which were made elsewhere.
-    llvm::SmallVector<TemplateArgument, 8> Deduced(TemplateParams->size());
+    llvm::SmallVector<DeducedTemplateArgument, 8> 
+      Deduced(TemplateParams->size());
     Sema::TemplateDeductionInfo Info(S.Context, Ovl->getNameLoc());
     unsigned TDF = 0;
 
@@ -1459,8 +1583,9 @@
   Sema::LocalInstantiationScope InstScope(*this);
   TemplateParameterList *TemplateParams
     = FunctionTemplate->getTemplateParameters();
-  llvm::SmallVector<TemplateArgument, 4> Deduced;
+  llvm::SmallVector<DeducedTemplateArgument, 4> Deduced;
   llvm::SmallVector<QualType, 4> ParamTypes;
+  unsigned NumExplicitlySpecified = 0;
   if (ExplicitTemplateArgs) {
     TemplateDeductionResult Result =
       SubstituteExplicitTemplateArguments(FunctionTemplate,
@@ -1471,6 +1596,8 @@
                                           Info);
     if (Result)
       return Result;
+
+    NumExplicitlySpecified = Deduced.size();
   } else {
     // Just fill in the parameter types from the function declaration.
     for (unsigned I = 0; I != CheckArgs; ++I)
@@ -1573,6 +1700,7 @@
   }
 
   return FinishTemplateArgumentDeduction(FunctionTemplate, Deduced,
+                                         NumExplicitlySpecified,
                                          Specialization, Info);
 }
 
@@ -1612,7 +1740,8 @@
 
   // Substitute any explicit template arguments.
   Sema::LocalInstantiationScope InstScope(*this);
-  llvm::SmallVector<TemplateArgument, 4> Deduced;
+  llvm::SmallVector<DeducedTemplateArgument, 4> Deduced;
+  unsigned NumExplicitlySpecified = 0;
   llvm::SmallVector<QualType, 4> ParamTypes;
   if (ExplicitTemplateArgs) {
     if (TemplateDeductionResult Result
@@ -1621,6 +1750,8 @@
                                                 Deduced, ParamTypes,
                                                 &FunctionType, Info))
       return Result;
+
+    NumExplicitlySpecified = Deduced.size();
   }
 
   // Template argument deduction for function templates in a SFINAE context.
@@ -1639,6 +1770,7 @@
   }
   
   return FinishTemplateArgumentDeduction(FunctionTemplate, Deduced,
+                                         NumExplicitlySpecified,
                                          Specialization, Info);
 }
 
@@ -1707,7 +1839,7 @@
   //   A) as described in 14.8.2.4.
   TemplateParameterList *TemplateParams
     = FunctionTemplate->getTemplateParameters();
-  llvm::SmallVector<TemplateArgument, 4> Deduced;
+  llvm::SmallVector<DeducedTemplateArgument, 4> Deduced;
   Deduced.resize(TemplateParams->size());
 
   // C++0x [temp.deduct.conv]p4:
@@ -1742,7 +1874,8 @@
   Sema::LocalInstantiationScope InstScope(*this);
   FunctionDecl *Spec = 0;
   TemplateDeductionResult Result
-    = FinishTemplateArgumentDeduction(FunctionTemplate, Deduced, Spec, Info);
+    = FinishTemplateArgumentDeduction(FunctionTemplate, Deduced, 0, Spec, 
+                                      Info);
   Specialization = cast_or_null<CXXConversionDecl>(Spec);
   return Result;
 }
@@ -1800,11 +1933,11 @@
 /// but it may still fail, later, for other reasons.
 static Sema::TemplateDeductionResult
 DeduceTemplateArgumentsDuringPartialOrdering(Sema &S,
-                                          TemplateParameterList *TemplateParams,
+                                        TemplateParameterList *TemplateParams,
                                              QualType ParamIn, QualType ArgIn,
                                              Sema::TemplateDeductionInfo &Info,
-                             llvm::SmallVectorImpl<TemplateArgument> &Deduced,
-    llvm::SmallVectorImpl<DeductionQualifierComparison> *QualifierComparisons) {
+                      llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced,
+   llvm::SmallVectorImpl<DeductionQualifierComparison> *QualifierComparisons) {
   CanQualType Param = S.Context.getCanonicalType(ParamIn);
   CanQualType Arg = S.Context.getCanonicalType(ArgIn);
 
@@ -1878,7 +2011,7 @@
   
   assert(Proto1 && Proto2 && "Function templates must have prototypes");
   TemplateParameterList *TemplateParams = FT2->getTemplateParameters();
-  llvm::SmallVector<TemplateArgument, 4> Deduced;
+  llvm::SmallVector<DeducedTemplateArgument, 4> Deduced;
   Deduced.resize(TemplateParams->size());
 
   // C++0x [temp.deduct.partial]p3:
@@ -2205,7 +2338,7 @@
   // computation is slightly simpler than the general problem of function
   // template partial ordering, because class template partial specializations
   // are more constrained. We know that every template parameter is deduc
-  llvm::SmallVector<TemplateArgument, 4> Deduced;
+  llvm::SmallVector<DeducedTemplateArgument, 4> Deduced;
   Sema::TemplateDeductionInfo Info(Context, Loc);
   
   // Determine whether PS1 is at least as specialized as PS2
@@ -2526,8 +2659,9 @@
 
 /// \brief Marks all of the template parameters that will be deduced by a
 /// call to the given function template.
-void Sema::MarkDeducedTemplateParameters(FunctionTemplateDecl *FunctionTemplate,
-                                         llvm::SmallVectorImpl<bool> &Deduced) {
+void 
+Sema::MarkDeducedTemplateParameters(FunctionTemplateDecl *FunctionTemplate,
+                                    llvm::SmallVectorImpl<bool> &Deduced) {
   TemplateParameterList *TemplateParams 
     = FunctionTemplate->getTemplateParameters();
   Deduced.clear();

Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp?rev=99734&r1=99733&r2=99734&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp Sat Mar 27 21:42:43 2010
@@ -745,101 +745,13 @@
                                             DeclarationName());
     assert(!TargetType.isNull() && "type substitution failed for param type");
     assert(!TargetType->isDependentType() && "param type still dependent");
-
-    if (VD->getDeclContext()->isRecord() && 
-        (isa<CXXMethodDecl>(VD) || isa<FieldDecl>(VD))) {
-      // If the value is a class member, we might have a pointer-to-member.
-      // Determine whether the non-type template template parameter is of
-      // pointer-to-member type. If so, we need to build an appropriate
-      // expression for a pointer-to-member, since a "normal" DeclRefExpr
-      // would refer to the member itself.
-      if (TargetType->isMemberPointerType()) {
-        QualType ClassType
-          = SemaRef.Context.getTypeDeclType(
-                                        cast<RecordDecl>(VD->getDeclContext()));
-        NestedNameSpecifier *Qualifier
-          = NestedNameSpecifier::Create(SemaRef.Context, 0, false,
-                                        ClassType.getTypePtr());
-        CXXScopeSpec SS;
-        SS.setScopeRep(Qualifier);
-        OwningExprResult RefExpr 
-          = SemaRef.BuildDeclRefExpr(VD, 
-                                     VD->getType().getNonReferenceType(), 
-                                     E->getLocation(), 
-                                     &SS);
-        if (RefExpr.isInvalid())
-          return SemaRef.ExprError();
-
-        RefExpr = SemaRef.CreateBuiltinUnaryOp(E->getLocation(), 
-                                               UnaryOperator::AddrOf, 
-                                               move(RefExpr));
-        assert(!RefExpr.isInvalid() &&
-               SemaRef.Context.hasSameType(((Expr*) RefExpr.get())->getType(),
-                                           TargetType));
-        return move(RefExpr);
-      }
-    }
-
-    QualType T = VD->getType().getNonReferenceType();
-
-    if (TargetType->isPointerType()) {
-      // C++03 [temp.arg.nontype]p5:
-      //  - For a non-type template-parameter of type pointer to
-      //    object, qualification conversions and the array-to-pointer
-      //    conversion are applied.
-      //  - For a non-type template-parameter of type pointer to
-      //    function, only the function-to-pointer conversion is
-      //    applied.
-
-      OwningExprResult RefExpr
-        = SemaRef.BuildDeclRefExpr(VD, T, E->getLocation());
-      if (RefExpr.isInvalid())
-        return SemaRef.ExprError();
-
-      // Decay functions and arrays.
-      Expr *RefE = (Expr *)RefExpr.get();
-      SemaRef.DefaultFunctionArrayConversion(RefE);
-      if (RefE != RefExpr.get()) {
-        RefExpr.release();
-        RefExpr = SemaRef.Owned(RefE);
-      }
-
-      // Qualification conversions.
-      RefExpr.release();
-      SemaRef.ImpCastExprToType(RefE, TargetType.getUnqualifiedType(),
-                                CastExpr::CK_NoOp);
-      return SemaRef.Owned(RefE);
-    }
-
-    // If the non-type template parameter has reference type, qualify the
-    // resulting declaration reference with the extra qualifiers on the
-    // type that the reference refers to.
-    if (const ReferenceType *TargetRef = TargetType->getAs<ReferenceType>())
-      T = SemaRef.Context.getQualifiedType(T, 
-                                  TargetRef->getPointeeType().getQualifiers());
-    
-    return SemaRef.BuildDeclRefExpr(VD, T, E->getLocation());
+    return SemaRef.BuildExpressionFromDeclTemplateArgument(Arg,
+                                                           TargetType,
+                                                           E->getLocation());
   }
 
-  assert(Arg.getKind() == TemplateArgument::Integral);
-  QualType T = Arg.getIntegralType();
-  if (T->isCharType() || T->isWideCharType())
-    return SemaRef.Owned(new (SemaRef.Context) CharacterLiteral(
-                                              Arg.getAsIntegral()->getZExtValue(),
-                                              T->isWideCharType(),
-                                              T,
-                                              E->getSourceRange().getBegin()));
-  if (T->isBooleanType())
-    return SemaRef.Owned(new (SemaRef.Context) CXXBoolLiteralExpr(
-                                            Arg.getAsIntegral()->getBoolValue(),
-                                            T,
-                                            E->getSourceRange().getBegin()));
-
-  assert(Arg.getAsIntegral()->getBitWidth() == SemaRef.Context.getIntWidth(T));
-  return SemaRef.Owned(new (SemaRef.Context) IntegerLiteral(
-                                                *Arg.getAsIntegral(),
-                                                T,
-                                                E->getSourceRange().getBegin()));
+  return SemaRef.BuildExpressionFromIntegralTemplateArgument(Arg, 
+                                                E->getSourceRange().getBegin());
 }
                                                    
 

Modified: cfe/trunk/lib/Sema/SemaType.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=99734&r1=99733&r2=99734&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaType.cpp (original)
+++ cfe/trunk/lib/Sema/SemaType.cpp Sat Mar 27 21:42:43 2010
@@ -680,8 +680,11 @@
       return QualType();
     }
     if (ConstVal == 0) {
-      // GCC accepts zero sized static arrays.
-      Diag(ArraySize->getLocStart(), diag::ext_typecheck_zero_array_size)
+      // GCC accepts zero sized static arrays. We allow them when
+      // we're not in a SFINAE context.
+      Diag(ArraySize->getLocStart(), 
+           isSFINAEContext()? diag::err_typecheck_zero_array_size
+                            : diag::ext_typecheck_zero_array_size)
         << ArraySize->getSourceRange();
     }
     T = Context.getConstantArrayType(T, ConstVal, ASM, Quals);

Added: cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p17.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p17.cpp?rev=99734&view=auto
==============================================================================
--- cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p17.cpp (added)
+++ cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p17.cpp Sat Mar 27 21:42:43 2010
@@ -0,0 +1,31 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+template<int i> class A {  };
+template<short s> void f(A<s>); // expected-note{{failed template argument deduction}}
+
+void k1() { 
+  A<1> a;
+  f(a); // expected-error{{no matching function for call}}
+  f<1>(a);
+}
+template<const short cs> class B { }; 
+template<short s> void g(B<s>); 
+void k2() {
+  B<1> b; 
+  g(b); // OK: cv-qualifiers are ignored on template parameter types
+}
+
+template<short s> void h(int (&)[s]); // expected-note{{failed template argument deduction}}
+void k3() {
+  int array[5];
+  h(array);
+  h<5>(array);
+}
+
+template<short s> void h(int (&)[s], A<s>);  // expected-note{{failed template argument deduction}}
+void k4() {
+  A<5> a;
+  int array[5];
+  h(array, a); // expected-error{{no matching function for call}}
+  h<5>(array, a);
+}

Propchange: cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p17.cpp
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p17.cpp
------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p17.cpp
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: cfe/trunk/test/SemaTemplate/temp_arg_nontype.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/temp_arg_nontype.cpp?rev=99734&r1=99733&r2=99734&view=diff
==============================================================================
--- cfe/trunk/test/SemaTemplate/temp_arg_nontype.cpp (original)
+++ cfe/trunk/test/SemaTemplate/temp_arg_nontype.cpp Sat Mar 27 21:42:43 2010
@@ -171,3 +171,12 @@
   int h();
   template int f<int, h>();
 }
+
+namespace PR6723 {
+  template<unsigned char C> void f(int (&a)[C]); // expected-note 2{{candidate template ignored}}
+  void g() {
+    int arr512[512];
+    f(arr512); // expected-error{{no matching function for call}}
+    f<512>(arr512); // expected-error{{no matching function for call}}
+  }
+}





More information about the cfe-commits mailing list