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.