diff options
author | Nathaniel Shead <nathanieloshead@gmail.com> | 2024-06-27 11:08:15 +1000 |
---|---|---|
committer | Nathaniel Shead <nathanieloshead@gmail.com> | 2024-07-12 22:47:30 +1000 |
commit | d6bf4b1c93221118b3008a878ec508f6412dfc55 (patch) | |
tree | 35e3c8792daa0fa077d4eabebc74b1eaa38a51df /gcc/cp/module.cc | |
parent | 61715e9340ab8941d40d62158fe437e9dbe3e068 (diff) | |
download | gcc-d6bf4b1c93221118b3008a878ec508f6412dfc55.zip gcc-d6bf4b1c93221118b3008a878ec508f6412dfc55.tar.gz gcc-d6bf4b1c93221118b3008a878ec508f6412dfc55.tar.bz2 |
c++: Introduce USING_DECLs for non-function usings [PR114683]
With modules, a non-function using-declaration is not completely
interchangable with the declaration that it refers to; in particular,
such a using-declaration may be exported without revealing the name of
the entity it refers to.
This patch fixes this by building USING_DECLs for all using-declarations
that bind a non-function from a different scope. These new decls can
than have purviewness and exportingness attached to them without
affecting the decl that they refer to.
We do this for all such usings, not just usings that may be revealed in
a module; this way we can verify the change in representation against
the (more comprehensive) non-modules testsuites, and in a future patch
we can use the locations of these using-decls to enhance relevant
diagnostics.
Another possible approach would be to reuse OVERLOADs for this, as is
already done within add_binding_entity for modules. I didn't do this
because lots of code (as well as the names of the accessors) makes
assumptions that OVERLOADs refer to function overload sets, and so
splitting this up reduced semantic burden and made it easier to avoid
unintentional changes. This did mean that we need to move out the
definitions of ovl_iterator::{purview,exporting}_p, because the
structures for module decls are declared later on in cp-tree.h.
Building USING_DECLs changed a couple of code paths when adjusting
bindings; in particular, pushdecl recognises global using-declarations
as usings now, and so checks fall through to update_binding. To not
regress g++.dg/lookup/linkage2.C the checks for 'extern' declarations no
longer were sufficient (they don't handle 'extern "C"'); but
duplicate_decls performed all the relevant checks anyway.
Otherwise in general we strip using-decls from all lookup_* functions
where necessary. Over time for diagnostics purposes it would probably
be good to slowly revert this (especially e.g. lookup_elaborated_type
causes some diagnostic quality regressions here) but this patch doesn't
do so to minimise churn.
This patch also tries not to build USING_DECLs when just redeclaring an
existing declaration, and instead reveals that declaration in-place.
This requires reworking some logic handling CONST_DECLs in module
streaming, since a non-using CONST_DECL may now be exported indepenently
of its containing enum.
'add_binding_entity' needs to explicitly write the names of unscoped
enumerators so that lazy loading will trigger when the name is found by
name lookup; it does this by pretending that the enum declarations are
always usings so that it doesn't double-write definitions. By also
checking if the enumerator was marked purview/exported we can use that
to override a non-purview/non-exported TYPE_DECL and ensure it's made
visible regardless.
When reading we should get the exported flag on the enumeration
constant, and so should properly create a binding for it. We don't need
to do anything to handle importedness as that checking is skipped for
EK_USINGs.
Some other places assume that module information for a CONST_DECL
inherits module information from its containing type. This includes:
- get_originating_module_decl, for determining if the name was imported
or has module attachment; I don't /think/ this change should affect
that, so I'm leaving this untouched.
- binding_cmp, for sorting by exportedness; since now an enumerator
could be exported without the containing decl being exported, we need
to handle this here too.
PR c++/114683
gcc/cp/ChangeLog:
* cp-tree.h (class ovl_iterator): Move definitions of purview_p
and exporting_p to name-lookup.cc.
* module.cc (depset::hash::add_binding_entity): Strip
using-decls. Remove workarounds. Handle CONST_DECLs with
different purview/exported from their enum.
(enum ct_bind_flags): Remove unnecessary cbf_wrapped flag.
(module_state::write_cluster): Likewise.
(module_state::read_cluster): Build USING_DECL for non-function
usings.
(binding_cmp): Handle CONST_DECLs with different purview and/or
exported from their enum.
(set_instantiating_module): Support CONST_DECLs.
* name-lookup.cc (get_fixed_binding_slot): Strip USING_DECLs.
(name_lookup::process_binding): Strip USING_DECLs.
(name_lookup::process_module_binding): Remove workaround.
(update_binding): Strip USING_DECLs, remove incorrect check for
non-extern variables.
(ovl_iterator::purview_p): Support USING_DECLs.
(ovl_iterator::exporting_p): Support USING_DECLs.
(walk_module_binding): Handle stat hack type.
(do_nonmember_using_decl): Strip USING_DECLs when comparing;
build USING_DECLs for non-function usings in different scope
rather than binding directly.
(get_namespace_binding): Strip USING_DECLs.
(lookup_name): Strip USING_DECLs.
(lookup_elaborated_type): Strip USING_DECLs.
* decl.cc (poplevel): Still support -Wunused for using-decls.
(lookup_and_check_tag): Remove unnecessary strip_using_decl.
* parser.cc (cp_parser_template_name): Likewise.
(cp_parser_nonclass_name): Likewise.
(cp_parser_class_name): Likewise.
gcc/testsuite/ChangeLog:
* g++.dg/lookup/using29.C: Update errors.
* g++.dg/lookup/using53.C: Update errors, add XFAILs.
* g++.dg/modules/using-22_b.C: Remove xfails.
* g++.dg/warn/Wunused-var-18.C: Update error, add check.
* g++.dg/lookup/using68.C: New test.
* g++.dg/modules/using-24_a.C: New test.
* g++.dg/modules/using-24_b.C: New test.
* g++.dg/modules/using-25_a.C: New test.
* g++.dg/modules/using-25_b.C: New test.
* g++.dg/modules/using-enum-4_a.C: New test.
* g++.dg/modules/using-enum-4_b.C: New test.
* g++.dg/modules/using-enum-4_c.C: New test.
Signed-off-by: Nathaniel Shead <nathanieloshead@gmail.com>
Reviewed-by: Jason Merrill <jason@redhat.com>
Diffstat (limited to 'gcc/cp/module.cc')
-rw-r--r-- | gcc/cp/module.cc | 103 |
1 files changed, 73 insertions, 30 deletions
diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index da18024..d385b42 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -13122,13 +13122,17 @@ bool depset::hash::add_binding_entity (tree decl, WMB_Flags flags, void *data_) { auto data = static_cast <add_binding_data *> (data_); + decl = strip_using_decl (decl); if (!(TREE_CODE (decl) == NAMESPACE_DECL && !DECL_NAMESPACE_ALIAS (decl))) { tree inner = decl; if (TREE_CODE (inner) == CONST_DECL - && TREE_CODE (DECL_CONTEXT (inner)) == ENUMERAL_TYPE) + && TREE_CODE (DECL_CONTEXT (inner)) == ENUMERAL_TYPE + /* A using-decl could make a CONST_DECL purview for a non-purview + enumeration. */ + && (!DECL_LANG_SPECIFIC (inner) || !DECL_MODULE_PURVIEW_P (inner))) inner = TYPE_NAME (DECL_CONTEXT (inner)); else if (TREE_CODE (inner) == TEMPLATE_DECL) inner = DECL_TEMPLATE_RESULT (inner); @@ -13156,18 +13160,17 @@ depset::hash::add_binding_entity (tree decl, WMB_Flags flags, void *data_) /* Ignore NTTP objects. */ return false; - bool unscoped_enum_const_p = false; if (!(flags & WMB_Using) && CP_DECL_CONTEXT (decl) != data->ns) { - /* A using that lost its wrapper or an unscoped enum - constant. */ - /* FIXME: Ensure that unscoped enums are differentiated from - 'using enum' declarations when PR c++/114683 is fixed. */ - unscoped_enum_const_p = (TREE_CODE (decl) == CONST_DECL); + /* An unscoped enum constant implicitly brought into the containing + namespace. We treat this like a using-decl. */ + gcc_checking_assert (TREE_CODE (decl) == CONST_DECL); + flags = WMB_Flags (flags | WMB_Using); - if (DECL_MODULE_EXPORT_P (TREE_CODE (decl) == CONST_DECL - ? TYPE_NAME (TREE_TYPE (decl)) - : STRIP_TEMPLATE (decl))) + if (DECL_MODULE_EXPORT_P (TYPE_NAME (TREE_TYPE (decl))) + /* A using-decl can make an enum constant exported for a + non-exported enumeration. */ + || (DECL_LANG_SPECIFIC (decl) && DECL_MODULE_EXPORT_P (decl))) flags = WMB_Flags (flags | WMB_Export); } @@ -13225,8 +13228,7 @@ depset::hash::add_binding_entity (tree decl, WMB_Flags flags, void *data_) if (flags & WMB_Using) { decl = ovl_make (decl, NULL_TREE); - if (!unscoped_enum_const_p) - OVL_USING_P (decl) = true; + OVL_USING_P (decl) = true; OVL_PURVIEW_P (decl) = true; if (flags & WMB_Export) OVL_EXPORT_P (decl) = true; @@ -13250,12 +13252,8 @@ depset::hash::add_binding_entity (tree decl, WMB_Flags flags, void *data_) data->met_namespace = true; if (data->hash->add_namespace_entities (decl, data->partitions)) { - /* It contains an exported thing, so it is exported. - - FIXME we have to set DECL_MODULE_PURVIEW_P instead of asserting - that it is already set because of the c++/114683 issue with - exported using-declarations; see do_nonmember_using_decl. */ - DECL_MODULE_PURVIEW_P (decl) = true; + /* It contains an exported thing, so it is exported. */ + gcc_checking_assert (DECL_MODULE_PURVIEW_P (decl)); DECL_MODULE_EXPORT_P (decl) = true; } @@ -13744,6 +13742,10 @@ binding_cmp (const void *a_, const void *b_) a_export = OVL_EXPORT_P (a_ent); a_ent = OVL_FUNCTION (a_ent); } + else if (TREE_CODE (a_ent) == CONST_DECL + && DECL_LANG_SPECIFIC (a_ent) + && DECL_MODULE_EXPORT_P (a_ent)) + a_export = true; else a_export = DECL_MODULE_EXPORT_P (TREE_CODE (a_ent) == CONST_DECL ? TYPE_NAME (TREE_TYPE (a_ent)) @@ -13756,6 +13758,10 @@ binding_cmp (const void *a_, const void *b_) b_export = OVL_EXPORT_P (b_ent); b_ent = OVL_FUNCTION (b_ent); } + else if (TREE_CODE (b_ent) == CONST_DECL + && DECL_LANG_SPECIFIC (b_ent) + && DECL_MODULE_EXPORT_P (b_ent)) + b_export = true; else b_export = DECL_MODULE_EXPORT_P (TREE_CODE (b_ent) == CONST_DECL ? TYPE_NAME (TREE_TYPE (b_ent)) @@ -14964,7 +14970,6 @@ enum ct_bind_flags cbf_export = 0x1, /* An exported decl. */ cbf_hidden = 0x2, /* A hidden (friend) decl. */ cbf_using = 0x4, /* A using decl. */ - cbf_wrapped = 0x8, /* ... that is wrapped. */ }; /* DEP belongs to a different cluster, seed it to prevent @@ -15127,13 +15132,9 @@ module_state::write_cluster (elf_out *to, depset *scc[], unsigned size, if (!(TREE_CODE (bound) == CONST_DECL && UNSCOPED_ENUM_P (TREE_TYPE (bound)) && decl == TYPE_NAME (TREE_TYPE (bound)))) - { - /* An unscope enumerator in its enumeration's - scope is not a using. */ - flags |= cbf_using; - if (OVL_USING_P (ovl)) - flags |= cbf_wrapped; - } + /* An unscoped enumerator in its enumeration's + scope is not a using. */ + flags |= cbf_using; if (OVL_EXPORT_P (ovl)) flags |= cbf_export; } @@ -15300,13 +15301,54 @@ module_state::read_cluster (unsigned snum) /* Stat hack. */ if (type || !DECL_IMPLICIT_TYPEDEF_P (decl)) sec.set_overrun (); - type = decl; + + if (flags & cbf_using) + { + type = build_lang_decl_loc (UNKNOWN_LOCATION, + USING_DECL, + DECL_NAME (decl), + NULL_TREE); + USING_DECL_DECLS (type) = decl; + USING_DECL_SCOPE (type) = CP_DECL_CONTEXT (decl); + DECL_CONTEXT (type) = ns; + + DECL_MODULE_PURVIEW_P (type) = true; + if (flags & cbf_export) + DECL_MODULE_EXPORT_P (type) = true; + } + else + type = decl; } else { - if (decls - || (flags & (cbf_hidden | cbf_wrapped)) - || DECL_FUNCTION_TEMPLATE_P (decl)) + if ((flags & cbf_using) && + !DECL_DECLARES_FUNCTION_P (decl)) + { + /* We should only see a single non-function using-decl + for a binding; more than that would clash. */ + if (decls) + sec.set_overrun (); + + /* FIXME: Propagate the location of the using-decl + for use in diagnostics. */ + decls = build_lang_decl_loc (UNKNOWN_LOCATION, + USING_DECL, + DECL_NAME (decl), + NULL_TREE); + USING_DECL_DECLS (decls) = decl; + /* We don't currently record the actual scope of the + using-declaration, but this approximation should + generally be good enough. */ + USING_DECL_SCOPE (decls) = CP_DECL_CONTEXT (decl); + DECL_CONTEXT (decls) = ns; + + DECL_MODULE_PURVIEW_P (decls) = true; + if (flags & cbf_export) + DECL_MODULE_EXPORT_P (decls) = true; + } + else if (decls + || (flags & (cbf_hidden | cbf_using)) + || DECL_FUNCTION_TEMPLATE_P (decl)) { decls = ovl_make (decl, decls); if (flags & cbf_using) @@ -19202,6 +19244,7 @@ set_instantiating_module (tree decl) || TREE_CODE (decl) == TYPE_DECL || TREE_CODE (decl) == CONCEPT_DECL || TREE_CODE (decl) == TEMPLATE_DECL + || TREE_CODE (decl) == CONST_DECL || (TREE_CODE (decl) == NAMESPACE_DECL && DECL_NAMESPACE_ALIAS (decl))); |