Tested x86_64-pc-linux-gnu, applying to trunk.

-- 8< --

A conversation today pointed out that the current diagnostic for this case
doesn't mention the constant evaluation failure, it just says e.g.

"'p' is not a valid template argument for 'int*' because it is not the
address of a variable"

This patch improves the diagnostic in C++17 and above (post-N4268) to
diagnose failed constant-evaluation.

gcc/cp/ChangeLog:

        * pt.cc (convert_nontype_argument_function): Check
        cxx_constant_value on failure.
        (invalid_tparm_referent_p): Likewise.

gcc/testsuite/ChangeLog:

        * g++.dg/tc1/dr49.C: Adjust diagnostic.
        * g++.dg/template/func2.C: Likewise.
        * g++.dg/cpp1z/nontype8.C: New test.
---
 gcc/cp/pt.cc                          | 52 +++++++++++++++------------
 gcc/testsuite/g++.dg/cpp1z/nontype8.C | 12 +++++++
 gcc/testsuite/g++.dg/tc1/dr49.C       |  4 +--
 gcc/testsuite/g++.dg/template/func2.C |  3 +-
 4 files changed, 45 insertions(+), 26 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp1z/nontype8.C

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 71ae764ce8d..0b7a05c3455 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -6952,14 +6952,22 @@ convert_nontype_argument_function (tree type, tree expr,
        {
          auto_diagnostic_group d;
          location_t loc = cp_expr_loc_or_input_loc (expr);
-         error_at (loc, "%qE is not a valid template argument for type %qT",
-                   expr, type);
-         if (TYPE_PTR_P (type))
-           inform (loc, "it must be the address of a function "
-                   "with external linkage");
+         tree c;
+         if (cxx_dialect >= cxx17
+             && (c = cxx_constant_value (fn),
+                 c == error_mark_node))
+           ;
          else
-           inform (loc, "it must be the name of a function with "
-                   "external linkage");
+           {
+             error_at (loc, "%qE is not a valid template argument for "
+                       "type %qT", expr, type);
+             if (TYPE_PTR_P (type))
+               inform (loc, "it must be the address of a function "
+                       "with external linkage");
+             else
+               inform (loc, "it must be the name of a function with "
+                       "external linkage");
+           }
        }
       return NULL_TREE;
     }
@@ -7402,22 +7410,22 @@ invalid_tparm_referent_p (tree type, tree expr, 
tsubst_flags_t complain)
        /* Null pointer values are OK in C++11.  */;
       else
        {
-         if (VAR_P (expr))
-           {
-             if (complain & tf_error)
-               error ("%qD is not a valid template argument "
-                      "because %qD is a variable, not the address of "
-                      "a variable", expr, expr);
-             return true;
-           }
+         tree c;
+         if (!(complain & tf_error))
+           ;
+         else if (cxx_dialect >= cxx17
+                  && (c = cxx_constant_value (expr),
+                      c == error_mark_node))
+           ;
+         else if (VAR_P (expr))
+           error ("%qD is not a valid template argument "
+                  "because %qD is a variable, not the address of "
+                  "a variable", expr, expr);
          else
-           {
-             if (complain & tf_error)
-               error ("%qE is not a valid template argument for %qT "
-                      "because it is not the address of a variable",
-                      expr, type);
-             return true;
-           }
+           error ("%qE is not a valid template argument for %qT "
+                  "because it is not the address of a variable",
+                  expr, type);
+         return true;
        }
     }
   return false;
diff --git a/gcc/testsuite/g++.dg/cpp1z/nontype8.C 
b/gcc/testsuite/g++.dg/cpp1z/nontype8.C
new file mode 100644
index 00000000000..b81e85b9044
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/nontype8.C
@@ -0,0 +1,12 @@
+// Test that the diagnostic mentions lack of constexpr
+// { dg-do compile { target c++17 } }
+
+template <auto f> void g() {}
+void x()
+{
+  using fp = void (*)();
+  fp f = nullptr;              // { dg-message "constexpr" }
+  g<f>();                      // { dg-error "" }
+  int *p = nullptr;            // { dg-message "constexpr" }
+  g<p>();                      // { dg-error "" }
+}
diff --git a/gcc/testsuite/g++.dg/tc1/dr49.C b/gcc/testsuite/g++.dg/tc1/dr49.C
index 753d96b6977..6ddea6bf2dd 100644
--- a/gcc/testsuite/g++.dg/tc1/dr49.C
+++ b/gcc/testsuite/g++.dg/tc1/dr49.C
@@ -10,8 +10,8 @@ template struct R<&p>; // OK
 template struct S<&p>; // OK due to parameter adjustment
 
 int *ptr;
-template struct R<ptr>; // { dg-error "argument" }
-template struct S<ptr>; // { dg-error "argument" }
+template struct R<ptr>; // { dg-error "template argument|constant expression" }
+template struct S<ptr>; // { dg-error "template argument|constant expression" }
 
 int v[5];
 template struct R<v>; // OK due to implicit argument conversion
diff --git a/gcc/testsuite/g++.dg/template/func2.C 
b/gcc/testsuite/g++.dg/template/func2.C
index 0116f23d945..360f4301517 100644
--- a/gcc/testsuite/g++.dg/template/func2.C
+++ b/gcc/testsuite/g++.dg/template/func2.C
@@ -4,8 +4,7 @@ typedef void (*fptr)();
 fptr zeroptr = 0;
 template<typename T, fptr F> struct foo { };
 template<typename T> struct foo<T,zeroptr> { };
-// { dg-error "not a valid template argument" "not valid" { target *-*-* } .-1 
} 
-// { dg-message "must be the address" "must be the address " { target *-*-* } 
.-2 }
+// { dg-error "template argument|constant expression" "not valid" { target 
*-*-* } .-1 } 
 
 // The rest is needed to trigger the ICE in 4.0 to 4.3:
 void f() { }

base-commit: 45fd943eabfe8e71aeecf001e9200f4d52748610
-- 
2.50.1

Reply via email to