C++: namespaces and scopes for enum values (PR c++/88121)
commit58bcbab7b7531f50f61ba8fe31bd3a784041b4bc
authordmalcolm <dmalcolm@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 29 Nov 2018 21:21:56 +0000 (29 21:21 +0000)
committerdmalcolm <dmalcolm@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 29 Nov 2018 21:21:56 +0000 (29 21:21 +0000)
tree381aecd2dd2f35a631c30c149b1033b171aa0de3
parentd247a0a25ad262a27bf26dfc1e4a62bb90cf7bcd
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.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@266644 138bc75d-0d04-0410-961f-82ee72b054a4
gcc/cp/ChangeLog
gcc/cp/cp-name-hint.h
gcc/cp/error.c
gcc/cp/name-lookup.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/lookup/suggestions-scoped-enums.C [new file with mode: 0644]
gcc/testsuite/g++.dg/lookup/suggestions-unscoped-enums.C [new file with mode: 0644]