]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++: improve non-constant template arg diagnostic
authorJason Merrill <jason@redhat.com>
Wed, 30 Jul 2025 16:00:06 +0000 (12:00 -0400)
committerJason Merrill <jason@redhat.com>
Wed, 30 Jul 2025 16:00:06 +0000 (12:00 -0400)
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
gcc/testsuite/g++.dg/cpp1z/nontype8.C [new file with mode: 0644]
gcc/testsuite/g++.dg/tc1/dr49.C
gcc/testsuite/g++.dg/template/func2.C

index 71ae764ce8d9a1eb1d07c4dba4ccf5cb50a04764..0b7a05c34555e4f0071f17c4c857151f65f85822 100644 (file)
@@ -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 (file)
index 0000000..b81e85b
--- /dev/null
@@ -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 "" }
+}
index 753d96b6977174804e3f2ea0caa1bf5256cfb23e..6ddea6bf2dddcc7640aaf7033220fdcc049d54c3 100644 (file)
@@ -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
index 0116f23d94523aa88dfb327d4b7e0fe22407d50d..360f43015170e0191e0883bc1d685a83a2722257 100644 (file)
@@ -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() { }