When a template-id refers to a single function template, and the
explicitly-specified template arguments are enough to determine the
instantiation, and either template argument deduction fails or is not
performed in that context, we can resolve the template-id down to a
function template specialization (so sayeth C++0x
[temp.arg.explicit]p3). Fixes PR5811.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@91852 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 8e1ed41..35fee3d 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -1036,6 +1036,8 @@
 
   FunctionDecl *ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
                                                    bool Complain);
+  FunctionDecl *ResolveSingleFunctionTemplateSpecialization(Expr *From);
+
   Expr *FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn);
   OwningExprResult FixOverloadedFunctionReference(OwningExprResult, 
                                                   FunctionDecl *Fn);
@@ -2664,7 +2666,10 @@
     TDK_TooFewArguments,
     /// \brief The explicitly-specified template arguments were not valid
     /// template arguments for the given template.
-    TDK_InvalidExplicitArguments
+    TDK_InvalidExplicitArguments,
+    /// \brief The arguments included an overloaded function name that could
+    /// not be resolved to a suitable function.
+    TDK_FailedOverloadResolution
   };
 
   /// \brief Provides information about an attempted template argument
@@ -2778,6 +2783,12 @@
                           CXXConversionDecl *&Specialization,
                           TemplateDeductionInfo &Info);
 
+  TemplateDeductionResult
+  DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
+                          const TemplateArgumentListInfo *ExplicitTemplateArgs,
+                          FunctionDecl *&Specialization,
+                          TemplateDeductionInfo &Info);
+
   FunctionTemplateDecl *getMoreSpecializedTemplate(FunctionTemplateDecl *FT1,
                                                    FunctionTemplateDecl *FT2,
                                            TemplatePartialOrderingContext TPOC);
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index 4565e94..fbcb807 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -4591,6 +4591,93 @@
   return 0;
 }
 
+/// \brief Given an expression that refers to an overloaded function, try to 
+/// resolve that overloaded function expression down to a single function.
+///
+/// This routine can only resolve template-ids that refer to a single function
+/// template, where that template-id refers to a single template whose template
+/// arguments are either provided by the template-id or have defaults, 
+/// as described in C++0x [temp.arg.explicit]p3.
+FunctionDecl *Sema::ResolveSingleFunctionTemplateSpecialization(Expr *From) {
+  // C++ [over.over]p1:
+  //   [...] [Note: any redundant set of parentheses surrounding the
+  //   overloaded function name is ignored (5.1). ]
+  Expr *OvlExpr = From->IgnoreParens();
+  
+  // C++ [over.over]p1:
+  //   [...] The overloaded function name can be preceded by the &
+  //   operator.
+  if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(OvlExpr)) {
+    if (UnOp->getOpcode() == UnaryOperator::AddrOf)
+      OvlExpr = UnOp->getSubExpr()->IgnoreParens();
+  }
+  
+  bool HasExplicitTemplateArgs = false;
+  TemplateArgumentListInfo ExplicitTemplateArgs;
+  
+  llvm::SmallVector<NamedDecl*,8> Fns;
+  
+  // Look into the overloaded expression.
+  if (UnresolvedLookupExpr *UL
+      = dyn_cast<UnresolvedLookupExpr>(OvlExpr)) {
+    Fns.append(UL->decls_begin(), UL->decls_end());
+    if (UL->hasExplicitTemplateArgs()) {
+      HasExplicitTemplateArgs = true;
+      UL->copyTemplateArgumentsInto(ExplicitTemplateArgs);
+    }
+  } else if (UnresolvedMemberExpr *ME
+             = dyn_cast<UnresolvedMemberExpr>(OvlExpr)) {
+    Fns.append(ME->decls_begin(), ME->decls_end());
+    if (ME->hasExplicitTemplateArgs()) {
+      HasExplicitTemplateArgs = true;
+      ME->copyTemplateArgumentsInto(ExplicitTemplateArgs);
+    }
+  }
+  
+  // If we didn't actually find any template-ids, we're done.
+  if (Fns.empty() || !HasExplicitTemplateArgs)
+    return 0;
+  
+  // Look through all of the overloaded functions, searching for one
+  // whose type matches exactly.
+  FunctionDecl *Matched = 0;
+  for (llvm::SmallVectorImpl<NamedDecl*>::iterator I = Fns.begin(),
+       E = Fns.end(); I != E; ++I) {
+    // C++0x [temp.arg.explicit]p3:
+    //   [...] In contexts where deduction is done and fails, or in contexts
+    //   where deduction is not done, if a template argument list is 
+    //   specified and it, along with any default template arguments, 
+    //   identifies a single function template specialization, then the 
+    //   template-id is an lvalue for the function template specialization.
+    FunctionTemplateDecl *FunctionTemplate = cast<FunctionTemplateDecl>(*I);
+    
+    // C++ [over.over]p2:
+    //   If the name is a function template, template argument deduction is
+    //   done (14.8.2.2), and if the argument deduction succeeds, the
+    //   resulting template argument list is used to generate a single
+    //   function template specialization, which is added to the set of
+    //   overloaded functions considered.
+    // FIXME: We don't really want to build the specialization here, do we?
+    FunctionDecl *Specialization = 0;
+    TemplateDeductionInfo Info(Context);
+    if (TemplateDeductionResult Result
+          = DeduceTemplateArguments(FunctionTemplate, &ExplicitTemplateArgs,
+                                    Specialization, Info)) {
+      // FIXME: make a note of the failed deduction for diagnostics.
+      (void)Result;
+      continue;
+    } 
+    
+    // Multiple matches; we can't resolve to a single declaration.
+    if (Matched)
+      return 0;
+
+    Matched = Specialization;
+  }
+
+  return Matched;
+}
+    
 /// \brief Add a single candidate to the overload set.
 static void AddOverloadedCallCandidate(Sema &S,
                                        NamedDecl *Callee,
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 9b046e3..e6bd77d 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -2189,6 +2189,9 @@
     Diag(SR.getBegin(), diag::err_template_arg_unnamed_type) << SR;
     Diag(Tag->getDecl()->getLocation(), diag::note_template_unnamed_type_here);
     return true;
+  } else if (Context.hasSameUnqualifiedType(Arg, Context.OverloadTy)) {
+    SourceRange SR = ArgInfo->getTypeLoc().getFullSourceRange();
+    return Diag(SR.getBegin(), diag::err_template_arg_overload_type) << SR;
   }
 
   return false;
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp
index 5434bea..11798c4 100644
--- a/lib/Sema/SemaTemplateDeduction.cpp
+++ b/lib/Sema/SemaTemplateDeduction.cpp
@@ -1506,15 +1506,39 @@
                               ParamType->getAs<PointerType>()->getPointeeType())))
       TDF |= TDF_DerivedClass;
 
