https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87364

            Bug ID: 87364
           Summary: Pretty print of enumerator never prints the id, always
                    falls back to C-style cast output
           Product: gcc
           Version: 8.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: wjwray at gmail dot com
  Target Milestone: ---

In  c-pretty-print.c
    c_pretty_printer::constant calls pp_c_enumeration_constant

/******************** pp_c_enumeration_constant ****************/

/* Attempt to print out an ENUMERATOR. Return true on success.
   Else return false; that means the value was obtained by a cast,
   in which case print out the type-id part of the cast-expression
   -- the casted value is then printed by pp_c_integer_literal. */

static bool
pp_c_enumeration_constant (c_pretty_printer *pp, tree e)
{
  bool value_is_named = true;
  tree type = TREE_TYPE (e);
  tree value;

  /* Find the name of this constant. */
  for (value = TYPE_VALUES (type);
       value != NULL_TREE && !tree_int_cst_equal (TREE_VALUE (value), e);
       value = TREE_CHAIN (value))
    ;

  if (value != NULL_TREE)
    pp->id_expression (TREE_PURPOSE (value));
  else
  {
    /* Value must have been cast. */
    pp_c_type_cast (pp, type);
    value_is_named = false;
  }

  return value_is_named;
}
/***************************************************************/
The code iterates over the enumerators, comparing with the given e,
prints the id if found else falls back to print the C-style cast.

However, the comparison always fails so it always prints the cast
(after iterating over all the enumerators) and never the id.

The comparison in the enumeration loop can be fixed by adding DECL_INITIAL
to 'unwrap' the enumerator's value so it compares correctly as INTEGER_CST,
terminating the loop and pretty-printing the id instead of the C-style cast.

  /* Find the name of this constant. */
  for (value = TYPE_VALUES (type);
       value != NULL_TREE
    && !tree_int_cst_equal (DECL_INITIAL( TREE_VALUE(value)), e);
                           ^^^^^^^^^^^^^                   ^
       value = TREE_CHAIN (value))
     ;

With this patch, the loop exits early when it finds an enumerator of the
given value and prints the found-enumerator's id via:

  if (value != NULL_TREE)
    pp->id_expression (TREE_PURPOSE (value));

However, this one-line fix is not sufficient.
This code is located in c-pretty-print.c and has not been updated
to deal with C++11 scoped enums (pp->id_expression does not print
nested name specifiers as pp_cxx_nested_name_specifier does).
It is not obvious how best to split between c and cxx pretty-print.

I can provide test cases, based on __PRETTY_FUNCTION__ output.
I can also attempt a patch and tests, with some assistance.

The bug also turns up in compiler error message output.
See this Compiler Explorer example https://godbolt.org/z/1df0Sk

  enum e { a, b, c=0 };
  template <auto> struct wauto; // deliberately incomplete to trigger..
  wauto<a> v; // error: aggregate 'wauto<(e)0> v' has incomplete type..

The error output should print 'a' in place of '(e)0'

(Clang prints 'wauto<a>', MSVC prints 'wauto<0>' - no type info.)


The docs need a fix for this exact same issue.
The GCC Internals doc is inconsistent on enumerator value.

GCC Internals https://gcc.gnu.org/onlinedocs/gccint.pdf
Chapter 11 GENERIC 11.3 Types (p 158 of current pdf):

  ENUMERAL_TYPE
    Used to represent an enumeration type
    ... the TREE_VALUE will be an INTEGER_CST giving the value
     assigned to that constant...

 *This is incorrect - TREE_VALUE is not an INTEGER_CST -
  this leads to the bug in pp_c_enumeration_constant.*

Chapter 11 GENERIC  11.4 Declarations (p 161)

  CONST_DECL
    These nodes are used to represent enumeration constants.
    The value of the constant is given by DECL_INITIAL which
    will be an INTEGER_CST with the same type as the TREE_TYPE
    of the CONST_DECL, i.e., an ENUMERAL_TYPE.

 *This is correct - DECL_INITIAL is needed to get the value*

My guess is that DECL_INITIAL was introduced at some point
but not all the code and docs were updated for the change
(I'd be interested to know if this was indeed the case).


A closing thought:
The pretty-printing code will need an overhaul for C++20 with
the proposed changes for generalised non-type template args.

Reply via email to