https://gcc.gnu.org/g:72bb6fbbc56fe6a45058f4f6eac0ed6cc4f16473
commit r15-6708-g72bb6fbbc56fe6a45058f4f6eac0ed6cc4f16473 Author: Jason Merrill <ja...@redhat.com> Date: Mon Dec 23 12:32:54 2024 -0500 c++: print stub object as std::declval If the result of build_stub_object gets printed by %E it looks something like '(A&&)1', which seems confusing. Let's instead print it as 'std::declval<A>()' since that's how the library writes the same idea. gcc/cp/ChangeLog: * method.cc (is_stub_object): New. * cp-tree.h (is_stub_object): Declare. * error.cc (dump_expr): Use it. gcc/testsuite/ChangeLog: * g++.dg/gomp/declare-variant-3.C: Update diagnostic. * g++.dg/gomp/declare-variant-5.C: Likewise. Diff: --- gcc/cp/cp-tree.h | 1 + gcc/cp/error.cc | 9 +++++++++ gcc/cp/method.cc | 12 ++++++++++++ gcc/testsuite/g++.dg/gomp/declare-variant-3.C | 4 ++-- gcc/testsuite/g++.dg/gomp/declare-variant-5.C | 4 ++-- 5 files changed, 26 insertions(+), 4 deletions(-) diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 1d741ecedc37..6184d99f4afc 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -7456,6 +7456,7 @@ extern tree get_copy_assign (tree); extern tree get_default_ctor (tree); extern tree get_dtor (tree, tsubst_flags_t); extern tree build_stub_object (tree); +extern bool is_stub_object (tree); extern tree build_invoke (tree, const_tree, tsubst_flags_t); extern tree strip_inheriting_ctors (tree); diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc index feb6853b4f7b..cc4cc4a7eb46 100644 --- a/gcc/cp/error.cc +++ b/gcc/cp/error.cc @@ -2604,6 +2604,15 @@ dump_expr (cxx_pretty_printer *pp, tree t, int flags) dump_expr (pp, CALL_EXPR_FN (t), flags | TFF_EXPR_IN_PARENS); dump_call_expr_args (pp, t, flags, true); } + else if (is_stub_object (t)) + { + pp_string (pp, "std::declval<"); + if (lvalue_p (t)) /* T& */ + dump_type (pp, TREE_TYPE (STRIP_REFERENCE_REF (t)), flags); + else /* T */ + dump_type (pp, TREE_TYPE (t), flags); + pp_string (pp, ">()"); + } else { if (TREE_OPERAND (t,0) != NULL_TREE diff --git a/gcc/cp/method.cc b/gcc/cp/method.cc index 0f9f23ae93a4..64535f52019f 100644 --- a/gcc/cp/method.cc +++ b/gcc/cp/method.cc @@ -1914,6 +1914,18 @@ build_stub_object (tree reftype) return convert_from_reference (stub); } +/* True iff EXPR is the result of build_stub_object. */ + +bool +is_stub_object (tree expr) +{ + if (!REFERENCE_REF_P (expr)) + return false; + expr = TREE_OPERAND (expr, 0); + return (TREE_CODE (expr) == CONVERT_EXPR + && TREE_OPERAND (expr, 0) == integer_one_node); +} + /* Build a std::declval<TYPE>() expression and return it. */ tree diff --git a/gcc/testsuite/g++.dg/gomp/declare-variant-3.C b/gcc/testsuite/g++.dg/gomp/declare-variant-3.C index 376eefc2dc1f..8c0cfd218ad4 100644 --- a/gcc/testsuite/g++.dg/gomp/declare-variant-3.C +++ b/gcc/testsuite/g++.dg/gomp/declare-variant-3.C @@ -86,7 +86,7 @@ struct E { int e; }; void fn19 (E, int); -#pragma omp declare variant (fn19)match(user={condition(0)}) // { dg-error {could not convert '[^']*' from 'int' to 'E'} } +#pragma omp declare variant (fn19)match(user={condition(0)}) // { dg-error {could not convert 'std::declval<int>\(\)' from 'int' to 'E'} } void fn20 (int, E); struct F { operator int () const { return 42; } int f; }; @@ -95,7 +95,7 @@ void fn21 (int, F); #pragma omp declare variant ( fn21 ) match (user = { condition ( 1 - 1 ) } ) // { dg-error "variant 'void fn21\\\(int, F\\\)' and base 'void fn22\\\(F, F\\\)' have incompatible types" } void fn22 (F, F); -#pragma omp declare variant (fn19) match (user={condition(0)}) // { dg-error {could not convert '[^']*' from 'F' to 'E'} } +#pragma omp declare variant (fn19) match (user={condition(0)}) // { dg-error {could not convert 'std::declval<F>\(\)' from 'F' to 'E'} } void fn23 (F, int); void fn24 (int); diff --git a/gcc/testsuite/g++.dg/gomp/declare-variant-5.C b/gcc/testsuite/g++.dg/gomp/declare-variant-5.C index a52fa528e1ff..a4747ac030b9 100644 --- a/gcc/testsuite/g++.dg/gomp/declare-variant-5.C +++ b/gcc/testsuite/g++.dg/gomp/declare-variant-5.C @@ -74,7 +74,7 @@ struct E { int e; }; void fn19 (E, int) {} -#pragma omp declare variant (fn19)match(user={condition(0)}) // { dg-error {could not convert '[^']*' from 'int' to 'E'} } +#pragma omp declare variant (fn19)match(user={condition(0)}) // { dg-error {could not convert 'std::declval<int>\(\)' from 'int' to 'E'} } void fn20 (int, E) {} struct F { operator int () const { return 42; } int f; }; @@ -83,7 +83,7 @@ void fn21 (int, F) {} #pragma omp declare variant ( fn21 ) match (user = { condition ( 1 - 1 ) } ) // { dg-error "variant 'void fn21\\\(int, F\\\)' and base 'void fn22\\\(F, F\\\)' have incompatible types" } void fn22 (F, F) {} -#pragma omp declare variant (fn19) match (user={condition(0)}) // { dg-error {could not convert '[^']*' from 'F' to 'E'} } +#pragma omp declare variant (fn19) match (user={condition(0)}) // { dg-error {could not convert 'std::declval<F>\(\)' from 'F' to 'E'} } void fn23 (F, int) {} void fn24 (int);