C++: namespaces and scopes for enum values (PR c++/88121)
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, which 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.
This patch tweaks dump_scope to detect unscoped enums, and to use the
enclosing namespace for them, 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 };
| ^~~~~~~~~~~
The patch also fixes scope-printing for values within scoped enums.
To exercise this, the patch extends the scanner for namespaces for
exact matches for a name, so that we also scan inside scoped
enums, to cover the case where someone doesn't supply the scope.
Hence with the patch given e.g.:
enum class vegetable { CARROT, TURNIP };
we're able to offer e.g.:
suggestions-scoped-enums.C:50:3: error: 'CARROT' was not declared in
this scope; did you mean 'vegetable::CARROT'?
50 | CARROT;
| ^~~~~~
| vegetable::CARROT
and this exercises the code path above. The patch updates dump_scope
for scoped enums so that we print the scope when printing the
value ("vegetable::CARROT"), rather than just the name of the value
("CARROT").
Finally, the patch adds spell-corrections within a scoped enum,
giving e.g.:
suggestions-scoped-enums.C:18:14: error: 'TURNUP' is not a member of
'vegetable'; did you mean 'TURNIP'?
18 | vegetable::TURNUP;
| ^~~~~~
| TURNIP
gcc/cp/ChangeLog:
PR c++/88121
* cp-name-hint.h (suggest_alternative_in_scoped_enum): New decl.
* error.c (dump_scope): Ensure that we print any scope for values
of unscoped enums. Print the scope of values of scoped enums.
(qualified_name_lookup_error): Offer suggestions for failures
within scoped enums by calling suggest_alternative_in_scoped_enum.
* name-lookup.c (class namespace_hints): Update comment to mention
scoped enums.
(namespace_hints::namespace_hints): Call
maybe_add_candidate_for_scoped_enum.
(namespace_hints::maybe_add_candidate_for_scoped_enum): New member
(suggest_alternatives_for): Update comment to mention scoped
enums.
(suggest_alternative_in_scoped_enum): New function.
gcc/testsuite/ChangeLog:
PR c++/88121
* g++.dg/lookup/suggestions-scoped-enums.C: New test.
* g++.dg/lookup/suggestions-unscoped-enums.C: New test.
From-SVN: r266644