/* Anonymous types can't be forward-declared. */
&& !IDENTIFIER_ANON_P (DECL_NAME (not_tmpl)))
dep->set_flag_bit<DB_IS_PENDING_BIT> ();
+
+ /* Namespace-scope functions can be found by ADL by template
+ instantiations in this module. We need to create bindings
+ for them so that name lookup recognises they exist, if they
+ won't be discarded. add_binding_entity is too early to do
+ this for GM functions, because if nobody ends up using them
+ we'll have leftover bindings laying around, and it's tricky
+ to delete them and any namespaces they've implicitly created
+ deps on. The downside is this means we don't pick up on
+ using-decls, but by [module.global.frag] p3.6 we don't have
+ to. */
+ if (ek == EK_DECL
+ && !for_binding
+ && !dep->is_import ()
+ && !dep->is_tu_local ()
+ && DECL_NAMESPACE_SCOPE_P (decl)
+ && DECL_DECLARES_FUNCTION_P (decl)
+ /* Compiler-generated functions won't participate in ADL. */
+ && !DECL_ARTIFICIAL (decl)
+ /* A hidden friend doesn't need a binding. */
+ && !(DECL_LANG_SPECIFIC (not_tmpl)
+ && DECL_UNIQUE_FRIEND_P (not_tmpl)))
+ {
+ /* This will only affect GM functions. */
+ gcc_checking_assert (!DECL_LANG_SPECIFIC (not_tmpl)
+ || !DECL_MODULE_PURVIEW_P (not_tmpl));
+ /* We shouldn't see any instantiations or specialisations. */
+ gcc_checking_assert (!DECL_LANG_SPECIFIC (decl)
+ || !DECL_USE_TEMPLATE (decl));
+
+ tree ns = CP_DECL_CONTEXT (decl);
+ tree name = DECL_NAME (decl);
+ depset *binding = find_binding (ns, name);
+ if (!binding)
+ {
+ binding = make_binding (ns, name);
+ add_namespace_context (binding, ns);
+
+ depset **slot = binding_slot (ns, name, /*insert=*/true);
+ *slot = binding;
+ }
+
+ binding->deps.safe_push (dep);
+ dep->deps.safe_push (binding);
+ dump (dumper::DEPEND)
+ && dump ("Built ADL binding for %C:%N",
+ TREE_CODE (decl), decl);
+ }
}
if (!dep->is_import ())
if ((!DECL_LANG_SPECIFIC (inner) || !DECL_MODULE_PURVIEW_P (inner))
&& !((flags & WMB_Using) && (flags & WMB_Purview)))
- /* Ignore entities not within the module purview. */
+ /* Ignore entities not within the module purview. We'll need to
+ create bindings for any non-discarded function calls for ADL,
+ but it's simpler to handle that at the point of use rather
+ than trying to clear out bindings after the fact. */
return false;
if (!header_module_p () && data->hash->is_tu_local_entity (decl))
binding->deps.safe_push (dep);
dep->deps.safe_push (binding);
+ dump (dumper::DEPEND)
+ && dump ("Built binding for deduction guide %C:%N",
+ TREE_CODE (decl), decl);
}
}
print_node (file, "template", TI_TEMPLATE (node), indent+4);
print_node (file, "args", TI_ARGS (node), indent+4);
if (TI_TEMPLATE (node)
+ && TREE_CODE (TI_TEMPLATE (node)) == TEMPLATE_DECL
&& PRIMARY_TEMPLATE_P (TI_TEMPLATE (node)))
print_node (file, "partial", TI_PARTIAL_INFO (node), indent+4);
if (TI_PENDING_TEMPLATE_FLAG (node))
--- /dev/null
+// PR c++/121705
+// { dg-additional-options "-fmodules -Wno-global-module -fdump-lang-module-graph" }
+// { dg-module-cmi M }
+
+module;
+namespace helpers {
+ template <typename T> bool operator<(T, int);
+}
+namespace ns {
+ struct E {};
+ bool operator==(E, int);
+ template <typename T> bool foo(E, T);
+
+ // won't be found
+ using helpers::operator<; // NB [module.global.frag] p3.6
+ void unused(E);
+}
+export module M;
+
+export template <typename T> bool test_op(T t, int x) {
+ // ensure it's not discarded
+ ns::E{} == x;
+ foo(ns::E{}, x);
+ // { dg-final { scan-lang-dump {Built ADL binding for function_decl:'::ns::operator=='} module } }
+ // { dg-final { scan-lang-dump {Built ADL binding for template_decl:'::ns::template foo'} module } }
+ return t == x && foo(t, x);
+}
+
+export template <typename T> bool test_using(T t, int x) {
+ // ensure it's not discarded
+ ns::E{} < 0;
+ // { dg-final { scan-lang-dump {Built ADL binding for template_decl:'::helpers::template operator<'} module } }
+ return t < x;
+}
+
+export template <typename T> void test_unused(T t) {
+ // we never use this non-dependently, so it gets discarded
+ unused(t);
+ // { dg-final { scan-lang-dump-not {'::ns::unused'} module } }
+}
+
+export using ns::E;
--- /dev/null
+// PR c++/121705
+// { dg-additional-options "-fmodules" }
+
+import M;
+int main() {
+ test_op(E{}, 0);
+
+ test_using(E{}, 0); // { dg-message "here" }
+ // { dg-error "no match for 'operator<'" "" { target *-*-* } 0 }
+
+ test_unused(E{}); // { dg-message "here" }
+ // { dg-error "'unused' was not declared" "" { target *-*-* } 0 }
+}
{
return foo () + bar <int> () + baz <int> ();
}
+
+export using ::foo;
+export using ::bar;
+export using ::baz;
// C++20 P1766R1 - Mitigating minor modules maladies
-// { dg-do run }
+// { dg-module-do run }
// { dg-additional-options "-fmodules-ts" }
import M;
int
-foo (int i = 42)
+foo (int i = 42) // { dg-bogus "default argument given for parameter 1 of 'int foo\\\(int\\\)'" "PR99000" { xfail *-*-* } }
{
return i;
}
-template <typename T, typename U = int>
+template <typename T, typename U = int> // { dg-bogus "redefinition of default argument for 'class U'" "PR99000" { xfail *-*-* } }
int
bar ()
{
return sizeof (U);
}
-template <typename T, int N = 42>
+template <typename T, int N = 42> // { dg-bogus "redefinition of default argument for 'int N'" "PR99000" { xfail *-*-* } }
int
baz ()
{
+++ /dev/null
-// C++20 P1766R1 - Mitigating minor modules maladies
-// { dg-additional-options "-fmodules-ts -Wno-global-module" }
-// { dg-module-cmi M }
-
-module;
-
-int foo (int i = 42);
-template <typename T, typename U = int>
-int bar ();
-template <typename T, int N = 42>
-int baz ();
-
-export module M;
-
-export inline int
-qux ()
-{
- return foo () + bar <int> () + baz <int> ();
-}
-
-export using ::foo;
-export using ::bar;
-export using ::baz;
+++ /dev/null
-// C++20 P1766R1 - Mitigating minor modules maladies
-// { dg-additional-options "-fmodules-ts" }
-
-import M;
-
-int
-foo (int i = 42) // { dg-error "default argument given for parameter 1 of 'int foo\\\(int\\\)'" }
-{
- return i;
-}
-
-template <typename T, typename U = int> // { dg-error "redefinition of default argument for 'class U'" }
-int
-bar ()
-{
- return sizeof (U);
-}
-
-template <typename T, int N = 42> // { dg-error "redefinition of default argument for 'int N'" }
-int
-baz ()
-{
- return N;
-}
-
-int
-main ()
-{
- if (foo () + bar <int> () + baz <int> () != qux ())
- __builtin_abort ();
- if (foo () != foo (42)
- || bar <int> () != bar <int, int> ()
- || baz <int> () != baz <int, 42> ())
- __builtin_abort ();
-}
--- /dev/null
+// { dg-additional-options "-fmodules -Wno-global-module -fdump-lang-module" }
+// { dg-module-cmi M }
+
+module;
+namespace test {
+ struct S {};
+ void go(S);
+}
+export module M;
+
+// Ideally we don't emit any namespaces that only have discarded entries
+// { dg-final { scan-lang-dump-not {Writing namespace:[0-9]* '::test'} module } }