]> granicus.if.org Git - clang/commitdiff
When a template-id refers to a single function template, and the
authorDouglas Gregor <dgregor@apple.com>
Mon, 21 Dec 2009 23:17:24 +0000 (23:17 +0000)
committerDouglas Gregor <dgregor@apple.com>
Mon, 21 Dec 2009 23:17:24 +0000 (23:17 +0000)
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

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 [new file with mode: 0644]
test/SemaCXX/decltype-overloaded-functions.cpp

index 25f9693ec0b42b7d5e65b747aa75e0106f559a80..3662bd4793da5ad8e24a49bb9893ffd36b4a09c1 100644 (file)
@@ -589,7 +589,8 @@ def err_temp_copy_deleted : Error<
   
 // 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 @@ def err_template_arg_unnamed_type : Error<
   "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">;
index 8e1ed4137502eada3eb1dfbe503a6de0c9aab2b5..35fee3d8669143c28c900bfd087b8490b0de255a 100644 (file)
@@ -1036,6 +1036,8 @@ public:
 
   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 @@ public:
     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 @@ public:
                           CXXConversionDecl *&Specialization,
                           TemplateDeductionInfo &Info);
 
+  TemplateDeductionResult
+  DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
+                          const TemplateArgumentListInfo *ExplicitTemplateArgs,
+                          FunctionDecl *&Specialization,
+                          TemplateDeductionInfo &Info);
+
   FunctionTemplateDecl *getMoreSpecializedTemplate(FunctionTemplateDecl *FT1,
                                                    FunctionTemplateDecl *FT2,
                                            TemplatePartialOrderingContext TPOC);
index 4565e94ebe8a23eb8514aeba94092d483aefd885..fbcb8074289d823671a6c15a2f1d64694f4c9ff7 100644 (file)
@@ -4591,6 +4591,93 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
   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,
index 9b046e3696a0d4ee00fdf1bf8e5d2d4eedf51d3f..e6bd77d208a8b316bd7577bdac4a5d2d9fd38afd 100644 (file)
@@ -2189,6 +2189,9 @@ bool Sema::CheckTemplateArgument(TemplateTypeParmDecl *Param,
     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;
index 5434beaef1259a58d386fb6b14684d342217f28d..11798c468ab0d104b5908e6606715099d81a9ba9 100644 (file)
@@ -1506,15 +1506,39 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
                               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 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
 }
 
 /// \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 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
   // 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 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
   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, 
index 37f19f2be4c6dfce13aedf8b18204c72c96e8db0..ed30229e952371814d39a48d1ca99c7b05678c02 100644 (file)
@@ -308,7 +308,11 @@ static QualType ConvertDeclSpecToType(Declarator &TheDeclarator, Sema &TheSema){
     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::getQualifiedNameType(const CXXScopeSpec &SS, QualType T) {
 }
 
 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);
 }
diff --git a/test/CXX/temp/temp.fct.spec/temp.arg.explicit/p3-nodeduct.cpp b/test/CXX/temp/temp.fct.spec/temp.arg.explicit/p3-nodeduct.cpp
new file mode 100644 (file)
index 0000000..a8b83d4
--- /dev/null
@@ -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}}
index 6013d0ae8b4e4bba5d61af63b53c33a263d493c5..906e868a42821452631ea6ee3c2b6862854ad451 100644 (file)
@@ -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); };