+2018-11-29 David Malcolm <dmalcolm@redhat.com>
+
+ 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.
+
2018-11-28 Marek Polacek <polacek@redhat.com>
Implement P1094R2, Nested inline namespaces.
extern name_hint suggest_alternatives_for (location_t, tree, bool);
extern name_hint suggest_alternatives_in_other_namespaces (location_t, tree);
extern name_hint suggest_alternative_in_explicit_scope (location_t, tree, tree);
+extern name_hint suggest_alternative_in_scoped_enum (tree, tree);
#endif /* GCC_CP_NAME_HINT_H */
if (scope == NULL_TREE)
return;
+ /* Enum values within an unscoped enum will be CONST_DECL with an
+ ENUMERAL_TYPE as their "scope". Use CP_TYPE_CONTEXT of the
+ ENUMERAL_TYPE, so as to print any enclosing namespace. */
+ if (UNSCOPED_ENUM_P (scope))
+ scope = CP_TYPE_CONTEXT (scope);
+
if (TREE_CODE (scope) == NAMESPACE_DECL)
{
if (scope != global_namespace)
pp_cxx_colon_colon (pp);
}
}
- else if (AGGREGATE_TYPE_P (scope))
+ else if (AGGREGATE_TYPE_P (scope)
+ || SCOPED_ENUM_P (scope))
{
dump_type (pp, scope, f);
pp_cxx_colon_colon (pp);
print_candidates (decl);
}
else
- error_at (location, "%qD is not a member of %qT", name, scope);
+ {
+ name_hint hint;
+ if (SCOPED_ENUM_P (scope))
+ hint = suggest_alternative_in_scoped_enum (name, scope);
+ if (const char *suggestion = hint.suggestion ())
+ {
+ gcc_rich_location richloc (location);
+ richloc.add_fixit_replace (suggestion);
+ error_at (&richloc,
+ "%qD is not a member of %qT; did you mean %qs?",
+ name, scope, suggestion);
+ }
+ else
+ error_at (location, "%qD is not a member of %qT", name, scope);
+ }
}
else if (scope != global_namespace)
{
};
/* A class for encapsulating the result of a search across
- multiple namespaces for an unrecognized name seen at a
- given source location. */
+ multiple namespaces (and scoped enums within them) for an
+ unrecognized name seen at a given source location. */
class namespace_hints
{
name_hint maybe_decorate_with_limit (name_hint);
private:
+ void maybe_add_candidate_for_scoped_enum (tree scoped_enum, tree name);
+
location_t m_loc;
tree m_name;
vec<tree> m_candidates;
bool m_limited;
};
-/* Constructor for namespace_hints. Search namespaces, looking for a match
- for unrecognized NAME seen at LOC. */
+/* Constructor for namespace_hints. Search namespaces and scoped enums,
+ looking for an exact match for unrecognized NAME seen at LOC. */
namespace_hints::namespace_hints (location_t loc, tree name)
: m_loc(loc), m_name (name)
for (tree decl = NAMESPACE_LEVEL (ns)->names;
decl; decl = TREE_CHAIN (decl))
- if (TREE_CODE (decl) == NAMESPACE_DECL
- && !DECL_NAMESPACE_ALIAS (decl)
- && !DECL_NAMESPACE_INLINE_P (decl))
- children.safe_push (decl);
+ {
+ if (TREE_CODE (decl) == NAMESPACE_DECL
+ && !DECL_NAMESPACE_ALIAS (decl)
+ && !DECL_NAMESPACE_INLINE_P (decl))
+ children.safe_push (decl);
+
+ /* Look for exact matches for NAME within scoped enums.
+ These aren't added to the worklist, and so don't count
+ against the search limit. */
+ if (TREE_CODE (decl) == TYPE_DECL)
+ {
+ tree type = TREE_TYPE (decl);
+ if (SCOPED_ENUM_P (type))
+ maybe_add_candidate_for_scoped_enum (type, name);
+ }
+ }
while (!m_limited && !children.is_empty ())
{
return hint;
}
+/* Look inside SCOPED_ENUM for exact matches for NAME.
+ If one is found, add its CONST_DECL to m_candidates. */
+
+void
+namespace_hints::maybe_add_candidate_for_scoped_enum (tree scoped_enum,
+ tree name)
+{
+ gcc_assert (SCOPED_ENUM_P (scoped_enum));
+
+ for (tree iter = TYPE_VALUES (scoped_enum); iter; iter = TREE_CHAIN (iter))
+ {
+ tree id = TREE_PURPOSE (iter);
+ if (id == name)
+ {
+ m_candidates.safe_push (TREE_VALUE (iter));
+ return;
+ }
+ }
+}
+
/* Generate a name_hint at LOCATION for NAME, an IDENTIFIER_NODE for which
name lookup failed.
- Search through all available namespaces and generate a suggestion and/or
- a deferred diagnostic that lists possible candidate(s).
+ Search through all available namespaces and any scoped enums within them
+ and generate a suggestion and/or a deferred diagnostic that lists possible
+ candidate(s).
If no exact matches are found, and SUGGEST_MISSPELLINGS is true, then also
look for near-matches and suggest the best near-match, if there is one.
return name_hint ();
}
+/* Given NAME, look within SCOPED_ENUM for possible spell-correction
+ candidates. */
+
+name_hint
+suggest_alternative_in_scoped_enum (tree name, tree scoped_enum)
+{
+ gcc_assert (SCOPED_ENUM_P (scoped_enum));
+
+ best_match <tree, const char *> bm (name);
+ for (tree iter = TYPE_VALUES (scoped_enum); iter; iter = TREE_CHAIN (iter))
+ {
+ tree id = TREE_PURPOSE (iter);
+ bm.consider (IDENTIFIER_POINTER (id));
+ }
+ return name_hint (bm.get_best_meaningful_candidate (), NULL);
+}
+
/* Look up NAME (an IDENTIFIER_NODE) in SCOPE (either a NAMESPACE_DECL
or a class TYPE).
+2018-11-29 David Malcolm <dmalcolm@redhat.com>
+
+ PR c++/88121
+ * g++.dg/lookup/suggestions-scoped-enums.C: New test.
+ * g++.dg/lookup/suggestions-unscoped-enums.C: New test.
+
2018-11-29 Peter Bergner <bergner@linux.ibm.com>
PR target/87496
--- /dev/null
+// { dg-do compile { target c++11 } }
+// { dg-options "-fdiagnostics-show-caret" }
+
+/* Verify that we offer suggestions for misspelled values
+ in scoped enums, and for values from scoped enums that
+ are missing their scope.
+ Verify that we emit fix-it hints for those cases for
+ which we have adequate location information. */
+
+enum class vegetable { CARROT, TURNIP }; // { dg-line decl_of_vegetable }
+namespace pasta
+{
+ enum class shape { LASAGNA, LINGUINE, SPAGHETTI, TAGLIATELLE }; // { dg-line decl_of_shape }
+}
+
+void misspelled_value_in_scoped_enum ()
+{
+ vegetable::TURNUP; // { dg-error "'TURNUP' is not a member of 'vegetable'; did you mean 'TURNIP'" }
+ /* { dg-begin-multiline-output "" }
+ vegetable::TURNUP;
+ ^~~~~~
+ TURNIP
+ { dg-end-multiline-output "" } */
+}
+
+void misspelled_value_using_explicit_ns ()
+{
+ pasta::shape::SPOOGHETTI; // { dg-error "'SPOOGHETTI' is not a member of 'pasta::shape'; did you mean 'SPAGHETTI'" }
+ /* { dg-begin-multiline-output "" }
+ pasta::shape::SPOOGHETTI;
+ ^~~~~~~~~~
+ SPAGHETTI
+ { dg-end-multiline-output "" } */
+}
+
+namespace pasta {
+void misspelled_value_using_implicit_ns ()
+{
+ shape::SPOOGHETTI; // { dg-error "'SPOOGHETTI' is not a member of 'pasta::shape'; did you mean 'SPAGHETTI'" }
+ /* { dg-begin-multiline-output "" }
+ shape::SPOOGHETTI;
+ ^~~~~~~~~~
+ SPAGHETTI
+ { dg-end-multiline-output "" } */
+}
+} // namespace pasta
+
+void unqualified_enum_in_global_ns ()
+{
+ CARROT; // { dg-error "'CARROT' was not declared in this scope; did you mean 'vegetable::CARROT'" }
+ /* { dg-begin-multiline-output "" }
+ CARROT;
+ ^~~~~~
+ vegetable::CARROT
+ { dg-end-multiline-output "" } */
+ // { dg-message "'vegetable::CARROT' declared here" "" { target *-*-* } decl_of_vegetable }
+ /* { dg-begin-multiline-output "" }
+ enum class vegetable { CARROT, TURNIP };
+ ^~~~~~
+ { dg-end-multiline-output "" } */
+}
+
+void unqualified_enum_in_ns ()
+{
+ LASAGNA; // { dg-error "'LASAGNA' was not declared in this scope; did you mean 'pasta::shape::LASAGNA'" }
+ /* { dg-begin-multiline-output "" }
+ LASAGNA;
+ ^~~~~~~
+ pasta::shape::LASAGNA
+ { dg-end-multiline-output "" } */
+ // { dg-message "'pasta::shape::LASAGNA' declared here" "" { target *-*-* } decl_of_shape }
+ /* { dg-begin-multiline-output "" }
+ enum class shape { LASAGNA, LINGUINE, SPAGHETTI, TAGLIATELLE };
+ ^~~~~~~
+ { dg-end-multiline-output "" } */
+}
+
+/* We can't guarantee location information here, so don't expect a
+ fix-it hint. */
+
+void unqualified_enum_in_explicit_ns ()
+{
+ pasta::LINGUINE; // { dg-error "'LINGUINE' is not a member of 'pasta'; did you mean 'pasta::shape::LINGUINE'" }
+ /* { dg-begin-multiline-output "" }
+ pasta::LINGUINE;
+ ^~~~~~~~
+ { dg-end-multiline-output "" } */
+ // { dg-message "'pasta::shape::LINGUINE' declared here" "" { target *-*-* } decl_of_shape }
+ /* { dg-begin-multiline-output "" }
+ enum class shape { LASAGNA, LINGUINE, SPAGHETTI, TAGLIATELLE };
+ ^~~~~~~~
+ { dg-end-multiline-output "" } */
+}
+
+namespace pasta {
+void unqualified_enum_in_implicit_ns ()
+{
+ TAGLIATELLE; // { dg-error "'TAGLIATELLE' was not declared in this scope; did you mean 'pasta::shape::TAGLIATELLE'" }
+ /* { dg-begin-multiline-output "" }
+ TAGLIATELLE;
+ ^~~~~~~~~~~
+ pasta::shape::TAGLIATELLE
+ { dg-end-multiline-output "" } */
+ // { dg-message "'pasta::shape::TAGLIATELLE' declared here" "" { target *-*-* } decl_of_shape }
+ /* { dg-begin-multiline-output "" }
+ enum class shape { LASAGNA, LINGUINE, SPAGHETTI, TAGLIATELLE };
+ ^~~~~~~~~~~
+ { dg-end-multiline-output "" } */
+}
+}
--- /dev/null
+// { 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_b
+{
+ enum enum_in_outer_ns_b { 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_b::NIGHT'" }
+ /* { dg-begin-multiline-output "" }
+ outer_ns_a::NIGHT;
+ ^~~~~
+ { dg-end-multiline-output "" } */
+ /* { dg-begin-multiline-output "" }
+ enum enum_in_outer_ns_b { NIGHT, DAY };
+ ^~~~~
+ { dg-end-multiline-output "" } */
+}