When copying the enumerators imported by a class-scope using-enum declaration, we need to override current_access_specifier so that finish_member_declaration gives them the same access as the using-enum decl. The processing of a using-enum is performed after we've seen the entire definition of the class, so current_access_specifier at this point is otherwise set to the last access specifier within the class.
For consistency, this patch makes build_enumerator use set_current_access_from_decl too. Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for trunk/11? PR c++/100862 gcc/cp/ChangeLog: * pt.c (set_current_access_from_decl): Move to ... * class.c (set_current_access_from_decl): ... here. (handle_using_decl): Use it to propagate the access of the using-enum decl to the copy of the imported enumerator. * cp-tree.h (set_current_access_from_decl): Declare. * decl.c (build_enumerator): Simplify using make_temp_override and set_current_access_from_decl. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/using-enum-9.C: New test. --- gcc/cp/class.c | 15 ++++++++++++ gcc/cp/cp-tree.h | 1 + gcc/cp/decl.c | 12 ++-------- gcc/cp/pt.c | 14 ------------ gcc/testsuite/g++.dg/cpp2a/using-enum-9.C | 28 +++++++++++++++++++++++ 5 files changed, 46 insertions(+), 24 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp2a/using-enum-9.C diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 354addde773..b53a4dbdd4e 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -207,6 +207,19 @@ static bool type_maybe_constexpr_default_constructor (tree); static bool type_maybe_constexpr_destructor (tree); static bool field_poverlapping_p (tree); +/* Set CURRENT_ACCESS_SPECIFIER based on the protection of DECL. */ + +void +set_current_access_from_decl (tree decl) +{ + if (TREE_PRIVATE (decl)) + current_access_specifier = access_private_node; + else if (TREE_PROTECTED (decl)) + current_access_specifier = access_protected_node; + else + current_access_specifier = access_public_node; +} + /* Return a COND_EXPR that executes TRUE_STMT if this execution of the 'structor is in charge of 'structing virtual bases, or FALSE_STMT otherwise. */ @@ -1359,6 +1372,8 @@ handle_using_decl (tree using_decl, tree t) CONST_DECL_USING_P is true. */ gcc_assert (TREE_CODE (decl) == CONST_DECL); + auto cas = make_temp_override (current_access_specifier); + set_current_access_from_decl (using_decl); tree copy = copy_decl (decl); DECL_CONTEXT (copy) = t; DECL_ARTIFICIAL (copy) = true; diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index c95a820037f..b1b7e615bcc 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -8186,6 +8186,7 @@ struct atom_hasher : default_hash_traits<tree> extern bool subsumes (tree, tree); /* In class.c */ +extern void set_current_access_from_decl (tree); extern void cp_finish_injected_record_type (tree); /* in vtable-class-hierarchy.c */ diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index e7268d5ad18..fb21a3a1ae8 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -16333,17 +16333,9 @@ incremented enumerator value is too large for %<long%>")); For which case we need to make sure that the access of `S::i' matches the access of `S::E'. */ - tree saved_cas = current_access_specifier; - if (TREE_PRIVATE (TYPE_NAME (enumtype))) - current_access_specifier = access_private_node; - else if (TREE_PROTECTED (TYPE_NAME (enumtype))) - current_access_specifier = access_protected_node; - else - current_access_specifier = access_public_node; - + auto cas = make_temp_override (current_access_specifier); + set_current_access_from_decl (TYPE_NAME (enumtype)); finish_member_declaration (decl); - - current_access_specifier = saved_cas; } else pushdecl (decl); diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 31302803c62..86259e900e9 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -190,7 +190,6 @@ static tree tsubst_arg_types (tree, tree, tree, tsubst_flags_t, tree); static tree tsubst_function_type (tree, tree, tsubst_flags_t, tree); static bool check_specialization_scope (void); static tree process_partial_specialization (tree); -static void set_current_access_from_decl (tree); static enum template_base_result get_template_base (tree, tree, tree, tree, bool , tree *); static tree try_class_unification (tree, tree, tree, tree, bool); @@ -26431,19 +26430,6 @@ tsubst_initializer_list (tree t, tree argvec) return inits; } -/* Set CURRENT_ACCESS_SPECIFIER based on the protection of DECL. */ - -static void -set_current_access_from_decl (tree decl) -{ - if (TREE_PRIVATE (decl)) - current_access_specifier = access_private_node; - else if (TREE_PROTECTED (decl)) - current_access_specifier = access_protected_node; - else - current_access_specifier = access_public_node; -} - /* Instantiate an enumerated type. TAG is the template type, NEWTAG is the instantiation (which should have been created with start_enum) and ARGS are the template arguments to use. */ diff --git a/gcc/testsuite/g++.dg/cpp2a/using-enum-9.C b/gcc/testsuite/g++.dg/cpp2a/using-enum-9.C new file mode 100644 index 00000000000..3e026057b40 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/using-enum-9.C @@ -0,0 +1,28 @@ +// PR c++/100862 +// { dg-do compile { target c++20 } } + +enum class fruit { orange, apple }; + +struct A { +public: + using enum fruit; +private: +}; + +struct B { +protected: + using enum fruit; +public: +}; + +struct C { +private: + using enum fruit; +public: +}; + +int main() { + A::orange, A::apple; + B::orange, B::apple; // { dg-error "protected" } + C::orange, C::apple; // { dg-error "private" } +} -- 2.32.0.rc2