Mordante updated this revision to Diff 224753.
Mordante added a comment.

Removed the language version test.

I also added `clang/test/CXX/conv/conv.fctptr/template-noreturn.cpp` to show 
this is not enough to allow `noreturn` to all language versions, so this file 
should not be committed.

Do you want me to look at a way to allow the `noreturn` for C++98/C++11? If yes 
I prefer to make that a separate commit.

AFAIK the `[[noreturn]]` conversion is a clang extension, should I file a DR 
for the standard? AFAIK there isn't one yet.

If you still like the patch could you commit it (except 
`clang/test/CXX/conv/conv.fctptr/template-noreturn.cpp`) since I don't have 
commit access?


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D64874/new/

https://reviews.llvm.org/D64874

Files:
  clang/lib/Sema/SemaTemplate.cpp
  clang/test/CXX/conv/conv.fctptr/template-noexcept.cpp
  clang/test/CXX/conv/conv.fctptr/template-noreturn.cpp

Index: clang/test/CXX/conv/conv.fctptr/template-noreturn.cpp
===================================================================
--- /dev/null
+++ clang/test/CXX/conv/conv.fctptr/template-noreturn.cpp
@@ -0,0 +1,36 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++14 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++17 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++2a -fsyntax-only -verify %s
+
+typedef int (*fp)();
+typedef int (*fpnr)() __attribute__((noreturn));
+#if __cplusplus < 201703L
+// expected-note@+2 {{template parameter is declared here}}
+#endif
+template <fp>
+struct FP {};
+
+#if __cplusplus < 201703L
+// expected-note@+2 {{template parameter is declared here}}
+#endif
+template <fpnr>
+struct FPNR {};
+
+int f();
+int fnr() __attribute__((noreturn));
+
+FP<&f> fp_valid;
+FPNR<&fnr> fpnr_valid;
+
+#if __cplusplus < 201703L
+// expected-error@+2 {{non-type template argument of type 'int (*)() __attribute__((noreturn))' cannot be converted to a value of type 'fp' (aka 'int (*)()')}}
+#endif
+FP<&fnr> fp_invalid_before_cxx17;
+
+#if __cplusplus < 201703L
+// expected-error@+4 {{non-type template argument of type 'int (*)()' cannot be converted to a value of type 'fpnr' (aka 'int (*)() __attribute__((noreturn))')}}
+#else
+// expected-error@+2 {{value of type 'int (*)()' is not implicitly convertible to 'fpnr' (aka 'int (*)() __attribute__((noreturn))')}}
+#endif
+FPNR<&f> fpnr_invalid;
Index: clang/test/CXX/conv/conv.fctptr/template-noexcept.cpp
===================================================================
--- /dev/null
+++ clang/test/CXX/conv/conv.fctptr/template-noexcept.cpp
@@ -0,0 +1,44 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++14 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++17 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++2a -fsyntax-only -verify %s
+
+// Starting with C++17 the noexcept is part of the function signature but
+// a noexcept function can be converted to a noexcept(false) function.
+// The tests were added for PR40024.
+
+#if __cplusplus < 201703L
+// expected-no-diagnostics
+#endif
+
+namespace valid_conversion {
+struct S {
+  int f(void) noexcept { return 110; }
+} s;
+
+template <int (S::*a)(void)>
+int f10(void) { return (s.*a)(); }
+
+int foo(void) {
+  return f10<&S::f>();
+}
+} // namespace valid_conversion
+
+namespace invalid_conversion {
+struct S {
+  int f(void) { return 110; }
+} s;
+
+#if __cplusplus >= 201703L
+// expected-note@+3 {{candidate template ignored: invalid explicitly-specified argument for template parameter 'a'}}
+#endif
+template <int (S::*a)(void) noexcept>
+int f10(void) { return (s.*a)(); }
+
+#if __cplusplus >= 201703L
+// expected-error@+3 {{no matching function for call to 'f10'}}
+#endif
+int foo(void) {
+  return f10<&S::f>();
+}
+} // namespace invalid_conversion
Index: clang/lib/Sema/SemaTemplate.cpp
===================================================================
--- clang/lib/Sema/SemaTemplate.cpp
+++ clang/lib/Sema/SemaTemplate.cpp
@@ -6991,6 +6991,13 @@
                                     ObjCLifetimeConversion))
         RefExpr = ImpCastExprToType(RefExpr.get(), ParamType.getUnqualifiedType(), CK_NoOp);
 
+      // Starting with C++17 the noexcept is part of the function signature but
+      // a noexcept function can be converted to a noexcept(false) function.
+      QualType ResultTy;
+      if (IsFunctionConversion(((Expr *)RefExpr.get())->getType(),
+                               ParamType.getUnqualifiedType(), ResultTy))
+        RefExpr = ImpCastExprToType(RefExpr.get(), ResultTy, CK_NoOp);
+
       assert(!RefExpr.isInvalid() &&
              Context.hasSameType(((Expr*) RefExpr.get())->getType(),
                                  ParamType.getUnqualifiedType()));
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D64874: [... Richard Smith - zygoloid via Phabricator via cfe-commits
    • [PATCH] D648... Mark de Wever via Phabricator via cfe-commits

Reply via email to