r179680 - Fix PR15291: noreturn adjustment in overload resolution for function templates, from Alexander Zinenko!

Douglas Gregor dgregor at apple.com
Wed Apr 17 01:45:08 PDT 2013


Author: dgregor
Date: Wed Apr 17 03:45:07 2013
New Revision: 179680

URL: http://llvm.org/viewvc/llvm-project?rev=179680&view=rev
Log:
Fix PR15291: noreturn adjustment in overload resolution for function templates, from Alexander Zinenko!

Modified:
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaOverload.cpp
    cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
    cfe/trunk/test/SemaCXX/attr-noreturn.cpp

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=179680&r1=179679&r2=179680&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Wed Apr 17 03:45:07 2013
@@ -1877,7 +1877,7 @@ public:
   bool IsNoReturnConversion(QualType FromType, QualType ToType,
                             QualType &ResultTy);
   bool DiagnoseMultipleUserDefinedConversion(Expr *From, QualType ToType);
-
+  bool isSameOrCompatibleFunctionType(CanQualType Param, CanQualType Arg);
 
   ExprResult PerformMoveOrCopyInitialization(const InitializedEntity &Entity,
                                              const VarDecl *NRVOCandidate,
@@ -5616,7 +5616,8 @@ public:
                           TemplateArgumentListInfo *ExplicitTemplateArgs,
                           QualType ArgFunctionType,
                           FunctionDecl *&Specialization,
-                          sema::TemplateDeductionInfo &Info);
+                          sema::TemplateDeductionInfo &Info,
+                          bool InOverloadResolution = false);
 
   TemplateDeductionResult
   DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
@@ -5628,7 +5629,8 @@ public:
   DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
                           TemplateArgumentListInfo *ExplicitTemplateArgs,
                           FunctionDecl *&Specialization,
-                          sema::TemplateDeductionInfo &Info);
+                          sema::TemplateDeductionInfo &Info,
+                          bool InOverloadResolution = false);
 
   /// \brief Result type of DeduceAutoType.
   enum DeduceAutoResult {

Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=179680&r1=179679&r2=179680&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Wed Apr 17 03:45:07 2013
@@ -9134,17 +9134,19 @@ private:
           = S.DeduceTemplateArguments(FunctionTemplate, 
                                       &OvlExplicitTemplateArgs,
                                       TargetFunctionType, Specialization, 
-                                      Info)) {
+                                      Info, /*InOverloadResolution=*/true)) {
       // FIXME: make a note of the failed deduction for diagnostics.
       (void)Result;
       return false;
     } 
     
-    // Template argument deduction ensures that we have an exact match.
+    // Template argument deduction ensures that we have an exact match or
+    // compatible pointer-to-function arguments that would be adjusted by ICS.
     // This function template specicalization works.
     Specialization = cast<FunctionDecl>(Specialization->getCanonicalDecl());
-    assert(TargetFunctionType
-                      == Context.getCanonicalType(Specialization->getType()));
+    assert(S.isSameOrCompatibleFunctionType(
+              Context.getCanonicalType(Specialization->getType()),
+              Context.getCanonicalType(TargetFunctionType)));
     Matches.push_back(std::make_pair(CurAccessFunPair, Specialization));
     return true;
   }
@@ -9409,7 +9411,8 @@ Sema::ResolveSingleFunctionTemplateSpeci
     TemplateDeductionInfo Info(ovl->getNameLoc());
     if (TemplateDeductionResult Result
           = DeduceTemplateArguments(FunctionTemplate, &ExplicitTemplateArgs,
-                                    Specialization, Info)) {
+                                    Specialization, Info,
+                                    /*InOverloadResolution=*/true)) {
       // FIXME: make a note of the failed deduction for diagnostics.
       (void)Result;
       continue;

Modified: cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp?rev=179680&r1=179679&r2=179680&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp Wed Apr 17 03:45:07 2013
@@ -52,7 +52,11 @@ namespace clang {
     TDF_SkipNonDependent = 0x08,
     /// \brief Whether we are performing template argument deduction for
     /// parameters and arguments in a top-level template argument
-    TDF_TopLevelParameterTypeList = 0x10
+    TDF_TopLevelParameterTypeList = 0x10,
+    /// \brief Within template argument deduction from overload resolution per
+    /// C++ [over.over] allow matching function types that are compatible in
+    /// terms of noreturn and default calling convention adjustments.
+    TDF_InOverloadResolution = 0x20
   };
 }
 
