[cfe-commits] r91852 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.td lib/Sema/Sema.h lib/Sema/SemaOverload.cpp lib/Sema/SemaTemplate.cpp lib/Sema/SemaTemplateDeduction.cpp lib/Sema/SemaType.cpp test/CXX/temp/temp.fct.spec/temp.arg.explicit/p3-nodeduct.cpp test/SemaCXX/decltype-overloaded-functions.cpp

Douglas Gregor dgregor at apple.com
Mon Dec 21 15:17:24 PST 2009


Author: dgregor
Date: Mon Dec 21 17:17:24 2009
New Revision: 91852

URL: http://llvm.org/viewvc/llvm-project?rev=91852&view=rev
Log:
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.


Added:
    cfe/trunk/test/CXX/temp/temp.fct.spec/temp.arg.explicit/p3-nodeduct.cpp
Modified:
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaOverload.cpp
    cfe/trunk/lib/Sema/SemaTemplate.cpp
    cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
    cfe/trunk/lib/Sema/SemaType.cpp
    cfe/trunk/test/SemaCXX/decltype-overloaded-functions.cpp

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

==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Mon Dec 21 17:17:24 2009
@@ -589,7 +589,8 @@
   
 // C++0x decltype
 def err_cannot_determine_declared_type_of_overloaded_function : Error<
-    "can't determine the declared type of an overloaded function">;
+    "cannot determine the %select{type|declared type}0 of an overloaded "
+    "function">;
     
 // C++0x auto
 def err_auto_variable_cannot_appear_in_own_initializer : Error<
@@ -1007,6 +1008,8 @@
   "template argument uses unnamed type">;
 def note_template_unnamed_type_here : Note<
   "unnamed type used in template argument was declared here">;
+def err_template_arg_overload_type : Error<
+  "template argument is the type of an unresolved overloaded function">;
 def err_template_arg_not_class_template : Error<
   "template argument does not refer to a class template or template "
   "template parameter">;

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

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Mon Dec 21 17:17:24 2009
@@ -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);

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Mon Dec 21 17:17:24 2009
@@ -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,

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Mon Dec 21 17:17:24 2009
@@ -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;

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp Mon Dec 21 17:17:24 2009
@@ -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, 

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaType.cpp (original)
+++ cfe/trunk/lib/Sema/SemaType.cpp Mon Dec 21 17:17:24 2009
@@ -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);
 }

Added: cfe/trunk/test/CXX/temp/temp.fct.spec/temp.arg.explicit/p3-nodeduct.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.fct.spec/temp.arg.explicit/p3-nodeduct.cpp?rev=91852&view=auto

==============================================================================
--- cfe/trunk/test/CXX/temp/temp.fct.spec/temp.arg.explicit/p3-nodeduct.cpp (added)
+++ cfe/trunk/test/CXX/temp/temp.fct.spec/temp.arg.explicit/p3-nodeduct.cpp Mon Dec 21 17:17:24 2009
@@ -0,0 +1,37 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+// PR5811
+template <class F> void Call(F f) { f(1); }
+template <typename T> void f(T);
+void a() { Call(f<int>); }
+
+// Check the conversion of a template-id to a pointer
+template<typename T, T* Address> struct Constant { };
+Constant<void(int), &f<int> > constant0;
+
+template<typename T, T* Address> void constant_func();
+void test_constant_func() {
+  constant_func<void(int), &f<int> >();
+}
+
+
+// Check typeof() on a template-id referring to a single function
+template<typename T, typename U>
+struct is_same {
+  static const bool value = false;
+};
+
+template<typename T>
+struct is_same<T, T> {
+  static const bool value = true;
+};
+
+int typeof0[is_same<__typeof__(f<int>), void (int)>::value? 1 : -1];
+int typeof1[is_same<__typeof__(&f<int>), void (*)(int)>::value? 1 : -1];
+
+template <typename T> void g(T);
+template <typename T> void g(T, T);
+
+int typeof2[is_same<__typeof__(g<float>), void (int)>::value? 1 : -1]; // \
+     // expected-error{{cannot determine the type of an overloaded function}} \
+     // FIXME: expected-error{{use of undeclared identifier}}

Modified: cfe/trunk/test/SemaCXX/decltype-overloaded-functions.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/decltype-overloaded-functions.cpp?rev=91852&r1=91851&r2=91852&view=diff

==============================================================================
--- cfe/trunk/test/SemaCXX/decltype-overloaded-functions.cpp (original)
+++ cfe/trunk/test/SemaCXX/decltype-overloaded-functions.cpp Mon Dec 21 17:17:24 2009
@@ -2,10 +2,10 @@
 
 void f();
 void f(int);
-decltype(f) a; // expected-error{{can't determine the declared type of an overloaded function}}
+decltype(f) a; // expected-error{{cannot determine the declared type of an overloaded function}}
 
 template<typename T> struct S {
-  decltype(T::f) * f; // expected-error{{can't determine the declared type of an overloaded function}}
+  decltype(T::f) * f; // expected-error{{cannot determine the declared type of an overloaded function}}
 };
 
 struct K { void f(); void f(int); };





More information about the cfe-commits mailing list