]> granicus.if.org Git - clang/commitdiff
When explicit template arguments are provided for a function call,
authorDouglas Gregor <dgregor@apple.com>
Tue, 30 Jun 2009 23:57:56 +0000 (23:57 +0000)
committerDouglas Gregor <dgregor@apple.com>
Tue, 30 Jun 2009 23:57:56 +0000 (23:57 +0000)
substitute those template arguments into the function parameter types
prior to template argument deduction. There's still a bit of work to
do to make this work properly when only some of the template arguments
are specified.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@74576 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Sema/Sema.h
lib/Sema/SemaExpr.cpp
lib/Sema/SemaOverload.cpp
lib/Sema/SemaTemplateDeduction.cpp
test/CXX/temp/temp.fct.spec/temp.arg.explicit/p1.cpp

index 2379a1796406db3d462aea8a5d0707e569fac4df..9b906aadbd5945be5c3c8ca2b279325ad1968a87 100644 (file)
@@ -701,6 +701,9 @@ public:
                           bool SuppressUserConversions = false,
                           bool ForceRValue = false);
   void AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate,
+                                    bool HasExplicitTemplateArgs,
+                                  const TemplateArgument *ExplicitTemplateArgs,
+                                    unsigned NumExplicitTemplateArgs,
                                     Expr **Args, unsigned NumArgs,
                                     OverloadCandidateSet& CandidateSet,
                                     bool SuppressUserConversions = false,
@@ -747,6 +750,9 @@ public:
 
   FunctionDecl *ResolveOverloadedCallFn(Expr *Fn, NamedDecl *Callee,
                                         DeclarationName UnqualifiedName,
+                                        bool HasExplicitTemplateArgs,
+                                const TemplateArgument *ExplicitTemplateArgs,
+                                        unsigned NumExplicitTemplateArgs,
                                         SourceLocation LParenLoc,
                                         Expr **Args, unsigned NumArgs,
                                         SourceLocation *CommaLocs, 
@@ -2247,7 +2253,10 @@ public:
     TDK_TooManyArguments,
     /// \brief When performing template argument deduction for a class 
     /// template, there were too few call arguments.
-    TDK_TooFewArguments
+    TDK_TooFewArguments,
+    /// \brief The explicitly-specified template arguments were not valid
+    /// template arguments for the given template.
+    TDK_InvalidExplicitArguments
   };
 
   /// \brief Provides information about an attempted template argument
@@ -2329,6 +2338,9 @@ public:
                    
   TemplateDeductionResult
   DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
+                          bool HasExplicitTemplateArgs,
+                          const TemplateArgument *ExplicitTemplateArgs,
+                          unsigned NumExplicitTemplateArgs,
                           Expr **Args, unsigned NumArgs,
                           FunctionDecl *&Specialization,
                           TemplateDeductionInfo &Info);
index 2ee3c992b66e0d312cc4a950504aa7b966d54630..e9c88d7f6e8884eed7d32014fbb217dc8c7f0891 100644 (file)
@@ -2635,8 +2635,13 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc,
   }
 
   // If we're directly calling a function, get the appropriate declaration.
+  // Also, in C++, keep track of whether we should perform argument-dependent 
+  // lookup and whether there were any explicitly-specified template arguments.
   Expr *FnExpr = Fn;
   bool ADL = true;
