From cb617bedc8fe8008980841e019f7bddd1cc296ee Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Thu, 19 Feb 2026 07:55:38 +0100 Subject: [PATCH] c++: Fix up convert_nontype_argument [PR124070] Some of the following testcases are incorrectly accepted. The problem is in convert_nontype_argument. It just does maybe_constant_value earlier. Later on for integral/enum/floating point args it uses cxx_constant_value for complain & tf_error if not val_dep_p and expr is not a simple constant, similarly for class type it calls /* Replace the argument with a reference to the corresponding template parameter object. */ if (!val_dep_p) expr = create_template_parm_object (expr, complain); if (expr == error_mark_node) return NULL_TREE; etc. But for NULLPTR_TYPE_P and REFLECTION_TYPE_P cases (I bet Marek has based the latter on the former) it only verifies the type and not the actual expression. I think we need to do that, because if maybe_constant_value fails, it just returns the passed in argument and if nothing checks it, we accept whatever was there (and sometimes ICE later). The following patch implements that. 2026-02-19 Jakub Jelinek PR c++/124070 * pt.cc (convert_nontype_argument): For NULLPTR_TYPE_P case if expr is not integer_zerop and is not val_dep_p try harder, for complain & tf_error use cxx_constant_value and return NULL_TREE for error_mark_node, without tf_error return NULL_TREE. Similarly for REFLECTION_TYPE_P case if expr is not REFLECT_EXPR and is not val_dep_p try harder like for NULLPTR_TYPE_P. * g++.dg/cpp26/pr124070.C: New test. * g++.dg/reflect/parameters_of4.C: Expect different diagnostics. * g++.dg/reflect/define_aggregate7.C: New test. * g++.dg/reflect/define_aggregate8.C: New test. --- gcc/cp/pt.cc | 24 +++++++++++++++++++ gcc/testsuite/g++.dg/cpp26/pr124070.C | 20 ++++++++++++++++ .../g++.dg/reflect/define_aggregate7.C | 13 ++++++++++ .../g++.dg/reflect/define_aggregate8.C | 12 ++++++++++ gcc/testsuite/g++.dg/reflect/parameters_of4.C | 5 ++-- 5 files changed, 72 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp26/pr124070.C create mode 100644 gcc/testsuite/g++.dg/reflect/define_aggregate7.C create mode 100644 gcc/testsuite/g++.dg/reflect/define_aggregate8.C diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 00804a7eea15..c17870039ed2 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -8017,6 +8017,18 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain) "because it is of type %qT", expr, type, TREE_TYPE (expr)); return NULL_TREE; } + if (!integer_zerop (expr) && !val_dep_p) + { + if (complain & tf_error) + { + expr = cxx_constant_value (expr); + if (expr == error_mark_node) + return NULL_TREE; + gcc_assert (integer_zerop (expr)); + } + else + return NULL_TREE; + } return expr; } else if (CLASS_TYPE_P (type)) @@ -8037,6 +8049,18 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain) "because it is of type %qT", expr, type, TREE_TYPE (expr)); return NULL_TREE; } + if (!REFLECT_EXPR_P (expr) && !val_dep_p) + { + if (complain & tf_error) + { + expr = cxx_constant_value (expr); + if (expr == error_mark_node) + return NULL_TREE; + gcc_assert (REFLECT_EXPR_P (expr)); + } + else + return NULL_TREE; + } return expr; } /* A template non-type parameter must be one of the above. */ diff --git a/gcc/testsuite/g++.dg/cpp26/pr124070.C b/gcc/testsuite/g++.dg/cpp26/pr124070.C new file mode 100644 index 000000000000..4721c0ff2154 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp26/pr124070.C @@ -0,0 +1,20 @@ +// PR c++/124070 +// { dg-do compile { target c++26 } } + +constexpr decltype (nullptr) +bar (bool x) +{ + if (x) + throw 1; + return nullptr; +} + +template // { dg-error "uncaught exception '1'" } +constexpr void +foo () +{ +} + +consteval { + foo <> (); // { dg-error "no matching function for call to 'foo<>\\\(\\\)'" } +} diff --git a/gcc/testsuite/g++.dg/reflect/define_aggregate7.C b/gcc/testsuite/g++.dg/reflect/define_aggregate7.C new file mode 100644 index 000000000000..2ea8f86f35e2 --- /dev/null +++ b/gcc/testsuite/g++.dg/reflect/define_aggregate7.C @@ -0,0 +1,13 @@ +// PR c++/124070 +// { dg-do compile { target c++26 } } +// { dg-additional-options "-freflection" } + +#include + +struct S; +template // { dg-error "'define_aggregate' not evaluated from 'consteval' block" } +constexpr void foo () {} + +consteval { + foo <> (); // { dg-error "no matching function for call to 'foo<>\\\(\\\)'" } +} diff --git a/gcc/testsuite/g++.dg/reflect/define_aggregate8.C b/gcc/testsuite/g++.dg/reflect/define_aggregate8.C new file mode 100644 index 000000000000..55372d2e3cad --- /dev/null +++ b/gcc/testsuite/g++.dg/reflect/define_aggregate8.C @@ -0,0 +1,12 @@ +// PR c++/124070 +// { dg-do compile { target c++26 } } +// { dg-additional-options "-freflection" } + +#include + +struct S; +consteval void bar (std::meta::info a = define_aggregate (^^S, {})) {} +consteval { + bar (); +} +S s; diff --git a/gcc/testsuite/g++.dg/reflect/parameters_of4.C b/gcc/testsuite/g++.dg/reflect/parameters_of4.C index a5b4230db770..fe646e2f253f 100644 --- a/gcc/testsuite/g++.dg/reflect/parameters_of4.C +++ b/gcc/testsuite/g++.dg/reflect/parameters_of4.C @@ -4,9 +4,10 @@ #include -template void foo () {} // { dg-message "sorry, unimplemented: mangling" } +template void foo () {} void g () { - foo(); + foo(); // { dg-error "no matching function for call to" } } +// { dg-error "call to non-'constexpr' function" "" { target *-*-* } 0 }