+    // FIXME: C++0x [temp.deduct.call] paragraphs 6-9 deal with function
+    // pointer parameters.
+    
+    if (Context.hasSameUnqualifiedType(ArgType, Context.OverloadTy)) {
+      // We know that template argument deduction will fail if the argument is
+      // still an overloaded function. Check whether we can resolve this 
+      // argument as a single function template specialization per
+      // C++ [temp.arg.explicit]p3.
+      FunctionDecl *ExplicitSpec
+        = ResolveSingleFunctionTemplateSpecialization(Args[I]);
+      Expr *ResolvedArg = 0;
+      if (ExplicitSpec)
+        ResolvedArg = FixOverloadedFunctionReference(Args[I], ExplicitSpec);
+      if (!ExplicitSpec || !ResolvedArg) {
+        // Template argument deduction fails if we can't resolve the overloaded
+        // function.
+        return TDK_FailedOverloadResolution;
+      }
+      
+      // Get the type of the resolved argument.
+      ArgType = ResolvedArg->getType();
+      if (ArgType->isPointerType() || ArgType->isMemberPointerType())
+        TDF |= TDF_IgnoreQualifiers;
+      
+      ResolvedArg->Destroy(Context);
+    }
+    
     if (TemplateDeductionResult Result
         = ::DeduceTemplateArguments(Context, TemplateParams,
                                     ParamType, ArgType, Info, Deduced,
                                     TDF))
       return Result;
 
-    // FIXME: C++0x [temp.deduct.call] paragraphs 6-9 deal with function
-    // pointer parameters.
-
     // FIXME: we need to check that the deduced A is the same as A,
     // modulo the various allowed differences.
   }
@@ -1524,24 +1548,19 @@
 }
 
 /// \brief Deduce template arguments when taking the address of a function
-/// template (C++ [temp.deduct.funcaddr]) or matching a 
+/// template (C++ [temp.deduct.funcaddr]) or matching a specialization to
+/// a template.
 ///
 /// \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 ExplicitTemplateArguments the explicitly-specified template 
+/// arguments.
 ///
 /// \param ArgFunctionType the function type that will be used as the
 /// "argument" type (A) when performing template argument deduction from the