@@ -867,6 +871,32 @@ static bool hasInconsistentOrSupersetQua
                                                 == ParamQs.getCVRQualifiers());
 }
 
+/// \brief Compare types for equality with respect to possibly compatible
+/// function types (noreturn adjustment, implicit calling conventions). If any
+/// of parameter and argument is not a function, just perform type comparison.
+///
+/// \param Param the template parameter type.
+///
+/// \param Arg the argument type.
+bool Sema::isSameOrCompatibleFunctionType(CanQualType Param,
+                                          CanQualType Arg) {
+  const FunctionType *ParamFunction = Param->getAs<FunctionType>(),
+                     *ArgFunction   = Arg->getAs<FunctionType>();
+
+  // Just compare if not functions.
+  if (!ParamFunction || !ArgFunction)
+    return Param == Arg;
+
+  // Noreturn adjustment.
+  QualType AdjustedParam;
+  if (IsNoReturnConversion(Param, Arg, AdjustedParam))
+    return Arg == Context.getCanonicalType(AdjustedParam);
+
+  // FIXME: Compatible calling conventions.
+
+  return Param == Arg;
+}
+
 /// \brief Deduce the template arguments by comparing the parameter type and
 /// the argument type (C++ [temp.deduct.type]).
 ///
@@ -1103,6 +1133,8 @@ DeduceTemplateArgumentsByTypeMatch(Sema
     return Sema::TDK_Success;
 
   // Check the cv-qualifiers on the parameter and argument types.
+  CanQualType CanParam = S.Context.getCanonicalType(Param);
+  CanQualType CanArg = S.Context.getCanonicalType(Arg);
   if (!(TDF & TDF_IgnoreQualifiers)) {
     if (TDF & TDF_ParamWithReferenceType) {
       if (hasInconsistentOrSupersetQualifiersOf(Param, Arg))
@@ -1114,14 +1146,25 @@ DeduceTemplateArgumentsByTypeMatch(Sema
     
     // If the parameter type is not dependent, there is nothing to deduce.
     if (!Param->isDependentType()) {
-      if (!(TDF & TDF_SkipNonDependent) && Param != Arg)
-        return Sema::TDK_NonDeducedMismatch;
-      
+      if (!(TDF & TDF_SkipNonDependent)) {
+        bool NonDeduced = (TDF & TDF_InOverloadResolution)?
+                          !S.isSameOrCompatibleFunctionType(CanParam, CanArg) :
+                          Param != Arg;
+        if (NonDeduced) {
+          return Sema::TDK_NonDeducedMismatch;
+        }
+      }
       return Sema::TDK_Success;
     }
-  } else if (!Param->isDependentType() &&
-             Param.getUnqualifiedType() == Arg.getUnqualifiedType()) {
-    return Sema::TDK_Success;
+  } else if (!Param->isDependentType()) {
+    CanQualType ParamUnqualType = CanParam.getUnqualifiedType(),
+                ArgUnqualType = CanArg.getUnqualifiedType();
+    bool Success = (TDF & TDF_InOverloadResolution)?
+                   S.isSameOrCompatibleFunctionType(ParamUnqualType,
+                                                    ArgUnqualType) :
+                   ParamUnqualType == ArgUnqualType;
+    if (Success)
+      return Sema::TDK_Success;
   }
 
   switch (Param->getTypeClass()) {
@@ -3316,7 +3359,8 @@ Sema::DeduceTemplateArguments(FunctionTe
                               TemplateArgumentListInfo *ExplicitTemplateArgs,
                               QualType ArgFunctionType,
                               FunctionDecl *&Specialization,
-                              TemplateDeductionInfo &Info) {
+                              TemplateDeductionInfo &Info,
+                              bool InOverloadResolution) {
   if (FunctionTemplate->isInvalidDecl())
     return TDK_Invalid;
 
@@ -3348,11 +3392,13 @@ Sema::DeduceTemplateArguments(FunctionTe
   Deduced.resize(TemplateParams->size());
 
   if (!ArgFunctionType.isNull()) {
+    unsigned TDF = TDF_TopLevelParameterTypeList;
+    if (InOverloadResolution) TDF |= TDF_InOverloadResolution;
     // Deduce template arguments from the function type.
     if (TemplateDeductionResult Result
           = DeduceTemplateArgumentsByTypeMatch(*this, TemplateParams,
-                                      FunctionType, ArgFunctionType, Info,
-                                      Deduced, TDF_TopLevelParameterTypeList))
+                                               FunctionType, ArgFunctionType,
+                                               Info, Deduced, TDF))
       return Result;
   }
 
@@ -3363,10 +3409,17 @@ Sema::DeduceTemplateArguments(FunctionTe
     return Result;
 
   // If the requested function type does not match the actual type of the
-  // specialization, template argument deduction fails.
-  if (!ArgFunctionType.isNull() &&
-      !Context.hasSameType(ArgFunctionType, Specialization->getType()))
-    return TDK_MiscellaneousDeductionFailure;
+  // specialization with respect to arguments of compatible pointer to function
+  // types, template argument deduction fails.
+  if (!ArgFunctionType.isNull()) {
+    if (InOverloadResolution && !isSameOrCompatibleFunctionType(
+                           Context.getCanonicalType(Specialization->getType()),
+                           Context.getCanonicalType(ArgFunctionType)))
+      return TDK_MiscellaneousDeductionFailure;
+    else if(!InOverloadResolution &&
+            !Context.hasSameType(Specialization->getType(), ArgFunctionType))
+      return TDK_MiscellaneousDeductionFailure;
+  }
 
   return TDK_Success;
 }
@@ -3499,9 +3552,11 @@ Sema::TemplateDeductionResult
 Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
                               TemplateArgumentListInfo *ExplicitTemplateArgs,
                               FunctionDecl *&Specialization,
-                              TemplateDeductionInfo &Info) {
+                              TemplateDeductionInfo &Info,
+                              bool InOverloadResolution) {
   return DeduceTemplateArguments(FunctionTemplate, ExplicitTemplateArgs,
-                                 QualType(), Specialization, Info);
+                                 QualType(), Specialization, Info,
+                                 InOverloadResolution);
 }
 
 namespace {

Modified: cfe/trunk/test/SemaCXX/attr-noreturn.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/attr-noreturn.cpp?rev=179680&r1=179679&r2=179680&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/attr-noreturn.cpp (original)
+++ cfe/trunk/test/SemaCXX/attr-noreturn.cpp Wed Apr 17 03:45:07 2013
@@ -80,3 +80,86 @@ namespace PR12948 {
   template<typename> void wibble()  __attribute__((__noreturn__));
   template<typename> voidfn wibble;
 }
+
+// PR15291
+// Overload resolution per over.over should allow implicit noreturn adjustment.
+namespace PR15291 {
+  __attribute__((noreturn)) void foo(int) {}
+  __attribute__((noreturn)) void foo(double) {}
+
+  template <typename T>
+  __attribute__((noreturn)) void bar(T) {}
+
+  void baz(int) {}
+  void baz(double) {}
+
+  template <typename T>
+  void qux(T) {}
+
+  // expected-note at +5 {{candidate function [with T = void (*)(int) __attribute__((noreturn))] not viable: no overload of 'baz' matching 'void (*)(int) __attribute__((noreturn))' for 1st argument}}
+  // expected-note at +4 {{candidate function [with T = void (*)(int) __attribute__((noreturn))] not viable: no overload of 'qux' matching 'void (*)(int) __attribute__((noreturn))' for 1st argument}}
+  // expected-note at +3 {{candidate function [with T = void (*)(int) __attribute__((noreturn))] not viable: no overload of 'bar' matching 'void (*)(int) __attribute__((noreturn))' for 1st argument}}
+  // expected-note at +2 {{candidate function [with T = void (*)(int)] not viable: no overload of 'bar' matching 'void (*)(int)' for 1st argument}}
+  // expected-note at +1 {{candidate function [with T = void (int)] not viable: no overload of 'bar' matching 'void (*)(int)' for 1st argument}}
+  template <typename T> void accept_T(T) {}
+
+  // expected-note at +1 {{candidate function not viable: no overload of 'bar' matching 'void (*)(int)' for 1st argument}}
+  void accept_fptr(void (*f)(int)) {
+    f(42);
+  }
+
+  // expected-note at +2 {{candidate function not viable: no overload of 'baz' matching 'void (*)(int) __attribute__((noreturn))' for 1st argument}}
+  // expected-note at +1 {{candidate function not viable: no overload of 'qux' matching 'void (*)(int) __attribute__((noreturn))' for 1st argument}}
+  void accept_noreturn_fptr(void __attribute__((noreturn)) (*f)(int)) {
+    f(42);
+  }
+
+  typedef void (*fptr_t)(int);
+  typedef void __attribute__((noreturn)) (*fptr_noreturn_t)(int);
+
+  // expected-note at +1 {{candidate function not viable: no overload of 'bar' matching 'fptr_t' (aka 'void (*)(int)') for 1st argument}}
+  void accept_fptr_t(fptr_t f) {
+    f(42);
+  }
+
+  // expected-note at +2 {{candidate function not viable: no overload of 'baz' matching 'fptr_noreturn_t' (aka 'void (*)(int) __attribute__((noreturn))') for 1st argument}}
+  // expected-note at +1 {{candidate function not viable: no overload of 'qux' matching 'fptr_noreturn_t' (aka 'void (*)(int) __attribute__((noreturn))') for 1st argument}}
+  void accept_fptr_noreturn_t(fptr_noreturn_t f) {
+    f(42);
+  }
+
+  // Stripping noreturn should work if everything else is correct.
+  void strip_noreturn() {
+    accept_fptr(foo);
+    accept_fptr(bar<int>);
+    accept_fptr(bar<double>); // expected-error {{no matching function for call to 'accept_fptr'}}
+
+    accept_fptr_t(foo);
+    accept_fptr_t(bar<int>);
+    accept_fptr_t(bar<double>); // expected-error {{no matching function for call to 'accept_fptr_t'}}
+
+    accept_T<void __attribute__((noreturn)) (*)(int)>(foo);
+    accept_T<void __attribute__((noreturn)) (*)(int)>(bar<int>);
+    accept_T<void __attribute__((noreturn)) (*)(int)>(bar<double>); // expected-error {{no matching function for call to 'accept_T'}}
+
+    accept_T<void (*)(int)>(foo);
+    accept_T<void (*)(int)>(bar<int>);
+    accept_T<void (*)(int)>(bar<double>); // expected-error {{no matching function for call to 'accept_T'}}
+
+    accept_T<void (int)>(foo);
+    accept_T<void (int)>(bar<int>);
+    accept_T<void (int)>(bar<double>); // expected-error {{no matching function for call to 'accept_T'}}
+  }
+
+  // Introducing noreturn should not work.
+  void introduce_noreturn() {
+    accept_noreturn_fptr(baz); // expected-error {{no matching function for call to 'accept_noreturn_fptr'}}
+    accept_noreturn_fptr(qux<int>); // expected-error {{no matching function for call to 'accept_noreturn_fptr'}}
+
+    accept_fptr_noreturn_t(baz); // expected-error {{no matching function for call to 'accept_fptr_noreturn_t'}}
+    accept_fptr_noreturn_t(qux<int>); // expected-error {{no matching function for call to 'accept_fptr_noreturn_t'}}
+
+    accept_T<void __attribute__((noreturn)) (*)(int)>(baz); // expected-error {{no matching function for call to 'accept_T'}}
+    accept_T<void __attribute__((noreturn)) (*)(int)>(qux<int>); // expected-error {{no matching function for call to 'accept_T'}}
+  }
+}





More information about the cfe-commits mailing list