+  bool HasExplicitTemplateArgs = 0;
+  const TemplateArgument *ExplicitTemplateArgs = 0;
+  unsigned NumExplicitTemplateArgs = 0;
   while (true) {
     if (ImplicitCastExpr *IcExpr = dyn_cast<ImplicitCastExpr>(FnExpr))
       FnExpr = IcExpr->getSubExpr();
@@ -2661,6 +2666,28 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc,
     } else if (TemplateIdRefExpr *TemplateIdRef 
                  = dyn_cast<TemplateIdRefExpr>(FnExpr)) {
       NDecl = TemplateIdRef->getTemplateName().getAsTemplateDecl();
+      HasExplicitTemplateArgs = true;
+      ExplicitTemplateArgs = TemplateIdRef->getTemplateArgs();
+      NumExplicitTemplateArgs = TemplateIdRef->getNumTemplateArgs();
+      
+      // C++ [temp.arg.explicit]p6:
+      //   [Note: For simple function names, argument dependent lookup (3.4.2)
+      //   applies even when the function name is not visible within the 
+      //   scope of the call. This is because the call still has the syntactic
+      //   form of a function call (3.4.1). But when a function template with
+      //   explicit template arguments is used, the call does not have the
+      //   correct syntactic form unless there is a function template with 
+      //   that name visible at the point of the call. If no such name is 
+      //   visible, the call is not syntactically well-formed and 
+      //   argument-dependent lookup does not apply. If some such name is 
+      //   visible, argument dependent lookup applies and additional function
+      //   templates may be found in other namespaces.
+      //
+      // The summary of this paragraph is that, if we get to this point and the
+      // template-id was not a qualified name, then argument-dependent lookup
+      // is still possible.
+      if (TemplateIdRef->getQualifier())
+        ADL = false;
       break;
     } else {
       // Any kind of name that does not refer to a declaration (or
@@ -2692,8 +2719,12 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc,
       ADL = false;
 
     if (Ovl || FunctionTemplate || ADL) {
-      FDecl = ResolveOverloadedCallFn(Fn, NDecl, UnqualifiedName, LParenLoc, 
-                                      Args, NumArgs, CommaLocs, RParenLoc, ADL);
+      FDecl = ResolveOverloadedCallFn(Fn, NDecl, UnqualifiedName, 
+                                      HasExplicitTemplateArgs,
+                                      ExplicitTemplateArgs,
+                                      NumExplicitTemplateArgs,
+                                      LParenLoc, Args, NumArgs, CommaLocs, 
+                                      RParenLoc, ADL);
       if (!FDecl)
         return ExprError();
 
index f7deb1f26ffe8f56e403d711f26e0cabf28f5156..03ac2d9bb73a43feea59b44ec5a1ffdd91651591 100644 (file)
@@ -2166,8 +2166,9 @@ void Sema::AddFunctionCandidates(const FunctionSet &Functions,
       AddOverloadCandidate(FD, Args, NumArgs, CandidateSet, 
                            SuppressUserConversions);
     else
-      AddTemplateOverloadCandidate(cast<FunctionTemplateDecl>(*F), Args, 
-                                   NumArgs, CandidateSet, 
+      AddTemplateOverloadCandidate(cast<FunctionTemplateDecl>(*F),
+                                   /*FIXME: explicit args */false, 0, 0,
+                                   Args, NumArgs, CandidateSet, 
                                    SuppressUserConversions);
   }
 }
@@ -2273,6 +2274,9 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, Expr *Object,
 /// template specialization.
 void 
 Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate,
+                                   bool HasExplicitTemplateArgs,
+                                 const TemplateArgument *ExplicitTemplateArgs,
+                                   unsigned NumExplicitTemplateArgs,
                                    Expr **Args, unsigned NumArgs,
                                    OverloadCandidateSet& CandidateSet,
                                    bool SuppressUserConversions,
@@ -2289,8 +2293,9 @@ Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate,
   TemplateDeductionInfo Info(Context);
   FunctionDecl *Specialization = 0;
   if (TemplateDeductionResult Result
-        = DeduceTemplateArguments(FunctionTemplate, Args, NumArgs, 
-                                  Specialization, Info)) {
+        = DeduceTemplateArguments(FunctionTemplate, HasExplicitTemplateArgs,
+                                  ExplicitTemplateArgs, NumExplicitTemplateArgs,
+                                  Args, NumArgs, Specialization, Info)) {
     // FIXME: Record what happened with template argument deduction, so
     // that we can give the user a beautiful diagnostic.
     (void)Result;
@@ -3438,8 +3443,9 @@ Sema::AddArgumentDependentLookupCandidates(DeclarationName Name,
     if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*Func))
       AddOverloadCandidate(FD, Args, NumArgs, CandidateSet);
     else
-      AddTemplateOverloadCandidate(cast<FunctionTemplateDecl>(*Func), Args, 
-                                   NumArgs, CandidateSet);
+      AddTemplateOverloadCandidate(cast<FunctionTemplateDecl>(*Func),  
+                                   /*FIXME: explicit args */false, 0, 0,
+                                   Args, NumArgs, CandidateSet);
   }
 }
 
