@@ -813,6 +813,8 @@ typedef struct ptrmem_cst * ptrmem_cst_t;
#define OVL_LOOKUP_P(NODE) TREE_LANG_FLAG_4 (OVERLOAD_CHECK (NODE))
/* If set, this OVL_USING_P overload is exported. */
#define OVL_EXPORT_P(NODE) TREE_LANG_FLAG_5 (OVERLOAD_CHECK (NODE))
+/* If set, this OVL_USING_P overload is in the module purview. */
+#define OVL_PURVIEW_P(NODE) (OVERLOAD_CHECK (NODE)->base.public_flag)
/* If set, this overload includes name-independent declarations. */
#define OVL_NAME_INDEPENDENT_DECL_P(NODE) \
TREE_LANG_FLAG_6 (OVERLOAD_CHECK (NODE))
@@ -887,6 +889,11 @@ class ovl_iterator {
return (TREE_CODE (ovl) == USING_DECL
|| (TREE_CODE (ovl) == OVERLOAD && OVL_USING_P (ovl)));
}
+ /* Whether this using is in the module purview. */
+ bool purview_p () const
+ {
+ return OVL_PURVIEW_P (get_using ());
+ }
/* Whether this using is being exported. */
bool exporting_p () const
{
@@ -13137,9 +13137,8 @@ depset::hash::add_binding_entity (tree decl, WMB_Flags flags, void *data_)
inner = DECL_TEMPLATE_RESULT (inner);
if ((!DECL_LANG_SPECIFIC (inner) || !DECL_MODULE_PURVIEW_P (inner))
- && !((flags & WMB_Using) && (flags & WMB_Export)))
- /* Ignore global module fragment entities unless explicitly
- exported with a using declaration. */
+ && !((flags & WMB_Using) && (flags & WMB_Purview)))
+ /* Ignore entities not within the module purview. */
return false;
if (VAR_OR_FUNCTION_DECL_P (inner)
@@ -13189,6 +13188,7 @@ depset::hash::add_binding_entity (tree decl, WMB_Flags flags, void *data_)
{
if (!(flags & WMB_Hidden))
d->clear_hidden_binding ();
+ OVL_PURVIEW_P (d->get_entity ()) = true;
if (flags & WMB_Export)
OVL_EXPORT_P (d->get_entity ()) = true;
return bool (flags & WMB_Export);
@@ -13230,6 +13230,7 @@ depset::hash::add_binding_entity (tree decl, WMB_Flags flags, void *data_)
decl = ovl_make (decl, NULL_TREE);
if (!unscoped_enum_const_p)
OVL_USING_P (decl) = true;
+ OVL_PURVIEW_P (decl) = true;
if (flags & WMB_Export)
OVL_EXPORT_P (decl) = true;
}
@@ -15311,6 +15312,7 @@ module_state::read_cluster (unsigned snum)
{
dedup = true;
OVL_USING_P (decls) = true;
+ OVL_PURVIEW_P (decls) = true;
if (flags & cbf_export)
OVL_EXPORT_P (decls) = true;
}
@@ -4234,6 +4234,8 @@ walk_module_binding (tree binding, bitmap partitions,
if (iter.using_p ())
{
flags = WMB_Flags (flags | WMB_Using);
+ if (iter.purview_p ())
+ flags = WMB_Flags (flags | WMB_Purview);
if (iter.exporting_p ())
flags = WMB_Flags (flags | WMB_Export);
}
@@ -4307,6 +4309,8 @@ walk_module_binding (tree binding, bitmap partitions,
if (iter.using_p ())
{
flags = WMB_Flags (flags | WMB_Using);
+ if (iter.purview_p ())
+ flags = WMB_Flags (flags | WMB_Purview);
if (iter.exporting_p ())
flags = WMB_Flags (flags | WMB_Export);
}
@@ -5210,9 +5214,10 @@ do_nonmember_using_decl (name_lookup &lookup, bool fn_scope_p,
for (lkp_iterator usings (lookup.value); usings; ++usings)
{
tree new_fn = *usings;
- bool exporting = revealing_p && module_exporting_p ();
- if (exporting)
- exporting = check_can_export_using_decl (new_fn);
+ tree inner = STRIP_TEMPLATE (new_fn);
+ bool exporting_p = revealing_p && module_exporting_p ();
+ if (exporting_p)
+ exporting_p = check_can_export_using_decl (new_fn);
/* [namespace.udecl]
@@ -5239,18 +5244,18 @@ do_nonmember_using_decl (name_lookup &lookup, bool fn_scope_p,
;
else if (old.using_p ())
{
- if (exporting)
- /* Update in place. 'tis ok. */
+ /* Update in place. 'tis ok. */
+ OVL_PURVIEW_P (old.get_using ()) = true;
+ if (exporting_p)
OVL_EXPORT_P (old.get_using ()) = true;
- ;
- }
- else if (DECL_MODULE_EXPORT_P (new_fn))
- ;
- else
- {
- value = old.remove_node (value);
- found = false;
}
+ else if (!DECL_LANG_SPECIFIC (inner)
+ || !DECL_MODULE_PURVIEW_P (inner))
+ /* We need to re-insert this function as a revealed
+ (possibly exported) declaration. We can't remove
+ the existing decl because that will change any
+ overloads cached in template functions. */
+ found = false;
break;
}
else if (old.using_p ())
@@ -5261,8 +5266,14 @@ do_nonmember_using_decl (name_lookup &lookup, bool fn_scope_p,
continue; /* Parameters do not match. */
else if (decls_match (new_fn, old_fn))
{
- /* Extern "C" in different namespaces. */
+ /* Extern "C" in different namespaces. But similarly
+ to above, if revealing a not-revealed thing we may
+ need to reinsert. */
found = true;
+ if (revealing_p
+ && (!DECL_LANG_SPECIFIC (inner)
+ || !DECL_MODULE_PURVIEW_P (inner)))
+ found = false;
break;
}
else
@@ -5278,7 +5289,7 @@ do_nonmember_using_decl (name_lookup &lookup, bool fn_scope_p,
/* Unlike the decl-pushing case we don't drop anticipated
builtins here. They don't cause a problem, and we'd
like to match them with a future declaration. */
- value = ovl_insert (new_fn, value, 1 + exporting);
+ value = ovl_insert (new_fn, value, 1 + revealing_p + exporting_p);
}
}
else if (value
@@ -5291,32 +5302,32 @@ do_nonmember_using_decl (name_lookup &lookup, bool fn_scope_p,
}
else if (insert_p)
{
- if (revealing_p
- && module_exporting_p ()
- && check_can_export_using_decl (lookup.value)
- && lookup.value == value
- && !DECL_MODULE_EXPORT_P (value))
+ /* FIXME: Handle exporting declarations from a different scope
+ without also marking those declarations as exported.
+ This will require not just binding directly to the underlying
+ value; see c++/114863 and c++/114865. We allow this for purview
+ declarations for now as this doesn't (currently) cause ICEs
+ later down the line, but should also be revisited then. */
+ if (revealing_p)
{
- /* We're redeclaring the same value, but this time as
- newly exported: make sure to mark it as such. */
- if (TREE_CODE (value) == TEMPLATE_DECL)
- {
- DECL_MODULE_EXPORT_P (value) = true;
-
- tree result = DECL_TEMPLATE_RESULT (value);
- retrofit_lang_decl (result);
- DECL_MODULE_PURVIEW_P (result) = true;
- DECL_MODULE_EXPORT_P (result) = true;
- }
- else
+ if (module_exporting_p ()
+ && check_can_export_using_decl (lookup.value)
+ && lookup.value == value
+ && !DECL_MODULE_EXPORT_P (lookup.value))
{
- retrofit_lang_decl (value);
- DECL_MODULE_PURVIEW_P (value) = true;
- DECL_MODULE_EXPORT_P (value) = true;
+ /* We're redeclaring the same value, but this time as
+ newly exported: make sure to mark it as such. */
+ if (TREE_CODE (lookup.value) == TEMPLATE_DECL)
+ DECL_MODULE_EXPORT_P (DECL_TEMPLATE_RESULT (lookup.value)) = true;
+ DECL_MODULE_EXPORT_P (lookup.value) = true;
}
+ /* We're also revealing this declaration with a using-decl,
+ so mark it as purview to ensure it's emitted. */
+ tree inner = STRIP_TEMPLATE (lookup.value);
+ retrofit_lang_decl (inner);
+ DECL_MODULE_PURVIEW_P (inner) = true;
}
- else
- value = lookup.value;
+ value = lookup.value;
}
/* Now the type binding. */
@@ -5329,20 +5340,17 @@ do_nonmember_using_decl (name_lookup &lookup, bool fn_scope_p,
}
else if (insert_p)
{
- if (revealing_p
- && module_exporting_p ()
- && check_can_export_using_decl (lookup.type)
- && lookup.type == type
- && !DECL_MODULE_EXPORT_P (type))
+ if (revealing_p)
{
- /* We're redeclaring the same type, but this time as
- newly exported: make sure to mark it as such. */
- retrofit_lang_decl (type);
- DECL_MODULE_PURVIEW_P (type) = true;
- DECL_MODULE_EXPORT_P (type) = true;
+ /* As with revealing value bindings. */
+ if (module_exporting_p ()
+ && check_can_export_using_decl (lookup.type)
+ && lookup.type == type)
+ DECL_MODULE_EXPORT_P (lookup.type) = true;
+ retrofit_lang_decl (lookup.type);
+ DECL_MODULE_PURVIEW_P (lookup.type) = true;
}
- else
- type = lookup.type;
+ type = lookup.type;
}
}
@@ -495,6 +495,7 @@ enum WMB_Flags
WMB_Export = 1 << 1,
WMB_Using = 1 << 2,
WMB_Hidden = 1 << 3,
+ WMB_Purview = 1 << 4,
};
extern unsigned walk_module_binding (tree binding, bitmap partitions,
@@ -2353,11 +2353,11 @@ ovl_make (tree fn, tree next)
return result;
}
-/* Add FN to the (potentially NULL) overload set OVL. USING_OR_HIDDEN is >
- zero if this is a using-decl. It is > 1 if we're exporting the
- using decl. USING_OR_HIDDEN is < 0, if FN is hidden. (A decl
- cannot be both using and hidden.) We keep the hidden decls first,
- but remaining ones are unordered. */
+/* Add FN to the (potentially NULL) overload set OVL. USING_OR_HIDDEN is > 0
+ if this is a using-decl. It is > 1 if we're revealing the using decl.
+ It is > 2 if we're also exporting it. USING_OR_HIDDEN is < 0, if FN is
+ hidden. (A decl cannot be both using and hidden.) We keep the hidden
+ decls first, but remaining ones are unordered. */
tree
ovl_insert (tree fn, tree maybe_ovl, int using_or_hidden)
@@ -2384,6 +2384,8 @@ ovl_insert (tree fn, tree maybe_ovl, int using_or_hidden)
{
OVL_DEDUP_P (maybe_ovl) = OVL_USING_P (maybe_ovl) = true;
if (using_or_hidden > 1)
+ OVL_PURVIEW_P (maybe_ovl) = true;
+ if (using_or_hidden > 2)
OVL_EXPORT_P (maybe_ovl) = true;
}
}
new file mode 100644
@@ -0,0 +1,31 @@
+// PR c++/114867
+// { dg-additional-options "-fmodules-ts -Wno-global-module" }
+// { dg-module-cmi M }
+
+module;
+
+namespace ns {
+ template <typename T> void f(T);
+
+ namespace inner {
+ class E {};
+ int f(E);
+ }
+ using inner::f;
+}
+
+export module M;
+
+template <typename T>
+struct X {
+ void test() { ns::f(T{}); }
+};
+template struct X<int>;
+
+export namespace ns {
+ using ns::f;
+}
+
+export auto get_e() {
+ return ns::inner::E{};
+}
new file mode 100644
@@ -0,0 +1,13 @@
+// PR c++/114867
+// { dg-additional-options "-fmodules-ts" }
+
+import M;
+
+int main() {
+ int a = 0;
+ ns::f(a);
+
+ // Should also still find the inner::f overload
+ auto e = get_e();
+ int r = ns::f(e);
+}
new file mode 100644
@@ -0,0 +1,29 @@
+// { dg-additional-options "-fmodules-ts -Wno-global-module" }
+// { dg-module-cmi M }
+// Test revealing non-exported declarations still prevents
+// needed GMF declarations from being discarded
+
+module;
+
+struct A {};
+int f();
+
+namespace ns {
+ struct B {};
+ int g();
+}
+
+extern "C" int h();
+namespace ns {
+ extern "C" int h();
+}
+
+export module M;
+
+using ::A;
+using ::f;
+
+using ns::B;
+using ns::g;
+
+using ns::h;
new file mode 100644
@@ -0,0 +1,11 @@
+// { dg-additional-options "-fmodules-ts" }
+
+module M;
+
+void test() {
+ A a;
+ B b;
+ int x = f();
+ int y = g();
+ int z = h();
+}