diff options
author | Jason Merrill <jason@redhat.com> | 2021-01-27 00:51:01 -0500 |
---|---|---|
committer | Jason Merrill <jason@redhat.com> | 2021-01-27 15:08:05 -0500 |
commit | 9cd7c32549fa334885b716fe98b674f6447fa7c0 (patch) | |
tree | a75a9c54c180f5e49cceec4f6ec3e25cb248cb10 /gcc/cp/name-lookup.c | |
parent | 55163419211c6f17e3e22c68304384eba35782a3 (diff) | |
download | gcc-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.c | 144 |
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); } } |