Consider this test case: namespace json { enum { JSON_OBJECT }; }
void test () { JSON_OBJECT; } which erroneously accesses an enum value in another namespace without qualifying the access. GCC 6 through 8 issue a suggestion that doesn't mention the namespace: <source>: In function 'void test()': <source>:8:3: error: 'JSON_OBJECT' was not declared in this scope JSON_OBJECT; ^~~~~~~~~~~ <source>:8:3: note: suggested alternative: <source>:3:10: note: 'JSON_OBJECT' enum { JSON_OBJECT }; ^~~~~~~~~~~ which is suboptimal. I made the problem worse with r265610, as gcc 9 now consolidates the single suggestion into the error, and emits: <source>: In function 'void test()': <source>:8:3: error: 'JSON_OBJECT' was not declared in this scope; did you mean 'JSON_OBJECT'? 8 | JSON_OBJECT; | ^~~~~~~~~~~ | JSON_OBJECT <source>:3:10: note: 'JSON_OBJECT' declared here 3 | enum { JSON_OBJECT }; | ^~~~~~~~~~~ where the message: 'JSON_OBJECT' was not declared in this scope; did you mean 'JSON_OBJECT'? is nonsensical. The root cause is that dump_scope doesn't print anything when called for CONST_DECL in a namespace: the scope is an ENUMERAL_TYPE, rather than a namespace. This patch tweaks dump_scope to detect ENUMERAL_TYPE, and to use the enclosing namespace, so that the CONST_DECL is dumped as "json::JSON_OBJECT". This changes the output for the above so that it refers to the namespace, fixing the issue: <source>:8:3: error: 'JSON_OBJECT' was not declared in this scope; did you mean 'json::JSON_OBJECT'? 9 | JSON_OBJECT; | ^~~~~~~~~~~ | json::JSON_OBJECT <source>3:10: note: 'json::JSON_OBJECT' declared here 3 | enum { JSON_OBJECT }; | ^~~~~~~~~~~ Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu. OK for trunk? gcc/cp/ChangeLog: PR c++/88121 * error.c (dump_scope): Handle ENUMERAL_TYPE by using the CP_TYPE_CONTEXT of the type. gcc/testsuite/ChangeLog: PR c++/88121 * g++.dg/lookup/suggestions-scoped-enums.C: New test. * g++.dg/lookup/suggestions-unscoped-enums.C: New test. --- gcc/cp/error.c | 6 ++ .../g++.dg/lookup/suggestions-scoped-enums.C | 13 ++++ .../g++.dg/lookup/suggestions-unscoped-enums.C | 91 ++++++++++++++++++++++ 3 files changed, 110 insertions(+) create mode 100644 gcc/testsuite/g++.dg/lookup/suggestions-scoped-enums.C create mode 100644 gcc/testsuite/g++.dg/lookup/suggestions-unscoped-enums.C diff --git a/gcc/cp/error.c b/gcc/cp/error.c index 72b42bd..6fee62d 100644 --- a/gcc/cp/error.c +++ b/gcc/cp/error.c @@ -182,6 +182,12 @@ dump_scope (cxx_pretty_printer *pp, tree scope, int flags) if (scope == NULL_TREE) return; + /* Enum values will be CONST_DECL with an ENUMERAL_TYPE as their + "scope". Use CP_TYPE_CONTEXT of the ENUMERAL_TYPE, so as to + print the enclosing namespace. */ + if (TREE_CODE (scope) == ENUMERAL_TYPE) + scope = CP_TYPE_CONTEXT (scope); + if (TREE_CODE (scope) == NAMESPACE_DECL) { if (scope != global_namespace) diff --git a/gcc/testsuite/g++.dg/lookup/suggestions-scoped-enums.C b/gcc/testsuite/g++.dg/lookup/suggestions-scoped-enums.C new file mode 100644 index 0000000..2bf3ed6 --- /dev/null +++ b/gcc/testsuite/g++.dg/lookup/suggestions-scoped-enums.C @@ -0,0 +1,13 @@ +// { dg-do compile { target c++11 } } +// { dg-options "-fdiagnostics-show-caret" } + +enum class vegetable { CARROT, TURNIP }; + +void misspelled_value_in_scoped_enum () +{ + vegetable::TURNUP; // { dg-error "'TURNUP' is not a member of 'vegetable'" } + /* { dg-begin-multiline-output "" } + vegetable::TURNUP; + ^~~~~~ + { dg-end-multiline-output "" } */ +} diff --git a/gcc/testsuite/g++.dg/lookup/suggestions-unscoped-enums.C b/gcc/testsuite/g++.dg/lookup/suggestions-unscoped-enums.C new file mode 100644 index 0000000..bc610d0 --- /dev/null +++ b/gcc/testsuite/g++.dg/lookup/suggestions-unscoped-enums.C @@ -0,0 +1,91 @@ +// { dg-options "-fdiagnostics-show-caret" } + +enum { LASAGNA, SPAGHETTI }; +namespace outer_ns_a +{ + enum enum_in_outer_ns_a { STRAWBERRY, BANANA }; + namespace inner_ns + { + enum enum_in_inner_ns { ELEPHANT, LION }; + } +} +namespace outer_ns_2 +{ + enum enum_in_outer_ns_2 { NIGHT, DAY }; +} + +void misspelled_enum_in_global_ns () +{ + SPOOGHETTI; // { dg-error "'SPOOGHETTI' was not declared in this scope; did you mean 'SPAGHETTI'" } + /* { dg-begin-multiline-output "" } + SPOOGHETTI; + ^~~~~~~~~~ + SPAGHETTI + { dg-end-multiline-output "" } */ +} + +void unqualified_enum_in_outer_ns () +{ + BANANA; // { dg-error "'BANANA' was not declared in this scope; did you mean 'outer_ns_a::BANANA'" } + /* { dg-begin-multiline-output "" } + BANANA; + ^~~~~~ + outer_ns_a::BANANA + { dg-end-multiline-output "" } */ + /* { dg-begin-multiline-output "" } + enum enum_in_outer_ns_a { STRAWBERRY, BANANA }; + ^~~~~~ + { dg-end-multiline-output "" } */ +} + +namespace outer_ns_a +{ + void misspelled_unqualified_enum_in_outer_ns () { + BANANAS; // { dg-error "'BANANAS' was not declared in this scope; did you mean 'BANANA'" } + /* { dg-begin-multiline-output "" } + BANANAS; + ^~~~~~~ + BANANA + { dg-end-multiline-output "" } */ + } +}; + +void unqualified_enum_in_inner_ns () +{ + ELEPHANT; // { dg-error "'ELEPHANT' was not declared in this scope; did you mean 'outer_ns_a::inner_ns::ELEPHANT'" } + /* { dg-begin-multiline-output "" } + ELEPHANT; + ^~~~~~~~ + outer_ns_a::inner_ns::ELEPHANT + { dg-end-multiline-output "" } */ + /* { dg-begin-multiline-output "" } + enum enum_in_inner_ns { ELEPHANT, LION }; + ^~~~~~~~ + { dg-end-multiline-output "" } */ +} + +void partially_qualified_enum_in_inner_ns () +{ + outer_ns_a::ELEPHANT; // { dg-error "'ELEPHANT' is not a member of 'outer_ns_a'; did you mean 'outer_ns_a::inner_ns::ELEPHANT'" } + /* { dg-begin-multiline-output "" } + outer_ns_a::ELEPHANT; + ^~~~~~~~ + { dg-end-multiline-output "" } */ + /* { dg-begin-multiline-output "" } + enum enum_in_inner_ns { ELEPHANT, LION }; + ^~~~~~~~ + { dg-end-multiline-output "" } */ +} + +void wrongly_qualified_enum () +{ + outer_ns_a::NIGHT; // { dg-error "'NIGHT' is not a member of 'outer_ns_a'; did you mean 'outer_ns_2::NIGHT'" } + /* { dg-begin-multiline-output "" } + outer_ns_a::NIGHT; + ^~~~~ + { dg-end-multiline-output "" } */ + /* { dg-begin-multiline-output "" } + enum enum_in_outer_ns_2 { NIGHT, DAY }; + ^~~~~ + { dg-end-multiline-output "" } */ +} -- 1.8.5.3