From d7cd6b0df54a29e23adbf98e47965c217f6e0107 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Wed, 30 Jul 2025 12:00:06 -0400 Subject: [PATCH] c++: improve non-constant template arg diagnostic 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 71ae764ce8d9..0b7a05c34555 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 000000000000..b81e85b9044d --- /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 void g() {} +void x() +{ + using fp = void (*)(); + fp f = nullptr; // { dg-message "constexpr" } + g(); // { dg-error "" } + int *p = nullptr; // { dg-message "constexpr" } + g

(); // { dg-error "" } +} diff --git a/gcc/testsuite/g++.dg/tc1/dr49.C b/gcc/testsuite/g++.dg/tc1/dr49.C index 753d96b69771..6ddea6bf2ddd 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; // { dg-error "argument" } -template struct S; // { dg-error "argument" } +template struct R; // { dg-error "template argument|constant expression" } +template struct S; // { dg-error "template argument|constant expression" } int v[5]; template struct R; // 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 0116f23d9452..360f43015170 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 struct foo { }; template struct foo { }; -// { 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() { } -- 2.47.2