aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp/name-lookup.c
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2021-01-27 00:51:01 -0500
committerJason Merrill <jason@redhat.com>2021-01-27 15:08:05 -0500
commit9cd7c32549fa334885b716fe98b674f6447fa7c0 (patch)
treea75a9c54c180f5e49cceec4f6ec3e25cb248cb10 /gcc/cp/name-lookup.c
parent55163419211c6f17e3e22c68304384eba35782a3 (diff)
downloadgcc-9cd7c32549fa334885b716fe98b674f6447fa7c0.zip
gcc-9cd7c32549fa334885b716fe98b674f6447fa7c0.tar.gz
gcc-9cd7c32549fa334885b716fe98b674f6447fa7c0.tar.bz2
c++: Dependent using enum [PR97874]
The handling of dependent scopes and unsuitable scopes in lookup_using_decl was a bit convoluted; I tweaked it for a while and then eventually reorganized much of the function to hopefully be clearer. Along the way I noticed a couple of ways we were mishandling inherited constructors. The local binding for a dependent using is the USING_DECL. Implement instantiation of a dependent USING_DECL at function scope. gcc/cp/ChangeLog: PR c++/97874 * name-lookup.c (lookup_using_decl): Clean up handling of dependency and inherited constructors. (finish_nonmember_using_decl): Handle DECL_DEPENDENT_P. * pt.c (tsubst_expr): Handle DECL_DEPENDENT_P. gcc/testsuite/ChangeLog: PR c++/97874 * g++.dg/lookup/using4.C: No error in C++20. * g++.dg/cpp0x/decltype37.C: Adjust message. * g++.dg/template/crash75.C: Adjust message. * g++.dg/template/crash76.C: Adjust message. * g++.dg/cpp0x/inh-ctor36.C: New test. * g++.dg/cpp1z/inh-ctor39.C: New test. * g++.dg/cpp2a/using-enum-7.C: New test.
Diffstat (limited to 'gcc/cp/name-lookup.c')
-rw-r--r--gcc/cp/name-lookup.c144
1 files changed, 73 insertions, 71 deletions
diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
index 0fb0036..52e4a63 100644
--- a/gcc/cp/name-lookup.c
+++ b/gcc/cp/name-lookup.c
@@ -5729,6 +5729,16 @@ lookup_using_decl (tree scope, name_lookup &lookup)
/* Naming a class member. This is awkward in C++20, because we
might be naming an enumerator of an unrelated class. */
+ tree npscope = scope;
+ if (PACK_EXPANSION_P (scope))
+ npscope = PACK_EXPANSION_PATTERN (scope);
+
+ if (!MAYBE_CLASS_TYPE_P (npscope))
+ {
+ error ("%qT is not a class, namespace, or enumeration", npscope);
+ return NULL_TREE;
+ }
+
/* You cannot using-decl a destructor. */
if (TREE_CODE (lookup.name) == BIT_NOT_EXPR)
{
@@ -5737,14 +5747,13 @@ lookup_using_decl (tree scope, name_lookup &lookup)
}
/* Using T::T declares inheriting ctors, even if T is a typedef. */
- if (MAYBE_CLASS_TYPE_P (scope)
- && (lookup.name == TYPE_IDENTIFIER (scope)
- || constructor_name_p (lookup.name, scope)))
+ if (lookup.name == TYPE_IDENTIFIER (npscope)
+ || constructor_name_p (lookup.name, npscope))
{
if (!TYPE_P (current))
{
error ("non-member using-declaration names constructor of %qT",
- scope);
+ npscope);
return NULL_TREE;
}
maybe_warn_cpp0x (CPP0X_INHERITING_CTORS);
@@ -5752,88 +5761,79 @@ lookup_using_decl (tree scope, name_lookup &lookup)
CLASSTYPE_NON_AGGREGATE (current) = true;
}
- if (!MAYBE_CLASS_TYPE_P (scope))
- ;
+ if (!TYPE_P (current) && cxx_dialect < cxx20)
+ {
+ error ("using-declaration for member at non-class scope");
+ return NULL_TREE;
+ }
+
+ bool depscope = dependent_scope_p (scope);
+
+ if (depscope)
+ /* Leave binfo null. */;
else if (TYPE_P (current))
{
- dependent_p = dependent_scope_p (scope);
- if (!dependent_p)
+ binfo = lookup_base (current, scope, ba_any, &b_kind, tf_none);
+ gcc_checking_assert (b_kind >= bk_not_base);
+
+ if (b_kind == bk_not_base && any_dependent_bases_p ())
+ /* Treat as-if dependent. */
+ depscope = true;
+ else if (lookup.name == ctor_identifier
+ && (b_kind < bk_proper_base || !binfo_direct_p (binfo)))
{
- binfo = lookup_base (current, scope, ba_any, &b_kind, tf_none);
- gcc_checking_assert (b_kind >= bk_not_base);
-
- if (lookup.name == ctor_identifier)
+ if (any_dependent_bases_p ())
+ depscope = true;
+ else
{
- /* Even if there are dependent bases, SCOPE will not
- be direct base, no matter. */
- if (b_kind < bk_proper_base || !binfo_direct_p (binfo))
- {
- error ("%qT is not a direct base of %qT", scope, current);
- return NULL_TREE;
- }
+ error ("%qT is not a direct base of %qT", scope, current);
+ return NULL_TREE;
}
- else if (b_kind < bk_proper_base)
- binfo = TYPE_BINFO (scope);
- else if (IDENTIFIER_CONV_OP_P (lookup.name)
- && dependent_type_p (TREE_TYPE (lookup.name)))
- dependent_p = true;
}
+
+ if (b_kind < bk_proper_base)
+ binfo = TYPE_BINFO (scope);
}
else
binfo = TYPE_BINFO (scope);
+ dependent_p = (depscope
+ || (IDENTIFIER_CONV_OP_P (lookup.name)
+ && dependent_type_p (TREE_TYPE (lookup.name))));
+
if (!dependent_p)
- {
- if (binfo)
- lookup.value = lookup_member (binfo, lookup.name, /*protect=*/2,
- /*want_type=*/false, tf_none);
+ lookup.value = lookup_member (binfo, lookup.name, /*protect=*/2,
+ /*want_type=*/false, tf_none);
- tree saved_value = lookup.value;
- if (lookup.value
- && b_kind < bk_proper_base)
+ if (!depscope && b_kind < bk_proper_base)
+ {
+ if (cxx_dialect >= cxx20 && lookup.value
+ && TREE_CODE (lookup.value) == CONST_DECL)
{
- if (cxx_dialect >= cxx20
- && TREE_CODE (lookup.value) == CONST_DECL)
- {
- /* Using an unrelated enum; check access here rather
- than separately for class and non-class using. */
- perform_or_defer_access_check
- (binfo, lookup.value, lookup.value, tf_warning_or_error);
- /* And then if this is a copy from handle_using_decl, look
- through to the original enumerator. */
- if (CONST_DECL_USING_P (lookup.value))
- lookup.value = DECL_ABSTRACT_ORIGIN (lookup.value);
- }
- else
- lookup.value = NULL_TREE;
+ /* Using an unrelated enum; check access here rather
+ than separately for class and non-class using. */
+ perform_or_defer_access_check
+ (binfo, lookup.value, lookup.value, tf_warning_or_error);
+ /* And then if this is a copy from handle_using_decl, look
+ through to the original enumerator. */
+ if (CONST_DECL_USING_P (lookup.value))
+ lookup.value = DECL_ABSTRACT_ORIGIN (lookup.value);
}
-
- if (!lookup.value)
+ else if (!TYPE_P (current))
{
- if (!TYPE_P (current))
- {
- error ("using-declaration for member at non-class scope");
- return NULL_TREE;
- }
-
- if (b_kind < bk_proper_base)
- {
- if (b_kind == bk_not_base && any_dependent_bases_p ())
- /* Treat as-if dependent. */
- dependent_p = true;
- else
- {
- auto_diagnostic_group g;
- error_not_base_type (scope, current);
- if (saved_value && DECL_IMPLICIT_TYPEDEF_P (saved_value)
- && (TREE_CODE (TREE_TYPE (saved_value))
- == ENUMERAL_TYPE))
- inform (input_location,
- "did you mean %<using enum %T::%D%>?",
- scope, lookup.name);
- return NULL_TREE;
- }
- }
+ error ("using-declaration for member at non-class scope");
+ return NULL_TREE;
+ }
+ else
+ {
+ auto_diagnostic_group g;
+ error_not_base_type (scope, current);
+ if (lookup.value && DECL_IMPLICIT_TYPEDEF_P (lookup.value)
+ && TREE_CODE (TREE_TYPE (lookup.value)) == ENUMERAL_TYPE)
+ inform (input_location,
+ "did you mean %<using enum %T::%D%>?",
+ scope, lookup.name);
+ return NULL_TREE;
}
}
}
@@ -6455,6 +6455,8 @@ finish_nonmember_using_decl (tree scope, tree name)
else
{
add_decl_expr (using_decl);
+ if (DECL_DEPENDENT_P (using_decl))
+ lookup.value = using_decl;
push_using_decl_bindings (&lookup, name, NULL_TREE);
}
}