Index: lib/Sema/SemaOverload.cpp
===================================================================
--- lib/Sema/SemaOverload.cpp	(revision 176027)
+++ lib/Sema/SemaOverload.cpp	(working copy)
@@ -9100,11 +9100,13 @@
       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.SameTypesOrCompatibleFunctions(
+              Context.getCanonicalType(Specialization->getType()),
+              TargetFunctionType));
     Matches.push_back(std::make_pair(CurAccessFunPair, Specialization));
     return true;
   }
Index: lib/Sema/SemaTemplateDeduction.cpp
===================================================================
--- lib/Sema/SemaTemplateDeduction.cpp	(revision 176027)
+++ lib/Sema/SemaTemplateDeduction.cpp	(working copy)
@@ -867,6 +867,32 @@
                                                 == 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::SameTypesOrCompatibleFunctions(QualType Param,
+                                          QualType 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 == AdjustedParam;
+
+  // TODO(ftynse): Compatible calling conventions.
+
+  return Param == Arg;
+}
+
 /// \brief Deduce the template arguments by comparing the parameter type and
 /// the argument type (C++ [temp.deduct.type]).
 ///
@@ -1114,13 +1140,15 @@
     
     // If the parameter type is not dependent, there is nothing to deduce.
     if (!Param->isDependentType()) {
-      if (!(TDF & TDF_SkipNonDependent) && Param != Arg)
+      if (!(TDF & TDF_SkipNonDependent) && 
+          !S.SameTypesOrCompatibleFunctions(Param, Arg))
         return Sema::TDK_NonDeducedMismatch;
       
       return Sema::TDK_Success;
     }
   } else if (!Param->isDependentType() &&
-             Param.getUnqualifiedType() == Arg.getUnqualifiedType()) {
+             S.SameTypesOrCompatibleFunctions(Param.getUnqualifiedType(), 
+                                              Arg.getUnqualifiedType())) {
     return Sema::TDK_Success;
   }
 
@@ -3368,10 +3396,14 @@
     return Result;
 
   // If the requested function type does not match the actual type of the
-  // specialization, template argument deduction fails.
+  // specialization with respect to arguments of compatible pointer to function
+  // types, template argument deduction fails.
   if (!ArgFunctionType.isNull() &&
-      !Context.hasSameType(ArgFunctionType, Specialization->getType()))
+      !SameTypesOrCompatibleFunctions(
+        Specialization->getType().getCanonicalType(),
+        ArgFunctionType.getCanonicalType())) {
     return TDK_MiscellaneousDeductionFailure;
+  }
 
   return TDK_Success;
 }
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h	(revision 176027)
+++ include/clang/Sema/Sema.h	(working copy)
@@ -1816,6 +1816,7 @@
   bool IsNoReturnConversion(QualType FromType, QualType ToType,
                             QualType &ResultTy);
   bool DiagnoseMultipleUserDefinedConversion(Expr *From, QualType ToType);
+  bool SameTypesOrCompatibleFunctions(QualType Param, QualType Arg);
 
 
   ExprResult PerformMoveOrCopyInitialization(const InitializedEntity &Entity,
Index: test/SemaCXX/attr-noreturn.cpp
===================================================================
--- test/SemaCXX/attr-noreturn.cpp	(revision 176027)
+++ test/SemaCXX/attr-noreturn.cpp	(working copy)
@@ -80,3 +80,86 @@
   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@+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@+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@+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@+2 {{candidate function [with T = void (*)(int)] not viable: no overload of 'bar' matching 'void (*)(int)' for 1st argument}}
+  // expected-note@+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@+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@+2 {{candidate function not viable: no overload of 'baz' matching 'void (*)(int) __attribute__((noreturn))' for 1st argument}}
+  // expected-note@+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@+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@+2 {{candidate function not viable: no overload of 'baz' matching 'fptr_noreturn_t' (aka 'void (*)(int) __attribute__((noreturn))') for 1st argument}}
+  // expected-note@+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'}}
+  }
+}