-/// function template's function type.
+/// function template's function type. This type may be NULL, if there is no
+/// argument type to compare against, in C++0x [temp.arg.explicit]p3.
 ///
 /// \param Specialization if template argument deduction was successful,
 /// this will be set to the function template specialization produced by
@@ -1578,14 +1597,16 @@
   // Trap any errors that might occur.
   SFINAETrap Trap(*this);
 
-  // Deduce template arguments from the function type.
-  Deduced.resize(TemplateParams->size());
-  if (TemplateDeductionResult Result
-        = ::DeduceTemplateArguments(Context, TemplateParams,
-                                    FunctionType, ArgFunctionType, Info,
-                                    Deduced, 0))
-    return Result;
-
+  if (!ArgFunctionType.isNull()) {
+    // Deduce template arguments from the function type.
+    Deduced.resize(TemplateParams->size());
+    if (TemplateDeductionResult Result
+          = ::DeduceTemplateArguments(Context, TemplateParams,
+                                      FunctionType, ArgFunctionType, Info,
+                                      Deduced, 0))
+      return Result;
+  }
+  
   return FinishTemplateArgumentDeduction(FunctionTemplate, Deduced,
                                          Specialization, Info);
 }
@@ -1694,6 +1715,32 @@
   return Result;
 }
 
+/// \brief Deduce template arguments for a function template when there is
+/// nothing to deduce against (C++0x [temp.arg.explicit]p3).
+///
+/// \param FunctionTemplate the function template for which we are performing
+/// template argument deduction.
+///
+/// \param ExplicitTemplateArguments the explicitly-specified template 
+/// arguments.
+///
+/// \param Specialization if template argument deduction was successful,
+/// this will be set to the function template specialization produced by
+/// template argument deduction.
+///
+/// \param Info the argument will be updated to provide additional information
+/// about template argument deduction.
+///
+/// \returns the result of template argument deduction.
+Sema::TemplateDeductionResult
+Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
+                           const TemplateArgumentListInfo *ExplicitTemplateArgs,
+                              FunctionDecl *&Specialization,
+                              TemplateDeductionInfo &Info) {
+  return DeduceTemplateArguments(FunctionTemplate, ExplicitTemplateArgs,
+                                 QualType(), Specialization, Info);
+}
+
 /// \brief Stores the result of comparing the qualifiers of two types.
 enum DeductionQualifierComparison { 
   NeitherMoreQualified = 0, 
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index 37f19f2..ed30229 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -308,7 +308,11 @@
     Expr *E = static_cast<Expr *>(DS.getTypeRep());
     assert(E && "Didn't get an expression for typeof?");
     // TypeQuals handled by caller.
-    Result = Context.getTypeOfExprType(E);
+    Result = TheSema.BuildTypeofExprType(E);
+    if (Result.isNull()) {
+      Result = Context.IntTy;
+      TheDeclarator.setInvalidType(true);
+    }
     break;
   }
   case DeclSpec::TST_decltype: {
@@ -1826,14 +1830,41 @@
 }
 
 QualType Sema::BuildTypeofExprType(Expr *E) {
+  if (E->getType() == Context.OverloadTy) {
+    // C++ [temp.arg.explicit]p3 allows us to resolve a template-id to a 
+    // function template specialization wherever deduction cannot occur.
+    if (FunctionDecl *Specialization
+        = ResolveSingleFunctionTemplateSpecialization(E)) {
+      E = FixOverloadedFunctionReference(E, Specialization);
+      if (!E)
+        return QualType();      
+    } else {
+      Diag(E->getLocStart(),
+           diag::err_cannot_determine_declared_type_of_overloaded_function)
+        << false << E->getSourceRange();
+      return QualType();
+    }
+  }
+  
   return Context.getTypeOfExprType(E);
 }
 
 QualType Sema::BuildDecltypeType(Expr *E) {
   if (E->getType() == Context.OverloadTy) {
-    Diag(E->getLocStart(),
-         diag::err_cannot_determine_declared_type_of_overloaded_function);
-    return QualType();
+    // C++ [temp.arg.explicit]p3 allows us to resolve a template-id to a 
+    // function template specialization wherever deduction cannot occur.
+    if (FunctionDecl *Specialization
+          = ResolveSingleFunctionTemplateSpecialization(E)) {
+      E = FixOverloadedFunctionReference(E, Specialization);
+      if (!E)
+        return QualType();      
+    } else {
+      Diag(E->getLocStart(),
+           diag::err_cannot_determine_declared_type_of_overloaded_function)
+        << true << E->getSourceRange();
+      return QualType();
+    }
   }
+  
   return Context.getDecltypeType(E);
 }