c++: handle misspelled concepts and missing #include <concepts>

gcc/cp/ChangeLog:
	* name-lookup.cc (suggest_alternative_in_explicit_scope):
	Gracefully handle non-namespaces, such as scoped enums.
	* parser.cc (cp_parser_name_lookup_error): Provide
	a name_hint for the case where we're in an explicit scope.
	* std-name-hint.gperf: Add <concepts>.
	* std-name-hint.h: Regenerate.

gcc/testsuite/ChangeLog:
	* g++.dg/concepts/missing-header.C: New test.
	* g++.dg/concepts/misspelled-concept.C: New test.

Signed-off-by: David Malcolm <dmalcolm@redhat.com>
This commit is contained in:
David Malcolm 2024-12-06 11:33:59 -05:00
parent 4f5b7f1b73
commit 31c08879dc
6 changed files with 1316 additions and 1131 deletions

View file

@ -7351,6 +7351,9 @@ suggest_alternative_in_explicit_scope (location_t location, tree name,
if (name == error_mark_node)
return name_hint ();
if (TREE_CODE (scope) != NAMESPACE_DECL)
return name_hint ();
/* Resolve any namespace aliases. */
scope = ORIGINAL_NAMESPACE (scope);

View file

@ -3387,8 +3387,25 @@ cp_parser_name_lookup_error (cp_parser* parser,
if (decl == error_mark_node)
{
if (parser->scope && parser->scope != global_namespace)
error_at (location, "%<%E::%E%> has not been declared",
parser->scope, name);
{
auto_diagnostic_group sentinel;
name_hint hint
= suggest_alternative_in_explicit_scope (location, name,
parser->scope);;
if (const char *suggestion = hint.suggestion ())
{
/* Ideally we'd have a fix-it hint here, but LOCATION
isn't necessarily that of the name. */
error_at (location,
"%<%E::%E%> has not been declared;"
" did you mean %<%E::%s%>?",
parser->scope, name,
parser->scope, suggestion);
}
else
error_at (location, "%<%E::%E%> has not been declared",
parser->scope, name);
}
else if (parser->scope == global_namespace)
error_at (location, "%<::%E%> has not been declared", name);
else if (parser->object_scope

View file

@ -102,6 +102,39 @@ weak_ordering, "<compare>", cxx20
# <complex>
complex, "<complex>", cxx98
complex_literals, "<complex>", cxx14
# <concepts>
same_as, "<concepts>", cxx20
derived_from, "<concepts>", cxx20
convertible_to, "<concepts>", cxx20
common_reference_with, "<concepts>", cxx20
common_with, "<concepts>", cxx20
integral, "<concepts>", cxx20
signed_integral, "<concepts>", cxx20
unsigned_integral, "<concepts>", cxx20
floating_point, "<concepts>", cxx20
assignable_from, "<concepts>", cxx20
swappable, "<concepts>", cxx20
swappable_with, "<concepts>", cxx20
destructible, "<concepts>", cxx20
constructible_from, "<concepts>", cxx20
default_initializable, "<concepts>", cxx20
move_constructible, "<concepts>", cxx20
copy_constructible, "<concepts>", cxx20
equality_comparable, "<concepts>", cxx20
equality_comparable_with, "<concepts>", cxx20
totally_ordered, "<concepts>", cxx20
totally_ordered_with, "<concepts>", cxx20
movable, "<concepts>", cxx20
copyable, "<concepts>", cxx20
semiregular, "<concepts>", cxx20
regular, "<concepts>", cxx20
invocable, "<concepts>", cxx20
regular_invocable, "<concepts>", cxx20
predicate, "<concepts>", cxx20
relation, "<concepts>", cxx20
equivalence_relation, "<concepts>", cxx20
strict_weak_order, "<concepts>", cxx20
ranges::swap, "<concepts>", cxx20
# <condition_variable>
condition_variable, "<condition_variable>", cxx11
condition_variable_any, "<condition_variable>", cxx11

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,6 @@
// { dg-do compile { target c++20 } }
// { dg-options "-fconcepts" }
template <std::integral N> foo (N); // { dg-error "'std::integral' has not been declared" }
// { dg-message "'std::integral' is defined in header '<concepts>'" "note" { target *-*-* } .-1 }
// { dg-error "expected" "followup" { target *-*-* } .-2 }

View file

@ -0,0 +1,7 @@
// { dg-do compile { target c++20 } }
// { dg-options "-fconcepts" }
#include <concepts>
template <std::unsinged_integral N> foo (N); // { dg-error "'std::unsinged_integral' has not been declared; did you mean 'std::unsigned_integral'" }
// { dg-error "expected" "followup" { target *-*-* } .-1 }