@@ -3758,6 +3764,9 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
 /// arguments and Fn, and returns NULL.
 FunctionDecl *Sema::ResolveOverloadedCallFn(Expr *Fn, NamedDecl *Callee,
                                             DeclarationName UnqualifiedName,
+                                            bool HasExplicitTemplateArgs,
+                                 const TemplateArgument *ExplicitTemplateArgs,
+                                            unsigned NumExplicitTemplateArgs,
                                             SourceLocation LParenLoc,
                                             Expr **Args, unsigned NumArgs,
                                             SourceLocation *CommaLocs, 
@@ -3790,11 +3799,17 @@ FunctionDecl *Sema::ResolveOverloadedCallFn(Expr *Fn, NamedDecl *Callee,
          Func != FuncEnd; ++Func) {
       DeclContext *Ctx = 0;
       if (FunctionDecl *FunDecl = dyn_cast<FunctionDecl>(*Func)) {
+        if (HasExplicitTemplateArgs)
+          continue;
+        
         AddOverloadCandidate(FunDecl, Args, NumArgs, CandidateSet);
         Ctx = FunDecl->getDeclContext();
       } else {
         FunctionTemplateDecl *FunTmpl = cast<FunctionTemplateDecl>(*Func);
-        AddTemplateOverloadCandidate(FunTmpl, Args, NumArgs, CandidateSet);
+        AddTemplateOverloadCandidate(FunTmpl, HasExplicitTemplateArgs,
+                                     ExplicitTemplateArgs,
+                                     NumExplicitTemplateArgs,
+                                     Args, NumArgs, CandidateSet);
         Ctx = FunTmpl->getDeclContext();
       }
 
@@ -3803,6 +3818,7 @@ FunctionDecl *Sema::ResolveOverloadedCallFn(Expr *Fn, NamedDecl *Callee,
         ArgumentDependentLookup = false;
     }
   } else if (FunctionDecl *Func = dyn_cast_or_null<FunctionDecl>(Callee)) {
+    assert(!HasExplicitTemplateArgs && "Explicit template arguments?");
     AddOverloadCandidate(Func, Args, NumArgs, CandidateSet);
 
     if (Func->getDeclContext()->isRecord() ||
@@ -3810,7 +3826,10 @@ FunctionDecl *Sema::ResolveOverloadedCallFn(Expr *Fn, NamedDecl *Callee,
       ArgumentDependentLookup = false;
   } else if (FunctionTemplateDecl *FuncTemplate 
                = dyn_cast_or_null<FunctionTemplateDecl>(Callee)) {
-    AddTemplateOverloadCandidate(FuncTemplate, Args, NumArgs, CandidateSet);
+    AddTemplateOverloadCandidate(FuncTemplate, HasExplicitTemplateArgs,
+                                 ExplicitTemplateArgs,
+                                 NumExplicitTemplateArgs, 
+                                 Args, NumArgs, CandidateSet);
 
     if (FuncTemplate->getDeclContext()->isRecord())
       ArgumentDependentLookup = false;
@@ -3819,6 +3838,7 @@ FunctionDecl *Sema::ResolveOverloadedCallFn(Expr *Fn, NamedDecl *Callee,
   if (Callee)
     UnqualifiedName = Callee->getDeclName();
 
+  // FIXME: Pass explicit template arguments through for ADL
   if (ArgumentDependentLookup)
     AddArgumentDependentLookupCandidates(UnqualifiedName, Args, NumArgs,
                                          CandidateSet);
index 5300385540496b12c53d92b4cbc75218d0d96c72..810de048c2133a1a12e414f4d8a7e43ca956fdcb 100644 (file)
@@ -868,6 +868,16 @@ static bool isSimpleTemplateIdType(QualType T) {
 /// \param FunctionTemplate the function template for which we are performing
 /// template argument deduction.
 ///
+/// \param HasExplicitTemplateArgs whether any template arguments were 
+/// explicitly specified.
+///
+/// \param ExplicitTemplateArguments when @p HasExplicitTemplateArgs is true,
+/// the explicitly-specified template arguments.
+///
+/// \param NumExplicitTemplateArguments when @p HasExplicitTemplateArgs is true,
+/// the number of explicitly-specified template arguments in 
+/// @p ExplicitTemplateArguments. This value may be zero.
+///
 /// \param Args the function call arguments
 ///
 /// \param NumArgs the number of arguments in Args
@@ -880,22 +890,22 @@ static bool isSimpleTemplateIdType(QualType T) {
 /// about template argument deduction.
 ///
 /// \returns the result of template argument deduction.
-///
-/// FIXME: We will also need to pass in any explicitly-specified template
-/// arguments.
 Sema::TemplateDeductionResult
 Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
+                              bool HasExplicitTemplateArgs,
+                              const TemplateArgument *ExplicitTemplateArgs,
+                              unsigned NumExplicitTemplateArgs,
                               Expr **Args, unsigned NumArgs,
                               FunctionDecl *&Specialization,
                               TemplateDeductionInfo &Info) {
   FunctionDecl *Function = FunctionTemplate->getTemplatedDecl();
-  
+
   // C++ [temp.deduct.call]p1:
   //   Template argument deduction is done by comparing each function template
   //   parameter type (call it P) with the type of the corresponding argument
   //   of the call (call it A) as described below.
   unsigned CheckArgs = NumArgs;
-  if (NumArgs < Function->getNumParams())
+  if (NumArgs < Function->getMinRequiredArguments())
     return TDK_TooFewArguments;
   else if (NumArgs > Function->getNumParams()) {
     const FunctionProtoType *Proto 
@@ -905,18 +915,83 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
     
     CheckArgs = Function->getNumParams();
   }
-  
+    
   // Template argument deduction for function templates in a SFINAE context.
   // Trap any errors that might occur.
   SFINAETrap Trap(*this);
-  
-  // Deduce template arguments from the function parameters.
-  llvm::SmallVector<TemplateArgument, 4> Deduced;
-  Deduced.resize(FunctionTemplate->getTemplateParameters()->size());  
+
+  // The types of the parameters from which we will perform template argument
+  // deduction.
   TemplateParameterList *TemplateParams
     = FunctionTemplate->getTemplateParameters();
+  llvm::SmallVector<TemplateArgument, 4> Deduced;
+  llvm::SmallVector<QualType, 4> ParamTypes;
+  if (NumExplicitTemplateArgs) {
+    // C++ [temp.arg.explicit]p3:
+    //   Template arguments that are present shall be specified in the 
+    //   declaration order of their corresponding template-parameters. The 
+    //   template argument list shall not specify more template-arguments than
+    //   there are corresponding template-parameters. 
+    TemplateArgumentListBuilder Builder(TemplateParams, 
+                                        NumExplicitTemplateArgs);
+    if (CheckTemplateArgumentList(FunctionTemplate,
+                                  SourceLocation(), SourceLocation(),
+                                  ExplicitTemplateArgs,
+                                  NumExplicitTemplateArgs,
+                                  SourceLocation(),
+                                  Builder) || Trap.hasErrorOccurred())
+      return TDK_InvalidExplicitArguments;
+
+    // Enter a new template instantiation context for the substitution of the
+    // explicitly-specified template arguments into the 
+    InstantiatingTemplate Inst(*this, FunctionTemplate->getLocation(), 
+                               FunctionTemplate, Deduced.data(), Deduced.size());
+    if (Inst)
+      return TDK_InstantiationDepth;
+
+    // Form the template argument list from the explicitly-specified
+    // template arguments.
+    TemplateArgumentList *ExplicitArgumentList 
+      = new (Context) TemplateArgumentList(Context, Builder, /*TakeArgs=*/true);
+    Info.reset(ExplicitArgumentList);
+    
+    // Instantiate the types of each of the function parameters given the
+    // explicitly-specified template arguments.
+    for (FunctionDecl::param_iterator P = Function->param_begin(),
+                                   PEnd = Function->param_end();
+         P != PEnd;
+         ++P) {
+      QualType ParamType = InstantiateType((*P)->getType(), 
+                                           *ExplicitArgumentList, 
+                                           (*P)->getLocation(), 
+                                           (*P)->getDeclName());
+      if (ParamType.isNull() || Trap.hasErrorOccurred())
+        return TDK_SubstitutionFailure;
+      
+      ParamTypes.push_back(ParamType);
+    }
+    
+    // C++ [temp.arg.explicit]p2:
+    //   Trailing template arguments that can be deduced (14.8.2) may be 
+    //   omitted from the list of explicit template- arguments. If all of the 
+    //   template arguments can be deduced, they may all be omitted; in this
+    //   case, the empty template argument list <> itself may also be omitted.
+    //
+    // Take all of the explicitly-specified arguments and put them into the
+    // set of deduced template arguments. 
+    Deduced.reserve(TemplateParams->size());
+    for (unsigned I = 0, N = ExplicitArgumentList->size(); I != N; ++I)
+      Deduced.push_back(ExplicitArgumentList->get(I));
+  } else {
+    // Just fill in the parameter types from the function declaration.
+    for (unsigned I = 0; I != CheckArgs; ++I)
+      ParamTypes.push_back(Function->getParamDecl(I)->getType());
+  }
+  
+  // Deduce template arguments from the function parameters.
+  Deduced.resize(TemplateParams->size());  
   for (unsigned I = 0; I != CheckArgs; ++I) {
-    QualType ParamType = Function->getParamDecl(I)->getType();
+    QualType ParamType = ParamTypes[I];
     QualType ArgType = Args[I]->getType();
     
     // C++ [temp.deduct.call]p2:
@@ -998,11 +1073,6 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
     // FIXME: C++ [temp.deduct.call] paragraphs 6-9 deal with function
     // pointer parameters. 
   }
-
-  InstantiatingTemplate Inst(*this, FunctionTemplate->getLocation(), 
-                             FunctionTemplate, Deduced.data(), Deduced.size());
-  if (Inst)
-    return TDK_InstantiationDepth;
   
   // C++ [temp.deduct.type]p2:
   //   [...] or if any template argument remains neither deduced nor
@@ -1030,6 +1100,13 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
     = new (Context) TemplateArgumentList(Context, Builder, /*TakeArgs=*/true);
   Info.reset(DeducedArgumentList);
   
+  // Enter a new template instantiation context while we instantiate the
+  // actual function declaration.
+  InstantiatingTemplate Inst(*this, FunctionTemplate->getLocation(), 
+                             FunctionTemplate, Deduced.data(), Deduced.size());
+  if (Inst)
+    return TDK_InstantiationDepth; 
+                                  
   // Substitute the deduced template arguments into the function template 
   // declaration to produce the function template specialization.
   Specialization = cast_or_null<FunctionDecl>(
index 97c5ce96f602462d328c217068db134187bd035b..088a9e55eb3e6759e549dd7906cbe75d9ec71da4 100644 (file)
@@ -2,10 +2,11 @@
 
 template<typename T> struct A { };
 
-template<typename T> T make(A<T>);
+template<typename T> T make();
+template<typename T> T make2(const T&);
 
 void test_make() {
-  int& ir0 = make<int&>(A<int&>());
-  A<int> a0 = make< A<int> >(A<A<int> >());
+  int& ir0 = make<int&>();
+  A<int> a0 = make< A<int> >();
+  A<int> a1 = make2< A<int> >(A<int>());
 }
-