[gcc r15-4061] c++: Allow references to internal-linkage vars in C++11 [PR113266]

2024-10-04 Thread Nathaniel Shead via Gcc-cvs
https://gcc.gnu.org/g:247643c7e21b087e6c93b8b8d49b4268bf84b03b

commit r15-4061-g247643c7e21b087e6c93b8b8d49b4268bf84b03b
Author: Nathaniel Shead 
Date:   Fri Oct 4 12:01:38 2024 +1000

c++: Allow references to internal-linkage vars in C++11 [PR113266]

[temp.arg.nontype] changed in C++11 to allow naming internal-linkage
variables and functions.  We currently already handle internal-linkage
functions, but variables were missed; this patch updates this.

PR c++/113266
PR c++/116911

gcc/cp/ChangeLog:

* parser.cc (cp_parser_template_argument): Allow
internal-linkage variables since C++11.

gcc/testsuite/ChangeLog:

* g++.dg/cpp0x/nontype6.C: New test.

Signed-off-by: Nathaniel Shead 

Diff:
---
 gcc/cp/parser.cc  | 17 -
 gcc/testsuite/g++.dg/cpp0x/nontype6.C | 19 +++
 2 files changed, 31 insertions(+), 5 deletions(-)

diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 08f9c89f1f04..9d31a975dcf9 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -19864,9 +19864,11 @@ cp_parser_template_argument (cp_parser* parser)
 
  -- the name of a non-type template-parameter; or
 
- -- the name of an object or function with external linkage...
+ -- the name of an object or function with external (or internal,
+   since C++11) linkage...
 
- -- the address of an object or function with external linkage...
+ -- the address of an object or function with external (or internal,
+   since C++11) linkage...
 
  -- a pointer to member...  */
   /* Look for a non-type template parameter.  */
@@ -19929,11 +19931,16 @@ cp_parser_template_argument (cp_parser* parser)
probe = TREE_OPERAND (probe, 1);
  if (VAR_P (probe))
{
- /* A variable without external linkage might still be a
+ /* A variable without valid linkage might still be a
 valid constant-expression, so no error is issued here
 if the external-linkage check fails.  */
- if (!address_p && !DECL_EXTERNAL_LINKAGE_P (probe))
-   cp_parser_simulate_error (parser);
+ if (!address_p)
+   {
+ linkage_kind linkage = decl_linkage (probe);
+ if (linkage != lk_external
+ && (cxx_dialect < cxx11 || linkage != lk_internal))
+   cp_parser_simulate_error (parser);
+   }
}
  else if (is_overloaded_fn (argument))
/* All overloaded functions are allowed; if the external
diff --git a/gcc/testsuite/g++.dg/cpp0x/nontype6.C 
b/gcc/testsuite/g++.dg/cpp0x/nontype6.C
new file mode 100644
index ..5543d1e8b6d2
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/nontype6.C
@@ -0,0 +1,19 @@
+// PR c++/113266, PR c++/116911
+// { dg-do compile }
+
+template  struct a {};
+static int guard1;
+a b;  // { dg-error "constant-expression|invalid" "" { target 
c++98_only } }
+
+namespace {
+  int guard2;
+}
+a c;  // OK in C++98 because guard2 has external linkage
+  // OK since C++11 because we can refer to an internal linkage 
decl
+
+void nolinkage() {
+  static int guard3;
+  a d;  // { dg-error "constant-expression|invalid" "" { target 
c++98_only } }
+  // { dg-error "constant expression|no linkage" "" { target { c++11 && 
c++14_down } } .-1 }
+  // OK since C++17 since we can now refer to no-linkage decls
+}


[gcc r15-4060] c++: Return the underlying decl rather than the USING_DECL from update_binding [PR116913]

2024-10-04 Thread Nathaniel Shead via Gcc-cvs
https://gcc.gnu.org/g:6a1e109158940ce3a2d1ceed3e1b614ea6c9a2de

commit r15-4060-g6a1e109158940ce3a2d1ceed3e1b614ea6c9a2de
Author: Nathaniel Shead 
Date:   Fri Oct 4 10:46:57 2024 +1000

c++: Return the underlying decl rather than the USING_DECL from 
update_binding [PR116913]

Users of pushdecl assume that the returned decl will be a possibly
updated decl matching the one that was passed in.  My r15-3910 change
broke this since in some cases we would now return USING_DECLs; this
patch fixes the situation.

PR c++/116913

gcc/cp/ChangeLog:

* name-lookup.cc (update_binding): Return the strip_using'd old
decl rather than the binding.

gcc/testsuite/ChangeLog:

* g++.dg/lookup/using70.C: New test.

Signed-off-by: Nathaniel Shead 

Diff:
---
 gcc/cp/name-lookup.cc |  4 ++--
 gcc/testsuite/g++.dg/lookup/using70.C | 13 +
 2 files changed, 15 insertions(+), 2 deletions(-)

diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc
index 4754ef5a5229..609bd6e8c9b5 100644
--- a/gcc/cp/name-lookup.cc
+++ b/gcc/cp/name-lookup.cc
@@ -3101,7 +3101,7 @@ update_binding (cp_binding_level *level, cxx_binding 
*binding, tree *slot,
{
  if (same_type_p (TREE_TYPE (old), TREE_TYPE (decl)))
/* Two type decls to the same type.  Do nothing.  */
-   return old_bval;
+   return old;
  else
goto conflict;
}
@@ -3114,7 +3114,7 @@ update_binding (cp_binding_level *level, cxx_binding 
*binding, tree *slot,
 
  /* The new one must be an alias at this point.  */
  gcc_assert (DECL_NAMESPACE_ALIAS (decl));
- return old_bval;
+ return old;
}
   else if (TREE_CODE (old) == VAR_DECL)
{
diff --git a/gcc/testsuite/g++.dg/lookup/using70.C 
b/gcc/testsuite/g++.dg/lookup/using70.C
new file mode 100644
index ..14838eea7ec3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lookup/using70.C
@@ -0,0 +1,13 @@
+// PR c++/116913
+// { dg-do compile { target c++11 } }
+
+namespace ns {
+  struct c {};
+  using d = int;
+}
+
+using ns::c;
+using ns::d;
+
+using c = ns::c;
+using d = ns::d;


[gcc r15-3939] c++: Implement resolution for DR 36 [PR116160]

2024-09-27 Thread Nathaniel Shead via Gcc-cvs
https://gcc.gnu.org/g:2196a20b82bdde2aeb099bcfd164fa29a698e837

commit r15-3939-g2196a20b82bdde2aeb099bcfd164fa29a698e837
Author: Nathaniel Shead 
Date:   Fri Sep 20 00:47:12 2024 +1000

c++: Implement resolution for DR 36 [PR116160]

This implements part of P1787 to no longer complain about redeclaring an
entity via using-decl other than in a class scope.

PR c++/116160

gcc/cp/ChangeLog:

* name-lookup.cc (supplement_binding): Allow redeclaration via
USING_DECL if not in class scope.
(do_nonmember_using_decl): Remove function-scope exemption.
(push_using_decl_bindings): Remove outdated comment.

gcc/testsuite/ChangeLog:

* g++.dg/cpp0x/using-enum-3.C: No longer expect an error.
* g++.dg/lookup/using53.C: Remove XFAIL.
* g++.dg/cpp2a/using-enum-11.C: New test.

Signed-off-by: Nathaniel Shead 
Reviewed-by: Jason Merrill 

Diff:
---
 gcc/cp/name-lookup.cc  | 12 +++-
 gcc/testsuite/g++.dg/cpp0x/using-enum-3.C  |  2 +-
 gcc/testsuite/g++.dg/cpp2a/using-enum-11.C |  9 +
 gcc/testsuite/g++.dg/lookup/using53.C  |  2 +-
 4 files changed, 18 insertions(+), 7 deletions(-)

diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc
index a2f94e0f363e..4754ef5a5229 100644
--- a/gcc/cp/name-lookup.cc
+++ b/gcc/cp/name-lookup.cc
@@ -2874,6 +2874,12 @@ supplement_binding (cxx_binding *binding, tree decl)
 "%<-std=c++2c%> or %<-std=gnu++2c%>");
   binding->value = name_lookup::ambiguous (decl, binding->value);
 }
+  else if (binding->scope->kind != sk_class
+  && TREE_CODE (decl) == USING_DECL
+  && decls_match (target_bval, target_decl))
+/* Since P1787 (DR 36) it is OK to redeclare entities via using-decl,
+   except in class scopes.  */
+ok = false;
   else
 {
   if (!error_operand_p (bval))
@@ -5377,8 +5383,7 @@ do_nonmember_using_decl (name_lookup &lookup, bool 
fn_scope_p,
   else if (value
   /* Ignore anticipated builtins.  */
   && !anticipated_builtin_p (value)
-  && (fn_scope_p
-  || !decls_match (lookup.value, strip_using_decl (value
+  && !decls_match (lookup.value, strip_using_decl (value)))
 {
   diagnose_name_conflict (lookup.value, value);
   failed = true;
@@ -6651,9 +6656,6 @@ push_using_decl_bindings (name_lookup *lookup, tree name, 
tree value)
   type = binding->type;
 }
 
-  /* DR 36 questions why using-decls at function scope may not be
- duplicates.  Disallow it, as C++11 claimed and PR 20420
- implemented.  */
   if (lookup)
 do_nonmember_using_decl (*lookup, true, true, &value, &type);
 
diff --git a/gcc/testsuite/g++.dg/cpp0x/using-enum-3.C 
b/gcc/testsuite/g++.dg/cpp0x/using-enum-3.C
index 34f8bf4fa0bb..4638181c63ce 100644
--- a/gcc/testsuite/g++.dg/cpp0x/using-enum-3.C
+++ b/gcc/testsuite/g++.dg/cpp0x/using-enum-3.C
@@ -9,7 +9,7 @@
 void f ()
 {
   enum e { a };
-  using e::a;  // { dg-error "redeclaration" }
+  using e::a;  // { dg-bogus "redeclaration" "P1787" }
   // { dg-error "enum" "" { target { ! c++2a } } .-1 }
 }
 
diff --git a/gcc/testsuite/g++.dg/cpp2a/using-enum-11.C 
b/gcc/testsuite/g++.dg/cpp2a/using-enum-11.C
new file mode 100644
index ..ff99ed422d5f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/using-enum-11.C
@@ -0,0 +1,9 @@
+// PR c++/116160
+// { dg-do compile { target c++20 } }
+
+enum class Blah { b };
+void foo() {
+  using Blah::b;
+  using Blah::b;
+  using enum Blah;
+}
diff --git a/gcc/testsuite/g++.dg/lookup/using53.C 
b/gcc/testsuite/g++.dg/lookup/using53.C
index e91829e939a9..8279c73bfc4f 100644
--- a/gcc/testsuite/g++.dg/lookup/using53.C
+++ b/gcc/testsuite/g++.dg/lookup/using53.C
@@ -52,5 +52,5 @@ void
 f ()
 {
   using N::i;
-  using N::i;   // { dg-bogus "conflicts" "See P1787 (CWG36)" { xfail 
*-*-* } }
+  using N::i;   // { dg-bogus "conflicts" "See P1787 (CWG36)" }
 }


[gcc r15-3938] c++: Don't strip USING_DECLs when updating local bindings [PR116748]

2024-09-27 Thread Nathaniel Shead via Gcc-cvs
https://gcc.gnu.org/g:b9ac51a843f9dc807b00ab7f49f64968807a4ee8

commit r15-3938-gb9ac51a843f9dc807b00ab7f49f64968807a4ee8
Author: Nathaniel Shead 
Date:   Fri Sep 20 00:05:04 2024 +1000

c++: Don't strip USING_DECLs when updating local bindings [PR116748]

Currently update_binding strips USING_DECLs too eagerly, leading to ICEs
in pop_local_decl as it can't find the decl it's popping in the binding
list.  Let's rather try to keep the original USING_DECL around.

This also means that using59.C can point to the location of the
using-decl rather than the underlying object directly; this is in the
direction required to fix PR c++/106851 (though more work is needed to
emit properly helpful diagnostics here).

PR c++/116748

gcc/cp/ChangeLog:

* name-lookup.cc (update_binding): Maintain USING_DECLs in the
binding slots.

gcc/testsuite/ChangeLog:

* g++.dg/lookup/using59.C: Update location.
* g++.dg/lookup/using69.C: New test.

Signed-off-by: Nathaniel Shead 
Reviewed-by: Jason Merrill 

Diff:
---
 gcc/cp/name-lookup.cc | 12 +++-
 gcc/testsuite/g++.dg/lookup/using59.C |  4 ++--
 gcc/testsuite/g++.dg/lookup/using69.C | 10 ++
 3 files changed, 19 insertions(+), 7 deletions(-)

diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc
index eb365b259d92..a2f94e0f363e 100644
--- a/gcc/cp/name-lookup.cc
+++ b/gcc/cp/name-lookup.cc
@@ -3005,6 +3005,8 @@ update_binding (cp_binding_level *level, cxx_binding 
*binding, tree *slot,
 
   if (old == error_mark_node)
 old = NULL_TREE;
+
+  tree old_bval = old;
   old = strip_using_decl (old);
 
   if (DECL_IMPLICIT_TYPEDEF_P (decl))
@@ -3021,7 +3023,7 @@ update_binding (cp_binding_level *level, cxx_binding 
*binding, tree *slot,
  gcc_checking_assert (!to_type);
  hide_type = hiding;
  to_type = decl;
- to_val = old;
+ to_val = old_bval;
}
   else
hide_value = hiding;
@@ -3034,7 +3036,7 @@ update_binding (cp_binding_level *level, cxx_binding 
*binding, tree *slot,
   /* OLD is an implicit typedef.  Move it to to_type.  */
   gcc_checking_assert (!to_type);
 
-  to_type = old;
+  to_type = old_bval;
   hide_type = hide_value;
   old = NULL_TREE;
   hide_value = false;
@@ -3093,7 +3095,7 @@ update_binding (cp_binding_level *level, cxx_binding 
*binding, tree *slot,
{
  if (same_type_p (TREE_TYPE (old), TREE_TYPE (decl)))
/* Two type decls to the same type.  Do nothing.  */
-   return old;
+   return old_bval;
  else
goto conflict;
}
@@ -3106,7 +3108,7 @@ update_binding (cp_binding_level *level, cxx_binding 
*binding, tree *slot,
 
  /* The new one must be an alias at this point.  */
  gcc_assert (DECL_NAMESPACE_ALIAS (decl));
- return old;
+ return old_bval;
}
   else if (TREE_CODE (old) == VAR_DECL)
{
@@ -3121,7 +3123,7 @@ update_binding (cp_binding_level *level, cxx_binding 
*binding, tree *slot,
   else
{
conflict:
- diagnose_name_conflict (decl, old);
+ diagnose_name_conflict (decl, old_bval);
  to_val = NULL_TREE;
}
 }
diff --git a/gcc/testsuite/g++.dg/lookup/using59.C 
b/gcc/testsuite/g++.dg/lookup/using59.C
index 3c3a73c28d59..b7ec325d2348 100644
--- a/gcc/testsuite/g++.dg/lookup/using59.C
+++ b/gcc/testsuite/g++.dg/lookup/using59.C
@@ -1,10 +1,10 @@
 
 namespace Y
 {
-  extern int I; //  { dg-message "previous declaration" }
+  extern int I;
 }
 
-using Y::I;
+using Y::I; // { dg-message "previous declaration" }
 extern int I; // { dg-error "conflicts with a previous" }
 
 extern int J;
diff --git a/gcc/testsuite/g++.dg/lookup/using69.C 
b/gcc/testsuite/g++.dg/lookup/using69.C
new file mode 100644
index ..7d52b73b9ce0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lookup/using69.C
@@ -0,0 +1,10 @@
+// PR c++/116748
+
+namespace ns {
+  struct empty;
+}
+
+void foo() {
+  using ns::empty;
+  int empty;
+}


[gcc r15-3937] c++/modules: Propagate purview/import for templates in duplicate_decls [PR116803]

2024-09-27 Thread Nathaniel Shead via Gcc-cvs
https://gcc.gnu.org/g:cf9efe5ec14fea3ad5746fbefb22544bb9424d9d

commit r15-3937-gcf9efe5ec14fea3ad5746fbefb22544bb9424d9d
Author: Nathaniel Shead 
Date:   Fri Sep 27 18:58:27 2024 +1000

c++/modules: Propagate purview/import for templates in duplicate_decls 
[PR116803]

We need to ensure that for a declaration in the module purview, that the
resulting declaration has PURVIEW_P set and IMPORT_P cleared so that we
understand it might be something requiring exporting.  This is normally
handled for a declaration by set_instantiating_module, but when this
declaration is a redeclaration duplicate_decls needs to propagate this
to olddecl.

This patch only changes the logic for template declarations, because in
the non-template case the whole contents of olddecl's DECL_LANG_SPECIFIC
is replaced with newdecl's (which includes these flags), so there's
nothing to do.

PR c++/116803

gcc/cp/ChangeLog:

* decl.cc (duplicate_decls): Propagate DECL_MODULE_PURVIEW_P and
DECL_MODULE_IMPORT_P for template redeclarations.

gcc/testsuite/ChangeLog:

* g++.dg/modules/merge-18_a.H: New test.
* g++.dg/modules/merge-18_b.H: New test.
* g++.dg/modules/merge-18_c.C: New test.

Signed-off-by: Nathaniel Shead 
Reviewed-by: Jason Merrill 

Diff:
---
 gcc/cp/decl.cc| 10 ++
 gcc/testsuite/g++.dg/modules/merge-18_a.H |  8 
 gcc/testsuite/g++.dg/modules/merge-18_b.H | 13 +
 gcc/testsuite/g++.dg/modules/merge-18_c.C | 10 ++
 4 files changed, 41 insertions(+)

diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index 6a7ba416cf8a..07fb9855cd20 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -2528,6 +2528,16 @@ duplicate_decls (tree newdecl, tree olddecl, bool 
hiding, bool was_hidden)
}
}
 
+  /* Propagate purviewness and importingness as with
+set_instantiating_module.  */
+  if (modules_p ())
+   {
+ if (DECL_MODULE_PURVIEW_P (new_result))
+   DECL_MODULE_PURVIEW_P (old_result) = true;
+ if (!DECL_MODULE_IMPORT_P (new_result))
+   DECL_MODULE_IMPORT_P (old_result) = false;
+   }
+
   /* If the new declaration is a definition, update the file and
 line information on the declaration, and also make
 the old declaration the same definition.  */
diff --git a/gcc/testsuite/g++.dg/modules/merge-18_a.H 
b/gcc/testsuite/g++.dg/modules/merge-18_a.H
new file mode 100644
index ..8d86ad980ba5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/merge-18_a.H
@@ -0,0 +1,8 @@
+// PR c++/116803
+// { dg-additional-options "-fmodule-header" }
+// { dg-module-cmi {} }
+
+namespace ns {
+  template  void foo();
+  template  extern const int bar;
+}
diff --git a/gcc/testsuite/g++.dg/modules/merge-18_b.H 
b/gcc/testsuite/g++.dg/modules/merge-18_b.H
new file mode 100644
index ..2a762e2ac498
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/merge-18_b.H
@@ -0,0 +1,13 @@
+// PR c++/116803
+// { dg-additional-options "-fmodule-header -fdump-lang-module" }
+// { dg-module-cmi {} }
+
+import "merge-18_a.H";
+
+namespace ns {
+  template  void foo() {}
+  template  const int bar = 123;
+}
+
+// { dg-final { scan-lang-dump {Writing definition '::ns::template foo'} 
module } }
+// { dg-final { scan-lang-dump {Writing definition '::ns::template bar'} 
module } }
diff --git a/gcc/testsuite/g++.dg/modules/merge-18_c.C 
b/gcc/testsuite/g++.dg/modules/merge-18_c.C
new file mode 100644
index ..b90d85f75024
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/merge-18_c.C
@@ -0,0 +1,10 @@
+// PR c++/116803
+// { dg-module-do link }
+// { dg-additional-options "-fmodules-ts" }
+
+import "merge-18_b.H";
+
+int main() {
+  ns::foo();
+  static_assert(ns::bar == 123);
+}


[gcc r15-3913] c++/modules: Allow imported references in constant expressions

2024-09-26 Thread Nathaniel Shead via Gcc-cvs
https://gcc.gnu.org/g:1a0b33ebc57ebcc9595b19050f5c36c1f9d39e3e

commit r15-3913-g1a0b33ebc57ebcc9595b19050f5c36c1f9d39e3e
Author: Nathaniel Shead 
Date:   Thu Sep 12 20:06:39 2024 +1000

c++/modules: Allow imported references in constant expressions

Currently the streaming code uses TREE_CONSTANT to determine whether an
entity will have a definition that is interesting to stream out.  This
is not sufficient, however; we also need to write the definition of
references, since although not TREE_CONSTANT they can still be usable in
constant expressions.

As such this patch uses the existing decl_maybe_constant_var function
which correctly handles this case.

gcc/cp/ChangeLog:

* module.cc (has_definition): Use decl_maybe_constant_var
instead of TREE_CONSTANT.

gcc/testsuite/ChangeLog:

* g++.dg/modules/cexpr-5_a.C: New test.
* g++.dg/modules/cexpr-5_b.C: New test.

Signed-off-by: Nathaniel Shead 
Reviewed-by: Jason Merrill 

Diff:
---
 gcc/cp/module.cc |  2 +-
 gcc/testsuite/g++.dg/modules/cexpr-5_a.C | 13 +
 gcc/testsuite/g++.dg/modules/cexpr-5_b.C |  9 +
 3 files changed, 23 insertions(+), 1 deletion(-)

diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index f5df9e875d3a..65b37b4b5544 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -11829,7 +11829,7 @@ has_definition (tree decl)
   since there's no TU to emit them in otherwise.  */
return true;
 
- if (!TREE_CONSTANT (decl))
+ if (!decl_maybe_constant_var_p (decl))
return false;
 
  return true;
diff --git a/gcc/testsuite/g++.dg/modules/cexpr-5_a.C 
b/gcc/testsuite/g++.dg/modules/cexpr-5_a.C
new file mode 100644
index ..3a9f00523f65
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/cexpr-5_a.C
@@ -0,0 +1,13 @@
+// { dg-additional-options "-fmodules-ts" }
+// { dg-module-cmi M }
+
+export module M;
+
+int x = 123;
+void f() {}
+
+int& xr = x;
+auto& fr = f;
+
+constexpr int& cxr = xr;
+constexpr auto& cfr = fr;
diff --git a/gcc/testsuite/g++.dg/modules/cexpr-5_b.C 
b/gcc/testsuite/g++.dg/modules/cexpr-5_b.C
new file mode 100644
index ..4b1b901104bc
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/cexpr-5_b.C
@@ -0,0 +1,9 @@
+// { dg-additional-options "-fmodules-ts" }
+
+module M;
+
+constexpr auto& use_xr = xr;
+constexpr auto& use_fr = fr;
+
+static_assert(&cxr == &use_xr);
+static_assert(&cfr == &use_fr);


[gcc r15-3912] c++/modules: Fix linkage checks for exported using-decls

2024-09-26 Thread Nathaniel Shead via Gcc-cvs
https://gcc.gnu.org/g:d0762e93ce1ed046e1dd9477ebe0ad941c298677

commit r15-3912-gd0762e93ce1ed046e1dd9477ebe0ad941c298677
Author: Nathaniel Shead 
Date:   Wed Sep 4 01:18:19 2024 +1000

c++/modules: Fix linkage checks for exported using-decls

This fixes some inconsistencies with what kinds of linkage various
entities are assumed to have.  This also fixes handling of exported
using-decls binding to GM entities and type aliases to better align with
the standard's requirements.

gcc/cp/ChangeLog:

* name-lookup.cc (check_can_export_using_decl): Handle internal
linkage GM entities (but ignore in header units); use linkage
of entity ultimately referred to by aliases.

gcc/testsuite/ChangeLog:

* g++.dg/modules/using-10.C: Add tests for no-linkage, fix
expected linkage of aliases.
* g++.dg/modules/using-12.C: Likewise.
* g++.dg/modules/using-27.C: New test.
* g++.dg/modules/using-28_a.C: New test.
* g++.dg/modules/using-28_b.C: New test.
* g++.dg/modules/using-29.H: New test.

Signed-off-by: Nathaniel Shead 
Reviewed-by: Jason Merrill 

Diff:
---
 gcc/cp/name-lookup.cc | 57 ++-
 gcc/testsuite/g++.dg/modules/using-10.C   | 56 +++---
 gcc/testsuite/g++.dg/modules/using-12.C   | 42 ---
 gcc/testsuite/g++.dg/modules/using-27.C   | 14 
 gcc/testsuite/g++.dg/modules/using-28_a.C | 12 +++
 gcc/testsuite/g++.dg/modules/using-28_b.C |  8 +
 gcc/testsuite/g++.dg/modules/using-29.H   |  6 
 7 files changed, 154 insertions(+), 41 deletions(-)

diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc
index c0f89f98d87e..eb365b259d92 100644
--- a/gcc/cp/name-lookup.cc
+++ b/gcc/cp/name-lookup.cc
@@ -5206,38 +5206,47 @@ pushdecl_outermost_localscope (tree x)
 static bool
 check_can_export_using_decl (tree binding)
 {
-  tree decl = STRIP_TEMPLATE (binding);
-
-  /* Linkage is determined by the owner of an enumerator.  */
-  if (TREE_CODE (decl) == CONST_DECL)
-decl = TYPE_NAME (DECL_CONTEXT (decl));
+  /* Declarations in header units are always OK.  */
+  if (header_module_p ())
+return true;
 
-  /* If the using decl is exported, the things it refers
- to must also be exported (or not have module attachment).  */
-  if (!DECL_MODULE_EXPORT_P (decl)
-  && (DECL_LANG_SPECIFIC (decl)
- && DECL_MODULE_ATTACH_P (decl)))
+  /* We want the linkage of the underlying entity, so strip typedefs.
+ If the underlying entity is a builtin type then we're OK.  */
+  tree entity = binding;
+  if (TREE_CODE (entity) == TYPE_DECL)
 {
-  bool internal_p = !TREE_PUBLIC (decl);
+  entity = TYPE_MAIN_DECL (TREE_TYPE (entity));
+  if (!entity)
+   return true;
+}
 
-  /* A template in an anonymous namespace doesn't constrain TREE_PUBLIC
-until it's instantiated, so double-check its context.  */
-  if (!internal_p && TREE_CODE (binding) == TEMPLATE_DECL)
-   internal_p = decl_internal_context_p (decl);
+  linkage_kind linkage = decl_linkage (entity);
+  tree not_tmpl = STRIP_TEMPLATE (entity);
 
+  /* Attachment is determined by the owner of an enumerator.  */
+  if (TREE_CODE (not_tmpl) == CONST_DECL)
+not_tmpl = TYPE_NAME (DECL_CONTEXT (not_tmpl));
+
+  /* If the using decl is exported, the things it refers to must
+ have external linkage.  decl_linkage returns lk_external for
+ module linkage so also check for attachment.  */
+  if (linkage != lk_external
+  || (DECL_LANG_SPECIFIC (not_tmpl)
+ && DECL_MODULE_ATTACH_P (not_tmpl)
+ && !DECL_MODULE_EXPORT_P (not_tmpl)))
+{
   auto_diagnostic_group d;
   error ("exporting %q#D that does not have external linkage",
 binding);
-  if (TREE_CODE (decl) == TYPE_DECL && !DECL_IMPLICIT_TYPEDEF_P (decl))
-   /* An un-exported explicit type alias has no linkage.  */
-   inform (DECL_SOURCE_LOCATION (binding),
-   "%q#D declared here with no linkage", binding);
-  else if (internal_p)
-   inform (DECL_SOURCE_LOCATION (binding),
-   "%q#D declared here with internal linkage", binding);
+  if (linkage == lk_none)
+   inform (DECL_SOURCE_LOCATION (entity),
+   "%q#D declared here with no linkage", entity);
+  else if (linkage == lk_internal)
+   inform (DECL_SOURCE_LOCATION (entity),
+   "%q#D declared here with internal linkage", entity);
   else
-   inform (DECL_SOURCE_LOCATION (binding),
-   "%q#D declared here with module linkage", binding);
+   inform (DECL_SOURCE_LOCATION (entity),
+   "%q#D declared here with module linkage", entity);
   return false;
 }
 
diff --git a/gcc/testsuite/g++.dg/modules/using-10.C 
b/gcc/testsuite/g++.dg/modules/using-10.C
index d468a36f5d

[gcc r15-3911] c++/modules: Use decl_linkage in maybe_record_mergeable_decl

2024-09-26 Thread Nathaniel Shead via Gcc-cvs
https://gcc.gnu.org/g:ad08ef098a8c8bb9c148d0a32e91456fdf58ffc1

commit r15-3911-gad08ef098a8c8bb9c148d0a32e91456fdf58ffc1
Author: Nathaniel Shead 
Date:   Wed Sep 4 02:42:58 2024 +1000

c++/modules: Use decl_linkage in maybe_record_mergeable_decl

This avoids any possible inconsistencies (current or future) about
whether a declaration is internal or not.

gcc/cp/ChangeLog:

* name-lookup.cc (maybe_record_mergeable_decl): Use decl_linkage
instead of ad-hoc checks.

Signed-off-by: Nathaniel Shead 
Reviewed-by: Jason Merrill 

Diff:
---
 gcc/cp/name-lookup.cc | 9 +
 1 file changed, 1 insertion(+), 8 deletions(-)

diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc
index 50e169eca43e..c0f89f98d87e 100644
--- a/gcc/cp/name-lookup.cc
+++ b/gcc/cp/name-lookup.cc
@@ -3725,17 +3725,10 @@ maybe_record_mergeable_decl (tree *slot, tree name, 
tree decl)
   if (TREE_CODE (*slot) != BINDING_VECTOR)
 return;
 
-  if (!TREE_PUBLIC (CP_DECL_CONTEXT (decl)))
-/* Member of internal namespace.  */
+  if (decl_linkage (decl) == lk_internal)
 return;
 
   tree not_tmpl = STRIP_TEMPLATE (decl);
-  if ((TREE_CODE (not_tmpl) == FUNCTION_DECL
-   || VAR_P (not_tmpl))
-  && DECL_THIS_STATIC (not_tmpl))
-/* Internal linkage.  */
-return;
-
   bool is_attached = (DECL_LANG_SPECIFIC (not_tmpl)
  && DECL_MODULE_ATTACH_P (not_tmpl));
   tree *gslot = get_fixed_binding_slot


[gcc r15-3910] c++: Update decl_linkage for C++11

2024-09-26 Thread Nathaniel Shead via Gcc-cvs
https://gcc.gnu.org/g:af4471cb422a867f1877c7c08bb63fa75afe

commit r15-3910-gaf4471cb422a867f1877c7c08bb63fa75afe
Author: Nathaniel Shead 
Date:   Mon Aug 19 16:38:41 2024 +1000

c++: Update decl_linkage for C++11

Currently modules code uses a variety of ad-hoc methods to attempt to
determine whether an entity has internal linkage, which leads to
inconsistencies and some correctness issues as different edge cases are
neglected.  While investigating this I discovered 'decl_linkage', but it
doesn't seem to have been updated to account for the C++11 clarification
that all entities declared in an anonymous namespace are internal.

I'm not convinced that even in C++98 it was intended that e.g. types in
anonymous namespaces should be external, but some tests in the testsuite
rely on this, so for compatibility I restricted those modifications to
C++11 and later.

This should have relatively minimal impact as not much seems to actually
rely on decl_linkage, but does change the mangling of symbols in
anonymous namespaces slightly.  Previously, we had

  namespace {
int x;  // mangled as '_ZN12_GLOBAL__N_11xE'
static int y;  // mangled as '_ZN12_GLOBAL__N_1L1yE'
  }

but with this patch the x is now mangled like y (with the extra 'L').
For contrast, Clang currently mangles neither x nor y with the 'L'.
Since this only affects internal-linkage entities I don't believe this
should break ABI in any observable fashion.

gcc/cp/ChangeLog:

* name-lookup.cc (do_namespace_alias): Propagate TREE_PUBLIC for
namespace aliases.
* tree.cc (decl_linkage): Update rules for C++11.

gcc/testsuite/ChangeLog:

* g++.dg/modules/mod-sym-4.C: Update test to account for
non-static internal-linkage variables new mangling.

Signed-off-by: Nathaniel Shead 
Reviewed-by: Jason Merrill 

Diff:
---
 gcc/cp/name-lookup.cc|  1 +
 gcc/cp/tree.cc   | 92 
 gcc/testsuite/g++.dg/modules/mod-sym-4.C |  4 +-
 3 files changed, 60 insertions(+), 37 deletions(-)

diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc
index c7a693e02d59..50e169eca43e 100644
--- a/gcc/cp/name-lookup.cc
+++ b/gcc/cp/name-lookup.cc
@@ -6610,6 +6610,7 @@ do_namespace_alias (tree alias, tree name_space)
   DECL_NAMESPACE_ALIAS (alias) = name_space;
   DECL_EXTERNAL (alias) = 1;
   DECL_CONTEXT (alias) = FROB_CONTEXT (current_scope ());
+  TREE_PUBLIC (alias) = TREE_PUBLIC (DECL_CONTEXT (alias));
   set_originating_module (alias);
 
   pushdecl (alias);
diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
index e8d8b2ab6f70..0a7a56cc6e2e 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -5841,7 +5841,7 @@ char_type_p (tree type)
  || same_type_p (type, wchar_type_node));
 }
 
-/* Returns the kind of linkage associated with the indicated DECL.  Th
+/* Returns the kind of linkage associated with the indicated DECL.  The
value returned is as specified by the language standard; it is
independent of implementation details regarding template
instantiation, etc.  For example, it is possible that a declaration
@@ -5858,53 +5858,75 @@ decl_linkage (tree decl)
  linkage first, and then transform that into a concrete
  implementation.  */
 
-  /* Things that don't have names have no linkage.  */
-  if (!DECL_NAME (decl))
-return lk_none;
+  /* An explicit type alias has no linkage.  */
+  if (TREE_CODE (decl) == TYPE_DECL
+  && !DECL_IMPLICIT_TYPEDEF_P (decl)
+  && !DECL_SELF_REFERENCE_P (decl))
+{
+  /* But this could be a typedef name for linkage purposes, in which
+case we're interested in the linkage of the main decl.  */
+  if (decl == TYPE_NAME (TYPE_MAIN_VARIANT (TREE_TYPE (decl
+   decl = TYPE_MAIN_DECL (TREE_TYPE (decl));
+  else
+   return lk_none;
+}
 
-  /* Fields have no linkage.  */
-  if (TREE_CODE (decl) == FIELD_DECL)
+  /* Namespace-scope entities with no name usually have no linkage.  */
+  if (NAMESPACE_SCOPE_P (decl)
+  && (!DECL_NAME (decl) || IDENTIFIER_ANON_P (DECL_NAME (decl
+{
+  if (TREE_CODE (decl) == TYPE_DECL && !TYPE_ANON_P (TREE_TYPE (decl)))
+   /* This entity has a typedef name for linkage purposes.  */;
+  else if (TREE_CODE (decl) == NAMESPACE_DECL && cxx_dialect >= cxx11)
+   /* An anonymous namespace has internal linkage since C++11.  */
+   return lk_internal;
+  else
+   return lk_none;
+}
+
+  /* Fields and parameters have no linkage.  */
+  if (TREE_CODE (decl) == FIELD_DECL || TREE_CODE (decl) == PARM_DECL)
 return lk_none;
 
-  /* Things in local scope do not have linkage.  */
+  /* Things in block scope do not have linkage.  */
   if (decl_function_context (decl))
 return lk_none;
 
+  /* Things in class scope have the linkage 

[gcc r15-3906] libgcc, libstdc++: Make declarations no longer TU-local [PR115126]

2024-09-26 Thread Nathaniel Shead via Gcc-cvs
https://gcc.gnu.org/g:6a4d1c374eed177eceb12a50f3b25bd20f8b347a

commit r15-3906-g6a4d1c374eed177eceb12a50f3b25bd20f8b347a
Author: Nathaniel Shead 
Date:   Tue Sep 24 23:53:59 2024 +1000

libgcc, libstdc++: Make declarations no longer TU-local [PR115126]

In C++20, modules streaming check for exposures of TU-local entities.
In general exposing internal linkage functions in a header is liable to
cause ODR violations in C++, and this is now detected in a module
context.

This patch goes through and removes 'static' from many declarations
exposed through libstdc++ to prevent code like the following from
failing:

  export module M;
  extern "C++" {
#include 
  }

Since gthreads is used from C as well, we need to choose whether to use
'inline' or 'static inline' depending on whether we're compiling for C
or C++ (since the semantics of 'inline' are different between the
languages).  Additionally we need to remove static global variables, so
we migrate these to function-local statics to avoid the ODR issues.

There doesn't seem to be a good workaround for weakrefs, so I've left
them as-is and will work around it in the modules streaming code to
consider them as not TU-local.

The same issue occurs in the objective-C specific parts of gthreads, but
I'm not familiar with the surrounding context and we don't currently
test modules with Objective C++ anyway so I've left it as-is.

PR libstdc++/115126

libgcc/ChangeLog:

* gthr-posix.h (__GTHREAD_ALWAYS_INLINE): New macro.
(__GTHREAD_INLINE): New macro.
(__gthread_active): Convert from variable to (hidden) function.
(__gthread_active_p): Mark as __GTHREAD_INLINE instead of
static; make visibility("hidden") when it has a static local
variable.
(__gthread_trigger): Mark as __GTHREAD_INLINE instead of static.
(__gthread_create): Likewise.
(__gthread_join): Likewise.
(__gthread_detach): Likewise.
(__gthread_equal): Likewise.
(__gthread_self): Likewise.
(__gthread_yield): Likewise.
(__gthread_once): Likewise.
(__gthread_key_create): Likewise.
(__gthread_key_delete): Likewise.
(__gthread_getspecific): Likewise.
(__gthread_setspecific): Likewise.
(__gthread_mutex_init_function): Likewise.
(__gthread_mutex_destroy): Likewise.
(__gthread_mutex_lock): Likewise.
(__gthread_mutex_trylock): Likewise.
(__gthread_mutex_timedlock): Likewise.
(__gthread_mutex_unlock): Likewise.
(__gthread_recursive_mutex_init_function): Likewise.
(__gthread_recursive_mutex_lock): Likewise.
(__gthread_recursive_mutex_trylock): Likewise.
(__gthread_recursive_mutex_timedlock): Likewise.
(__gthread_recursive_mutex_unlock): Likewise.
(__gthread_recursive_mutex_destroy): Likewise.
(__gthread_cond_init_function): Likewise.
(__gthread_cond_broadcast): Likewise.
(__gthread_cond_signal): Likewise.
(__gthread_cond_wait): Likewise.
(__gthread_cond_timedwait): Likewise.
(__gthread_cond_wait_recursive): Likewise.
(__gthread_cond_destroy): Likewise.
(__gthread_rwlock_rdlock): Likewise.
(__gthread_rwlock_tryrdlock): Likewise.
(__gthread_rwlock_wrlock): Likewise.
(__gthread_rwlock_trywrlock): Likewise.
(__gthread_rwlock_unlock): Likewise.
* gthr-single.h: (__GTHREAD_ALWAYS_INLINE): New macro.
(__GTHREAD_INLINE): New macro.
(__gthread_active_p): Mark as __GTHREAD_INLINE instead of static.
(__gthread_once): Likewise.
(__gthread_key_create): Likewise.
(__gthread_key_delete): Likewise.
(__gthread_getspecific): Likewise.
(__gthread_setspecific): Likewise.
(__gthread_mutex_destroy): Likewise.
(__gthread_mutex_lock): Likewise.
(__gthread_mutex_trylock): Likewise.
(__gthread_mutex_unlock): Likewise.
(__gthread_recursive_mutex_lock): Likewise.
(__gthread_recursive_mutex_trylock): Likewise.
(__gthread_recursive_mutex_unlock): Likewise.
(__gthread_recursive_mutex_destroy): Likewise.

libstdc++-v3/ChangeLog:

* include/bits/shared_ptr.h (std::__is_shared_ptr): Remove
unnecessary 'static'.
* include/bits/unique_ptr.h (std::__is_unique_ptr): Likewise.
* include/std/future (std::__create_task_state): Likewise.
* include/std/shared_mutex (_GLIBCXX_GTRHW): Likewise.
(__glibcxx_rwlock_init): Likewise.
(__glibcxx_r

[gcc r15-3884] testsuite: Fix testcase g++.dg/modules/indirect-1_b.C [PR116846]

2024-09-25 Thread Nathaniel Shead via Gcc-cvs
https://gcc.gnu.org/g:064d5c67d7ad2be446c19e84f0cd993ecab784c3

commit r15-3884-g064d5c67d7ad2be446c19e84f0cd993ecab784c3
Author: Nathaniel Shead 
Date:   Thu Sep 26 11:12:02 2024 +1000

testsuite: Fix testcase g++.dg/modules/indirect-1_b.C [PR116846]

r15-3878 exposed a mistake in the testcase, probably from an older
version of the dumping logic.

Apart from the slightly different syntax for the dump line, also check
for importing the type_decl rather than the const_decl (we need the type
anyway and importing the type also brings along the enumerators so it
would be unnecessary to seed an import for them as well).

PR c++/116846

gcc/testsuite/ChangeLog:

* g++.dg/modules/indirect-1_b.C: Fix testcase.

Signed-off-by: Nathaniel Shead 

Diff:
---
 gcc/testsuite/g++.dg/modules/indirect-1_b.C | 7 ++-
 1 file changed, 2 insertions(+), 5 deletions(-)

diff --git a/gcc/testsuite/g++.dg/modules/indirect-1_b.C 
b/gcc/testsuite/g++.dg/modules/indirect-1_b.C
index dee8a00ef15e..e5abf66c7b3d 100644
--- a/gcc/testsuite/g++.dg/modules/indirect-1_b.C
+++ b/gcc/testsuite/g++.dg/modules/indirect-1_b.C
@@ -48,8 +48,5 @@ namespace bar
 // { dg-final { scan-lang-dump {Lazily binding '::foo::Scoped'@'foo' section:} 
module } }
 // { dg-final { scan-lang-dump-not {Lazily binding 
'::foo::Scoped@foo:.::[ABCD]'@'foo' section:} module } }
 
-// XFAIL is for PR116846
-// { dg-final { scan-lang-dump {Wrote named import:-[0-9]* 
const_decl:'::foo::Plain@\(foo\)::C'@foo} module { xfail *-*-* } } }
-// { dg-final { scan-lang-dump {Wrote named import:-[0-9]* 
const_decl:'::foo::Plain@\(foo\)::B'@foo} module { xfail *-*-* } } }
-// { dg-final { scan-lang-dump {Wrote named import:-[0-9]* 
const_decl:'::foo::Scoped@\(foo\)::C'@foo} module { xfail *-*-* } } }
-// { dg-final { scan-lang-dump {Wrote named import:-[0-9]* 
const_decl:'::foo::Scoped@\(foo\)::B'@foo} module { xfail *-*-* } } }
+// { dg-final { scan-lang-dump-times {Wrote import:-[0-9]* 
type_decl:'::foo::Plain@foo:.'@foo} 2 module } }
+// { dg-final { scan-lang-dump-times {Wrote import:-[0-9]* 
type_decl:'::foo::Scoped@foo:.'@foo} 2 module } }


[gcc r15-3592] c++/modules: Really always track partial specialisations [PR116496]

2024-09-11 Thread Nathaniel Shead via Gcc-cvs
https://gcc.gnu.org/g:ba393bf8879e5cf1f917bd88246d6b80ac081052

commit r15-3592-gba393bf8879e5cf1f917bd88246d6b80ac081052
Author: Nathaniel Shead 
Date:   Wed Sep 11 22:41:21 2024 +1000

c++/modules: Really always track partial specialisations [PR116496]

My last fix for this issue (PR c++/114947, r15-810) didn't go far
enough; I had assumed that the issue where we lost track of partial
specialisations we would need to walk again later was limited to
partitions (where we always re-walk all specialisations), but the linked
PR is the same cause but for header units, and it is possible to
construct test cases exposing the same bug just for normal modules.

As such this patch just unconditionally ensures that whenever we modify
DECL_TEMPLATE_SPECIALIZATIONS we also track any partial specialisations
that might have added.

Also clean up a couple of comments and assertions to make expected state
more obvious when processing these specs.

PR c++/116496

gcc/cp/ChangeLog:

* module.cc (trees_in::decl_value): Don't call
set_defining_module_for_partial_spec here.
(depset::hash::add_partial_entities): Clarity assertions.
* pt.cc (add_mergeable_specialization): Always call
set_defining_module_for_partial_spec when adding a partial spec.

gcc/testsuite/ChangeLog:

* g++.dg/modules/partial-5_a.C: New test.
* g++.dg/modules/partial-5_b.C: New test.

Signed-off-by: Nathaniel Shead 

Diff:
---
 gcc/cp/module.cc   | 25 -
 gcc/cp/pt.cc   |  1 +
 gcc/testsuite/g++.dg/modules/partial-5_a.C |  9 +
 gcc/testsuite/g++.dg/modules/partial-5_b.C |  9 +
 4 files changed, 31 insertions(+), 13 deletions(-)

diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index dc0e9e5520f9..f5df9e875d3a 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -8434,11 +8434,6 @@ trees_in::decl_value ()
  add_mergeable_specialization (!is_type, &spec, decl, spec_flags);
}
 
-  /* When making a CMI from a partition we're going to need to walk partial
-specializations again, so make sure they're tracked.  */
-  if (state->is_partition () && (spec_flags & 2))
-   set_defining_module_for_partial_spec (inner);
-
   if (NAMESPACE_SCOPE_P (decl)
  && (mk == MK_named || mk == MK_unique
  || mk == MK_enum || mk == MK_friend_spec)
@@ -13356,16 +13351,20 @@ depset::hash::add_partial_entities (vec 
*partial_classes)
 specialization.  */
  gcc_checking_assert (dep->get_entity_kind ()
   == depset::EK_PARTIAL);
+
+ /* Only emit GM entities if reached.  */
+ if (!DECL_LANG_SPECIFIC (inner)
+ || !DECL_MODULE_PURVIEW_P (inner))
+   dep->set_flag_bit ();
}
   else
-   /* It was an explicit specialization, not a partial one.  */
-   gcc_checking_assert (dep->get_entity_kind ()
-== depset::EK_SPECIALIZATION);
-
-  /* Only emit GM entities if reached.  */
-  if (!DECL_LANG_SPECIFIC (inner)
- || !DECL_MODULE_PURVIEW_P (inner))
-   dep->set_flag_bit ();
+   {
+ /* It was an explicit specialization, not a partial one.
+We should have already added this.  */
+ gcc_checking_assert (dep->get_entity_kind ()
+  == depset::EK_SPECIALIZATION);
+ gcc_checking_assert (dep->is_special ());
+   }
 }
 }
 
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 310e5dfff033..cb3164d49147 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -31684,6 +31684,7 @@ add_mergeable_specialization (bool decl_p, spec_entry 
*elt, tree decl,
 DECL_TEMPLATE_SPECIALIZATIONS (elt->tmpl));
   TREE_TYPE (cons) = decl_p ? TREE_TYPE (elt->spec) : elt->spec;
   DECL_TEMPLATE_SPECIALIZATIONS (elt->tmpl) = cons;
+  set_defining_module_for_partial_spec (STRIP_TEMPLATE (decl));
 }
 }
 
diff --git a/gcc/testsuite/g++.dg/modules/partial-5_a.C 
b/gcc/testsuite/g++.dg/modules/partial-5_a.C
new file mode 100644
index ..768e6995f0ff
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/partial-5_a.C
@@ -0,0 +1,9 @@
+// PR c++/116496
+// { dg-additional-options "-fmodules-ts -std=c++20 -Wno-global-module" }
+// { dg-module-cmi A }
+
+module;
+template  struct S {};
+export module A;
+template  struct S {};
+template  requires false struct S {};
diff --git a/gcc/testsuite/g++.dg/modules/partial-5_b.C 
b/gcc/testsuite/g++.dg/modules/partial-5_b.C
new file mode 100644
index ..95401fe8b562
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/partial-5_b.C
@@ -0,0 +1,9 @@
+// PR c++/116496
+// { dg-additional-options "-fmodules-ts -std=c++20 -Wno-global-module" }
+// { dg-module-cmi B }
+
+module;
+template  struct S {

[gcc r15-3482] c++: Add missing auto_diagnostic_groups

2024-09-05 Thread Nathaniel Shead via Gcc-cvs
https://gcc.gnu.org/g:cb76fcf5ebf0817e6f1b7c019071362f7a5f3ae0

commit r15-3482-gcb76fcf5ebf0817e6f1b7c019071362f7a5f3ae0
Author: Nathaniel Shead 
Date:   Wed Aug 7 19:20:19 2024 +1000

c++: Add missing auto_diagnostic_groups

This patch goes through all .cc files in gcc/cp and adds in any
auto_diagnostic_groups that seem to be missing by looking for any
'inform' calls that aren't grouped with their respective error/warning.
Now with SARIF output support this seems to be a bit more important.

The patch isn't complete; I've tried to also track helper functions used
for diagnostics to group them, but some may have been missed.
Additionally there are a few functions that are definitely missing
groupings but I wasn't able to see an obvious way to add them without
potentially grouping together unrelated messages.

This list includes:

- lazy_load_{binding,pendings} "during load of {binding,pendings} for"
- cp_finish_decomp "in initialization of structured binding variable"
- require_deduced_type "using __builtin_source_location"
- convert_nontype_argument "in template argument for type %qT"
- coerce_template_params "so any instantiation with a non-empty parameter 
pack"
- tsubst_default_argument "when instantiating default argument"
- invalid_nontype_parm_type_p "invalid template non-type parameter"

gcc/cp/ChangeLog:

* class.cc (add_method): Add missing auto_diagnostic_group.
(handle_using_decl): Likewise.
(maybe_warn_about_overly_private_class): Likewise.
(check_field_decl): Likewise.
(check_field_decls): Likewise.
(resolve_address_of_overloaded_function): Likewise.
(note_name_declared_in_class): Likewise.
* constraint.cc (associate_classtype_constraints): Likewise.
(diagnose_trait_expr): Clean up whitespace.
* coroutines.cc (find_coro_traits_template_decl): Add missing
auto_diagnostic_group.
(coro_promise_type_found_p): Likewise.
(coro_diagnose_throwing_fn): Likewise.
* cvt.cc (build_expr_type_conversion): Likewise.
* decl.cc (validate_constexpr_redeclaration): Likewise.
(duplicate_function_template_decls): Likewise.
(duplicate_decls): Likewise.
(lookup_label_1): Likewise.
(check_previous_goto_1): Likewise.
(check_goto_1): Likewise.
(make_typename_type): Likewise.
(make_unbound_class_template): Likewise.
(check_tag_decl): Likewise.
(start_decl): Likewise.
(maybe_commonize_var): Likewise.
(check_for_uninitialized_const_var): Likewise.
(reshape_init_class): Likewise.
(check_initializer): Likewise.
(cp_finish_decl): Likewise.
(find_decomp_class_base): Likewise.
(cp_finish_decomp): Likewise.
(expand_static_init): Likewise.
(grokfndecl): Likewise.
(grokdeclarator): Likewise.
(check_elaborated_type_specifier): Likewise.
(lookup_and_check_tag): Likewise.
(xref_tag): Likewise.
(cxx_simulate_enum_decl): Likewise.
(finish_function): Likewise.
* decl2.cc (check_classfn): Likewise.
(record_mangling): Likewise.
(mark_used): Likewise.
* error.cc (qualified_name_lookup_error): Likewise.
* except.cc (build_throw): Likewise.
* init.cc (get_nsdmi): Likewise.
(diagnose_uninitialized_cst_or_ref_member_1): Likewise.
(warn_placement_new_too_small): Likewise.
(build_new_1): Likewise.
(build_vec_delete_1): Likewise.
(build_delete): Likewise.
* lambda.cc (add_capture): Likewise.
(add_default_capture): Likewise.
* lex.cc (unqualified_fn_lookup_error): Likewise.
* method.cc (synthesize_method): Likewise.
(defaulted_late_check): Likewise.
* module.cc (trees_in::is_matching_decl): Likewise.
(trees_in::read_enum_def): Likewise.
(module_state::check_not_purview): Likewise.
(module_state::deferred_macro): Likewise.
(module_state::read_config): Likewise.
(module_state::check_read): Likewise.
(declare_module): Likewise.
(init_modules): Likewise.
* name-lookup.cc (diagnose_name_conflict): Likewise.
(lookup_using_decl): Likewise.
(set_decl_namespace): Likewise.
(finish_using_directive): Likewise.
(push_namespace): Likewise.
(add_imported_namespace): Likewise.
* parser.cc (cp_parser_check_for_definition_in_return_type): 
Likewise.
(cp_parser_userdef_numeric_literal): Likewise.
(cp_parser_nested_na

[gcc r15-3207] c++/modules: Fix include translation for already-seen headers [PR99243]

2024-08-26 Thread Nathaniel Shead via Gcc-cvs
https://gcc.gnu.org/g:215ff991a8681f968823b913e1c79a32d339c097

commit r15-3207-g215ff991a8681f968823b913e1c79a32d339c097
Author: Nathaniel Shead 
Date:   Thu Aug 22 20:41:54 2024 +1000

c++/modules: Fix include translation for already-seen headers [PR99243]

After importing a header unit we learn about and setup any header
modules that we transitively depend on.  However, this causes
'set_filename' to fail an assertion if we then come across this header
as an #include and attempt to translate it into a module.  We still need
to do this translation so that libcpp learns that this is a header unit,
but we shouldn't error just because we've already seen it as an import.

Instead this patch merely checks and errors to handle the case of a
broken mapper implementation which supplies a different CMI path from
the one we already got.

As a drive-by fix, also make failing to find the CMI for a module be a
fatal error: any further errors in the TU are unlikely to be helpful.

PR c++/99243

gcc/cp/ChangeLog:

* module.cc (module_state::set_filename): Handle repeated calls
to 'set_filename' as long as the CMI path matches.
(maybe_translate_include): Adjust comment.

gcc/testsuite/ChangeLog:

* g++.dg/modules/map-2.C: Prune additional fatal error message.
* g++.dg/modules/inc-xlate-4_a.H: New test.
* g++.dg/modules/inc-xlate-4_b.H: New test.
* g++.dg/modules/inc-xlate-4_c.H: New test.

Signed-off-by: Nathaniel Shead 

Diff:
---
 gcc/cp/module.cc | 18 +-
 gcc/testsuite/g++.dg/modules/inc-xlate-4_a.H |  5 +
 gcc/testsuite/g++.dg/modules/inc-xlate-4_b.H |  5 +
 gcc/testsuite/g++.dg/modules/inc-xlate-4_c.H |  6 ++
 gcc/testsuite/g++.dg/modules/map-2.C |  3 ++-
 5 files changed, 31 insertions(+), 6 deletions(-)

diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index 4cd7e1c284b8..95c2405fcd47 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -20086,14 +20086,21 @@ canonicalize_header_name (cpp_reader *reader, 
location_t loc, bool unquoted,
 
 void module_state::set_filename (const Cody::Packet &packet)
 {
-  gcc_checking_assert (!filename);
   if (packet.GetCode () == Cody::Client::PC_PATHNAME)
-filename = xstrdup (packet.GetString ().c_str ());
+{
+  /* If we've seen this import before we better have the same CMI.  */
+  const std::string &path = packet.GetString ();
+  if (!filename)
+   filename = xstrdup (packet.GetString ().c_str ());
+  else if (filename != path)
+   error_at (loc, "mismatching compiled module interface: "
+ "had %qs, got %qs", filename, path.c_str ());
+}
   else
 {
   gcc_checking_assert (packet.GetCode () == Cody::Client::PC_ERROR);
-  error_at (loc, "unknown Compiled Module Interface: %s",
-   packet.GetString ().c_str ());
+  fatal_error (loc, "unknown compiled module interface: %s",
+  packet.GetString ().c_str ());
 }
 }
 
@@ -20127,7 +20134,8 @@ maybe_translate_include (cpp_reader *reader, line_maps 
*lmaps, location_t loc,
 translate = packet.GetInteger () ? xlate_kind::text : xlate_kind::unknown;
   else if (packet.GetCode () == Cody::Client::PC_PATHNAME)
 {
-  /* Record the CMI name for when we do the import.  */
+  /* Record the CMI name for when we do the import.
+We may already know about this import, but libcpp doesn't yet.  */
   module_state *import = get_module (build_string (len, path));
   import->set_filename (packet);
   translate = xlate_kind::import;
diff --git a/gcc/testsuite/g++.dg/modules/inc-xlate-4_a.H 
b/gcc/testsuite/g++.dg/modules/inc-xlate-4_a.H
new file mode 100644
index ..8afb49d01a5a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/inc-xlate-4_a.H
@@ -0,0 +1,5 @@
+// PR c++/99243
+// { dg-additional-options "-fmodule-header" }
+// { dg-module-cmi {} }
+
+void foo();
diff --git a/gcc/testsuite/g++.dg/modules/inc-xlate-4_b.H 
b/gcc/testsuite/g++.dg/modules/inc-xlate-4_b.H
new file mode 100644
index ..0e67566f5716
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/inc-xlate-4_b.H
@@ -0,0 +1,5 @@
+// PR c++/99243
+// { dg-additional-options "-fmodule-header" }
+// { dg-module-cmi {} }
+
+#include "inc-xlate-4_a.H"
diff --git a/gcc/testsuite/g++.dg/modules/inc-xlate-4_c.H 
b/gcc/testsuite/g++.dg/modules/inc-xlate-4_c.H
new file mode 100644
index ..c2fa647bce84
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/inc-xlate-4_c.H
@@ -0,0 +1,6 @@
+// PR c++/99243
+// { dg-additional-options "-fmodule-header" }
+// { dg-module-cmi {} }
+
+#include "inc-xlate-4_b.H"
+#include "inc-xlate-4_a.H"
diff --git a/gcc/testsuite/g++.dg/modules/map-2.C 
b/gcc/testsuite/g++.dg/modules/map-2.C
index 94d3f7a1a41d..3f95aea36705 100644
--- a/gcc/testsuite/g++.dg/modul

[gcc r15-3206] c++/modules: Clean up include translation [PR110980]

2024-08-26 Thread Nathaniel Shead via Gcc-cvs
https://gcc.gnu.org/g:98608342932e8951a4c8db3e9df79f9187424d53

commit r15-3206-g98608342932e8951a4c8db3e9df79f9187424d53
Author: Nathaniel Shead 
Date:   Thu Aug 22 21:04:11 2024 +1000

c++/modules: Clean up include translation [PR110980]

Currently the handling of include translation is confusing to read,
using a tri-state integer without much clarity on what different states
mean.  This patch cleans this up to use explicit enumerators indicating
the different possible states instead, and fixes a bug where the option
'-flang-info-include-translate' ended being accidentally unusable.

PR c++/110980

gcc/cp/ChangeLog:

* module.cc (maybe_translate_include): Clean up.

gcc/testsuite/ChangeLog:

* g++.dg/modules/inc-xlate-2_a.H: New test.
* g++.dg/modules/inc-xlate-2_b.H: New test.
* g++.dg/modules/inc-xlate-3.h: New test.
* g++.dg/modules/inc-xlate-3_a.H: New test.

Signed-off-by: Nathaniel Shead 

Diff:
---
 gcc/cp/module.cc | 23 ++-
 gcc/testsuite/g++.dg/modules/inc-xlate-2_a.H |  3 +++
 gcc/testsuite/g++.dg/modules/inc-xlate-2_b.H |  5 +
 gcc/testsuite/g++.dg/modules/inc-xlate-3.h   |  2 ++
 gcc/testsuite/g++.dg/modules/inc-xlate-3_a.H |  5 +
 5 files changed, 29 insertions(+), 9 deletions(-)

diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index 07477d33955c..4cd7e1c284b8 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -20118,15 +20118,19 @@ maybe_translate_include (cpp_reader *reader, 
line_maps *lmaps, location_t loc,
   size_t len = strlen (path);
   path = canonicalize_header_name (NULL, loc, true, path, len);
   auto packet = mapper->IncludeTranslate (path, Cody::Flags::None, len);
-  int xlate = false;
+
+  enum class xlate_kind {
+unknown, text, import,
+  } translate = xlate_kind::unknown;
+
   if (packet.GetCode () == Cody::Client::PC_BOOL)
-xlate = -int (packet.GetInteger ());
+translate = packet.GetInteger () ? xlate_kind::text : xlate_kind::unknown;
   else if (packet.GetCode () == Cody::Client::PC_PATHNAME)
 {
   /* Record the CMI name for when we do the import.  */
   module_state *import = get_module (build_string (len, path));
   import->set_filename (packet);
-  xlate = +1;
+  translate = xlate_kind::import;
 }
   else
 {
@@ -20136,9 +20140,9 @@ maybe_translate_include (cpp_reader *reader, line_maps 
*lmaps, location_t loc,
 }
 
   bool note = false;
-  if (note_include_translate_yes && xlate > 1)
+  if (note_include_translate_yes && translate == xlate_kind::import)
 note = true;
-  else if (note_include_translate_no && xlate == 0)
+  else if (note_include_translate_no && translate == xlate_kind::unknown)
 note = true;
   else if (note_includes)
 /* We do not expect the note_includes vector to be large, so O(N)
@@ -20148,15 +20152,16 @@ maybe_translate_include (cpp_reader *reader, 
line_maps *lmaps, location_t loc,
note = true;
 
   if (note)
-inform (loc, xlate
+inform (loc, translate == xlate_kind::import
? G_("include %qs translated to import")
-   : G_("include %qs processed textually") , path);
+   : G_("include %qs processed textually"), path);
 
-  dump () && dump (xlate ? "Translating include to import"
+  dump () && dump (translate == xlate_kind::import
+  ? "Translating include to import"
   : "Keeping include as include");
   dump.pop (0);
 
-  if (!(xlate > 0))
+  if (translate != xlate_kind::import)
 return nullptr;
   
   /* Create the translation text.  */
diff --git a/gcc/testsuite/g++.dg/modules/inc-xlate-2_a.H 
b/gcc/testsuite/g++.dg/modules/inc-xlate-2_a.H
new file mode 100644
index ..d6a4866a6766
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/inc-xlate-2_a.H
@@ -0,0 +1,3 @@
+// PR c++/110980
+// { dg-additional-options "-fmodule-header" }
+// { dg-module-cmi {} }
diff --git a/gcc/testsuite/g++.dg/modules/inc-xlate-2_b.H 
b/gcc/testsuite/g++.dg/modules/inc-xlate-2_b.H
new file mode 100644
index ..f04dd430feca
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/inc-xlate-2_b.H
@@ -0,0 +1,5 @@
+// PR c++/110980
+// { dg-additional-options "-fmodule-header -flang-info-include-translate" }
+// { dg-module-cmi {} }
+
+#include "inc-xlate-2_a.H"  // { dg-message "translated to import" }
diff --git a/gcc/testsuite/g++.dg/modules/inc-xlate-3.h 
b/gcc/testsuite/g++.dg/modules/inc-xlate-3.h
new file mode 100644
index ..c0584bada0c2
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/inc-xlate-3.h
@@ -0,0 +1,2 @@
+// PR c++/110980
+// Just an empty file to be an include target.
diff --git a/gcc/testsuite/g++.dg/modules/inc-xlate-3_a.H 
b/gcc/testsuite/g++.dg/modules/inc-xlate-3_a.H
new file mode 100644
index ..47772089149a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/inc-xlate-3_a.H
@@ -0,0 +1,5 @

[gcc r15-3053] c++/modules: Remove unnecessary errors when not writing compiled module

2024-08-20 Thread Nathaniel Shead via Gcc-cvs
https://gcc.gnu.org/g:e668771ff0dcc3c72937768e5c37b6f287b97799

commit r15-3053-ge668771ff0dcc3c72937768e5c37b6f287b97799
Author: Nathaniel Shead 
Date:   Sun Aug 18 21:35:23 2024 +1000

c++/modules: Remove unnecessary errors when not writing compiled module

It was pointed out to me that the current error referencing an internal
linkage entity reads almost like an ICE message, with the message
finishing with the unhelpful:

m.cpp:1:8: error: failed to write compiled module: Bad file data
1 | export module M;
  |^~

Similarly, whenever we decide not to emit a module CMI due to other
errors we currently emit the following message:

m.cpp:1:8: warning: not writing module ‘M’ due to errors
1 | export module M;
  |^~

Neither of these messages really add anything useful; users already
understand that when an error is reported then the normal outputs will
not be created, so these messages are just noise.

There is one case we still need this latter message, however; when an
error in a template has been silenced with '-Wno-template-body' we still
don't want to write a module CMI, so emit an error now instead.

This patch also removes a number of dg-prune-output directives in the
testsuite that are no longer needed with this change.

gcc/cp/ChangeLog:

* module.cc (module_state::write_begin): Return a boolean to
indicate errors rather than just doing set_error().
(finish_module_processing): Prevent emission of unnecessary
errors; only indicate module writing occurred if write_begin
succeeds.

gcc/testsuite/ChangeLog:

* g++.dg/modules/export-1.C: Remove message.
* g++.dg/modules/internal-1.C: Remove message.
* g++.dg/modules/ambig-2_b.C: Remove unnecessary pruning.
* g++.dg/modules/atom-decl-2.C: Likewise.
* g++.dg/modules/atom-pragma-3.C: Likewise.
* g++.dg/modules/atom-preamble-2_f.C: Likewise.
* g++.dg/modules/block-decl-2.C: Likewise.
* g++.dg/modules/dir-only-4.C: Likewise.
* g++.dg/modules/enum-12.C: Likewise.
* g++.dg/modules/exp-xlate-1_b.C: Likewise.
* g++.dg/modules/export-3.C: Likewise.
* g++.dg/modules/friend-3.C: Likewise.
* g++.dg/modules/friend-5_b.C: Likewise.
* g++.dg/modules/inc-xlate-1_e.C: Likewise.
* g++.dg/modules/linkage-2.C: Likewise.
* g++.dg/modules/local-extern-1.C: Likewise.
* g++.dg/modules/main-1.C: Likewise.
* g++.dg/modules/map-2.C: Likewise.
* g++.dg/modules/mod-decl-1.C: Likewise.
* g++.dg/modules/mod-decl-3.C: Likewise.
* g++.dg/modules/pr99174.H: Likewise.
* g++.dg/modules/pr99468.H: Likewise.
* g++.dg/modules/token-1.C: Likewise.
* g++.dg/modules/token-3.C: Likewise.
* g++.dg/modules/token-4.C: Likewise.
* g++.dg/modules/token-5.C: Likewise.
* g++.dg/modules/using-10.C: Likewise.
* g++.dg/modules/using-12.C: Likewise.
* g++.dg/modules/using-3.C: Likewise.
* g++.dg/modules/using-9.C: Likewise.
* g++.dg/modules/using-enum-2.C: Likewise.
* g++.dg/modules/permissive-error-1.C: New test.
* g++.dg/modules/permissive-error-2.C: New test.

Signed-off-by: Nathaniel Shead 
Reviewed-by: Jason Merrill 

Diff:
---
 gcc/cp/module.cc  | 42 ++-
 gcc/testsuite/g++.dg/modules/ambig-2_b.C  |  2 --
 gcc/testsuite/g++.dg/modules/atom-decl-2.C|  2 --
 gcc/testsuite/g++.dg/modules/atom-pragma-3.C  |  2 --
 gcc/testsuite/g++.dg/modules/atom-preamble-2_f.C  |  1 -
 gcc/testsuite/g++.dg/modules/block-decl-2.C   |  2 --
 gcc/testsuite/g++.dg/modules/dir-only-4.C |  1 -
 gcc/testsuite/g++.dg/modules/enum-12.C|  2 --
 gcc/testsuite/g++.dg/modules/exp-xlate-1_b.C  |  1 -
 gcc/testsuite/g++.dg/modules/export-1.C   |  2 --
 gcc/testsuite/g++.dg/modules/export-3.C   |  2 --
 gcc/testsuite/g++.dg/modules/friend-3.C   |  1 -
 gcc/testsuite/g++.dg/modules/friend-5_b.C |  1 -
 gcc/testsuite/g++.dg/modules/inc-xlate-1_e.C  |  2 --
 gcc/testsuite/g++.dg/modules/internal-1.C |  2 +-
 gcc/testsuite/g++.dg/modules/linkage-2.C  |  2 --
 gcc/testsuite/g++.dg/modules/local-extern-1.C |  3 --
 gcc/testsuite/g++.dg/modules/main-1.C |  1 -
 gcc/testsuite/g++.dg/modules/map-2.C  |  2 --
 gcc/testsuite/g++.dg/modules/mod-decl-1.C |  2 --
 gcc/testsuite/g++.dg/modules/mod-decl-3.C |  2 --
 gcc/testsuite/g++.dg/modules/permissive-error-1.C | 10 ++
 gcc/testsuite/g++.dg/modules/permissive-error-2.C | 11 +

[gcc r15-3033] c++/modules: Disable streaming definitions of non-vague-linkage GMF decls [PR115020]

2024-08-20 Thread Nathaniel Shead via Gcc-cvs
https://gcc.gnu.org/g:c1a53d9dcf9ebf0a6b4528a8c3eae48a583f272c

commit r15-3033-gc1a53d9dcf9ebf0a6b4528a8c3eae48a583f272c
Author: Nathaniel Shead 
Date:   Sat Aug 17 22:37:30 2024 +1000

c++/modules: Disable streaming definitions of non-vague-linkage GMF decls 
[PR115020]

The error in the linked PR is caused because 'DECL_THIS_STATIC' is true
for the static member function, causing the streaming code to assume
that this is an internal linkage GM entity that needs to be explicitly
streamed, which then on read-in gets marked as a vague linkage function
(despite being non-inline) causing import_export_decl to complain.

However, I don't see any reason why we should care about this:
definitions in the GMF should just be emitted as per usual regardless of
whether they're internal-linkage or not.  Actually the only thing we
care about here are header modules, since they have no TU to write
definitions into.  As such this patch removes these conditions from
'has_definition' and updates some comments to clarify.

PR c++/115020

gcc/cp/ChangeLog:

* module.cc (has_definition): Only force writing definitions for
header_module_p.

gcc/testsuite/ChangeLog:

* g++.dg/modules/pr115020_a.C: New test.
* g++.dg/modules/pr115020_b.C: New test.

Signed-off-by: Nathaniel Shead 
Reviewed-by: Jason Merrill 

Diff:
---
 gcc/cp/module.cc  | 14 +++---
 gcc/testsuite/g++.dg/modules/pr115020_a.C | 10 ++
 gcc/testsuite/g++.dg/modules/pr115020_b.C | 10 ++
 3 files changed, 27 insertions(+), 7 deletions(-)

diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index ce0ba69641b..7c42aea05ee 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -11790,10 +11790,9 @@ has_definition (tree decl)
   if (DECL_DECLARED_INLINE_P (decl))
return true;
 
-  if (DECL_THIS_STATIC (decl)
- && (header_module_p ()
- || (!DECL_LANG_SPECIFIC (decl) || !DECL_MODULE_PURVIEW_P (decl
-   /* GM static function.  */
+  if (header_module_p ())
+   /* We always need to write definitions in header modules,
+  since there's no TU to emit them in otherwise.  */
return true;
 
   if (DECL_TEMPLATE_INFO (decl))
@@ -11826,11 +11825,12 @@ has_definition (tree decl)
   else
{
  if (!DECL_INITIALIZED_P (decl))
+   /* Not defined.  */
return false;
 
- if (header_module_p ()
- || (!DECL_LANG_SPECIFIC (decl) || !DECL_MODULE_PURVIEW_P (decl)))
-   /* GM static variable.  */
+ if (header_module_p ())
+   /* We always need to write definitions in header modules,
+  since there's no TU to emit them in otherwise.  */
return true;
 
  if (!TREE_CONSTANT (decl))
diff --git a/gcc/testsuite/g++.dg/modules/pr115020_a.C 
b/gcc/testsuite/g++.dg/modules/pr115020_a.C
new file mode 100644
index 000..8c190f13b1e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/pr115020_a.C
@@ -0,0 +1,10 @@
+// PR c++/115020
+// { dg-additional-options "-fmodules-ts -Wno-global-module" }
+// { dg-module-cmi M:a }
+
+module;
+struct Check { static void assertion(); };
+void Check::assertion() {}
+
+module M:a;
+Check c;
diff --git a/gcc/testsuite/g++.dg/modules/pr115020_b.C 
b/gcc/testsuite/g++.dg/modules/pr115020_b.C
new file mode 100644
index 000..e299454ed54
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/pr115020_b.C
@@ -0,0 +1,10 @@
+// PR c++/115020
+// { dg-additional-options "-fmodules-ts -Wno-global-module" }
+// { dg-module-cmi M }
+
+module;
+struct Check { static void assertion(); };
+
+export module M;
+import :a;
+void foo() { Check::assertion(); }


[gcc r15-3032] c++/modules: Handle transitive reachability for deduction guides [PR116403]

2024-08-20 Thread Nathaniel Shead via Gcc-cvs
https://gcc.gnu.org/g:6f115a8eeea41d383dfb1bbb1af6ac9a97aee180

commit r15-3032-g6f115a8eeea41d383dfb1bbb1af6ac9a97aee180
Author: Nathaniel Shead 
Date:   Sun Aug 18 11:36:40 2024 +1000

c++/modules: Handle transitive reachability for deduction guides [PR116403]

Currently we implement [temp.deduct.guide] p1 by forcing all deduction
guides to be considered as exported.  However this is not sufficient:
for transitive non-exported imports we will still hide the deduction
guide from name lookup, causing errors.

This patch instead adjusts name lookup to have a new ANY_REACHABLE flag
to allow for this case.  Currently this is only used by deduction guides
but there are some other circumstances where this may be useful in the
future (e.g. finding existing temploid friends).

PR c++/116403

gcc/cp/ChangeLog:

* pt.cc (deduction_guides_for): Use ANY_REACHABLE for lookup of
deduction guides.
* module.cc (depset::hash::add_deduction_guides): Likewise.
(module_state::write_cluster): No longer override deduction
guides as exported.
* name-lookup.cc (name_lookup::search_namespace_only): Ignore
visibility when LOOK_want::ANY_REACHABLE is specified.
(check_module_override): Ignore visibility when checking for
ambiguating deduction guides.
* name-lookup.h (LOOK_want): New flag 'ANY_REACHABLE'.

gcc/testsuite/ChangeLog:

* g++.dg/modules/dguide-4_a.C: New test.
* g++.dg/modules/dguide-4_b.C: New test.
* g++.dg/modules/dguide-4_c.C: New test.

Signed-off-by: Nathaniel Shead 
Reviewed-by: Jason Merrill 

Diff:
---
 gcc/cp/module.cc  |  7 +-
 gcc/cp/name-lookup.cc | 38 ---
 gcc/cp/name-lookup.h  |  5 +++-
 gcc/cp/pt.cc  |  3 ++-
 gcc/testsuite/g++.dg/modules/dguide-4_a.C | 18 +++
 gcc/testsuite/g++.dg/modules/dguide-4_b.C |  9 
 gcc/testsuite/g++.dg/modules/dguide-4_c.C | 15 
 7 files changed, 79 insertions(+), 16 deletions(-)

diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index 0a4ceffa3d6..ce0ba69641b 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -13645,7 +13645,7 @@ depset::hash::add_deduction_guides (tree decl)
   if (find_binding (ns, name))
 return;
 
-  tree guides = lookup_qualified_name (ns, name, LOOK_want::NORMAL,
+  tree guides = lookup_qualified_name (ns, name, LOOK_want::ANY_REACHABLE,
   /*complain=*/false);
   if (guides == error_mark_node)
 return;
@@ -15228,11 +15228,6 @@ module_state::write_cluster (elf_out *to, depset 
*scc[], unsigned size,
  flags |= cbf_hidden;
else if (DECL_MODULE_EXPORT_P (STRIP_TEMPLATE (bound)))
  flags |= cbf_export;
-   else if (deduction_guide_p (bound))
- /* Deduction guides are always exported so that they are
-visible to name lookup whenever their class template
-is reachable.  */
- flags |= cbf_export;
  }
 
gcc_checking_assert (DECL_P (bound));
diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc
index 872f1af0b2e..70ad4cbf3b5 100644
--- a/gcc/cp/name-lookup.cc
+++ b/gcc/cp/name-lookup.cc
@@ -916,7 +916,8 @@ name_lookup::search_namespace_only (tree scope)
if (unsigned base = cluster->indices[jx].base)
  if (unsigned span = cluster->indices[jx].span)
do
- if (bitmap_bit_p (imports, base))
+ if (bool (want & LOOK_want::ANY_REACHABLE)
+ || bitmap_bit_p (imports, base))
goto found;
while (++base, --span);
continue;
@@ -960,9 +961,17 @@ name_lookup::search_namespace_only (tree scope)
dup_detect |= dup;
  }
 
-   if (STAT_TYPE_VISIBLE_P (bind))
- type = STAT_TYPE (bind);
-   bind = STAT_VISIBLE (bind);
+   if (bool (want & LOOK_want::ANY_REACHABLE))
+ {
+   type = STAT_TYPE (bind);
+   bind = STAT_DECL (bind);
+ }
+   else
+ {
+   if (STAT_TYPE_VISIBLE_P (bind))
+ type = STAT_TYPE (bind);
+   bind = STAT_VISIBLE (bind);
+ }
  }
 
/* And process it.  */
@@ -3761,6 +3770,10 @@ check_module_override (tree decl, tree mvec, bool hiding,
   tree nontmpl = STRIP_TEMPLATE (decl);
   bool attached = DECL_LANG_SPECIFIC (nontm

[gcc r15-3031] c++/modules: Avoid rechecking initializers when streaming NTTPs [PR116382]

2024-08-20 Thread Nathaniel Shead via Gcc-cvs
https://gcc.gnu.org/g:0b7904e274fbd6a736d63c0fed28ea32f9cb5997

commit r15-3031-g0b7904e274fbd6a736d63c0fed28ea32f9cb5997
Author: Nathaniel Shead 
Date:   Fri Aug 16 15:06:33 2024 +1000

c++/modules: Avoid rechecking initializers when streaming NTTPs [PR116382]

When reading an NTTP we call get_template_parm_object which delegates
setting of DECL_INITIAL to the general cp_finish_decl procedure, which
calls check_initializer to validate and record it.

Apart from being unnecessary (it must have already been validated by the
writing module), this also causes errors in cases like the linked PR, as
validating may end up needing to call lazy_load_pendings to determine
any specialisations that may exist which violates assumptions of the
modules streaming code.

This patch works around the issue by adding a flag to
get_template_parm_object to disable these checks when not needed.

PR c++/116382

gcc/cp/ChangeLog:

* cp-tree.h (get_template_parm_object): Add check_init param.
* module.cc (trees_in::tree_node): Pass check_init=false when
building NTTPs.
* pt.cc (get_template_parm_object): Prevent cp_finish_decl from
validating the initializer when check_init=false.

gcc/testsuite/ChangeLog:

* g++.dg/modules/tpl-nttp-1_a.C: New test.
* g++.dg/modules/tpl-nttp-1_b.C: New test.

Signed-off-by: Nathaniel Shead 
Reviewed-by: Jason Merrill 

Diff:
---
 gcc/cp/cp-tree.h|  3 ++-
 gcc/cp/module.cc|  6 +-
 gcc/cp/pt.cc| 18 ++
 gcc/testsuite/g++.dg/modules/tpl-nttp-1_a.C |  8 
 gcc/testsuite/g++.dg/modules/tpl-nttp-1_b.C |  6 ++
 5 files changed, 35 insertions(+), 6 deletions(-)

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 039c70710a2..a9ce44bb214 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -7626,7 +7626,8 @@ enum { nt_opaque = false, nt_transparent = true };
 extern tree alias_template_specialization_p (const_tree, bool);
 extern tree dependent_alias_template_spec_p (const_tree, bool);
 extern bool dependent_opaque_alias_p(const_tree);
-extern tree get_template_parm_object   (tree expr, tree mangle);
+extern tree get_template_parm_object   (tree expr, tree mangle,
+bool check_init = true);
 extern tree tparm_object_argument  (tree);
 extern bool explicit_class_specialization_p (tree);
 extern bool push_tinst_level(tree);
diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index c3218bd5caf..0a4ceffa3d6 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -9938,7 +9938,11 @@ trees_in::tree_node (bool is_use)
tree name = tree_node ();
if (!get_overrun ())
  {
-   res = get_template_parm_object (init, name);
+   /* We don't want to check the initializer as that may require
+  name lookup, which could recursively start lazy loading.
+  Instead we know that INIT is already valid so we can just
+  apply that directly.  */
+   res = get_template_parm_object (init, name, /*check_init=*/false);
int tag = insert (res);
dump (dumper::TREE)
  && dump ("Created nttp object:%d %N", tag, name);
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 32d164f0fd5..76edc7aad50 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -7361,10 +7361,11 @@ create_template_parm_object (tree expr, tsubst_flags_t 
complain)
 static GTY(()) hash_map *tparm_obj_values;
 
 /* Find or build an nttp object for (already-validated) EXPR with name
-   NAME.  */
+   NAME.  When CHECK_INIT is false we don't need to process the initialiser,
+   it's already been done.  */
 
 tree
-get_template_parm_object (tree expr, tree name)
+get_template_parm_object (tree expr, tree name, bool check_init/*=true*/)
 {
   tree decl = get_global_binding (name);
   if (decl)
@@ -7385,11 +7386,20 @@ get_template_parm_object (tree expr, tree name)
 {
   /* If EXPR contains any PTRMEM_CST, they will get clobbered by
 lower_var_init before we're done mangling.  So store the original
-value elsewhere.  */
-  tree copy = unshare_constructor (expr);
+value elsewhere.  We only need to unshare EXPR if it's not yet
+been processed.  */
+  tree copy = check_init ? unshare_constructor (expr) : expr;
   hash_map_safe_put (tparm_obj_values, decl, copy);
 }
 
+  if (!check_init)
+{
+  /* The EXPR is the already processed initializer, set it on the NTTP
+object now so that cp_finish_decl doesn't do it again later.  */
+  DECL_INITIAL (decl) = expr;
+  DECL_INITIALIZED_P (decl) = 1;
+}
+
   pushdecl_top_level_and_finish (decl, expr);
 
   return decl;
diff --git 

[gcc r15-3030] c++/modules: Fix type lookup in DECL_TEMPLATE_INSTANTIATIONS [PR116364]

2024-08-20 Thread Nathaniel Shead via Gcc-cvs
https://gcc.gnu.org/g:c310d29cac1c3a770f48ab8bb2d295ef9cc08c53

commit r15-3030-gc310d29cac1c3a770f48ab8bb2d295ef9cc08c53
Author: Nathaniel Shead 
Date:   Thu Aug 15 21:46:09 2024 +1000

c++/modules: Fix type lookup in DECL_TEMPLATE_INSTANTIATIONS [PR116364]

We need to use the DECL_TEMPLATE_INSTANTIATIONS property to find
reachable specialisations from a template to ensure that any GM
specialisations are properly marked as reachable.

Currently the modules code uses the decl when rebuilding this property,
but this is not always correct; it appears that for type specialisations
we need to use the TREE_TYPE of the decl instead so that the
specialisation is correctly found.  This patch makes the required
adjustments.

PR c++/116364

gcc/cp/ChangeLog:

* cp-tree.h (get_mergeable_specialization_flags): Adjust
signature.
* module.cc (trees_out::decl_value): Indicate whether this is a
type or decl specialisation.
* pt.cc (get_mergeable_specialization_flags): Match against the
type of a non-decl specialisation.
(add_mergeable_specialization): Use the already calculated spec
instead of always adding decl to DECL_TEMPLATE_INSTANTIATIONS.

gcc/testsuite/ChangeLog:

* g++.dg/modules/tpl-spec-9_a.C: New test.
* g++.dg/modules/tpl-spec-9_b.C: New test.
* g++.dg/modules/tpl-spec-9_c.C: New test.

Signed-off-by: Nathaniel Shead 
Reviewed-by: Jason Merrill 

Diff:
---
 gcc/cp/cp-tree.h|  3 ++-
 gcc/cp/module.cc|  3 ++-
 gcc/cp/pt.cc|  8 +---
 gcc/testsuite/g++.dg/modules/tpl-spec-9_a.C | 12 
 gcc/testsuite/g++.dg/modules/tpl-spec-9_b.C |  5 +
 gcc/testsuite/g++.dg/modules/tpl-spec-9_c.C |  5 +
 6 files changed, 31 insertions(+), 5 deletions(-)

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index a53fbcb43ec..039c70710a2 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -7672,7 +7672,8 @@ extern void walk_specializations  (bool,
  void *),
 void *);
 extern tree match_mergeable_specialization (bool is_decl, spec_entry *);
-extern unsigned get_mergeable_specialization_flags (tree tmpl, tree spec);
+extern unsigned get_mergeable_specialization_flags (bool is_decl, tree tmpl,
+   tree spec);
 extern void add_mergeable_specialization(bool is_decl, spec_entry *,
 tree outer, unsigned);
 extern tree add_to_template_args   (tree, tree);
diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index f4d137b13a1..c3218bd5caf 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -7981,7 +7981,8 @@ trees_out::decl_value (tree decl, depset *dep)
  auto *entry = reinterpret_cast  (dep->deps[0]);
 
  if (streaming_p ())
-   u (get_mergeable_specialization_flags (entry->tmpl, decl));
+   u (get_mergeable_specialization_flags (mk & MK_tmpl_decl_mask,
+  entry->tmpl, decl));
  tree_node (entry->tmpl);
  tree_node (entry->args);
}
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 684ee0c8a60..32d164f0fd5 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -31561,13 +31561,14 @@ match_mergeable_specialization (bool decl_p, 
spec_entry *elt)
specialization lists of TMPL.  */
 
 unsigned
-get_mergeable_specialization_flags (tree tmpl, tree decl)
+get_mergeable_specialization_flags (bool decl_p, tree tmpl, tree decl)
 {
   unsigned flags = 0;
 
+  tree spec = decl_p ? decl : TREE_TYPE (decl);
   for (tree inst = DECL_TEMPLATE_INSTANTIATIONS (tmpl);
inst; inst = TREE_CHAIN (inst))
-if (TREE_VALUE (inst) == decl)
+if (TREE_VALUE (inst) == spec)
   {
flags |= 1;
break;
@@ -31625,7 +31626,8 @@ add_mergeable_specialization (bool decl_p, spec_entry 
*elt, tree decl,
 
   if (flags & 1)
 DECL_TEMPLATE_INSTANTIATIONS (elt->tmpl)
-  = tree_cons (elt->args, decl, DECL_TEMPLATE_INSTANTIATIONS (elt->tmpl));
+  = tree_cons (elt->args, elt->spec,
+  DECL_TEMPLATE_INSTANTIATIONS (elt->tmpl));
 
   if (flags & 2)
 {
diff --git a/gcc/testsuite/g++.dg/modules/tpl-spec-9_a.C 
b/gcc/testsuite/g++.dg/modules/tpl-spec-9_a.C
new file mode 100644
index 000..d7c02bb279d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/tpl-spec-9_a.C
@@ -0,0 +1,12 @@
+// PR c++/116364
+// { dg-additional-options "-fmodules-ts -Wno-global-module" }
+// { dg-module-cmi foo:part }
+
+module;
+template  struct S {};
+template <> struct S
+  { static constexpr bool value = true; };
+export module foo:part;
+
+export templa

[gcc r15-2819] c++: Propagate TREE_ADDRESSABLE in fixup_type_variants [PR115062]

2024-08-08 Thread Nathaniel Shead via Gcc-cvs
https://gcc.gnu.org/g:71aebb36174c194231da5f9c7c23f81dbb082ca4

commit r15-2819-g71aebb36174c194231da5f9c7c23f81dbb082ca4
Author: Nathaniel Shead 
Date:   Thu Aug 8 17:52:03 2024 +1000

c++: Propagate TREE_ADDRESSABLE in fixup_type_variants [PR115062]

This has caused issues with modules when an import fills in the
definition of a type already created with a typedef.

PR c++/115062

gcc/cp/ChangeLog:

* class.cc (fixup_type_variants): Propagate TREE_ADDRESSABLE.
(finish_struct_bits): Cleanup now that TREE_ADDRESSABLE is
propagated by fixup_type_variants.

gcc/testsuite/ChangeLog:

* g++.dg/modules/pr115062_a.H: New test.
* g++.dg/modules/pr115062_b.H: New test.
* g++.dg/modules/pr115062_c.C: New test.

Signed-off-by: Nathaniel Shead 

Diff:
---
 gcc/cp/class.cc   | 31 ++-
 gcc/testsuite/g++.dg/modules/pr115062_a.H |  6 ++
 gcc/testsuite/g++.dg/modules/pr115062_b.H | 14 ++
 gcc/testsuite/g++.dg/modules/pr115062_c.C |  9 +
 4 files changed, 43 insertions(+), 17 deletions(-)

diff --git a/gcc/cp/class.cc b/gcc/cp/class.cc
index 718601756ddc..fb6c33709500 100644
--- a/gcc/cp/class.cc
+++ b/gcc/cp/class.cc
@@ -2312,6 +2312,7 @@ fixup_type_variants (tree type)
   TYPE_PRECISION (variant) = TYPE_PRECISION (type);
   TYPE_MODE_RAW (variant) = TYPE_MODE_RAW (type);
   TYPE_EMPTY_P (variant) = TYPE_EMPTY_P (type);
+  TREE_ADDRESSABLE (variant) = TREE_ADDRESSABLE (type);
 }
 }
 
@@ -2378,8 +2379,17 @@ fixup_attribute_variants (tree t)
 static void
 finish_struct_bits (tree t)
 {
-  /* Fix up variants (if any).  */
-  fixup_type_variants (t);
+  /* If this type has a copy constructor or a destructor, force its
+ mode to be BLKmode, and force its TREE_ADDRESSABLE bit to be
+ nonzero.  This will cause it to be passed by invisible reference
+ and prevent it from being returned in a register.  */
+  if (type_has_nontrivial_copy_init (t)
+  || TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t))
+{
+  SET_DECL_MODE (TYPE_MAIN_DECL (t), BLKmode);
+  SET_TYPE_MODE (t, BLKmode);
+  TREE_ADDRESSABLE (t) = 1;
+}
 
   if (BINFO_N_BASE_BINFOS (TYPE_BINFO (t)) && TYPE_POLYMORPHIC_P (t))
 /* For a class w/o baseclasses, 'finish_struct' has set
@@ -2392,21 +2402,8 @@ finish_struct_bits (tree t)
looking in the vtables).  */
 get_pure_virtuals (t);
 
-  /* If this type has a copy constructor or a destructor, force its
- mode to be BLKmode, and force its TREE_ADDRESSABLE bit to be
- nonzero.  This will cause it to be passed by invisible reference
- and prevent it from being returned in a register.  */
-  if (type_has_nontrivial_copy_init (t)
-  || TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t))
-{
-  tree variants;
-  SET_DECL_MODE (TYPE_MAIN_DECL (t), BLKmode);
-  for (variants = t; variants; variants = TYPE_NEXT_VARIANT (variants))
-   {
- SET_TYPE_MODE (variants, BLKmode);
- TREE_ADDRESSABLE (variants) = 1;
-   }
-}
+  /* Fix up variants (if any).  */
+  fixup_type_variants (t);
 }
 
 /* Issue warnings about T having private constructors, but no friends,
diff --git a/gcc/testsuite/g++.dg/modules/pr115062_a.H 
b/gcc/testsuite/g++.dg/modules/pr115062_a.H
new file mode 100644
index ..3c9daac317e6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/pr115062_a.H
@@ -0,0 +1,6 @@
+// PR c++/115062
+// { dg-additional-options "-fmodule-header" }
+// { dg-module-cmi {} }
+
+template  class S;
+typedef S X;
diff --git a/gcc/testsuite/g++.dg/modules/pr115062_b.H 
b/gcc/testsuite/g++.dg/modules/pr115062_b.H
new file mode 100644
index ..d8da59591ec5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/pr115062_b.H
@@ -0,0 +1,14 @@
+// PR c++/115062
+// { dg-additional-options "-fmodule-header" }
+// { dg-module-cmi {} }
+
+template 
+struct S {
+  int a;
+  long b;
+  union {};
+  ~S();
+  void foo();
+};
+extern template void S::foo();
+S operator+(S, const char *);
diff --git a/gcc/testsuite/g++.dg/modules/pr115062_c.C 
b/gcc/testsuite/g++.dg/modules/pr115062_c.C
new file mode 100644
index ..5255b9ffca7a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/pr115062_c.C
@@ -0,0 +1,9 @@
+// PR c++/115062
+// { dg-additional-options "-fmodules-ts" }
+
+import "pr115062_a.H";
+import "pr115062_b.H";
+
+int main() {
+  X x = X() + "";
+}


[gcc r15-2818] c++/modules: Assume header bindings are global module

2024-08-08 Thread Nathaniel Shead via Gcc-cvs
https://gcc.gnu.org/g:0de1481a9d91e936135da4f882314499eea38a36

commit r15-2818-g0de1481a9d91e936135da4f882314499eea38a36
Author: Nathaniel Shead 
Date:   Thu Aug 8 22:00:07 2024 +1000

c++/modules: Assume header bindings are global module

While stepping through some code I noticed that we do some extra work
(finding the originating module decl, stripping the template, and
inspecting the attached-ness) for every declaration taken from a header
unit.  This doesn't seem necessary though since no declaration in a
header unit can be attached to anything but the global module, so we can
just assume that global_p will be true.

This was the original behaviour before I removed this assumption while
refactoring for r15-2807-gc592310d5275e0.

gcc/cp/ChangeLog:

* module.cc (module_state::read_cluster): Assume header module
declarations will require GM merging.

Signed-off-by: Nathaniel Shead 

Diff:
---
 gcc/cp/module.cc | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index 58ad8cbdb614..f4d137b13a17 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -15361,7 +15361,7 @@ module_state::read_cluster (unsigned snum)
tree visible = NULL_TREE;
tree type = NULL_TREE;
bool dedup = false;
-   bool global_p = false;
+   bool global_p = is_header ();
 
/* We rely on the bindings being in the reverse order of
   the resulting overload set.  */


[gcc r15-2808] c++/modules: Handle instantiating already tsubsted template friend classes [PR115801]

2024-08-07 Thread Nathaniel Shead via Gcc-cvs
https://gcc.gnu.org/g:79209273663672ff05663554741fd2558b4aac99

commit r15-2808-g79209273663672ff05663554741fd2558b4aac99
Author: Nathaniel Shead 
Date:   Tue Aug 6 15:41:38 2024 +1000

c++/modules: Handle instantiating already tsubsted template friend classes 
[PR115801]

With modules it may be the case that a template friend class provided
with a qualified name is not found by name lookup at instantiation time,
due to the class not being exported from its module.  This causes issues
in tsubst_friend_class which did not handle this case.

This is caused by the named friend class not actually requiring
tsubsting.  This was already worked around for the "found by name
lookup" case (g++.dg/template/friend5.C), but it looks like there's no
need to do name lookup at all for this particular case to work.

We do need to be careful to continue to do name lookup to handle
templates from an outer current instantiation though; this patch adds a
new testcase for this as well.  This should not impact modules (because
exportingness will only affect namespace lookup).

PR c++/115801

gcc/cp/ChangeLog:

* pt.cc (tsubst_friend_class): Return the type immediately when
no tsubsting or name lookup is required.

gcc/testsuite/ChangeLog:

* g++.dg/modules/tpl-friend-16_a.C: New test.
* g++.dg/modules/tpl-friend-16_b.C: New test.
* g++.dg/template/friend82.C: New test.

Signed-off-by: Nathaniel Shead 
Reviewed-by: Patrick Palka 
Reviewed-by: Jason Merrill 

Diff:
---
 gcc/cp/pt.cc   |  8 ++
 gcc/testsuite/g++.dg/modules/tpl-friend-16_a.C | 40 ++
 gcc/testsuite/g++.dg/modules/tpl-friend-16_b.C | 17 +++
 gcc/testsuite/g++.dg/template/friend82.C   | 23 +++
 4 files changed, 88 insertions(+)

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 3e55d5c0fea5..1dde7d167fd6 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -11732,6 +11732,14 @@ tsubst_friend_class (tree friend_tmpl, tree args)
   return TREE_TYPE (tmpl);
 }
 
+  if (TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (friend_tmpl)) == 1)
+/* The template has already been fully substituted, e.g. for
+
+template  friend class ::C;
+
+   so we can just return it directly.  */
+return TREE_TYPE (friend_tmpl);
+
   tree context = CP_DECL_CONTEXT (friend_tmpl);
   if (TREE_CODE (context) == NAMESPACE_DECL)
 push_nested_namespace (context);
diff --git a/gcc/testsuite/g++.dg/modules/tpl-friend-16_a.C 
b/gcc/testsuite/g++.dg/modules/tpl-friend-16_a.C
new file mode 100644
index ..e1cdcd98e1e0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/tpl-friend-16_a.C
@@ -0,0 +1,40 @@
+// PR c++/115801
+// { dg-additional-options "-fmodules-ts -Wno-global-module" }
+// { dg-module-cmi test }
+
+module;
+
+template  struct GMF;
+template  struct GMF_Hidden {
+  int go() { GMF gmf; return gmf.x; }
+};
+
+template  struct GMF {
+private:
+  template  friend struct ::GMF_Hidden;
+  int x = 1;
+};
+
+template  int test_gmf() {
+  GMF_Hidden h; return h.go();
+}
+
+export module test;
+
+export using ::GMF;
+export using ::test_gmf;
+
+export template  struct Attached;
+template  struct Attached_Hidden {
+  int go() { Attached attached; return attached.x; }
+};
+
+template  struct Attached {
+private:
+  template  friend struct ::Attached_Hidden;
+  int x = 2;
+};
+
+export template  int test_attached() {
+  Attached_Hidden h; return h.go();
+}
diff --git a/gcc/testsuite/g++.dg/modules/tpl-friend-16_b.C 
b/gcc/testsuite/g++.dg/modules/tpl-friend-16_b.C
new file mode 100644
index ..d3484ab19b11
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/tpl-friend-16_b.C
@@ -0,0 +1,17 @@
+// PR c++/115801
+// { dg-additional-options "-fmodules-ts" }
+
+import test;
+
+int main() {
+  GMF gmf;
+  Attached attached;
+
+  int a = test_gmf();
+  int b = test_attached();
+
+  GMF_Hidden gmf_hidden;  // { dg-error "not declared" }
+  Attached_Hidden attached_hidden;  // { dg-error "not declared" }
+}
+
+// { dg-prune-output "expected primary-expression" }
diff --git a/gcc/testsuite/g++.dg/template/friend82.C 
b/gcc/testsuite/g++.dg/template/friend82.C
new file mode 100644
index ..28a057dd23e5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/friend82.C
@@ -0,0 +1,23 @@
+// { dg-do compile }
+
+template
+struct A {
+  template struct B;
+
+  template
+  struct C {
+template friend struct A::B;
+  private:
+int x;
+  };
+};
+
+template 
+template 
+struct A::B {
+  int foo(A::C c) { return c.x; }  // { dg-error "private" }
+};
+
+template struct A::C;
+template struct A::B;  // { dg-bogus "" }
+template struct A::B;  // { dg-message "required from here" }


[gcc r15-2807] c++/modules: Fix merging of GM entities in partitions [PR114950]

2024-08-07 Thread Nathaniel Shead via Gcc-cvs
https://gcc.gnu.org/g:c592310d5275e09977504c136419686bd2277af0

commit r15-2807-gc592310d5275e09977504c136419686bd2277af0
Author: Nathaniel Shead 
Date:   Mon Aug 5 22:37:57 2024 +1000

c++/modules: Fix merging of GM entities in partitions [PR114950]

Currently name lookup generally seems to assume that all entities
declared within a named module (partition) are attached to said module,
which is not true for GM entities (e.g. via extern "C++"), and causes
issues with deduplication.

This patch fixes the issue by ensuring that module attachment of a
declaration is consistently used to handling merging.  Handling this
exposes some issues with deduplicating temploid friends; to resolve this
we always create the BINDING_SLOT_PARTITION slot so that we have
somewhere to place attached names (from any module).

This doesn't yet completely handle issues with allowing otherwise
conflicting temploid friends from different modules to co-exist in the
same module if neither are reachable from the other via name lookup.

PR c++/114950

gcc/cp/ChangeLog:

* module.cc (trees_out::decl_value): Stream bit indicating
imported temploid friends early.
(trees_in::decl_value): Use this bit with key_mergeable.
(trees_in::key_mergeable): Allow merging attached declarations
if they're imported temploid friends (which must be namespace
scope).
(module_state::read_cluster): Check for GM entities that may
require merging even when importing from partitions.
* name-lookup.cc (enum binding_slots): Adjust comment.
(get_fixed_binding_slot): Always create partition slot.
(name_lookup::search_namespace_only): Support binding vectors
with both partition and GM entities to dedup.
(walk_module_binding): Likewise.
(name_lookup::adl_namespace_fns): Likewise.
(set_module_binding): Likewise.
(check_module_override): Use attachment of the decl when
checking overrides rather than named_module_p.
(lookup_imported_hidden_friend): Use partition slot for finding
mergeable template bindings.
* name-lookup.h (set_module_binding): Split mod_glob_flag
parameter into separate global_p and partition_p params.

gcc/testsuite/ChangeLog:

* g++.dg/modules/tpl-friend-13_e.C: Adjust error message.
* g++.dg/modules/ambig-2_a.C: New test.
* g++.dg/modules/ambig-2_b.C: New test.
* g++.dg/modules/part-9_a.C: New test.
* g++.dg/modules/part-9_b.C: New test.
* g++.dg/modules/part-9_c.C: New test.
* g++.dg/modules/tpl-friend-15.h: New test.
* g++.dg/modules/tpl-friend-15_a.C: New test.
* g++.dg/modules/tpl-friend-15_b.C: New test.
* g++.dg/modules/tpl-friend-15_c.C: New test.

Signed-off-by: Nathaniel Shead 
Reviewed-by: Jason Merrill 

Diff:
---
 gcc/cp/module.cc   | 52 +
 gcc/cp/name-lookup.cc  | 65 +-
 gcc/cp/name-lookup.h   |  2 +-
 gcc/testsuite/g++.dg/modules/ambig-2_a.C   |  7 +++
 gcc/testsuite/g++.dg/modules/ambig-2_b.C   | 10 
 gcc/testsuite/g++.dg/modules/part-9_a.C| 10 
 gcc/testsuite/g++.dg/modules/part-9_b.C| 10 
 gcc/testsuite/g++.dg/modules/part-9_c.C|  8 
 gcc/testsuite/g++.dg/modules/tpl-friend-13_e.C |  4 +-
 gcc/testsuite/g++.dg/modules/tpl-friend-15.h   | 11 +
 gcc/testsuite/g++.dg/modules/tpl-friend-15_a.C |  8 
 gcc/testsuite/g++.dg/modules/tpl-friend-15_b.C |  8 
 gcc/testsuite/g++.dg/modules/tpl-friend-15_c.C |  7 +++
 13 files changed, 148 insertions(+), 54 deletions(-)

diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index 0f3e1d97c53b..58ad8cbdb614 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -2958,7 +2958,8 @@ private:
 public:
   tree decl_container ();
   tree key_mergeable (int tag, merge_kind, tree decl, tree inner, tree type,
- tree container, bool is_attached);
+ tree container, bool is_attached,
+ bool is_imported_temploid_friend);
   unsigned binfo_mergeable (tree *);
 
 private:
@@ -7806,6 +7807,7 @@ trees_out::decl_value (tree decl, depset *dep)
   || !TYPE_PTRMEMFUNC_P (TREE_TYPE (decl)));
 
   merge_kind mk = get_merge_kind (decl, dep);
+  bool is_imported_temploid_friend = imported_temploid_friends->get (decl);
 
   if (CHECKING_P)
 {
@@ -7841,13 +7843,11 @@ trees_out::decl_value (tree decl, depset *dep)
  && DECL_MODULE_ATTACH_P (not_tmpl))
is_attached = true;
 
- /* But don't consider imported temploid friends as attached,
-   

[gcc r15-2806] c++/modules: Clarify error message in read_enum_def

2024-08-07 Thread Nathaniel Shead via Gcc-cvs
https://gcc.gnu.org/g:c0ad382caa38873bb6078edf5314930504bc01f1

commit r15-2806-gc0ad382caa38873bb6078edf5314930504bc01f1
Author: Nathaniel Shead 
Date:   Wed Aug 7 19:17:52 2024 +1000

c++/modules: Clarify error message in read_enum_def

This error message reads to me the wrong way around, particularly in the
context of other errors.  Updated so that the ellipsis connect.

gcc/cp/ChangeLog:

* module.cc (trees_in::read_enum_def): Clarify error.

gcc/testsuite/ChangeLog:

* g++.dg/modules/enum-bad-1_b.C: Update error message.

Signed-off-by: Nathaniel Shead 

Diff:
---
 gcc/cp/module.cc| 4 ++--
 gcc/testsuite/g++.dg/modules/enum-bad-1_b.C | 6 +++---
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index 723f0890d96e..0f3e1d97c53b 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -12687,9 +12687,9 @@ trees_in::read_enum_def (tree defn, tree maybe_template)
  if (known_decl && new_decl)
{
  inform (DECL_SOURCE_LOCATION (new_decl),
- "... this enumerator %qD", new_decl);
+ "enumerator %qD does not match ...", new_decl);
  inform (DECL_SOURCE_LOCATION (known_decl),
- "enumerator %qD does not match ...", known_decl);
+ "... this enumerator %qD", known_decl);
}
  else if (known_decl || new_decl)
{
diff --git a/gcc/testsuite/g++.dg/modules/enum-bad-1_b.C 
b/gcc/testsuite/g++.dg/modules/enum-bad-1_b.C
index b01cd66a14d0..23e17b088a2c 100644
--- a/gcc/testsuite/g++.dg/modules/enum-bad-1_b.C
+++ b/gcc/testsuite/g++.dg/modules/enum-bad-1_b.C
@@ -13,13 +13,13 @@ import "enum-bad-1_a.H";
 
 
 ONE one;
-// { dg-regexp {In module [^\n]*enum-bad-1_a.H, imported at 
[^\n]*enum-bad-1_b.C:8:\n[^\n]*enum-bad-1_a.H:5:6: error: definition of 'enum 
ONE' does not match\n[^\n]*enum-bad-1_b.C:3:6: note: existing definition 'enum 
ONE'\nIn module [^\n]*enum-bad-1_a.H, imported at 
[^\n]*enum-bad-1_b.C:8:\n[^\n]*enum-bad-1_a.H:5:11: note: ... this enumerator 
'A'\n[^\n]*enum-bad-1_b.C:3:11: note: enumerator 'Q' does not match 
...\n[^\n]*enum-bad-1_b.C:15:1: note: during load of binding '::ONE'\n} }
+// { dg-regexp {In module [^\n]*enum-bad-1_a.H, imported at 
[^\n]*enum-bad-1_b.C:8:\n[^\n]*enum-bad-1_a.H:5:6: error: definition of 'enum 
ONE' does not match\n[^\n]*enum-bad-1_b.C:3:6: note: existing definition 'enum 
ONE'\nIn module [^\n]*enum-bad-1_a.H, imported at 
[^\n]*enum-bad-1_b.C:8:\n[^\n]*enum-bad-1_a.H:5:11: note: enumerator 'A' does 
not match ...\n[^\n]*enum-bad-1_b.C:3:11: note: ... this enumerator 
'Q'\n[^\n]*enum-bad-1_b.C:15:1: note: during load of binding '::ONE'\n} }
 
 int i = TWO;
-// { dg-regexp {In module [^\n]*enum-bad-1_a.H, imported at 
[^\n]*enum-bad-1_b.C:8:\n[^\n]*enum-bad-1_a.H:6:6: error: definition of 
'enum' does not match\n[^\n]*enum-bad-1_b.C:4:6: note: existing 
definition 'enum'\nIn module [^\n]*enum-bad-1_a.H, imported at 
[^\n]*enum-bad-1_b.C:8:\n[^\n]*enum-bad-1_a.H:6:12: note: ... this enumerator 
'THREE'\n[^\n]*enum-bad-1_b.C:4:12: note: enumerator 'DREI' does not match 
...\n[^\n]*enum-bad-1_b.C:18:9: note: during load of binding '::TWO'\n} }
+// { dg-regexp {In module [^\n]*enum-bad-1_a.H, imported at 
[^\n]*enum-bad-1_b.C:8:\n[^\n]*enum-bad-1_a.H:6:6: error: definition of 
'enum' does not match\n[^\n]*enum-bad-1_b.C:4:6: note: existing 
definition 'enum'\nIn module [^\n]*enum-bad-1_a.H, imported at 
[^\n]*enum-bad-1_b.C:8:\n[^\n]*enum-bad-1_a.H:6:12: note: enumerator 'THREE' 
does not match ...\n[^\n]*enum-bad-1_b.C:4:12: note: ... this enumerator 
'DREI'\n[^\n]*enum-bad-1_b.C:18:9: note: during load of binding '::TWO'\n} }
 
 FOUR four;
-// { dg-regexp {In module [^\n]*enum-bad-1_a.H, imported at 
[^\n]*enum-bad-1_b.C:8:\n[^\n]*enum-bad-1_a.H:7:6: error: definition of 'enum 
FOUR' does not match\n[^\n]*enum-bad-1_b.C:5:6: note: existing definition 'enum 
FOUR'\nIn module [^\n]*enum-bad-1_a.H, imported at 
[^\n]*enum-bad-1_b.C:8:\n[^\n]*enum-bad-1_a.H:7:12: note: ... this enumerator 
'B'\n[^\n]*enum-bad-1_b.C:5:12: note: enumerator 'B' does not match 
...\n[^\n]*enum-bad-1_b.C:21:1: note: during load of binding '::FOUR'\n} }
+// { dg-regexp {In module [^\n]*enum-bad-1_a.H, imported at 
[^\n]*enum-bad-1_b.C:8:\n[^\n]*enum-bad-1_a.H:7:6: error: definition of 'enum 
FOUR' does not match\n[^\n]*enum-bad-1_b.C:5:6: note: existing definition 'enum 
FOUR'\nIn module [^\n]*enum-bad-1_a.H, imported at 
[^\n]*enum-bad-1_b.C:8:\n[^\n]*enum-bad-1_a.H:7:12: note: enumerator 'B' does 
not match ...\n[^\n]*enum-bad-1_b.C:5:12: note: ... this enumerator 
'B'\n[^\n]*enum-bad-1_b.C:21:1: note: during load of binding '::FOUR'\n} }
 
 FIVE five;
 // { dg-regexp {In module [^\n]*enum-bad-1_a.H, imported at 
[^\n]*enum-bad-1_b.C:8:\n[^\n]*enum-bad-1_a.H:8:6: error: definition of 'enum 
FIVE' does not matc

[gcc r15-2779] c++/modules: Ensure deduction guides are always reachable [PR115231]

2024-08-06 Thread Nathaniel Shead via Gcc-cvs
https://gcc.gnu.org/g:ca287145f23ec3ea987fc2eacde3994096cc528e

commit r15-2779-gca287145f23ec3ea987fc2eacde3994096cc528e
Author: Nathaniel Shead 
Date:   Sat Jun 15 22:50:14 2024 +1000

c++/modules: Ensure deduction guides are always reachable [PR115231]

Deduction guides are represented as 'normal' functions currently, and
have no special handling in modules.  However, this causes some issues;
by [temp.deduct.guide] a deduction guide is not found by normal name
lookup and instead all reachable deduction guides for a class template
should be considered, but this does not happen currently.

To solve this, this patch ensures that all deduction guides are
considered exported to ensure that they are always visible to importers
if they are reachable.  Another alternative here would be to add a new
kind of "all reachable" flag to name lookup, but that is complicated by
some difficulties in handling GM entities; this may be a better way to
go if more kinds of entities end up needing this handling, however.

Another issue here is that because deduction guides are "unrelated"
functions, they will usually get discarded from the GMF, so this patch
ensures that when finding dependencies, GMF deduction guides will also
have bindings created.  We do this in find_dependencies so that we don't
unnecessarily create bindings for GMF deduction guides that are never
reached; for consistency we do this for *all* deduction guides, not just
GM ones.  We also make sure that the opposite (a deduction guide being
the only purview reference to a GMF template) correctly marks it as
reachable.

Finally, when merging deduction guides from multiple modules, the name
lookup code may now return two-dimensional overload sets, so update
callers to match.

As a small drive-by improvement this patch also updates the error pretty
printing code to add a space before the '->' when printing a deduction
guide, so we get 'S(int) -> S' instead of 'S(int)-> S'.

PR c++/115231

gcc/cp/ChangeLog:

* error.cc (dump_function_decl): Add a space before '->' when
printing deduction guides.
* module.cc (depset::hash::add_binding_entity): Don't create
bindings for guides here, only mark dependencies.
(depset::hash::add_deduction_guides): New.
(depset::hash::find_dependencies): Add deduction guide
dependencies for a class template.
(module_state::write_cluster): Always consider deduction guides
as exported.
* pt.cc (deduction_guides_for): Use 'lkp_iterator' instead of
'ovl_iterator'.

gcc/testsuite/ChangeLog:

* g++.dg/modules/dguide-1_a.C: New test.
* g++.dg/modules/dguide-1_b.C: New test.
* g++.dg/modules/dguide-2_a.C: New test.
* g++.dg/modules/dguide-2_b.C: New test.
* g++.dg/modules/dguide-3_a.C: New test.
* g++.dg/modules/dguide-3_b.C: New test.
* g++.dg/modules/dguide-3_c.C: New test.
* g++.dg/modules/dguide-3_d.C: New test.

Signed-off-by: Nathaniel Shead 

Diff:
---
 gcc/cp/error.cc   |  1 +
 gcc/cp/module.cc  | 65 +++
 gcc/cp/pt.cc  |  2 +-
 gcc/testsuite/g++.dg/modules/dguide-1_a.C | 44 +
 gcc/testsuite/g++.dg/modules/dguide-1_b.C | 20 ++
 gcc/testsuite/g++.dg/modules/dguide-2_a.C | 24 
 gcc/testsuite/g++.dg/modules/dguide-2_b.C | 19 +
 gcc/testsuite/g++.dg/modules/dguide-3_a.C | 10 +
 gcc/testsuite/g++.dg/modules/dguide-3_b.C | 10 +
 gcc/testsuite/g++.dg/modules/dguide-3_c.C |  6 +++
 gcc/testsuite/g++.dg/modules/dguide-3_d.C | 30 ++
 11 files changed, 230 insertions(+), 1 deletion(-)

diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc
index ee3868efaed6..6c22ff55b463 100644
--- a/gcc/cp/error.cc
+++ b/gcc/cp/error.cc
@@ -1936,6 +1936,7 @@ dump_function_decl (cxx_pretty_printer *pp, tree t, int 
flags)
dump_type_suffix (pp, ret, flags);
   else if (deduction_guide_p (t))
{
+ pp->set_padding (pp_before);
  pp_cxx_ws_string (pp, "->");
  dump_type (pp, TREE_TYPE (TREE_TYPE (t)), flags);
}
diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index 7130faf26f52..723f0890d96e 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -2589,6 +2589,9 @@ public:
 void add_partial_entities (vec *);
 void add_class_entities (vec *);
 
+  private:
+void add_deduction_guides (tree decl);
+
   public:
 void find_dependencies (module_state *);
 bool finalize_dependencies ();
@@ -13172,6 +13175,15 @@ depset::hash::add_binding_entity (tree decl, WMB_Flags 
flags, void *data_)
/* Ignore NTTP objects.  */
return false;

[gcc r15-2778] c++: Improve fixits for incorrect explicit instantiations

2024-08-06 Thread Nathaniel Shead via Gcc-cvs
https://gcc.gnu.org/g:b7f719612515a86d1d2a36e24b02ade3f0904e10

commit r15-2778-gb7f719612515a86d1d2a36e24b02ade3f0904e10
Author: Nathaniel Shead 
Date:   Mon Mar 4 22:59:56 2024 +1100

c++: Improve fixits for incorrect explicit instantiations

When forgetting the '<>' on an explicit specialisation, the suggested
fixit hint suggests to add 'template <>', but naively applying will
cause nonsense results like 'template template <> struct S {};'.

Instead check if we're currently parsing an explicit instantiation, and
if so inform about the issue (an instantiation cannot have a class body)
and suggest a fixit of simply '<>' to create a specialisation instead.

gcc/cp/ChangeLog:

* parser.cc (cp_parser_class_head): Clarify error message for
explicit instantiations.

gcc/testsuite/ChangeLog:

* g++.dg/template/explicit-instantiation9.C: New test.

Signed-off-by: Nathaniel Shead 

Diff:
---
 gcc/cp/parser.cc  | 19 ++-
 .../g++.dg/template/explicit-instantiation9.C |  6 ++
 2 files changed, 20 insertions(+), 5 deletions(-)

diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index f625b0a310c8..82f3903838e2 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -27721,11 +27721,20 @@ cp_parser_class_head (cp_parser* parser,
  class_head_start_location,
  get_finish (type_start_token->location));
   rich_location richloc (line_table, reported_loc);
-  richloc.add_fixit_insert_before (class_head_start_location,
-   "template <> ");
-  error_at (&richloc,
-   "an explicit specialization must be preceded by"
-   " %%>");
+  if (processing_explicit_instantiation)
+   {
+ richloc.add_fixit_insert_before ("<> ");
+ error_at (&richloc,
+   "an explicit instantiation cannot have a definition;"
+   " use %%> to declare a specialization");
+   }
+  else
+   {
+ richloc.add_fixit_insert_before ("template <> ");
+ error_at (&richloc,
+   "an explicit specialization must be preceded by"
+   " %%>");
+   }
   invalid_explicit_specialization_p = true;
   /* Take the same action that would have been taken by
 cp_parser_explicit_specialization.  */
diff --git a/gcc/testsuite/g++.dg/template/explicit-instantiation9.C 
b/gcc/testsuite/g++.dg/template/explicit-instantiation9.C
new file mode 100644
index ..c4400226ef83
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/explicit-instantiation9.C
@@ -0,0 +1,6 @@
+// Fixits for specialisations are not valid for instantiations
+
+template 
+struct S {};
+
+template struct S {};  // { dg-error "explicit instantiation cannot have 
a definition" }


[gcc r15-2334] c++/modules: Stream warning suppressions [PR115757]

2024-07-25 Thread Nathaniel Shead via Gcc-cvs
https://gcc.gnu.org/g:fd599d96d464caed8bf78e4a43120d9a121b7e7a

commit r15-2334-gfd599d96d464caed8bf78e4a43120d9a121b7e7a
Author: Nathaniel Shead 
Date:   Sun Jul 7 13:56:25 2024 +1000

c++/modules: Stream warning suppressions [PR115757]

Currently we don't stream the contents of 'nowarn_map'; this means that
warning suppressions don't get applied in importers, which is
particularly relevant for templates (as in the linked testcase).

Rather than streaming the whole contents of 'nowarn_map', this patch
instead just streams the exported suppressions for each tree node
individually, to not build up additional locations and suppressions for
tree nodes that do not need to be streamed.

PR c++/115757

gcc/cp/ChangeLog:

* module.cc (trees_out::core_vals): Write warning specs for
DECLs and EXPRs.
(trees_in::core_vals): Read warning specs.

gcc/ChangeLog:

* tree.h (put_warning_spec_at): Declare new function.
(has_warning_spec): Likewise.
(get_warning_spec): Likewise.
(put_warning_spec): Likewise.
* diagnostic-spec.h (nowarn_spec_t::from_bits): New function.
* diagnostic-spec.cc (put_warning_spec_at): New function.
* warning-control.cc (has_warning_spec): New function.
(get_warning_spec): New function.
(put_warning_spec): New function.

gcc/testsuite/ChangeLog:

* g++.dg/modules/warn-spec-1_a.C: New test.
* g++.dg/modules/warn-spec-1_b.C: New test.

Signed-off-by: Nathaniel Shead 

Diff:
---
 gcc/cp/module.cc | 12 
 gcc/diagnostic-spec.cc   | 21 +
 gcc/diagnostic-spec.h|  7 +++
 gcc/testsuite/g++.dg/modules/warn-spec-1_a.C | 10 ++
 gcc/testsuite/g++.dg/modules/warn-spec-1_b.C |  8 
 gcc/tree.h   |  9 +
 gcc/warning-control.cc   | 26 ++
 7 files changed, 93 insertions(+)

diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index 69764fd772d3..d1607a067575 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -6000,6 +6000,10 @@ trees_out::core_vals (tree t)
 
   if (state)
state->write_location (*this, t->decl_minimal.locus);
+
+  if (streaming_p ())
+   if (has_warning_spec (t))
+ u (get_warning_spec (t));
 }
 
   if (CODE_CONTAINS_STRUCT (code, TS_TYPE_COMMON))
@@ -6113,6 +6117,10 @@ trees_out::core_vals (tree t)
   if (state)
state->write_location (*this, t->exp.locus);
 
+  if (streaming_p ())
+   if (has_warning_spec (t))
+ u (get_warning_spec (t));
+
   /* Walk in forward order, as (for instance) REQUIRES_EXPR has a
  bunch of unscoped parms on its first operand.  It's safer to
  create those in order.  */
@@ -6576,6 +6584,8 @@ trees_in::core_vals (tree t)
   /* Don't zap the locus just yet, we don't record it correctly
 and thus lose all location information.  */
   t->decl_minimal.locus = state->read_location (*this);
+  if (has_warning_spec (t))
+   put_warning_spec (t, u ());
 }
 
   if (CODE_CONTAINS_STRUCT (code, TS_TYPE_COMMON))
@@ -6654,6 +6664,8 @@ trees_in::core_vals (tree t)
   if (CODE_CONTAINS_STRUCT (code, TS_EXP))
 {
   t->exp.locus = state->read_location (*this);
+  if (has_warning_spec (t))
+   put_warning_spec (t, u ());
 
   bool vl = TREE_CODE_CLASS (code) == tcc_vl_exp;
   for (unsigned limit = (vl ? VL_EXP_OPERAND_LENGTH (t)
diff --git a/gcc/diagnostic-spec.cc b/gcc/diagnostic-spec.cc
index 996ad6b273aa..addaf089f035 100644
--- a/gcc/diagnostic-spec.cc
+++ b/gcc/diagnostic-spec.cc
@@ -179,6 +179,27 @@ suppress_warning_at (location_t loc, opt_code opt /* = 
all_warnings */,
   return true;
 }
 
+/* Change the warning disposition for LOC to match OPTSPEC.  */
+
+void
+put_warning_spec_at (location_t loc, unsigned bits)
+{
+  gcc_checking_assert (!RESERVED_LOCATION_P (loc));
+
+  nowarn_spec_t optspec = nowarn_spec_t::from_bits (bits);
+  if (!optspec)
+{
+  if (nowarn_map)
+   nowarn_map->remove (loc);
+}
+  else
+{
+  if (!nowarn_map)
+   nowarn_map = nowarn_map_t::create_ggc (32);
+  nowarn_map->put (loc, optspec);
+}
+}
+
 /* Copy the no-warning disposition from one location to another.  */
 
 void
diff --git a/gcc/diagnostic-spec.h b/gcc/diagnostic-spec.h
index 22d4c0671584..0b155a5cde3f 100644
--- a/gcc/diagnostic-spec.h
+++ b/gcc/diagnostic-spec.h
@@ -56,6 +56,13 @@ public:
 
   nowarn_spec_t (opt_code);
 
+  static nowarn_spec_t from_bits (unsigned bits)
+  {
+nowarn_spec_t spec;
+spec.m_bits = bits;
+return spec;
+  }
+
   /* Return the raw bitset.  */
   operator unsigned() const
   {
diff --git a/gcc/testsuite/g++.dg/modules/warn-spec-1

[gcc r14-10453] c++/modules: Conditionally start timer during lazy load [PR115165]

2024-07-17 Thread Nathaniel Shead via Gcc-cvs
https://gcc.gnu.org/g:f0c3a1c16af234b55f48cf1cfe299417f93f163c

commit r14-10453-gf0c3a1c16af234b55f48cf1cfe299417f93f163c
Author: Nathaniel Shead 
Date:   Sun Jul 7 23:19:52 2024 +1000

c++/modules: Conditionally start timer during lazy load [PR115165]

While lazy loading, instantiation of pendings can sometimes recursively
perform name lookup and begin further lazy loading.  When using the
'-ftime-report' functionality this causes ICEs as we could start an
already-running timer for the importing.

This patch fixes the issue by using the 'timevar_cond*' API instead to
support such recursive calls.

PR c++/115165

gcc/cp/ChangeLog:

* module.cc (lazy_load_binding): Use 'timevar_cond*' APIs.
(lazy_load_pendings): Likewise.

gcc/testsuite/ChangeLog:

* g++.dg/modules/timevar-1_a.H: New test.
* g++.dg/modules/timevar-1_b.C: New test.

Signed-off-by: Nathaniel Shead 

Diff:
---
 gcc/cp/module.cc   |  8 
 gcc/testsuite/g++.dg/modules/timevar-1_a.H | 14 ++
 gcc/testsuite/g++.dg/modules/timevar-1_b.C | 10 ++
 3 files changed, 28 insertions(+), 4 deletions(-)

diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index b610b808240c..fb10537d3e34 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -19517,7 +19517,7 @@ lazy_load_binding (unsigned mod, tree ns, tree id, 
binding_slot *mslot)
 {
   int count = errorcount + warningcount;
 
-  timevar_start (TV_MODULE_IMPORT);
+  bool timer_running = timevar_cond_start (TV_MODULE_IMPORT);
 
   /* Make sure lazy loading from a template context behaves as if
  from a non-template context.  */
@@ -19547,7 +19547,7 @@ lazy_load_binding (unsigned mod, tree ns, tree id, 
binding_slot *mslot)
 
   function_depth--;
 
-  timevar_stop (TV_MODULE_IMPORT);
+  timevar_cond_stop (TV_MODULE_IMPORT, timer_running);
 
   if (!ok)
 fatal_error (input_location,
@@ -19586,7 +19586,7 @@ lazy_load_pendings (tree decl)
 
   int count = errorcount + warningcount;
 
-  timevar_start (TV_MODULE_IMPORT);
+  bool timer_running = timevar_cond_start (TV_MODULE_IMPORT);
   bool ok = !recursive_lazy ();
   if (ok)
 {
@@ -19620,7 +19620,7 @@ lazy_load_pendings (tree decl)
   function_depth--;
 }
 
-  timevar_stop (TV_MODULE_IMPORT);
+  timevar_cond_stop (TV_MODULE_IMPORT, timer_running);
 
   if (!ok)
 fatal_error (input_location, "failed to load pendings for %<%E%s%E%>",
diff --git a/gcc/testsuite/g++.dg/modules/timevar-1_a.H 
b/gcc/testsuite/g++.dg/modules/timevar-1_a.H
new file mode 100644
index ..efd7f0ecced0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/timevar-1_a.H
@@ -0,0 +1,14 @@
+// PR c++/115165
+// { dg-additional-options "-fmodule-header" }
+// { dg-module-cmi {} }
+
+template  struct A { virtual ~A(); };
+struct B : A {};
+struct C : B { C() {} };
+
+class D { C c; };
+void f(D);
+
+struct X {
+  friend void f(X);
+};
diff --git a/gcc/testsuite/g++.dg/modules/timevar-1_b.C 
b/gcc/testsuite/g++.dg/modules/timevar-1_b.C
new file mode 100644
index ..645f01697eb7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/timevar-1_b.C
@@ -0,0 +1,10 @@
+// PR c++/115165
+// { dg-additional-options "-fmodules-ts -ftime-report" }
+// { dg-allow-blank-lines-in-output 1 }
+// { dg-prune-output "Time variable" }
+// { dg-prune-output "\[0-9\]+%" }
+// { dg-prune-output "TOTAL" }
+// { dg-prune-output "checks" }
+
+import "timevar-1_a.H";
+X x;


[gcc r15-2121] c++/modules: Conditionally start timer during lazy load [PR115165]

2024-07-17 Thread Nathaniel Shead via Gcc-cvs
https://gcc.gnu.org/g:b7b2434cc7e712dc5055bde02c441393ae881f06

commit r15-2121-gb7b2434cc7e712dc5055bde02c441393ae881f06
Author: Nathaniel Shead 
Date:   Sun Jul 7 23:19:52 2024 +1000

c++/modules: Conditionally start timer during lazy load [PR115165]

While lazy loading, instantiation of pendings can sometimes recursively
perform name lookup and begin further lazy loading.  When using the
'-ftime-report' functionality this causes ICEs as we could start an
already-running timer for the importing.

This patch fixes the issue by using the 'timevar_cond*' API instead to
support such recursive calls.

PR c++/115165

gcc/cp/ChangeLog:

* module.cc (lazy_load_binding): Use 'timevar_cond*' APIs.
(lazy_load_pendings): Likewise.

gcc/testsuite/ChangeLog:

* g++.dg/modules/timevar-1_a.H: New test.
* g++.dg/modules/timevar-1_b.C: New test.

Signed-off-by: Nathaniel Shead 

Diff:
---
 gcc/cp/module.cc   |  8 
 gcc/testsuite/g++.dg/modules/timevar-1_a.H | 14 ++
 gcc/testsuite/g++.dg/modules/timevar-1_b.C | 10 ++
 3 files changed, 28 insertions(+), 4 deletions(-)

diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index d385b422168f..69764fd772d3 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -19604,7 +19604,7 @@ lazy_load_binding (unsigned mod, tree ns, tree id, 
binding_slot *mslot)
 {
   int count = errorcount + warningcount;
 
-  timevar_start (TV_MODULE_IMPORT);
+  bool timer_running = timevar_cond_start (TV_MODULE_IMPORT);
 
   /* Make sure lazy loading from a template context behaves as if
  from a non-template context.  */
@@ -19634,7 +19634,7 @@ lazy_load_binding (unsigned mod, tree ns, tree id, 
binding_slot *mslot)
 
   function_depth--;
 
-  timevar_stop (TV_MODULE_IMPORT);
+  timevar_cond_stop (TV_MODULE_IMPORT, timer_running);
 
   if (!ok)
 fatal_error (input_location,
@@ -19673,7 +19673,7 @@ lazy_load_pendings (tree decl)
 
   int count = errorcount + warningcount;
 
-  timevar_start (TV_MODULE_IMPORT);
+  bool timer_running = timevar_cond_start (TV_MODULE_IMPORT);
   bool ok = !recursive_lazy ();
   if (ok)
 {
@@ -19707,7 +19707,7 @@ lazy_load_pendings (tree decl)
   function_depth--;
 }
 
-  timevar_stop (TV_MODULE_IMPORT);
+  timevar_cond_stop (TV_MODULE_IMPORT, timer_running);
 
   if (!ok)
 fatal_error (input_location, "failed to load pendings for %<%E%s%E%>",
diff --git a/gcc/testsuite/g++.dg/modules/timevar-1_a.H 
b/gcc/testsuite/g++.dg/modules/timevar-1_a.H
new file mode 100644
index ..efd7f0ecced0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/timevar-1_a.H
@@ -0,0 +1,14 @@
+// PR c++/115165
+// { dg-additional-options "-fmodule-header" }
+// { dg-module-cmi {} }
+
+template  struct A { virtual ~A(); };
+struct B : A {};
+struct C : B { C() {} };
+
+class D { C c; };
+void f(D);
+
+struct X {
+  friend void f(X);
+};
diff --git a/gcc/testsuite/g++.dg/modules/timevar-1_b.C 
b/gcc/testsuite/g++.dg/modules/timevar-1_b.C
new file mode 100644
index ..645f01697eb7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/timevar-1_b.C
@@ -0,0 +1,10 @@
+// PR c++/115165
+// { dg-additional-options "-fmodules-ts -ftime-report" }
+// { dg-allow-blank-lines-in-output 1 }
+// { dg-prune-output "Time variable" }
+// { dg-prune-output "\[0-9\]+%" }
+// { dg-prune-output "TOTAL" }
+// { dg-prune-output "checks" }
+
+import "timevar-1_a.H";
+X x;


[gcc r14-10442] c++/modules: Propagate BINDING_VECTOR_*_DUPS_P on realloc [PR99242]

2024-07-16 Thread Nathaniel Shead via Gcc-cvs
https://gcc.gnu.org/g:5fad0b552c5851fb6ae6eb3616e50cc25af1391d

commit r14-10442-g5fad0b552c5851fb6ae6eb3616e50cc25af1391d
Author: Nathaniel Shead 
Date:   Mon Jul 8 22:25:17 2024 +1000

c++/modules: Propagate BINDING_VECTOR_*_DUPS_P on realloc [PR99242]

When importing modules, when a binding vector for a name runs out of
slots it gets reallocated with a larger size, and existing bindings are
copied across.  However, the flags to indicate whether deduping needs to
occur did not: this causes ICEs, as it allows a duplicate binding to be
added which then violates assumptions later on.

PR c++/99242

gcc/cp/ChangeLog:

* name-lookup.cc (append_imported_binding_slot): Propagate dups
flags.

gcc/testsuite/ChangeLog:

* g++.dg/modules/pr99242_a.H: New test.
* g++.dg/modules/pr99242_b.H: New test.
* g++.dg/modules/pr99242_c.H: New test.
* g++.dg/modules/pr99242_d.C: New test.

Signed-off-by: Nathaniel Shead 
(cherry picked from commit 1aa0f1627857c3e2d90982bdb07ca78ca10b26f3)

Diff:
---
 gcc/cp/name-lookup.cc| 4 
 gcc/testsuite/g++.dg/modules/pr99242_a.H | 3 +++
 gcc/testsuite/g++.dg/modules/pr99242_b.H | 3 +++
 gcc/testsuite/g++.dg/modules/pr99242_c.H | 3 +++
 gcc/testsuite/g++.dg/modules/pr99242_d.C | 7 +++
 5 files changed, 20 insertions(+)

diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc
index 4dffc0e9acc8..b752598564a3 100644
--- a/gcc/cp/name-lookup.cc
+++ b/gcc/cp/name-lookup.cc
@@ -352,6 +352,10 @@ append_imported_binding_slot (tree *slot, tree name, 
unsigned ix)
 
   tree new_vec = make_binding_vec (name, want);
   BINDING_VECTOR_NUM_CLUSTERS (new_vec) = have + 1;
+  BINDING_VECTOR_GLOBAL_DUPS_P (new_vec)
+   = BINDING_VECTOR_GLOBAL_DUPS_P (*slot);
+  BINDING_VECTOR_PARTITION_DUPS_P (new_vec)
+   = BINDING_VECTOR_PARTITION_DUPS_P (*slot);
   memcpy (BINDING_VECTOR_CLUSTER_BASE (new_vec),
  BINDING_VECTOR_CLUSTER_BASE (*slot),
  have * sizeof (binding_cluster));
diff --git a/gcc/testsuite/g++.dg/modules/pr99242_a.H 
b/gcc/testsuite/g++.dg/modules/pr99242_a.H
new file mode 100644
index ..2df0b4184ab3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/pr99242_a.H
@@ -0,0 +1,3 @@
+// { dg-additional-options "-fmodule-header" }
+// { dg-module-cmi {} }
+bool __is_constant_evaluated();
diff --git a/gcc/testsuite/g++.dg/modules/pr99242_b.H 
b/gcc/testsuite/g++.dg/modules/pr99242_b.H
new file mode 100644
index ..2df0b4184ab3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/pr99242_b.H
@@ -0,0 +1,3 @@
+// { dg-additional-options "-fmodule-header" }
+// { dg-module-cmi {} }
+bool __is_constant_evaluated();
diff --git a/gcc/testsuite/g++.dg/modules/pr99242_c.H 
b/gcc/testsuite/g++.dg/modules/pr99242_c.H
new file mode 100644
index ..2df0b4184ab3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/pr99242_c.H
@@ -0,0 +1,3 @@
+// { dg-additional-options "-fmodule-header" }
+// { dg-module-cmi {} }
+bool __is_constant_evaluated();
diff --git a/gcc/testsuite/g++.dg/modules/pr99242_d.C 
b/gcc/testsuite/g++.dg/modules/pr99242_d.C
new file mode 100644
index ..1046d1af9846
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/pr99242_d.C
@@ -0,0 +1,7 @@
+// { dg-additional-options "-fmodules-ts" }
+bool __is_constant_evaluated();
+import "pr99242_a.H";
+void f() { __is_constant_evaluated(); }
+import "pr99242_b.H";
+import "pr99242_c.H";
+void g() { __is_constant_evaluated(); }


[gcc r15-2079] c++/modules: Propagate BINDING_VECTOR_*_DUPS_P on realloc [PR99242]

2024-07-16 Thread Nathaniel Shead via Gcc-cvs
https://gcc.gnu.org/g:1aa0f1627857c3e2d90982bdb07ca78ca10b26f3

commit r15-2079-g1aa0f1627857c3e2d90982bdb07ca78ca10b26f3
Author: Nathaniel Shead 
Date:   Mon Jul 8 22:25:17 2024 +1000

c++/modules: Propagate BINDING_VECTOR_*_DUPS_P on realloc [PR99242]

When importing modules, when a binding vector for a name runs out of
slots it gets reallocated with a larger size, and existing bindings are
copied across.  However, the flags to indicate whether deduping needs to
occur did not: this causes ICEs, as it allows a duplicate binding to be
added which then violates assumptions later on.

PR c++/99242

gcc/cp/ChangeLog:

* name-lookup.cc (append_imported_binding_slot): Propagate dups
flags.

gcc/testsuite/ChangeLog:

* g++.dg/modules/pr99242_a.H: New test.
* g++.dg/modules/pr99242_b.H: New test.
* g++.dg/modules/pr99242_c.H: New test.
* g++.dg/modules/pr99242_d.C: New test.

Signed-off-by: Nathaniel Shead 

Diff:
---
 gcc/cp/name-lookup.cc| 4 
 gcc/testsuite/g++.dg/modules/pr99242_a.H | 3 +++
 gcc/testsuite/g++.dg/modules/pr99242_b.H | 3 +++
 gcc/testsuite/g++.dg/modules/pr99242_c.H | 3 +++
 gcc/testsuite/g++.dg/modules/pr99242_d.C | 7 +++
 5 files changed, 20 insertions(+)

diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc
index 361dc3d953d1..8823ab71c600 100644
--- a/gcc/cp/name-lookup.cc
+++ b/gcc/cp/name-lookup.cc
@@ -353,6 +353,10 @@ append_imported_binding_slot (tree *slot, tree name, 
unsigned ix)
 
   tree new_vec = make_binding_vec (name, want);
   BINDING_VECTOR_NUM_CLUSTERS (new_vec) = have + 1;
+  BINDING_VECTOR_GLOBAL_DUPS_P (new_vec)
+   = BINDING_VECTOR_GLOBAL_DUPS_P (*slot);
+  BINDING_VECTOR_PARTITION_DUPS_P (new_vec)
+   = BINDING_VECTOR_PARTITION_DUPS_P (*slot);
   memcpy (BINDING_VECTOR_CLUSTER_BASE (new_vec),
  BINDING_VECTOR_CLUSTER_BASE (*slot),
  have * sizeof (binding_cluster));
diff --git a/gcc/testsuite/g++.dg/modules/pr99242_a.H 
b/gcc/testsuite/g++.dg/modules/pr99242_a.H
new file mode 100644
index ..2df0b4184ab3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/pr99242_a.H
@@ -0,0 +1,3 @@
+// { dg-additional-options "-fmodule-header" }
+// { dg-module-cmi {} }
+bool __is_constant_evaluated();
diff --git a/gcc/testsuite/g++.dg/modules/pr99242_b.H 
b/gcc/testsuite/g++.dg/modules/pr99242_b.H
new file mode 100644
index ..2df0b4184ab3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/pr99242_b.H
@@ -0,0 +1,3 @@
+// { dg-additional-options "-fmodule-header" }
+// { dg-module-cmi {} }
+bool __is_constant_evaluated();
diff --git a/gcc/testsuite/g++.dg/modules/pr99242_c.H 
b/gcc/testsuite/g++.dg/modules/pr99242_c.H
new file mode 100644
index ..2df0b4184ab3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/pr99242_c.H
@@ -0,0 +1,3 @@
+// { dg-additional-options "-fmodule-header" }
+// { dg-module-cmi {} }
+bool __is_constant_evaluated();
diff --git a/gcc/testsuite/g++.dg/modules/pr99242_d.C 
b/gcc/testsuite/g++.dg/modules/pr99242_d.C
new file mode 100644
index ..1046d1af9846
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/pr99242_d.C
@@ -0,0 +1,7 @@
+// { dg-additional-options "-fmodules-ts" }
+bool __is_constant_evaluated();
+import "pr99242_a.H";
+void f() { __is_constant_evaluated(); }
+import "pr99242_b.H";
+import "pr99242_c.H";
+void g() { __is_constant_evaluated(); }


[gcc r15-2005] c++/modules: Add testcase for fixed issue with usings [PR115798]

2024-07-12 Thread Nathaniel Shead via Gcc-cvs
https://gcc.gnu.org/g:13757e50ff0b4e0dccfabc67b1322a2724bf3a5c

commit r15-2005-g13757e50ff0b4e0dccfabc67b1322a2724bf3a5c
Author: Nathaniel Shead 
Date:   Fri Jul 12 22:59:19 2024 +1000

c++/modules: Add testcase for fixed issue with usings [PR115798]

This issue was fixed by r15-2003-gd6bf4b1c932211, but seems worth adding
to the testsuite.

PR c++/115798

gcc/testsuite/ChangeLog:

* g++.dg/modules/using-26_a.C: New test.
* g++.dg/modules/using-26_b.C: New test.
* g++.dg/modules/using-26_c.C: New test.

Signed-off-by: Nathaniel Shead 

Diff:
---
 gcc/testsuite/g++.dg/modules/using-26_a.C | 15 +++
 gcc/testsuite/g++.dg/modules/using-26_b.C | 10 ++
 gcc/testsuite/g++.dg/modules/using-26_c.C |  9 +
 3 files changed, 34 insertions(+)

diff --git a/gcc/testsuite/g++.dg/modules/using-26_a.C 
b/gcc/testsuite/g++.dg/modules/using-26_a.C
new file mode 100644
index ..adab83d42433
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/using-26_a.C
@@ -0,0 +1,15 @@
+// PR c++/115798
+// { dg-additional-options "-fmodules-ts" }
+// { dg-module-cmi base }
+
+module;
+#include 
+export module base;
+
+export {
+  using ::int8_t;
+}
+
+export namespace std {
+  using std::int8_t;
+}
diff --git a/gcc/testsuite/g++.dg/modules/using-26_b.C 
b/gcc/testsuite/g++.dg/modules/using-26_b.C
new file mode 100644
index ..06ed599df41e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/using-26_b.C
@@ -0,0 +1,10 @@
+// PR c++/115798
+// { dg-additional-options "-fmodules-ts" }
+// { dg-module-cmi xstd }
+
+export module xstd;
+import base;
+
+export namespace std {
+  using std::int8_t;
+}
diff --git a/gcc/testsuite/g++.dg/modules/using-26_c.C 
b/gcc/testsuite/g++.dg/modules/using-26_c.C
new file mode 100644
index ..68f45cacb82e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/using-26_c.C
@@ -0,0 +1,9 @@
+// PR c++/115798
+// { dg-additional-options "-fmodules-ts" }
+
+import xstd;
+import base;
+
+int main() {
+  static_assert(__is_same(int8_t, std::int8_t));
+}


[gcc r15-2004] c++/modules: Handle redefinitions of using-decls

2024-07-12 Thread Nathaniel Shead via Gcc-cvs
https://gcc.gnu.org/g:1f7a21c6e85d553e7b5114e5ca1395118478dddf

commit r15-2004-g1f7a21c6e85d553e7b5114e5ca1395118478dddf
Author: Nathaniel Shead 
Date:   Fri Jul 5 13:52:01 2024 +1000

c++/modules: Handle redefinitions of using-decls

This fixes an ICE exposed by supporting exported non-function
using-decls.  Sometimes when preparing to define a class, xref_tag will
find a using-decl belonging to a different namespace, which triggers the
checking_assert in modules handling.

Ideally I feel that 'lookup_and_check_tag' should be told whether we're
about to define the type and handle erroring on redefinitions itself to
avoid this issue (and provide better diagnostics by acknowledging the
using-declaration), but this is complicated with the current
fragmentation of definition checking.  So for this patch we just fixup
the assertion and ensure that pushdecl properly errors on the
conflicting declaration later.

gcc/cp/ChangeLog:

* decl.cc (xref_tag): Move assertion into condition.
* name-lookup.cc (check_module_override): Check for conflicting
types and using-decls.

gcc/testsuite/ChangeLog:

* g++.dg/modules/using-19_a.C: New test.
* g++.dg/modules/using-19_b.C: New test.

Signed-off-by: Nathaniel Shead 

Diff:
---
 gcc/cp/decl.cc|  6 --
 gcc/cp/name-lookup.cc | 32 +--
 gcc/testsuite/g++.dg/modules/using-19_a.C | 18 +
 gcc/testsuite/g++.dg/modules/using-19_b.C | 10 ++
 4 files changed, 54 insertions(+), 12 deletions(-)

diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index 4ffc9a6dad25..e7bb4fa30892 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -16737,12 +16737,14 @@ xref_tag (enum tag_types tag_code, tree name,
  if (CLASS_TYPE_P (t) && CLASSTYPE_IS_TEMPLATE (t))
maybe_tmpl = CLASSTYPE_TI_TEMPLATE (t);
 
+ /* FIXME: we should do a more precise check for redefinitions
+of a conflicting using-declaration here, as these diagnostics
+are not ideal.  */
  if (DECL_LANG_SPECIFIC (decl)
  && DECL_MODULE_IMPORT_P (decl)
- && TREE_CODE (CP_DECL_CONTEXT (decl)) == NAMESPACE_DECL)
+ && CP_DECL_CONTEXT (decl) == current_namespace)
{
  /* Push it into this TU's symbol slot.  */
- gcc_checking_assert (current_namespace == CP_DECL_CONTEXT (decl));
  if (maybe_tmpl != decl)
/* We're in the template parm binding level.
   Pushtag has logic to slide under that, but we're
diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc
index e5f8562105e1..361dc3d953d1 100644
--- a/gcc/cp/name-lookup.cc
+++ b/gcc/cp/name-lookup.cc
@@ -3782,18 +3782,30 @@ check_module_override (tree decl, tree mvec, bool 
hiding,
  /* Errors could cause there to be nothing.  */
  continue;
 
+   tree type = NULL_TREE;
if (STAT_HACK_P (bind))
- /* We do not have to check STAT_TYPE here, the xref_tag
-machinery deals with that problem. */
- bind = STAT_VISIBLE (bind);
+ {
+   /* If there was a matching STAT_TYPE here then xref_tag
+  should have found it, but we need to check anyway because
+  a conflicting using-declaration may exist.  */
+   if (STAT_TYPE_VISIBLE_P (bind))
+ type = STAT_TYPE (bind);
+   bind = STAT_VISIBLE (bind);
+ }
 
-   for (ovl_iterator iter (bind); iter; ++iter)
- if (!iter.using_p ())
-   {
- match = duplicate_decls (decl, *iter, hiding);
- if (match)
-   goto matched;
-   }
+   if (type)
+ {
+   match = duplicate_decls (decl, strip_using_decl (type), hiding);
+   if (match)
+ goto matched;
+ }
+
+   for (ovl_iterator iter (strip_using_decl (bind)); iter; ++iter)
+ {
+   match = duplicate_decls (decl, *iter, hiding);
+   if (match)
+ goto matched;
+ }
   }
 
   if (TREE_PUBLIC (scope) && TREE_PUBLIC (STRIP_TEMPLATE (decl))
diff --git a/gcc/testsuite/g++.dg/modules/using-19_a.C 
b/gcc/testsuite/g++.dg/modules/using-19_a.C
new file mode 100644
index ..693a70ce7d46
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/using-19_a.C
@@ -0,0 +1,18 @@
+// { dg-additional-options "-fmodules-ts -Wno-global-module" }
+// { dg-module-cmi M }
+
+module;
+
+namespace hidden {
+  struct S {};
+  enum E { e };
+  void f();
+}
+
+export module M;
+export namespace exposed {
+  using hidden::S;
+  using hidden::E;
+  using hidden::e;
+  using hidden::f;
+}
diff --git a/gcc/testsuite/g++.dg/modules/using-19_b.C 
b/gcc/testsuite/g++.dg/modules/using-19_b.C
new file mode 100644
index ..dbe8d9f3c01e
--- /dev/null
++

[gcc r15-2003] c++: Introduce USING_DECLs for non-function usings [PR114683]

2024-07-12 Thread Nathaniel Shead via Gcc-cvs
https://gcc.gnu.org/g:d6bf4b1c93221118b3008a878ec508f6412dfc55

commit r15-2003-gd6bf4b1c93221118b3008a878ec508f6412dfc55
Author: Nathaniel Shead 
Date:   Thu Jun 27 11:08:15 2024 +1000

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.
(updat

[gcc r14-10407] c++/modules: Keep entity mapping info across duplicate_decls [PR99241]

2024-07-11 Thread Nathaniel Shead via Gcc-cvs
https://gcc.gnu.org/g:08c2abffe0a903e8cf16b469813b7dd0fb41275a

commit r14-10407-g08c2abffe0a903e8cf16b469813b7dd0fb41275a
Author: Nathaniel Shead 
Date:   Mon Jul 8 14:35:58 2024 +1000

c++/modules: Keep entity mapping info across duplicate_decls [PR99241]

When duplicate_decls finds a match with an existing imported
declaration, it clears DECL_LANG_SPECIFIC of the olddecl and replaces it
with the contents of newdecl; this clears DECL_MODULE_ENTITY_P causing
an ICE if the same declaration is imported again later.

This fixes the issue by ensuring that the flag is transferred to newdecl
before clearing so that it ends up on olddecl again.

For future-proofing we also do the same with DECL_MODULE_KEYED_DECLS_P,
though because we don't yet support textual redefinition merging we
can't yet test this works as intended.  I don't expect it's possible for
a new declaration already to have extra keyed decls mismatching that of
the old declaration though, so I don't do anything with 'keyed_map' at
this time.

PR c++/99241

gcc/cp/ChangeLog:

* decl.cc (duplicate_decls): Merge module entity information.

gcc/testsuite/ChangeLog:

* g++.dg/modules/pr99241_a.H: New test.
* g++.dg/modules/pr99241_b.H: New test.
* g++.dg/modules/pr99241_c.C: New test.

Signed-off-by: Nathaniel Shead 
(cherry picked from commit f04f9714fca40315360af109b9e5ca2305fd75db)

Diff:
---
 gcc/cp/decl.cc   | 10 ++
 gcc/testsuite/g++.dg/modules/pr99241_a.H |  3 +++
 gcc/testsuite/g++.dg/modules/pr99241_b.H |  3 +++
 gcc/testsuite/g++.dg/modules/pr99241_c.C |  5 +
 4 files changed, 21 insertions(+)

diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index 568b2becd4d0..ca00e9aea201 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -3120,6 +3120,16 @@ duplicate_decls (tree newdecl, tree olddecl, bool 
hiding, bool was_hidden)
   if (TREE_CODE (newdecl) == FIELD_DECL)
 DECL_PACKED (olddecl) = DECL_PACKED (newdecl);
 
+  /* Merge module entity mapping information.  */
+  if (DECL_LANG_SPECIFIC (olddecl)
+  && (DECL_MODULE_ENTITY_P (olddecl)
+ || DECL_MODULE_KEYED_DECLS_P (olddecl)))
+{
+  retrofit_lang_decl (newdecl);
+  DECL_MODULE_ENTITY_P (newdecl) = DECL_MODULE_ENTITY_P (olddecl);
+  DECL_MODULE_KEYED_DECLS_P (newdecl) = DECL_MODULE_KEYED_DECLS_P 
(olddecl);
+}
+
   /* The DECL_LANG_SPECIFIC information in OLDDECL will be replaced
  with that from NEWDECL below.  */
   if (DECL_LANG_SPECIFIC (olddecl))
diff --git a/gcc/testsuite/g++.dg/modules/pr99241_a.H 
b/gcc/testsuite/g++.dg/modules/pr99241_a.H
new file mode 100644
index ..c7031f08eb5d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/pr99241_a.H
@@ -0,0 +1,3 @@
+// { dg-additional-options "-fmodule-header" }
+// { dg-module-cmi {} }
+void terminate();
diff --git a/gcc/testsuite/g++.dg/modules/pr99241_b.H 
b/gcc/testsuite/g++.dg/modules/pr99241_b.H
new file mode 100644
index ..c7031f08eb5d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/pr99241_b.H
@@ -0,0 +1,3 @@
+// { dg-additional-options "-fmodule-header" }
+// { dg-module-cmi {} }
+void terminate();
diff --git a/gcc/testsuite/g++.dg/modules/pr99241_c.C 
b/gcc/testsuite/g++.dg/modules/pr99241_c.C
new file mode 100644
index ..7f2b1bb43eae
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/pr99241_c.C
@@ -0,0 +1,5 @@
+// { dg-additional-options "-fmodules-ts -fno-module-lazy" }
+
+import "pr99241_a.H";
+void terminate();
+import "pr99241_b.H";


[gcc r15-1968] c++/modules: Keep entity mapping info across duplicate_decls [PR99241]

2024-07-11 Thread Nathaniel Shead via Gcc-cvs
https://gcc.gnu.org/g:f04f9714fca40315360af109b9e5ca2305fd75db

commit r15-1968-gf04f9714fca40315360af109b9e5ca2305fd75db
Author: Nathaniel Shead 
Date:   Mon Jul 8 14:35:58 2024 +1000

c++/modules: Keep entity mapping info across duplicate_decls [PR99241]

When duplicate_decls finds a match with an existing imported
declaration, it clears DECL_LANG_SPECIFIC of the olddecl and replaces it
with the contents of newdecl; this clears DECL_MODULE_ENTITY_P causing
an ICE if the same declaration is imported again later.

This fixes the issue by ensuring that the flag is transferred to newdecl
before clearing so that it ends up on olddecl again.

For future-proofing we also do the same with DECL_MODULE_KEYED_DECLS_P,
though because we don't yet support textual redefinition merging we
can't yet test this works as intended.  I don't expect it's possible for
a new declaration already to have extra keyed decls mismatching that of
the old declaration though, so I don't do anything with 'keyed_map' at
this time.

PR c++/99241

gcc/cp/ChangeLog:

* decl.cc (duplicate_decls): Merge module entity information.

gcc/testsuite/ChangeLog:

* g++.dg/modules/pr99241_a.H: New test.
* g++.dg/modules/pr99241_b.H: New test.
* g++.dg/modules/pr99241_c.C: New test.

Signed-off-by: Nathaniel Shead 

Diff:
---
 gcc/cp/decl.cc   | 10 ++
 gcc/testsuite/g++.dg/modules/pr99241_a.H |  3 +++
 gcc/testsuite/g++.dg/modules/pr99241_b.H |  3 +++
 gcc/testsuite/g++.dg/modules/pr99241_c.C |  5 +
 4 files changed, 21 insertions(+)

diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index d4c65a199329..edf4c155bf77 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -3139,6 +3139,16 @@ duplicate_decls (tree newdecl, tree olddecl, bool 
hiding, bool was_hidden)
   if (TREE_CODE (newdecl) == FIELD_DECL)
 DECL_PACKED (olddecl) = DECL_PACKED (newdecl);
 
+  /* Merge module entity mapping information.  */
+  if (DECL_LANG_SPECIFIC (olddecl)
+  && (DECL_MODULE_ENTITY_P (olddecl)
+ || DECL_MODULE_KEYED_DECLS_P (olddecl)))
+{
+  retrofit_lang_decl (newdecl);
+  DECL_MODULE_ENTITY_P (newdecl) = DECL_MODULE_ENTITY_P (olddecl);
+  DECL_MODULE_KEYED_DECLS_P (newdecl) = DECL_MODULE_KEYED_DECLS_P 
(olddecl);
+}
+
   /* The DECL_LANG_SPECIFIC information in OLDDECL will be replaced
  with that from NEWDECL below.  */
   if (DECL_LANG_SPECIFIC (olddecl))
diff --git a/gcc/testsuite/g++.dg/modules/pr99241_a.H 
b/gcc/testsuite/g++.dg/modules/pr99241_a.H
new file mode 100644
index ..c7031f08eb5d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/pr99241_a.H
@@ -0,0 +1,3 @@
+// { dg-additional-options "-fmodule-header" }
+// { dg-module-cmi {} }
+void terminate();
diff --git a/gcc/testsuite/g++.dg/modules/pr99241_b.H 
b/gcc/testsuite/g++.dg/modules/pr99241_b.H
new file mode 100644
index ..c7031f08eb5d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/pr99241_b.H
@@ -0,0 +1,3 @@
+// { dg-additional-options "-fmodule-header" }
+// { dg-module-cmi {} }
+void terminate();
diff --git a/gcc/testsuite/g++.dg/modules/pr99241_c.C 
b/gcc/testsuite/g++.dg/modules/pr99241_c.C
new file mode 100644
index ..7f2b1bb43eae
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/pr99241_c.C
@@ -0,0 +1,5 @@
+// { dg-additional-options "-fmodules-ts -fno-module-lazy" }
+
+import "pr99241_a.H";
+void terminate();
+import "pr99241_b.H";


[gcc r15-1882] c++: Simplify uses of LAMBDA_EXPR_EXTRA_SCOPE

2024-07-07 Thread Nathaniel Shead via Gcc-cvs
https://gcc.gnu.org/g:24cb586cafd40f8fbea68641f97e3431ea76c1b8

commit r15-1882-g24cb586cafd40f8fbea68641f97e3431ea76c1b8
Author: Nathaniel Shead 
Date:   Sat Jun 15 22:47:07 2024 +1000

c++: Simplify uses of LAMBDA_EXPR_EXTRA_SCOPE

I noticed there already exists a getter to get the scope of a lambda
from its type directly rather than needing to go via
CLASSTYPE_LAMBDA_EXPR, we may as well use it.

gcc/cp/ChangeLog:

* module.cc (trees_out::get_merge_kind): Use
LAMBDA_TYPE_EXTRA_SCOPE instead of LAMBDA_EXPR_EXTRA_SCOPE.
(trees_out::key_mergeable): Likewise.

Signed-off-by: Nathaniel Shead 

Diff:
---
 gcc/cp/module.cc | 7 ++-
 1 file changed, 2 insertions(+), 5 deletions(-)

diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index dc5d046f04d..da180244e03 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -10686,9 +10686,7 @@ trees_out::get_merge_kind (tree decl, depset *dep)
   g++.dg/modules/lambda-6_a.C.  */
if (DECL_IMPLICIT_TYPEDEF_P (STRIP_TEMPLATE (decl))
&& LAMBDA_TYPE_P (TREE_TYPE (decl)))
- if (tree scope
- = LAMBDA_EXPR_EXTRA_SCOPE (CLASSTYPE_LAMBDA_EXPR
-(TREE_TYPE (decl
+ if (tree scope = LAMBDA_TYPE_EXTRA_SCOPE (TREE_TYPE (decl)))
{
  /* Lambdas attached to fields are keyed to its class.  */
  if (TREE_CODE (scope) == FIELD_DECL)
@@ -10993,8 +10991,7 @@ trees_out::key_mergeable (int tag, merge_kind mk, tree 
decl, tree inner,
case MK_keyed:
  {
gcc_checking_assert (LAMBDA_TYPE_P (TREE_TYPE (inner)));
-   tree scope = LAMBDA_EXPR_EXTRA_SCOPE (CLASSTYPE_LAMBDA_EXPR
- (TREE_TYPE (inner)));
+   tree scope = LAMBDA_TYPE_EXTRA_SCOPE (TREE_TYPE (inner));
gcc_checking_assert (TREE_CODE (scope) == VAR_DECL
 || TREE_CODE (scope) == FIELD_DECL
 || TREE_CODE (scope) == PARM_DECL


[gcc r15-964] c++/modules: Fix revealing with using-decls [PR114867]

2024-05-31 Thread Nathaniel Shead via Gcc-cvs
https://gcc.gnu.org/g:85f15ea65a97686ad39af0c14b7dd9a9372e3a19

commit r15-964-g85f15ea65a97686ad39af0c14b7dd9a9372e3a19
Author: Nathaniel Shead 
Date:   Sat Jun 1 01:14:44 2024 +1000

c++/modules: Fix revealing with using-decls [PR114867]

This patch fixes a couple issues with the current handling of revealing
declarations with using-decls.

Firstly, doing 'remove_node' when handling function overload sets is not
safe, because it not only mutates the OVERLOAD we're walking over but
potentially any other references to this OVERLOAD that are cached from
phase-1 template lookup.  This causes the attached using-17 testcase to
fail because the overload set in 'X::test()' no longer contains the
'ns::f(T)' template once instantiated at the end of the file.

This patch works around this by simply not removing the old declaration.
This does make the overload list potentially longer than it otherwise
would have been, but only when re-exporting the same set of functions in
a using-decl.  Additionally, because 'ovl_insert' always prepends these
newly inserted overloads, repeated exported using-decls won't continue
to add declarations, as the first exported using-decl will be found
before the original (unexported) declaration.

Another, related, issue is that using-decls of GMF entities currently
doesn't mark them as reachable unless they are also exported, and thus
they may not be available in e.g. module implementation units.  We solve
this with a new flag on OVERLOADs set when they are declared within the
module purview.  This starts to run into the more general issue of
handling using-decls of non-functions (see e.g. PR114863) but by just
marking such GMF entities as purview we can work around this for now.

This also allows us to get rid of the special-casing of exported
using-decls in 'add_binding_entity', which was incorrect anyway: a
non-exported using-decl still needs to be emitted anyway if it lives in
the module purview, even if referring to a non-purview item.

PR c++/114867

gcc/cp/ChangeLog:

* cp-tree.h (OVL_PURVIEW_P): New.
(ovl_iterator::purview_p): New.
* module.cc (depset::hash::add_binding_entity): Only ignore
entities not within module purview. Set OVL_PURVIEW_P on new
OVERLOADs for emitted declarations.
(module_state::read_cluster): Imported using-decls are always
in purview, mark as OVL_PURVIEW_P.
* name-lookup.h (enum WMB_Flags): New WMB_Purview flag.
* name-lookup.cc (walk_module_binding): Set WMB_Purview as
needed.
(do_nonmember_using_decl): Don't remove from existing OVERLOADs.
Also reveal non-exported decls. Also reveal 'extern "C"' decls.
Add workaround to reveal non-function decls.
* tree.cc (ovl_insert): Adjust to also set OVL_PURVIEW_P when
needed.

gcc/testsuite/ChangeLog:

* g++.dg/modules/using-17_a.C: New test.
* g++.dg/modules/using-17_b.C: New test.
* g++.dg/modules/using-18_a.C: New test.
* g++.dg/modules/using-18_b.C: New test.

Signed-off-by: Nathaniel Shead 

Diff:
---
 gcc/cp/cp-tree.h  |   7 ++
 gcc/cp/module.cc  |   8 ++-
 gcc/cp/name-lookup.cc | 106 --
 gcc/cp/name-lookup.h  |   1 +
 gcc/cp/tree.cc|  12 ++--
 gcc/testsuite/g++.dg/modules/using-17_a.C |  31 +
 gcc/testsuite/g++.dg/modules/using-17_b.C |  13 
 gcc/testsuite/g++.dg/modules/using-18_a.C |  29 
 gcc/testsuite/g++.dg/modules/using-18_b.C |  11 
 9 files changed, 161 insertions(+), 57 deletions(-)

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 6206482c602..565e4a9290e 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -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
   {
dif

[gcc r15-830] c++/modules: Improve diagnostic when redeclaring builtin in module [PR102345]

2024-05-24 Thread Nathaniel Shead via Gcc-cvs
https://gcc.gnu.org/g:28b508233a12c13295f960a2cb8a4864879acfb4

commit r15-830-g28b508233a12c13295f960a2cb8a4864879acfb4
Author: Nathaniel Shead 
Date:   Sat May 25 01:03:54 2024 +1000

c++/modules: Improve diagnostic when redeclaring builtin in module 
[PR102345]

If a user mistakenly includes a standard library header within the
module purview, they currently get a confusing "declaration conflicts
with builtin" error.  This patch updates the message to include "in
module", to help guide the user towards the likely cause.

PR c++/102345

gcc/cp/ChangeLog:

* module.cc (module_may_redeclare): Update error message.

gcc/testsuite/ChangeLog:

* g++.dg/modules/enum-12.C: Test for updated error.

Signed-off-by: Nathaniel Shead 

Diff:
---
 gcc/cp/module.cc   | 8 +++-
 gcc/testsuite/g++.dg/modules/enum-12.C | 2 +-
 2 files changed, 8 insertions(+), 2 deletions(-)

diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index 6cd7d9e0b93..3f8f84bb9fd 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -19140,7 +19140,13 @@ module_may_redeclare (tree olddecl, tree newdecl)
   decl = newdecl ? newdecl : olddecl;
   location_t loc = newdecl ? DECL_SOURCE_LOCATION (newdecl) : input_location;
   if (DECL_IS_UNDECLARED_BUILTIN (olddecl))
-error_at (loc, "declaration %qD conflicts with builtin", decl);
+{
+  if (newdecl_attached_p)
+   error_at (loc, "declaring %qD in module %qs conflicts with builtin "
+ "in global module", decl, new_mod->get_flatname ());
+  else
+   error_at (loc, "declaration %qD conflicts with builtin", decl);
+}
   else if (DECL_LANG_SPECIFIC (old_inner) && DECL_MODULE_IMPORT_P (old_inner))
 {
   auto_diagnostic_group d;
diff --git a/gcc/testsuite/g++.dg/modules/enum-12.C 
b/gcc/testsuite/g++.dg/modules/enum-12.C
index 064f220dedf..cf8f445e076 100644
--- a/gcc/testsuite/g++.dg/modules/enum-12.C
+++ b/gcc/testsuite/g++.dg/modules/enum-12.C
@@ -4,7 +4,7 @@
 
 export module foo;
 namespace std {
-  enum class align_val_t : decltype(sizeof(int)) {};  // { dg-error "conflicts 
with builtin" }
+  enum class align_val_t : decltype(sizeof(int)) {};  // { dg-error "in module 
.foo. conflicts with builtin" }
 }
 
 // { dg-prune-output "not writing module" }


[gcc r14-10241] c++: Propagate using decls from partitions [PR114868]

2024-05-24 Thread Nathaniel Shead via Gcc-cvs
https://gcc.gnu.org/g:782ad2033ea0709a25ef3e899cbb9491406146d5

commit r14-10241-g782ad2033ea0709a25ef3e899cbb9491406146d5
Author: Nathaniel Shead 
Date:   Tue Apr 9 21:49:58 2024 +1000

c++: Propagate using decls from partitions [PR114868]

The modules code currently neglects to set OVL_USING_P on the dependency
created for a using-decl, which causes it not to remember that the
OVL_EXPORT_P flag had been set on it when emitted from the primary
interface unit. This patch ensures that it occurs.

PR c++/114868

gcc/cp/ChangeLog:

* module.cc (depset::hash::add_binding_entity): Propagate
OVL_USING_P for using-declarations.

gcc/testsuite/ChangeLog:

* g++.dg/modules/using-15_a.C: New test.
* g++.dg/modules/using-15_b.C: New test.
* g++.dg/modules/using-15_c.C: New test.

Signed-off-by: Nathaniel Shead 
(cherry picked from commit 0d0215b10dbbe39d655ceda4af283f288ec7680c)

Diff:
---
 gcc/cp/module.cc  |  6 ++
 gcc/testsuite/g++.dg/modules/using-15_a.C | 14 ++
 gcc/testsuite/g++.dg/modules/using-15_b.C |  6 ++
 gcc/testsuite/g++.dg/modules/using-15_c.C |  8 
 4 files changed, 34 insertions(+)

diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index 85c410aaa4c..b610b808240 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -13151,10 +13151,14 @@ 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);
  flags = WMB_Flags (flags | WMB_Using);
  if (DECL_MODULE_EXPORT_P (TREE_CODE (decl) == CONST_DECL
? TYPE_NAME (TREE_TYPE (decl))
@@ -13215,6 +13219,8 @@ 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;
  if (flags & WMB_Export)
OVL_EXPORT_P (decl) = true;
}
diff --git a/gcc/testsuite/g++.dg/modules/using-15_a.C 
b/gcc/testsuite/g++.dg/modules/using-15_a.C
new file mode 100644
index 000..3f4bb6c5914
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/using-15_a.C
@@ -0,0 +1,14 @@
+// PR c++/114868
+// { dg-additional-options "-fmodules-ts -Wno-global-module" }
+// { dg-module-cmi M:a }
+
+module;
+namespace foo {
+  void a();
+}
+export module M:a;
+
+namespace bar {
+  // propagate usings from partitions
+  export using foo::a;
+}
diff --git a/gcc/testsuite/g++.dg/modules/using-15_b.C 
b/gcc/testsuite/g++.dg/modules/using-15_b.C
new file mode 100644
index 000..4b0cb745157
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/using-15_b.C
@@ -0,0 +1,6 @@
+// PR c++/114868
+// { dg-additional-options "-fmodules-ts" }
+// { dg-module-cmi M }
+
+export module M;
+export import :a;
diff --git a/gcc/testsuite/g++.dg/modules/using-15_c.C 
b/gcc/testsuite/g++.dg/modules/using-15_c.C
new file mode 100644
index 000..74dd10a5413
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/using-15_c.C
@@ -0,0 +1,8 @@
+// PR c++/114868
+// { dg-additional-options "-fmodules-ts" }
+import M;
+
+int main() {
+  bar::a();
+  foo::a();  // { dg-error "not been declared" }
+}


[gcc r14-10240] c++: Fix instantiation of imported temploid friends [PR114275]

2024-05-24 Thread Nathaniel Shead via Gcc-cvs
https://gcc.gnu.org/g:fd6fd88b1a93f4fb38f095688255ab5c00122810

commit r14-10240-gfd6fd88b1a93f4fb38f095688255ab5c00122810
Author: Nathaniel Shead 
Date:   Mon Apr 29 17:00:13 2024 +1000

c++: Fix instantiation of imported temploid friends [PR114275]

This patch fixes a number of issues with the handling of temploid friend
declarations.

The primary issue is that instantiations of friend declarations should
attach the declaration to the same module as the befriending class, by
[module.unit] p7.1 and [temp.friend] p2; this could be a different
module from the current TU, and so needs special handling.

The other main issue here is that we can't assume that just because name
lookup didn't find a definition for a hidden class template, that it
doesn't exist at all: it could be a non-exported entity that we've
nevertheless streamed in from an imported module.  We need to ensure
that when instantiating template friend classes that we return the same
TEMPLATE_DECL that we got from our imports, otherwise we will get later
issues with 'duplicate_decls' (rightfully) complaining that they're
different when trying to merge.

This doesn't appear necessary for function templates due to the existing
name lookup handling already finding these hidden declarations.

(cherry-picked from commits b5f6a56940e70838a07e885de03a92e2bd64674a and
ec2365e07537e8b17745d75c28a2b45bf33be119)

PR c++/105320
PR c++/114275

gcc/cp/ChangeLog:

* cp-tree.h (propagate_defining_module): Declare.
(remove_defining_module): Declare.
(lookup_imported_hidden_friend): Declare.
* decl.cc (duplicate_decls): Also check if hidden decls can be
redeclared in this module. Call remove_defining_module on
to-be-freed newdecl.
* module.cc (imported_temploid_friends): New.
(init_modules): Initialize it.
(trees_out::decl_value): Write it; don't consider imported
temploid friends as attached to a module.
(trees_in::decl_value): Read it for non-discarded decls.
(get_originating_module_decl): Follow the owning decl for an
imported temploid friend.
(propagate_defining_module): New.
(remove_defining_module): New.
* name-lookup.cc (get_mergeable_namespace_binding): New.
(lookup_imported_hidden_friend): New.
* pt.cc (tsubst_friend_function): Propagate defining module for
new friend functions.
(tsubst_friend_class): Lookup imported hidden friends.  Check
for valid module attachment of existing names.  Propagate
defining module for new classes.

gcc/testsuite/ChangeLog:

* g++.dg/modules/tpl-friend-10_a.C: New test.
* g++.dg/modules/tpl-friend-10_b.C: New test.
* g++.dg/modules/tpl-friend-10_c.C: New test.
* g++.dg/modules/tpl-friend-10_d.C: New test.
* g++.dg/modules/tpl-friend-11_a.C: New test.
* g++.dg/modules/tpl-friend-11_b.C: New test.
* g++.dg/modules/tpl-friend-12_a.C: New test.
* g++.dg/modules/tpl-friend-12_b.C: New test.
* g++.dg/modules/tpl-friend-12_c.C: New test.
* g++.dg/modules/tpl-friend-12_d.C: New test.
* g++.dg/modules/tpl-friend-12_e.C: New test.
* g++.dg/modules/tpl-friend-12_f.C: New test.
* g++.dg/modules/tpl-friend-13_a.C: New test.
* g++.dg/modules/tpl-friend-13_b.C: New test.
* g++.dg/modules/tpl-friend-13_c.C: New test.
* g++.dg/modules/tpl-friend-13_d.C: New test.
* g++.dg/modules/tpl-friend-13_e.C: New test.
* g++.dg/modules/tpl-friend-13_f.C: New test.
* g++.dg/modules/tpl-friend-13_g.C: New test.
* g++.dg/modules/tpl-friend-14_a.C: New test.
* g++.dg/modules/tpl-friend-14_b.C: New test.
* g++.dg/modules/tpl-friend-14_c.C: New test.
* g++.dg/modules/tpl-friend-14_d.C: New test.
* g++.dg/modules/tpl-friend-9.C: New test.

Signed-off-by: Nathaniel Shead 
Reviewed-by: Jason Merrill 
Reviewed-by: Patrick Palka 

Diff:
---
 gcc/cp/cp-tree.h   |  3 ++
 gcc/cp/decl.cc | 41 --
 gcc/cp/module.cc   | 75 ++
 gcc/cp/name-lookup.cc  | 53 ++
 gcc/cp/pt.cc   | 32 ++-
 gcc/testsuite/g++.dg/modules/tpl-friend-10_a.C | 15 ++
 gcc/testsuite/g++.dg/modules/tpl-friend-10_b.C |  5 ++
 gcc/testsuite/g++.dg/modules/tpl-friend-10_c.C |  7 +++
 gcc/testsuite/g++.dg/modules/tpl-friend-10_d.C |  8 +++
 gcc/testsuite/g++.dg/modules/tpl-friend-11_a.C | 14 +
 

[gcc r14-10239] c++: Standardise errors for module_may_redeclare

2024-05-24 Thread Nathaniel Shead via Gcc-cvs
https://gcc.gnu.org/g:557cddcc71c9025932b30f1f825dc600a82dfe03

commit r14-10239-g557cddcc71c9025932b30f1f825dc600a82dfe03
Author: Nathaniel Shead 
Date:   Sun Apr 14 23:03:11 2024 +1000

c++: Standardise errors for module_may_redeclare

Currently different places calling 'module_may_redeclare' all emit very
similar but slightly different error messages, and handle different
kinds of declarations differently.  This patch makes the function
perform its own error messages so that they're all in one place, and
prepares it for use with temploid friends.

gcc/cp/ChangeLog:

* cp-tree.h (module_may_redeclare): Add default parameter.
* decl.cc (duplicate_decls): Don't emit errors for failed
module_may_redeclare.
(xref_tag): Likewise.
(start_enum): Likewise.
* semantics.cc (begin_class_definition): Likewise.
* module.cc (module_may_redeclare): Clean up logic. Emit error
messages on failure.

gcc/testsuite/ChangeLog:

* g++.dg/modules/enum-12.C: Update error message.
* g++.dg/modules/friend-5_b.C: Likewise.
* g++.dg/modules/shadow-1_b.C: Likewise.

Signed-off-by: Nathaniel Shead 
Reviewed-by: Jason Merrill 
(cherry picked from commit 2faf040335f9b49c33ba6d40cf317920f27ce431)

Diff:
---
 gcc/cp/cp-tree.h  |   2 +-
 gcc/cp/decl.cc|  28 +--
 gcc/cp/module.cc  | 120 --
 gcc/cp/semantics.cc   |   6 +-
 gcc/testsuite/g++.dg/modules/enum-12.C|   2 +-
 gcc/testsuite/g++.dg/modules/friend-5_b.C |   2 +-
 gcc/testsuite/g++.dg/modules/shadow-1_b.C |   5 +-
 7 files changed, 89 insertions(+), 76 deletions(-)

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 64760a40215..d4a70807460 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -7402,7 +7402,7 @@ inline bool module_exporting_p ()
 
 extern module_state *get_module (tree name, module_state *parent = NULL,
 bool partition = false);
-extern bool module_may_redeclare (tree decl);
+extern bool module_may_redeclare (tree olddecl, tree newdecl = NULL);
 
 extern bool module_global_init_needed ();
 extern bool module_determine_import_inits ();
diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index fea66e838ce..93f81e42127 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -2279,18 +2279,8 @@ duplicate_decls (tree newdecl, tree olddecl, bool 
hiding, bool was_hidden)
   && TREE_CODE (olddecl) != NAMESPACE_DECL
   && !hiding)
 {
-  if (!module_may_redeclare (olddecl))
-   {
- if (DECL_ARTIFICIAL (olddecl))
-   error ("declaration %qD conflicts with builtin", newdecl);
- else
-   {
- error ("declaration %qD conflicts with import", newdecl);
- inform (olddecl_loc, "import declared %q#D here", olddecl);
-   }
-
- return error_mark_node;
-   }
+  if (!module_may_redeclare (olddecl, newdecl))
+   return error_mark_node;
 
   tree not_tmpl = STRIP_TEMPLATE (olddecl);
   if (DECL_LANG_SPECIFIC (not_tmpl)
@@ -16633,12 +16623,7 @@ xref_tag (enum tag_types tag_code, tree name,
{
  tree decl = TYPE_NAME (t);
  if (!module_may_redeclare (decl))
-   {
- auto_diagnostic_group d;
- error ("cannot declare %qD in a different module", decl);
- inform (DECL_SOURCE_LOCATION (decl), "previously declared here");
- return error_mark_node;
-   }
+   return error_mark_node;
 
  tree not_tmpl = STRIP_TEMPLATE (decl);
  if (DECL_LANG_SPECIFIC (not_tmpl)
@@ -16986,12 +16971,7 @@ start_enum (tree name, tree enumtype, tree 
underlying_type,
{
  tree decl = TYPE_NAME (enumtype);
  if (!module_may_redeclare (decl))
-   {
- auto_diagnostic_group d;
- error ("cannot declare %qD in different module", decl);
- inform (DECL_SOURCE_LOCATION (decl), "previously declared here");
- enumtype = error_mark_node;
-   }
+   enumtype = error_mark_node;
  else
set_instantiating_module (decl);
}
diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index 3bf863e15d4..c2f077d6fd8 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -19003,11 +19003,15 @@ get_importing_module (tree decl, bool flexible)
   return module->mod;
 }
 
-/* Is it permissible to redeclare DECL.  */
+/* Is it permissible to redeclare OLDDECL with NEWDECL.
+
+   If NEWDECL is NULL, assumes that OLDDECL will be redeclared using
+   the current scope's module and attachment.  */
 
 bool
-module_may_redeclare (tree decl)
+module_may_redeclare (tree olddecl, tree newdecl)
 {
+  tree decl = olddecl;
   for (;;)
 {
   tree ctx = CP_DECL_CONTEXT (decl);

[gcc r15-824] c++/modules: Improve errors for bad module-directives [PR115200]

2024-05-24 Thread Nathaniel Shead via Gcc-cvs
https://gcc.gnu.org/g:dae606a11eb99814e452b49241fa76f7678f53b8

commit r15-824-gdae606a11eb99814e452b49241fa76f7678f53b8
Author: Nathaniel Shead 
Date:   Fri May 24 00:08:57 2024 +1000

c++/modules: Improve errors for bad module-directives [PR115200]

This fixes an ICE when a module directive is not given at global scope.
Although not explicitly mentioned, it seems implied from [basic.link] p1
and [module.global.frag] that a module-declaration must appear at the
global scope after preprocessing.  Apart from this the patch also
slightly improves the errors given when accidentally using a module
control-line in other situations where it is not expected.

PR c++/115200

gcc/cp/ChangeLog:

* parser.cc (cp_parser_error_1): Special-case unexpected module
directives for better diagnostics.
(cp_parser_module_declaration): Check that the module
declaration is at global scope.
(cp_parser_import_declaration): Sync error message with that in
cp_parser_error_1.

gcc/testsuite/ChangeLog:

* g++.dg/modules/mod-decl-1.C: Update error messages.
* g++.dg/modules/mod-decl-6.C: New test.
* g++.dg/modules/mod-decl-7.C: New test.
* g++.dg/modules/mod-decl-8.C: New test.

Signed-off-by: Nathaniel Shead 
Reviewed-by: Jason Merrill 

Diff:
---
 gcc/cp/parser.cc  | 26 +++---
 gcc/testsuite/g++.dg/modules/mod-decl-1.C |  8 +---
 gcc/testsuite/g++.dg/modules/mod-decl-6.C | 11 +++
 gcc/testsuite/g++.dg/modules/mod-decl-7.C | 11 +++
 gcc/testsuite/g++.dg/modules/mod-decl-8.C | 14 ++
 5 files changed, 64 insertions(+), 6 deletions(-)

diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 476ddc0d63a..779625144db 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -3230,6 +3230,19 @@ cp_parser_error_1 (cp_parser* parser, const char* gmsgid,
   return;
 }
 
+  if (cp_token_is_module_directive (token))
+{
+  auto_diagnostic_group d;
+  error_at (token->location, "unexpected module directive");
+  if (token->keyword != RID__EXPORT)
+   inform (token->location, "perhaps insert a line break after"
+   " %qs, or other disambiguation, to prevent this being"
+   " considered a module control-line",
+   (token->keyword == RID__MODULE) ? "module" : "import");
+  cp_parser_skip_to_pragma_eol (parser, token);
+  return;
+}
+
   /* If this is actually a conflict marker, report it as such.  */
   if (token->type == CPP_LSHIFT
   || token->type == CPP_RSHIFT
@@ -15135,12 +15148,19 @@ cp_parser_module_declaration (cp_parser *parser, 
module_parse mp_state,
   parser->lexer->in_pragma = true;
   cp_token *token = cp_lexer_consume_token (parser->lexer);
 
+  tree scope = current_scope ();
   if (flag_header_unit)
 {
   error_at (token->location,
"module-declaration not permitted in header-unit");
   goto skip_eol;
 }
+  else if (scope != global_namespace)
+{
+  error_at (token->location, "module-declaration must be at global scope");
+  inform (DECL_SOURCE_LOCATION (scope), "scope opened here");
+  goto skip_eol;
+}
   else if (mp_state == MP_FIRST && !exporting
   && cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON))
 {
@@ -15217,9 +15237,9 @@ cp_parser_import_declaration (cp_parser *parser, 
module_parse mp_state,
   error_at (token->location, "post-module-declaration"
" imports must be contiguous");
 note_lexer:
-  inform (token->location, "perhaps insert a line break, or other"
- " disambiguation, to prevent this being considered a"
- " module control-line");
+  inform (token->location, "perhaps insert a line break after"
+ " %, or other disambiguation, to prevent this"
+ " being considered a module control-line");
 skip_eol:
   cp_parser_skip_to_pragma_eol (parser, token);
 }
diff --git a/gcc/testsuite/g++.dg/modules/mod-decl-1.C 
b/gcc/testsuite/g++.dg/modules/mod-decl-1.C
index 23d34483dd7..df398b3ef50 100644
--- a/gcc/testsuite/g++.dg/modules/mod-decl-1.C
+++ b/gcc/testsuite/g++.dg/modules/mod-decl-1.C
@@ -10,17 +10,19 @@ module foo.second; // { dg-error "only permitted as" }
 
 namespace Foo 
 {
-module third;  // { dg-error "only permitted as" }
+module third;  // { dg-error "must be at global scope" }
 }
 
 struct Baz
 {
-  module forth; // { dg-error "expected" }
+  module forth; // { dg-error "unexpected module directive" }
+  // { dg-message "line break after .module." "" { target *-*-* } .-1 }
 };
 
 void Bink ()
 {
-  module fifth; // { dg-error "expected" }
+  module fifth; // { dg-error "unexpected module directive" }
+  // { dg-message "line break after .module." "" { target *-*-* } .-1 }
 }
 
 module a.; // { dg-error "only 

[gcc r15-823] c++/modules: Remember that header units have CMIs

2024-05-24 Thread Nathaniel Shead via Gcc-cvs
https://gcc.gnu.org/g:03531ec45f15aa187bbab7842a1eb6cf746a104b

commit r15-823-g03531ec45f15aa187bbab7842a1eb6cf746a104b
Author: Nathaniel Shead 
Date:   Thu May 23 22:56:52 2024 +1000

c++/modules: Remember that header units have CMIs

This appears to be an oversight in the definition of module_has_cmi_p.
This change will allow us to use the function directly in more places
that need to additional work only if generating a module CMI in the
future, allowing us to do additional work only when we know we need it.

gcc/cp/ChangeLog:

* cp-tree.h (module_has_cmi_p): Also include header units.
(module_maybe_has_cmi_p): Update comment.
* module.cc (set_defining_module): Only need to track
declarations for later exporting if the module may have a CMI.
(set_defining_module_for_partial_spec): Likewise.
* name-lookup.cc (pushdecl): Likewise.

Signed-off-by: Nathaniel Shead 

Diff:
---
 gcc/cp/cp-tree.h  | 7 +++
 gcc/cp/module.cc  | 4 ++--
 gcc/cp/name-lookup.cc | 2 +-
 3 files changed, 6 insertions(+), 7 deletions(-)

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 7ae5b876735..655850a9ab6 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -7381,7 +7381,7 @@ inline bool module_interface_p ()
 inline bool module_partition_p ()
 { return module_kind & MK_PARTITION; }
 inline bool module_has_cmi_p ()
-{ return module_kind & (MK_INTERFACE | MK_PARTITION); }
+{ return module_kind & (MK_INTERFACE | MK_PARTITION | MK_HEADER); }
 
 inline bool module_purview_p ()
 { return module_kind & MK_PURVIEW; }
@@ -7393,9 +7393,8 @@ inline bool named_module_purview_p ()
 inline bool named_module_attach_p ()
 { return named_module_p () && module_attach_p (); }
 
-/* We don't know if this TU will have a CMI while parsing the GMF,
-   so tentatively assume that it might, for the purpose of determining
-   whether no-linkage decls could be used by an importer.  */
+/* Like module_has_cmi_p, but tentatively assumes that this TU may have a
+   CMI if we haven't seen the module-declaration yet.  */
 inline bool module_maybe_has_cmi_p ()
 { return module_has_cmi_p () || (named_module_p () && !module_purview_p ()); }
 
diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index 3ca963cb3e9..6cd7d9e0b93 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -19221,7 +19221,7 @@ set_defining_module (tree decl)
   gcc_checking_assert (!DECL_LANG_SPECIFIC (decl)
   || !DECL_MODULE_IMPORT_P (decl));
 
-  if (module_p ())
+  if (module_maybe_has_cmi_p ())
 {
   /* We need to track all declarations within a module, not just those
 in the module purview, because we don't necessarily know yet if
@@ -19261,7 +19261,7 @@ set_defining_module (tree decl)
 void
 set_defining_module_for_partial_spec (tree decl)
 {
-  if (module_p ()
+  if (module_maybe_has_cmi_p ()
   && DECL_IMPLICIT_TYPEDEF_P (decl)
   && CLASSTYPE_TEMPLATE_SPECIALIZATION (TREE_TYPE (decl)))
 vec_safe_push (partial_specializations, decl);
diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc
index 78f08acffaa..f1f8c19feb1 100644
--- a/gcc/cp/name-lookup.cc
+++ b/gcc/cp/name-lookup.cc
@@ -4103,7 +4103,7 @@ pushdecl (tree decl, bool hiding)
 
  if (level->kind == sk_namespace
  && TREE_PUBLIC (level->this_entity)
- && module_p ())
+ && module_maybe_has_cmi_p ())
maybe_record_mergeable_decl (slot, name, decl);
}
 }


[gcc r15-822] c++/modules: Fix treatment of unnamed types

2024-05-24 Thread Nathaniel Shead via Gcc-cvs
https://gcc.gnu.org/g:0173dcce92baa62a74929814a75edb75eeab1a54

commit r15-822-g0173dcce92baa62a74929814a75edb75eeab1a54
Author: Nathaniel Shead 
Date:   Thu May 23 22:50:58 2024 +1000

c++/modules: Fix treatment of unnamed types

In r14-9530 we relaxed "depending on type with no-linkage" errors for
declarations that could actually be accessed from different TUs anyway.
However, this also enabled it for unnamed types, which never work.

In a normal module interface, an unnamed type is TU-local by
[basic.link] p15.2, and so cannot be exposed or the program is
ill-formed.  We don't yet implement this checking but we should assume
that we will later; currently supporting this actually causes ICEs when
attempting to create the mangled name in some situations.

For a header unit, by [module.import] p5.3 it is unspecified whether two
TUs importing a header unit providing such a declaration are importing
the same header unit.  In this case, we would require name mangling
changes to somehow allow the (anonymous) type exported by such a header
unit to correspond across different TUs in the presence of other
anonymous declarations, so for this patch just assume that this case
would be an ODR violation instead.

gcc/cp/ChangeLog:

* tree.cc (no_linkage_check): Anonymous types can't be accessed
in a different TU.

gcc/testsuite/ChangeLog:

* g++.dg/modules/linkage-1_a.C: Remove anonymous type test.
* g++.dg/modules/linkage-1_b.C: Likewise.
* g++.dg/modules/linkage-1_c.C: Likewise.
* g++.dg/modules/linkage-2.C: Add note about anonymous types.

Signed-off-by: Nathaniel Shead 
Reviewed-by: Jason Merrill 

Diff:
---
 gcc/cp/tree.cc | 10 +-
 gcc/testsuite/g++.dg/modules/linkage-1_a.C |  4 
 gcc/testsuite/g++.dg/modules/linkage-1_b.C |  1 -
 gcc/testsuite/g++.dg/modules/linkage-1_c.C |  1 -
 gcc/testsuite/g++.dg/modules/linkage-2.C   |  6 ++
 5 files changed, 7 insertions(+), 15 deletions(-)

diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
index 0485a618c6c..fe3f034d000 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -2988,15 +2988,7 @@ no_linkage_check (tree t, bool relaxed_p)
   /* Only treat unnamed types as having no linkage if they're at
 namespace scope.  This is core issue 966.  */
   if (TYPE_UNNAMED_P (t) && TYPE_NAMESPACE_SCOPE_P (t))
-   {
- if (relaxed_p
- && TREE_PUBLIC (CP_TYPE_CONTEXT (t))
- && module_maybe_has_cmi_p ())
-   /* This type could possibly be accessed outside this TU.  */
-   return NULL_TREE;
- else
-   return t;
-   }
+   return t;
 
   for (r = CP_TYPE_CONTEXT (t); ; )
{
diff --git a/gcc/testsuite/g++.dg/modules/linkage-1_a.C 
b/gcc/testsuite/g++.dg/modules/linkage-1_a.C
index 750e31ff347..1d81312e94f 100644
--- a/gcc/testsuite/g++.dg/modules/linkage-1_a.C
+++ b/gcc/testsuite/g++.dg/modules/linkage-1_a.C
@@ -9,7 +9,3 @@ auto f() {
 }
 decltype(f()) g();  // { dg-warning "used but not defined" "" { target 
c++17_down } }
 export auto x = g();
-
-struct {} s;
-decltype(s) h();  // { dg-warning "used but not defined" "" { target 
c++17_down } }
-export auto y = h();
diff --git a/gcc/testsuite/g++.dg/modules/linkage-1_b.C 
b/gcc/testsuite/g++.dg/modules/linkage-1_b.C
index f23962d76b7..5bc0d1b888d 100644
--- a/gcc/testsuite/g++.dg/modules/linkage-1_b.C
+++ b/gcc/testsuite/g++.dg/modules/linkage-1_b.C
@@ -3,4 +3,3 @@
 module M;
 
 decltype(f()) g() { return {}; }
-decltype(s) h() { return {}; }
diff --git a/gcc/testsuite/g++.dg/modules/linkage-1_c.C 
b/gcc/testsuite/g++.dg/modules/linkage-1_c.C
index f1406b99032..9ff1491b67e 100644
--- a/gcc/testsuite/g++.dg/modules/linkage-1_c.C
+++ b/gcc/testsuite/g++.dg/modules/linkage-1_c.C
@@ -5,5 +5,4 @@ import M;
 
 int main() {
   auto a = x;
-  auto b = y;
 }
diff --git a/gcc/testsuite/g++.dg/modules/linkage-2.C 
b/gcc/testsuite/g++.dg/modules/linkage-2.C
index eb4d7b051af..d913d6a30fc 100644
--- a/gcc/testsuite/g++.dg/modules/linkage-2.C
+++ b/gcc/testsuite/g++.dg/modules/linkage-2.C
@@ -23,4 +23,10 @@ export void use() {
   h();
 }
 
+// Additionally, unnamed types have no linkage but are also TU-local, and thus
+// cannot be exposed in a module interface unit.  The non-TU-local entity 's'
+// here is an exposure of this type, so this should be an error; we don't yet
+// implement this checking however.
+struct {} s;  // { dg-error "TU-local" "" { xfail *-*-* } }
+
 // { dg-prune-output "not writing module" }


[gcc r15-810] c++/modules: Ensure all partial specialisations are tracked [PR114947]

2024-05-23 Thread Nathaniel Shead via Gcc-cvs
https://gcc.gnu.org/g:7fa0ffa4f789683ba80e93cd10546cb7bd2c3d8a

commit r15-810-g7fa0ffa4f789683ba80e93cd10546cb7bd2c3d8a
Author: Nathaniel Shead 
Date:   Sun May 12 22:31:01 2024 +1000

c++/modules: Ensure all partial specialisations are tracked [PR114947]

Constrained partial specialisations aren't all necessarily tracked on
the instantiation table.  The modules code uses a separate
'partial_specializations' table to track them instead to ensure that
they get walked and emitted when emitting a module, but currently this
does not always happen.

The attached testcase fails in two ways.  First, because the partial
specialisation is just a declaration (and not a definition),
'set_defining_module' never ends up getting called on it and so it never
gets added to the partial specialisation table.  We fix this by ensuring
that when partial specializations are created they always get added, and
so we never miss one. To prevent adding partial specialisations multiple
times we split this out as a new function.

The second way it fails is that when exporting the primary interface for
a module with partitions, we also re-walk the specializations of all
imported partitions to merge them into a single BMI.  So this patch
ensures that after calling 'match_mergeable_specialization' we also
ensure that if the name came from a partition it gets added to the
specialization table so that a dependency is correctly created for it.

PR c++/114947

gcc/cp/ChangeLog:

* cp-tree.h (set_defining_module_for_partial_spec): Declare.
* module.cc (trees_in::decl_value): Track partial specs coming
from partitions.
(set_defining_module): Don't track partial specialisations here
anymore.
(set_defining_module_for_partial_spec): New function.
* pt.cc (process_partial_specialization): Call it.

gcc/testsuite/ChangeLog:

* g++.dg/modules/partial-4_a.C: New test.
* g++.dg/modules/partial-4_b.C: New test.

Signed-off-by: Nathaniel Shead 

Diff:
---
 gcc/cp/cp-tree.h   |  1 +
 gcc/cp/module.cc   | 22 ++
 gcc/cp/pt.cc   |  2 ++
 gcc/testsuite/g++.dg/modules/partial-4_a.C |  8 
 gcc/testsuite/g++.dg/modules/partial-4_b.C |  5 +
 5 files changed, 34 insertions(+), 4 deletions(-)

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index ba9e848c177..7ae5b876735 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -7420,6 +7420,7 @@ extern unsigned get_importing_module (tree, bool = false) 
ATTRIBUTE_PURE;
 /* Where current instance of the decl got declared/defined/instantiated.  */
 extern void set_instantiating_module (tree);
 extern void set_defining_module (tree);
+extern void set_defining_module_for_partial_spec (tree);
 extern void maybe_key_decl (tree ctx, tree decl);
 extern void propagate_defining_module (tree decl, tree orig);
 extern void remove_defining_module (tree decl);
diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index 520dd710549..3ca963cb3e9 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -8416,6 +8416,11 @@ trees_in::decl_value ()
  add_mergeable_specialization (!is_type, &spec, decl, spec_flags);
}
 
+  /* When making a CMI from a partition we're going to need to walk partial
+specializations again, so make sure they're tracked.  */
+  if (state->is_partition () && (spec_flags & 2))
+   set_defining_module_for_partial_spec (inner);
+
   if (NAMESPACE_SCOPE_P (decl)
  && (mk == MK_named || mk == MK_unique
  || mk == MK_enum || mk == MK_friend_spec)
@@ -19246,13 +19251,22 @@ set_defining_module (tree decl)
  vec_safe_push (class_members, decl);
}
}
-  else if (DECL_IMPLICIT_TYPEDEF_P (decl)
-  && CLASSTYPE_TEMPLATE_SPECIALIZATION (TREE_TYPE (decl)))
-   /* This is a partial or explicit specialization.  */
-   vec_safe_push (partial_specializations, decl);
 }
 }
 
+/* Also remember DECL if it's a newly declared class template partial
+   specialization, because these are not necessarily added to the
+   instantiation tables.  */
+
+void
+set_defining_module_for_partial_spec (tree decl)
+{
+  if (module_p ()
+  && DECL_IMPLICIT_TYPEDEF_P (decl)
+  && CLASSTYPE_TEMPLATE_SPECIALIZATION (TREE_TYPE (decl)))
+vec_safe_push (partial_specializations, decl);
+}
+
 void
 set_originating_module (tree decl, bool friend_p ATTRIBUTE_UNUSED)
 {
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index a95ce6eb3da..dfce1b3c359 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -5456,6 +5456,8 @@ process_partial_specialization (tree decl)
   gcc_checking_assert (!TI_PARTIAL_INFO (tinfo));
   TI_PARTIAL_INFO (tinfo) = build_template_info (tmpl, NULL_TREE);
 
+  set_defining_modu

[gcc r15-762] c++: Strengthen checks on 'main'

2024-05-21 Thread Nathaniel Shead via Gcc-cvs
https://gcc.gnu.org/g:292fc21a8d7aa2f16e61ac941e22ada6ddd85500

commit r15-762-g292fc21a8d7aa2f16e61ac941e22ada6ddd85500
Author: Nathaniel Shead 
Date:   Sat May 11 22:25:44 2024 +1000

c++: Strengthen checks on 'main'

This patch adds some missing requirements for legal main declarations,
as according to [basic.start.main] p2.

gcc/cp/ChangeLog:

* decl.cc (grokfndecl): Check for main functions with language
linkage or module attachment.
(grokvardecl): Check for extern 'C' entities named main.

gcc/testsuite/ChangeLog:

* g++.dg/abi/main.C: Check pedwarn for main with linkage-spec.
* g++.dg/modules/contracts-1_b.C: Don't declare main in named
module.
* g++.dg/modules/contracts-3_b.C: Likewise.
* g++.dg/modules/contracts-4_d.C: Likewise.
* g++.dg/modules/horcrux-1_a.C: Export declarations, so that...
* g++.dg/modules/horcrux-1_b.C: Don't declare main in named
module.
* g++.dg/modules/main-1.C: New test.
* g++.dg/parse/linkage5.C: New test.
* g++.dg/parse/linkage6.C: New test.

Signed-off-by: Nathaniel Shead 

Diff:
---
 gcc/cp/decl.cc   | 19 +++
 gcc/testsuite/g++.dg/abi/main.C  |  3 ++-
 gcc/testsuite/g++.dg/modules/contracts-1_b.C |  4 
 gcc/testsuite/g++.dg/modules/contracts-3_b.C |  4 
 gcc/testsuite/g++.dg/modules/contracts-4_d.C |  2 --
 gcc/testsuite/g++.dg/modules/horcrux-1_a.C   |  3 +++
 gcc/testsuite/g++.dg/modules/horcrux-1_b.C   |  2 +-
 gcc/testsuite/g++.dg/modules/main-1.C|  5 +
 gcc/testsuite/g++.dg/parse/linkage5.C| 14 ++
 gcc/testsuite/g++.dg/parse/linkage6.C| 13 +
 10 files changed, 53 insertions(+), 16 deletions(-)

diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index 6fcab615d55..a992d54dc8f 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -10788,6 +10788,11 @@ grokfndecl (tree ctype,
  "cannot declare %<::main%> to be %qs", "consteval");
   if (!publicp)
error_at (location, "cannot declare %<::main%> to be static");
+  if (current_lang_depth () != 0)
+   pedwarn (location, OPT_Wpedantic, "cannot declare %<::main%> with a"
+" linkage specification");
+  if (module_attach_p ())
+   error_at (location, "cannot attach %<::main%> to a named module");
   inlinep = 0;
   publicp = 1;
 }
@@ -11287,10 +11292,16 @@ grokvardecl (tree type,
 DECL_INTERFACE_KNOWN (decl) = 1;
 
   if (DECL_NAME (decl)
-  && MAIN_NAME_P (DECL_NAME (decl))
-  && scope == global_namespace)
-error_at (DECL_SOURCE_LOCATION (decl),
- "cannot declare %<::main%> to be a global variable");
+  && MAIN_NAME_P (DECL_NAME (decl)))
+{
+  if (scope == global_namespace)
+   error_at (DECL_SOURCE_LOCATION (decl),
+ "cannot declare %<::main%> to be a global variable");
+  else if (DECL_EXTERN_C_P (decl))
+   error_at (DECL_SOURCE_LOCATION (decl),
+ "an entity named % cannot be declared with "
+ "C language linkage");
+}
 
   /* Check that the variable can be safely declared as a concept.
  Note that this also forbids explicit specializations.  */
diff --git a/gcc/testsuite/g++.dg/abi/main.C b/gcc/testsuite/g++.dg/abi/main.C
index 4c5f1ea213c..2797a16df5b 100644
--- a/gcc/testsuite/g++.dg/abi/main.C
+++ b/gcc/testsuite/g++.dg/abi/main.C
@@ -1,10 +1,11 @@
 /* { dg-do compile } */
+/* { dg-additional-options "-Wno-error=pedantic" }
 
 /* Check if entry points get implicit C linkage. If they don't, compiler will
  * error on incompatible declarations */
 
 int main();
-extern "C" int main();
+extern "C" int main();  // { dg-warning "linkage specification" }
 
 #ifdef __MINGW32__
 
diff --git a/gcc/testsuite/g++.dg/modules/contracts-1_b.C 
b/gcc/testsuite/g++.dg/modules/contracts-1_b.C
index 30c15f6928b..aa36c8d6b1b 100644
--- a/gcc/testsuite/g++.dg/modules/contracts-1_b.C
+++ b/gcc/testsuite/g++.dg/modules/contracts-1_b.C
@@ -1,15 +1,11 @@
 // { dg-module-do run }
 // { dg-additional-options "-fmodules-ts -fcontracts 
-fcontract-continuation-mode=on" }
-module;
 #include 
-export module bar;
-// { dg-module-cmi bar }
 import foo;
 
 template
 bool bar_fn_pre(T n) { printf("bar fn pre(%d)\n", n); return true; }
 
-export
 template
 T bar_fn(T n)
   [[ pre: bar_fn_pre(n) && n > 0 ]]
diff --git a/gcc/testsuite/g++.dg/modules/contracts-3_b.C 
b/gcc/testsuite/g++.dg/modules/contracts-3_b.C
index b1d6375391b..1a29e2c3e5d 100644
--- a/gcc/testsuite/g++.dg/modules/contracts-3_b.C
+++ b/gcc/testsuite/g++.dg/modules/contracts-3_b.C
@@ -1,15 +1,11 @@
 // { dg-module-do run }
 // { dg-additional-options "-fmodules-ts -fcontracts 
-fcontract-role=default:ignore,ignore,ignore" }
-module;
 #include 
-export module bar;
-// { dg-module-cmi bar }
 im

[gcc r14-10182] c++/modules: Stream unmergeable temporaries by value again [PR114856]

2024-05-07 Thread Nathaniel Shead via Gcc-cvs
https://gcc.gnu.org/g:61a095b05c244a6e0b1aec36ee1607def00654ab

commit r14-10182-g61a095b05c244a6e0b1aec36ee1607def00654ab
Author: Nathaniel Shead 
Date:   Tue Apr 30 22:29:57 2024 +1000

c++/modules: Stream unmergeable temporaries by value again [PR114856]

In r14-9266-g2823b4d96d9ec4 I gave all temporary vars a DECL_CONTEXT,
including those at namespace or global scope, so that they could be
properly merged across importers.  However, not all of these temporary
vars are actually supposed to be mergeable.

For instance, in the attached testcase we have an unnamed temporary var
used in the NSDMI of a class member, which cannot properly merged -- but
it also doesn't need to be, as it'll be thrown away when the class type
itself is merged anyway.

This patch reverts the change made above and instead makes a weaker
adjustment that only causes temporary vars with linkage have a
DECL_CONTEXT to merge from.  This way these unnamed, "unmergeable"
temporaries are properly streamed by value again.

PR c++/114856

gcc/cp/ChangeLog:

* call.cc (make_temporary_var_for_ref_to_temp): Set context for
temporaries with linkage.
* init.cc (create_temporary_var): Revert to only set context
when in a function decl.

gcc/testsuite/ChangeLog:

* g++.dg/modules/pr114856.h: New test.
* g++.dg/modules/pr114856_a.H: New test.
* g++.dg/modules/pr114856_b.C: New test.

Signed-off-by: Nathaniel Shead 
Reviewed-by: Jason Merrill 
Reviewed-by: Patrick Palka 
(cherry picked from commit e60032b382364897a58e67994baac896bcd03327)

Diff:
---
 gcc/cp/call.cc|  3 +++
 gcc/cp/init.cc|  2 +-
 gcc/testsuite/g++.dg/modules/pr114856.h   | 12 
 gcc/testsuite/g++.dg/modules/pr114856_a.H |  5 +
 gcc/testsuite/g++.dg/modules/pr114856_b.C |  5 +
 5 files changed, 26 insertions(+), 1 deletion(-)

diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index dbdd7c29fe88..38b9c4f08601 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -13800,6 +13800,9 @@ make_temporary_var_for_ref_to_temp (tree decl, tree 
type)
   tree name = mangle_ref_init_variable (decl);
   DECL_NAME (var) = name;
   SET_DECL_ASSEMBLER_NAME (var, name);
+
+  /* Set the context to make the variable mergeable in modules.  */
+  DECL_CONTEXT (var) = current_scope ();
 }
   else
 /* Create a new cleanup level if necessary.  */
diff --git a/gcc/cp/init.cc b/gcc/cp/init.cc
index a93ce00800c4..e758a8c8568b 100644
--- a/gcc/cp/init.cc
+++ b/gcc/cp/init.cc
@@ -4287,7 +4287,7 @@ create_temporary_var (tree type)
   TREE_USED (decl) = 1;
   DECL_ARTIFICIAL (decl) = 1;
   DECL_IGNORED_P (decl) = 1;
-  DECL_CONTEXT (decl) = current_scope ();
+  DECL_CONTEXT (decl) = current_function_decl;
 
   return decl;
 }
diff --git a/gcc/testsuite/g++.dg/modules/pr114856.h 
b/gcc/testsuite/g++.dg/modules/pr114856.h
new file mode 100644
index ..b1a3c2cd8341
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/pr114856.h
@@ -0,0 +1,12 @@
+// PR c++/114856
+
+#include 
+struct A {
+  ~A();
+};
+struct V {
+  V(std::initializer_list);
+};
+struct data {
+  V v{{}};
+};
diff --git a/gcc/testsuite/g++.dg/modules/pr114856_a.H 
b/gcc/testsuite/g++.dg/modules/pr114856_a.H
new file mode 100644
index ..6195277dbde1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/pr114856_a.H
@@ -0,0 +1,5 @@
+// PR c++/114856
+// { dg-additional-options "-fmodule-header" }
+// { dg-module-cmi {} }
+
+#include "pr114856.h"
diff --git a/gcc/testsuite/g++.dg/modules/pr114856_b.C 
b/gcc/testsuite/g++.dg/modules/pr114856_b.C
new file mode 100644
index ..f81dc8b81d5d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/pr114856_b.C
@@ -0,0 +1,5 @@
+// PR c++/114856
+// { dg-additional-options "-fmodules-ts" }
+
+#include "pr114856.h"
+import "pr114856_a.H";


[gcc r15-310] c++/modules: Stream unmergeable temporaries by value again [PR114856]

2024-05-07 Thread Nathaniel Shead via Gcc-cvs
https://gcc.gnu.org/g:e60032b382364897a58e67994baac896bcd03327

commit r15-310-ge60032b382364897a58e67994baac896bcd03327
Author: Nathaniel Shead 
Date:   Tue Apr 30 22:29:57 2024 +1000

c++/modules: Stream unmergeable temporaries by value again [PR114856]

In r14-9266-g2823b4d96d9ec4 I gave all temporary vars a DECL_CONTEXT,
including those at namespace or global scope, so that they could be
properly merged across importers.  However, not all of these temporary
vars are actually supposed to be mergeable.

For instance, in the attached testcase we have an unnamed temporary var
used in the NSDMI of a class member, which cannot properly merged -- but
it also doesn't need to be, as it'll be thrown away when the class type
itself is merged anyway.

This patch reverts the change made above and instead makes a weaker
adjustment that only causes temporary vars with linkage have a
DECL_CONTEXT to merge from.  This way these unnamed, "unmergeable"
temporaries are properly streamed by value again.

PR c++/114856

gcc/cp/ChangeLog:

* call.cc (make_temporary_var_for_ref_to_temp): Set context for
temporaries with linkage.
* init.cc (create_temporary_var): Revert to only set context
when in a function decl.

gcc/testsuite/ChangeLog:

* g++.dg/modules/pr114856.h: New test.
* g++.dg/modules/pr114856_a.H: New test.
* g++.dg/modules/pr114856_b.C: New test.

Signed-off-by: Nathaniel Shead 
Reviewed-by: Jason Merrill 
Reviewed-by: Patrick Palka 

Diff:
---
 gcc/cp/call.cc|  3 +++
 gcc/cp/init.cc|  2 +-
 gcc/testsuite/g++.dg/modules/pr114856.h   | 12 
 gcc/testsuite/g++.dg/modules/pr114856_a.H |  5 +
 gcc/testsuite/g++.dg/modules/pr114856_b.C |  5 +
 5 files changed, 26 insertions(+), 1 deletion(-)

diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index 7c4ecf08c4bd..e058da7735fa 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -13802,6 +13802,9 @@ make_temporary_var_for_ref_to_temp (tree decl, tree 
type)
   tree name = mangle_ref_init_variable (decl);
   DECL_NAME (var) = name;
   SET_DECL_ASSEMBLER_NAME (var, name);
+
+  /* Set the context to make the variable mergeable in modules.  */
+  DECL_CONTEXT (var) = current_scope ();
 }
   else
 /* Create a new cleanup level if necessary.  */
diff --git a/gcc/cp/init.cc b/gcc/cp/init.cc
index c1b5b7425c9b..7bb98f445c37 100644
--- a/gcc/cp/init.cc
+++ b/gcc/cp/init.cc
@@ -4287,7 +4287,7 @@ create_temporary_var (tree type)
   TREE_USED (decl) = 1;
   DECL_ARTIFICIAL (decl) = 1;
   DECL_IGNORED_P (decl) = 1;
-  DECL_CONTEXT (decl) = current_scope ();
+  DECL_CONTEXT (decl) = current_function_decl;
 
   return decl;
 }
diff --git a/gcc/testsuite/g++.dg/modules/pr114856.h 
b/gcc/testsuite/g++.dg/modules/pr114856.h
new file mode 100644
index ..b1a3c2cd8341
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/pr114856.h
@@ -0,0 +1,12 @@
+// PR c++/114856
+
+#include 
+struct A {
+  ~A();
+};
+struct V {
+  V(std::initializer_list);
+};
+struct data {
+  V v{{}};
+};
diff --git a/gcc/testsuite/g++.dg/modules/pr114856_a.H 
b/gcc/testsuite/g++.dg/modules/pr114856_a.H
new file mode 100644
index ..6195277dbde1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/pr114856_a.H
@@ -0,0 +1,5 @@
+// PR c++/114856
+// { dg-additional-options "-fmodule-header" }
+// { dg-module-cmi {} }
+
+#include "pr114856.h"
diff --git a/gcc/testsuite/g++.dg/modules/pr114856_b.C 
b/gcc/testsuite/g++.dg/modules/pr114856_b.C
new file mode 100644
index ..f81dc8b81d5d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/pr114856_b.C
@@ -0,0 +1,5 @@
+// PR c++/114856
+// { dg-additional-options "-fmodules-ts" }
+
+#include "pr114856.h"
+import "pr114856_a.H";


[gcc r15-221] c++: Allow IS_FAKE_BASE_TYPE for union types [PR114954]

2024-05-06 Thread Nathaniel Shead via Gcc-cvs
https://gcc.gnu.org/g:0c43c673b0d431ca02d83bf6fae9cd60e9a3d0a8

commit r15-221-g0c43c673b0d431ca02d83bf6fae9cd60e9a3d0a8
Author: Nathaniel Shead 
Date:   Mon May 6 13:05:52 2024 +1000

c++: Allow IS_FAKE_BASE_TYPE for union types [PR114954]

In some circumstances, unions can also have an __as_base type; we need
to make sure that IS_FAKE_BASE_TYPE correctly recognises this.

PR c++/114954

gcc/cp/ChangeLog:

* cp-tree.h (IS_FAKE_BASE_TYPE): Also apply to unions.

gcc/testsuite/ChangeLog:

* g++.dg/modules/pr114954.C: New test.

Signed-off-by: Nathaniel Shead 
Reviewed-by: Jason Merrill 

Diff:
---
 gcc/cp/cp-tree.h|  2 +-
 gcc/testsuite/g++.dg/modules/pr114954.C | 14 ++
 2 files changed, 15 insertions(+), 1 deletion(-)

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 4fadc9aaf48..db098c32f2d 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -2616,7 +2616,7 @@ struct GTY(()) lang_type {
 
 /* True iff NODE is the CLASSTYPE_AS_BASE version of some type.  */
 #define IS_FAKE_BASE_TYPE(NODE)\
-  (TREE_CODE (NODE) == RECORD_TYPE \
+  (RECORD_OR_UNION_TYPE_P (NODE)   \
&& TYPE_CONTEXT (NODE) && CLASS_TYPE_P (TYPE_CONTEXT (NODE))\
&& CLASSTYPE_AS_BASE (TYPE_CONTEXT (NODE)) == (NODE))
 
diff --git a/gcc/testsuite/g++.dg/modules/pr114954.C 
b/gcc/testsuite/g++.dg/modules/pr114954.C
new file mode 100644
index 000..a9787140808
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/pr114954.C
@@ -0,0 +1,14 @@
+// PR c++/114954
+// { dg-additional-options "-fmodules-ts" }
+// { dg-module-cmi main }
+
+export module main;
+
+template 
+union U {
+private:
+  char a[N + 1];
+  int b;
+};
+
+U<4> p;


[gcc r15-220] c++/modules: Fix dangling pointer with imported_temploid_friends

2024-05-06 Thread Nathaniel Shead via Gcc-cvs
https://gcc.gnu.org/g:ec2365e07537e8b17745d75c28a2b45bf33be119

commit r15-220-gec2365e07537e8b17745d75c28a2b45bf33be119
Author: Nathaniel Shead 
Date:   Fri May 3 19:36:17 2024 +1000

c++/modules: Fix dangling pointer with imported_temploid_friends

I got notified by Linaro CI and by checking testresults that there seems
to be some occasional failures in tpl-friend-4_b.C on some architectures
and standards modes since r15-59-gb5f6a56940e708.  I haven't been able
to reproduce but looking at the backtrace I suspect the issue is that
we're adding to the 'imported_temploid_friend' map a decl that is
ultimately discarded, which then has its address reused by a later decl
causing a failure in the assert in 'set_originating_module'.

This patch fixes the problem by ensuring 'imported_temploid_friends' is
correctly marked as a GTY root, and that 'duplicate_decls' properly
removes entries from the map for declarations that it frees.

PR c++/114275

gcc/cp/ChangeLog:

* cp-tree.h (remove_defining_module): Declare.
* decl.cc (duplicate_decls): Call remove_defining_module on
to-be-freed newdecl.
* module.cc (imported_temploid_friends): Mark as GTY root...
(init_modules): ...and allocate from ggc.
(trees_in::decl_value): Only track for declarations that won't
be discarded.
(remove_defining_module): New function.

Signed-off-by: Nathaniel Shead 
Reviewed-by: Jason Merrill 
Reviewed-by: Patrick Palka 

Diff:
---
 gcc/cp/cp-tree.h |  1 +
 gcc/cp/decl.cc   |  4 
 gcc/cp/module.cc | 19 ---
 3 files changed, 21 insertions(+), 3 deletions(-)

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 52d6841559c..4fadc9aaf48 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -7420,6 +7420,7 @@ extern void set_instantiating_module (tree);
 extern void set_defining_module (tree);
 extern void maybe_key_decl (tree ctx, tree decl);
 extern void propagate_defining_module (tree decl, tree orig);
+extern void remove_defining_module (tree decl);
 
 extern void mangle_module (int m, bool include_partition);
 extern void mangle_module_fini ();
diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index 04a151c341c..b112b70659f 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -3340,6 +3340,10 @@ duplicate_decls (tree newdecl, tree olddecl, bool 
hiding, bool was_hidden)
   if (flag_concepts)
 remove_constraints (newdecl);
 
+  /* And similarly for any module tracking data.  */
+  if (modules_p ())
+remove_defining_module (newdecl);
+
   ggc_free (newdecl);
 
   return olddecl;
diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index 44dc81eed3e..520dd710549 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -2731,7 +2731,7 @@ static keyed_map_t *keyed_table;
need to be attached to the same module as the temploid.  This maps
these decls to the temploid they are instantiated them, as there is
no other easy way to get this information.  */
-static hash_map *imported_temploid_friends;
+static GTY((cache)) decl_tree_cache_map *imported_temploid_friends;
 
 //
 /* Tree streaming.   The tree streaming is very specific to the tree
@@ -8327,7 +8327,8 @@ trees_in::decl_value ()
   if (TREE_CODE (inner) == FUNCTION_DECL
   || TREE_CODE (inner) == TYPE_DECL)
 if (tree owner = tree_node ())
-  imported_temploid_friends->put (decl, owner);
+  if (is_new)
+   imported_temploid_friends->put (decl, owner);
 
   /* Regular typedefs will have a NULL TREE_TYPE at this point.  */
   unsigned tdef_flags = 0;
@@ -19336,6 +19337,18 @@ propagate_defining_module (tree decl, tree orig)
 }
 }
 
+/* DECL is being freed, clear data we don't need anymore.  */
+
+void
+remove_defining_module (tree decl)
+{
+  if (!modules_p ())
+return;
+
+  if (imported_temploid_friends)
+imported_temploid_friends->remove (decl);
+}
+
 /* Create the flat name string.  It is simplest to have it handy.  */
 
 void
@@ -20550,7 +20563,7 @@ init_modules (cpp_reader *reader)
   entity_map = new entity_map_t (EXPERIMENT (1, 400));
   vec_safe_reserve (entity_ary, EXPERIMENT (1, 400));
   imported_temploid_friends
-   = new hash_map (EXPERIMENT (1, 400));
+   = decl_tree_cache_map::create_ggc (EXPERIMENT (1, 400));
 }
 
 #if CHECKING_P


[gcc r15-114] c++: Clear is_unbraced_* when parsing declaration_seq_opt [PR114917]

2024-05-02 Thread Nathaniel Shead via Gcc-cvs
https://gcc.gnu.org/g:7317d62a1200dbd3685015e5d6b811497a27fe5f

commit r15-114-g7317d62a1200dbd3685015e5d6b811497a27fe5f
Author: Nathaniel Shead 
Date:   Thu May 2 12:55:24 2024 +1000

c++: Clear is_unbraced_* when parsing declaration_seq_opt [PR114917]

Currently we incorrectly retain "in_unbraced_linkage_specification_p"
and "in_unbraced_export_declaration_p" when parsing a (braced)
declaration-seq.  This patch ensures that we clear these flags before
parsing the toplevel declarations.

Strictly speaking we don't need to save and restore the flags around the
parsing because there's currently no way to provide new declarations
within the unbraced context after the closing brace, but this patch does
it anyway in case this ever changes and for consistency with other
places that these flags are adjusted.

PR c++/114917

gcc/cp/ChangeLog:

* parser.cc (cp_parser_declaration_seq_opt): Clear
parser->in_unbraced_* flags when parsing toplevel declarations.

gcc/testsuite/ChangeLog:

* g++.dg/modules/export-5_a.C: New test.
* g++.dg/modules/export-5_b.C: New test.
* g++.dg/parse/linkage4.C: New test.

Signed-off-by: Nathaniel Shead 

Diff:
---
 gcc/cp/parser.cc  | 15 +++
 gcc/testsuite/g++.dg/modules/export-5_a.C | 17 +
 gcc/testsuite/g++.dg/modules/export-5_b.C | 13 +
 gcc/testsuite/g++.dg/parse/linkage4.C | 11 +++
 4 files changed, 56 insertions(+)

diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 7c3cfcfcf4b..66ce161252c 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -15341,6 +15341,16 @@ cp_parser_module_export (cp_parser *parser)
 static void
 cp_parser_declaration_seq_opt (cp_parser* parser)
 {
+  bool saved_in_unbraced_linkage_specification_p
+= parser->in_unbraced_linkage_specification_p;
+  bool saved_in_unbraced_export_declaration_p
+= parser->in_unbraced_export_declaration_p;
+
+  /* We're not in an unbraced linkage-specification
+ or export-declaration anymore.  */
+  parser->in_unbraced_linkage_specification_p = false;
+  parser->in_unbraced_export_declaration_p = false;
+
   while (true)
 {
   cp_token *token = cp_lexer_peek_token (parser->lexer);
@@ -15351,6 +15361,11 @@ cp_parser_declaration_seq_opt (cp_parser* parser)
   else
cp_parser_toplevel_declaration (parser);
 }
+
+  parser->in_unbraced_linkage_specification_p
+= saved_in_unbraced_linkage_specification_p;
+  parser->in_unbraced_export_declaration_p
+= saved_in_unbraced_export_declaration_p;
 }
 
 /* Parse a declaration.  The distinction between name-declaration
diff --git a/gcc/testsuite/g++.dg/modules/export-5_a.C 
b/gcc/testsuite/g++.dg/modules/export-5_a.C
new file mode 100644
index 000..a325591ca8e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/export-5_a.C
@@ -0,0 +1,17 @@
+// PR c++/114917
+// { dg-additional-options "-fmodules-ts" }
+// { dg-module-cmi M }
+
+export module M;
+
+export namespace ns {
+  template  struct S {};
+  template  struct S { using a = int; };
+  template <> struct S { using b = int; };
+  template struct S;
+};
+
+export extern "C++" namespace ns {
+  template  void foo() {}
+  template <> void foo() {}
+}
diff --git a/gcc/testsuite/g++.dg/modules/export-5_b.C 
b/gcc/testsuite/g++.dg/modules/export-5_b.C
new file mode 100644
index 000..cb10e37c7fc
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/export-5_b.C
@@ -0,0 +1,13 @@
+// PR c++/114917
+// { dg-additional-options "-fmodules-ts" }
+
+import M;
+
+int main() {
+  ns::S::a x{};
+  ns::S::b y{};
+  ns::S z{};
+
+  ns::foo();
+  ns::foo();
+}
diff --git a/gcc/testsuite/g++.dg/parse/linkage4.C 
b/gcc/testsuite/g++.dg/parse/linkage4.C
new file mode 100644
index 000..10fcc77e9d5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/parse/linkage4.C
@@ -0,0 +1,11 @@
+// PR c++/114917
+// { dg-do compile }
+
+extern "C++" namespace ns {
+  struct Incomplete;
+  Incomplete foo;  // { dg-error "incomplete type" }
+}
+
+extern "C" extern "C" {
+  static int bar;  // { dg-bogus "invalid" }
+}


[gcc r15-101] c++: Don't emit unused GMF partial specializations [PR114630]

2024-05-01 Thread Nathaniel Shead via Gcc-cvs
https://gcc.gnu.org/g:02917ac4528e32d1b2d0da5f45ef5937c56942cd

commit r15-101-g02917ac4528e32d1b2d0da5f45ef5937c56942cd
Author: Nathaniel Shead 
Date:   Thu Apr 11 19:15:35 2024 +1000

c++: Don't emit unused GMF partial specializations [PR114630]

The change in r14-8408 to also emit partial specializations in the
global module fragment caused the regression in the linked PR; this
patch fixes this by restricting emitted GM partial specializations to
those that are actually used.

PR c++/114630

gcc/cp/ChangeLog:

* module.cc (depset::hash::add_partial_entities): Mark GM
specializations as unreached.
(depset::hash::find_dependencies): Also reach entities in the
DECL_TEMPLATE_SPECIALIZATIONS list.

gcc/testsuite/ChangeLog:

* g++.dg/modules/partial-3.C: New test.

Signed-off-by: Nathaniel Shead 

Diff:
---
 gcc/cp/module.cc | 75 
 gcc/testsuite/g++.dg/modules/partial-3.C | 20 +
 2 files changed, 66 insertions(+), 29 deletions(-)

diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index f7725091f60..44dc81eed3e 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -13308,14 +13308,22 @@ depset::hash::add_partial_entities (vec 
*partial_classes)
   depset *dep = make_dependency (inner, depset::EK_DECL);
 
   if (dep->get_entity_kind () == depset::EK_REDIRECT)
-   /* We should have recorded the template as a partial
-  specialization.  */
-   gcc_checking_assert (dep->deps[0]->get_entity_kind ()
-== depset::EK_PARTIAL);
+   {
+ dep = dep->deps[0];
+ /* We should have recorded the template as a partial
+specialization.  */
+ gcc_checking_assert (dep->get_entity_kind ()
+  == depset::EK_PARTIAL);
+   }
   else
/* It was an explicit specialization, not a partial one.  */
gcc_checking_assert (dep->get_entity_kind ()
 == depset::EK_SPECIALIZATION);
+
+  /* Only emit GM entities if reached.  */
+  if (!DECL_LANG_SPECIFIC (inner)
+ || !DECL_MODULE_PURVIEW_P (inner))
+   dep->set_flag_bit ();
 }
 }
 
@@ -13636,31 +13644,40 @@ depset::hash::find_dependencies (module_state *module)
  if (!walker.is_key_order ()
  && TREE_CODE (decl) == TEMPLATE_DECL
  && !DECL_UNINSTANTIATED_TEMPLATE_FRIEND_P (decl))
-   /* Mark all the explicit & partial specializations as
-  reachable.  */
-   for (tree cons = DECL_TEMPLATE_INSTANTIATIONS (decl);
-cons; cons = TREE_CHAIN (cons))
- {
-   tree spec = TREE_VALUE (cons);
-   if (TYPE_P (spec))
- spec = TYPE_NAME (spec);
-   int use_tpl;
-   node_template_info (spec, use_tpl);
-   if (use_tpl & 2)
- {
-   depset *spec_dep = find_dependency (spec);
-   if (spec_dep->get_entity_kind () == EK_REDIRECT)
- spec_dep = spec_dep->deps[0];
-   if (spec_dep->is_unreached ())
- {
-   reached_unreached = true;
-   spec_dep->clear_flag_bit ();
-   dump (dumper::DEPEND)
- && dump ("Reaching unreached specialization"
-  " %C:%N", TREE_CODE (spec), spec);
- }
- }
- }
+   {
+ /* Mark all the explicit & partial specializations as
+reachable.  We search both specialization lists as some
+constrained partial specializations for class types are
+only found in DECL_TEMPLATE_SPECIALIZATIONS.  */
+ auto mark_reached = [this](tree spec)
+   {
+ if (TYPE_P (spec))
+   spec = TYPE_NAME (spec);
+ int use_tpl;
+ node_template_info (spec, use_tpl);
+ if (use_tpl & 2)
+   {
+ depset *spec_dep = find_dependency (spec);
+ if (spec_dep->get_entity_kind () == EK_REDIRECT)
+   spec_dep = spec_dep->deps[0];
+ if (spec_dep->is_unreached ())
+   {
+ reached_unreached = true;
+ spec_dep->clear_flag_bit ();
+ dump (dumper::DEPEND)
+   && dump ("Reaching unreached specialization"
+" %C:%N", TREE_CODE (spec), spe

[gcc r15-98] c++: Implement modules ABI for vtable emissions

2024-05-01 Thread Nathaniel Shead via Gcc-cvs
https://gcc.gnu.org/g:ad30265ccfb211fca35789df2d1404cc12302219

commit r15-98-gad30265ccfb211fca35789df2d1404cc12302219
Author: Nathaniel Shead 
Date:   Tue Apr 16 22:50:26 2024 +1000

c++: Implement modules ABI for vtable emissions

This patch implements the changes described in
https://github.com/itanium-cxx-abi/cxx-abi/pull/171.

One restriction that is lifted in the ABI that hasn't been updated here
is that the ABI no longer requires unique vtables to be emitted with
vague linkage.  I haven't changed this behaviour for this patch, but in
the future we could look into changing the relevant target hook
('class_data_always_comdat') to default to 'false'.  But the current
behaviour is more forgiving to changes in key function identification.

Since the ABI for vtables attached to named modules no longer depends on
key methods, this also resolves the issue described in PR c++/105224.

PR c++/105224

gcc/cp/ChangeLog:

* class.cc (finish_struct_1): Also push classes attached to a
module into the 'keyed_classes' list.
* decl.cc (record_key_method_defined): Don't push classes
attached to a named module into the 'keyed_classes' list.
* module.cc (trees_in::read_class_def): Likewise.
* decl2.cc (import_export_class): Uniquely emit vtables for
non-template classes attached to a named module.
(vtables_uniquely_emitted): New function.
(import_export_decl): Update comments. Update with knowledge
about new kinds of uniquely emitted vtables.

gcc/testsuite/ChangeLog:

* g++.dg/modules/virt-2_a.C: Update linkage requirements.
* g++.dg/modules/virt-2_b.C: Likewise.
* g++.dg/modules/virt-2_c.C: Likewise.
* g++.dg/modules/virt-4_a.C: New test.
* g++.dg/modules/virt-4_b.C: New test.

Signed-off-by: Nathaniel Shead 
Reviewed-by: Jason Merrill 

Diff:
---
 gcc/cp/class.cc |   7 ++-
 gcc/cp/decl.cc  |   8 ++-
 gcc/cp/decl2.cc | 102 +---
 gcc/cp/module.cc|  12 ++--
 gcc/testsuite/g++.dg/modules/virt-2_a.C |   3 -
 gcc/testsuite/g++.dg/modules/virt-2_b.C |   9 +--
 gcc/testsuite/g++.dg/modules/virt-2_c.C |  10 ++--
 gcc/testsuite/g++.dg/modules/virt-4_a.C |  31 ++
 gcc/testsuite/g++.dg/modules/virt-4_b.C |  23 +++
 9 files changed, 151 insertions(+), 54 deletions(-)

diff --git a/gcc/cp/class.cc b/gcc/cp/class.cc
index 5f258729940..5ef7c71af61 100644
--- a/gcc/cp/class.cc
+++ b/gcc/cp/class.cc
@@ -7820,8 +7820,11 @@ finish_struct_1 (tree t)
   /* If a polymorphic class has no key method, we may emit the vtable
 in every translation unit where the class definition appears.  If
 we're devirtualizing, we can look into the vtable even if we
-aren't emitting it.  */
-  if (!CLASSTYPE_KEY_METHOD (t))
+aren't emitting it.
+
+Additionally, if the class is attached to a named module, make sure
+to always emit the vtable in this TU.  */
+  if (!CLASSTYPE_KEY_METHOD (t) || module_attach_p ())
vec_safe_push (keyed_classes, t);
 }
 
diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index df855334133..de0c02a39ee 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -18481,7 +18481,13 @@ record_key_method_defined (tree fndecl)
 {
   tree fnclass = DECL_CONTEXT (fndecl);
   if (fndecl == CLASSTYPE_KEY_METHOD (fnclass))
-   vec_safe_push (keyed_classes, fnclass);
+   {
+ tree classdecl = TYPE_NAME (fnclass);
+ /* Classes attached to a named module are already handled.  */
+ if (!DECL_LANG_SPECIFIC (classdecl)
+ || !DECL_MODULE_ATTACH_P (classdecl))
+   vec_safe_push (keyed_classes, fnclass);
+   }
 }
 }
 
diff --git a/gcc/cp/decl2.cc b/gcc/cp/decl2.cc
index b8dc55b51d9..1f84878b2b9 100644
--- a/gcc/cp/decl2.cc
+++ b/gcc/cp/decl2.cc
@@ -2422,17 +2422,26 @@ import_export_class (tree ctype)
   import_export = -1;
   else if (TYPE_POLYMORPHIC_P (ctype))
 {
-  /* The ABI specifies that the virtual table and associated
-information are emitted with the key method, if any.  */
-  tree method = CLASSTYPE_KEY_METHOD (ctype);
-  /* If weak symbol support is not available, then we must be
-careful not to emit the vtable when the key function is
-inline.  An inline function can be defined in multiple
-translation units.  If we were to emit the vtable in each
-translation unit containing a definition, we would get
-multiple definition errors at link-time.  */
-  if (method && (flag_weak || ! DECL_DECLARED_INLINE_P (method)))
-   import_export = (DECL_REALLY_EXTERN (method) ? -1 : 1);
+  tree cdecl = TYPE_NAME (ctype);
+  if

[gcc r15-85] c++: Propagate using decls from partitions [PR114868]

2024-05-01 Thread Nathaniel Shead via Gcc-cvs
https://gcc.gnu.org/g:0d0215b10dbbe39d655ceda4af283f288ec7680c

commit r15-85-g0d0215b10dbbe39d655ceda4af283f288ec7680c
Author: Nathaniel Shead 
Date:   Tue Apr 9 21:49:58 2024 +1000

c++: Propagate using decls from partitions [PR114868]

The modules code currently neglects to set OVL_USING_P on the dependency
created for a using-decl, which causes it not to remember that the
OVL_EXPORT_P flag had been set on it when emitted from the primary
interface unit. This patch ensures that it occurs.

PR c++/114868

gcc/cp/ChangeLog:

* module.cc (depset::hash::add_binding_entity): Propagate
OVL_USING_P for using-declarations.

gcc/testsuite/ChangeLog:

* g++.dg/modules/using-15_a.C: New test.
* g++.dg/modules/using-15_b.C: New test.
* g++.dg/modules/using-15_c.C: New test.

Signed-off-by: Nathaniel Shead 

Diff:
---
 gcc/cp/module.cc  |  6 ++
 gcc/testsuite/g++.dg/modules/using-15_a.C | 14 ++
 gcc/testsuite/g++.dg/modules/using-15_b.C |  6 ++
 gcc/testsuite/g++.dg/modules/using-15_c.C |  8 
 4 files changed, 34 insertions(+)

diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index 5b8ff5bc483..fac0301d80e 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -13150,10 +13150,14 @@ 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);
  flags = WMB_Flags (flags | WMB_Using);
  if (DECL_MODULE_EXPORT_P (TREE_CODE (decl) == CONST_DECL
? TYPE_NAME (TREE_TYPE (decl))
@@ -13214,6 +13218,8 @@ 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;
  if (flags & WMB_Export)
OVL_EXPORT_P (decl) = true;
}
diff --git a/gcc/testsuite/g++.dg/modules/using-15_a.C 
b/gcc/testsuite/g++.dg/modules/using-15_a.C
new file mode 100644
index 000..3f4bb6c5914
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/using-15_a.C
@@ -0,0 +1,14 @@
+// PR c++/114868
+// { dg-additional-options "-fmodules-ts -Wno-global-module" }
+// { dg-module-cmi M:a }
+
+module;
+namespace foo {
+  void a();
+}
+export module M:a;
+
+namespace bar {
+  // propagate usings from partitions
+  export using foo::a;
+}
diff --git a/gcc/testsuite/g++.dg/modules/using-15_b.C 
b/gcc/testsuite/g++.dg/modules/using-15_b.C
new file mode 100644
index 000..4b0cb745157
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/using-15_b.C
@@ -0,0 +1,6 @@
+// PR c++/114868
+// { dg-additional-options "-fmodules-ts" }
+// { dg-module-cmi M }
+
+export module M;
+export import :a;
diff --git a/gcc/testsuite/g++.dg/modules/using-15_c.C 
b/gcc/testsuite/g++.dg/modules/using-15_c.C
new file mode 100644
index 000..74dd10a5413
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/using-15_c.C
@@ -0,0 +1,8 @@
+// PR c++/114868
+// { dg-additional-options "-fmodules-ts" }
+import M;
+
+int main() {
+  bar::a();
+  foo::a();  // { dg-error "not been declared" }
+}


[gcc r15-86] c++: Propagate hidden flag on decls from partitions

2024-05-01 Thread Nathaniel Shead via Gcc-cvs
https://gcc.gnu.org/g:3032ebf0c9b769f02f494e97417a1b68ad59c884

commit r15-86-g3032ebf0c9b769f02f494e97417a1b68ad59c884
Author: Nathaniel Shead 
Date:   Tue Apr 9 21:52:38 2024 +1000

c++: Propagate hidden flag on decls from partitions

While working on some other fixes I noticed that the partition handling
code used the wrong flag to propagate OVL_HIDDEN_P on exported bindings
from partitions. This patch fixes that, and renames the flag to be
clearer.

gcc/cp/ChangeLog:

* name-lookup.cc (walk_module_binding): Use the
partition-specific hidden flag instead of the top-level
decl_hidden.

gcc/testsuite/ChangeLog:

* g++.dg/modules/using-16_a.C: New test.
* g++.dg/modules/using-16_b.C: New test.
* g++.dg/modules/using-16_c.C: New test.

Signed-off-by: Nathaniel Shead 

Diff:
---
 gcc/cp/name-lookup.cc | 10 +-
 gcc/testsuite/g++.dg/modules/using-16_a.C | 11 +++
 gcc/testsuite/g++.dg/modules/using-16_b.C | 12 
 gcc/testsuite/g++.dg/modules/using-16_c.C | 11 +++
 4 files changed, 39 insertions(+), 5 deletions(-)

diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc
index 5d2319db43d..78f08acffaa 100644
--- a/gcc/cp/name-lookup.cc
+++ b/gcc/cp/name-lookup.cc
@@ -4290,19 +4290,19 @@ walk_module_binding (tree binding, bitmap partitions,
 
count += callback (btype, flags, data);
  }
-   bool hidden = STAT_DECL_HIDDEN_P (bind);
+   bool part_hidden = STAT_DECL_HIDDEN_P (bind);
for (ovl_iterator iter (MAYBE_STAT_DECL (STAT_DECL (bind)));
 iter; ++iter)
  {
if (iter.hidden_p ())
- hidden = true;
+ part_hidden = true;
gcc_checking_assert
- (!(hidden && DECL_IS_UNDECLARED_BUILTIN (*iter)));
+ (!(part_hidden && DECL_IS_UNDECLARED_BUILTIN 
(*iter)));
 
WMB_Flags flags = WMB_None;
if (maybe_dups)
  flags = WMB_Flags (flags | WMB_Dups);
-   if (decl_hidden)
+   if (part_hidden)
  flags = WMB_Flags (flags | WMB_Hidden);
if (iter.using_p ())
  {
@@ -4311,7 +4311,7 @@ walk_module_binding (tree binding, bitmap partitions,
  flags = WMB_Flags (flags | WMB_Export);
  }
count += callback (*iter, flags, data);
-   hidden = false;
+   part_hidden = false;
  }
  }
  }
diff --git a/gcc/testsuite/g++.dg/modules/using-16_a.C 
b/gcc/testsuite/g++.dg/modules/using-16_a.C
new file mode 100644
index 000..25d8bca5d1c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/using-16_a.C
@@ -0,0 +1,11 @@
+// { dg-additional-options "-fmodules-ts" }
+// { dg-module-cmi M:S }
+
+export module M:S;
+
+namespace foo {
+  // propagate hidden from partitions
+  export struct S {
+friend void f(S);
+  };
+};
diff --git a/gcc/testsuite/g++.dg/modules/using-16_b.C 
b/gcc/testsuite/g++.dg/modules/using-16_b.C
new file mode 100644
index 000..3f704a913f4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/using-16_b.C
@@ -0,0 +1,12 @@
+// { dg-additional-options "-fmodules-ts -Wno-global-module" }
+// { dg-module-cmi M }
+
+module;
+namespace bar {
+  void f(int);
+}
+export module M;
+export import :S;
+namespace foo {
+  export using bar::f;
+}
diff --git a/gcc/testsuite/g++.dg/modules/using-16_c.C 
b/gcc/testsuite/g++.dg/modules/using-16_c.C
new file mode 100644
index 000..5e46cd16013
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/using-16_c.C
@@ -0,0 +1,11 @@
+// { dg-additional-options "-fmodules-ts" }
+import M;
+
+int main() {
+  // this should be hidden and fail
+  foo::f(foo::S{});  // { dg-error "cannot convert" }
+
+  // but these should be legal
+  foo::f(10);
+  f(foo::S{});
+}


[gcc r15-84] c++: Implement P2615 'Meaningful Exports' [PR107688]

2024-04-30 Thread Nathaniel Shead via Gcc-cvs
https://gcc.gnu.org/g:79420dd344145819677b3f975bb305a778fcaf91

commit r15-84-g79420dd344145819677b3f975bb305a778fcaf91
Author: Nathaniel Shead 
Date:   Mon Mar 4 23:58:30 2024 +1100

c++: Implement P2615 'Meaningful Exports' [PR107688]

This clarifies which kinds of declarations may and may not be exported
in various contexts. The patch additionally fixes up some small issues
that were clarified by the paper.

Most of the changes are with regards to export-declarations, which are
applied for all standards modes that we support '-fmodules-ts' for.
However there are also a couple of changes made to linkage specifiers
('extern "C"'); I've applied these as since C++20, to line up with when
modules were actually introduced.

PR c++/107688

gcc/cp/ChangeLog:

* name-lookup.cc (push_namespace): Error when exporting
namespace with internal linkage.
* parser.h (struct cp_parser): Add new flag
'in_unbraced_export_declaration_p'.
* parser.cc (cp_debug_parser): Print the new flag.
(cp_parser_new): Initialise the new flag.
(cp_parser_module_export): Set the new flag.
(cp_parser_class_specifier): Clear and restore the new flag.
(cp_parser_import_declaration): Imports can now appear directly
in a linkage specification.
(cp_parser_declaration): Categorise declarations as "name" or
"special"; error on the later in contexts where the former is
required.
(cp_parser_class_head): Error when exporting a partial
specialisation.

gcc/testsuite/ChangeLog:

* g++.dg/modules/contracts-1_a.C: Avoid now-illegal syntax.
* g++.dg/modules/contracts-2_a.C: Likewise.
* g++.dg/modules/contracts-3_a.C: Likewise.
* g++.dg/modules/contracts-4_a.C: Likewise.
* g++.dg/modules/lang-1_c.C: Clarify now-legal syntax.
* g++.dg/modules/pr101582-1.C: Remove now-legal XFAILS.
* g++.dg/template/crash71.C: Update error messages.
* g++.dg/cpp2a/linkage-spec1.C: New test.
* g++.dg/modules/export-3.C: New test.
* g++.dg/modules/export-4_a.C: New test.
* g++.dg/modules/export-4_b.C: New test.

Signed-off-by: Nathaniel Shead 

Diff:
---
 gcc/cp/name-lookup.cc|  10 ++-
 gcc/cp/parser.cc | 105 +--
 gcc/cp/parser.h  |   6 +-
 gcc/testsuite/g++.dg/cpp2a/linkage-spec1.C   |  22 ++
 gcc/testsuite/g++.dg/modules/contracts-1_a.C |   2 +-
 gcc/testsuite/g++.dg/modules/contracts-2_a.C |   2 +-
 gcc/testsuite/g++.dg/modules/contracts-3_a.C |   2 +-
 gcc/testsuite/g++.dg/modules/contracts-4_a.C |   2 +-
 gcc/testsuite/g++.dg/modules/export-3.C  |  30 
 gcc/testsuite/g++.dg/modules/export-4_a.C|  23 ++
 gcc/testsuite/g++.dg/modules/export-4_b.C|  13 
 gcc/testsuite/g++.dg/modules/lang-1_c.C  |   2 +-
 gcc/testsuite/g++.dg/modules/pr101582-1.C|   8 +-
 gcc/testsuite/g++.dg/template/crash71.C  |   4 +-
 14 files changed, 197 insertions(+), 34 deletions(-)

diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc
index 4dffc0e9acc..5d2319db43d 100644
--- a/gcc/cp/name-lookup.cc
+++ b/gcc/cp/name-lookup.cc
@@ -9143,8 +9143,14 @@ push_namespace (tree name, bool make_inline)
 {
   /* A public namespace is exported only if explicitly marked, or
 it contains exported entities.  */
-  if (TREE_PUBLIC (ns) && module_exporting_p ())
-   DECL_MODULE_EXPORT_P (ns) = true;
+  if (module_exporting_p ())
+   {
+ if (TREE_PUBLIC (ns))
+   DECL_MODULE_EXPORT_P (ns) = true;
+ else if (!header_module_p ())
+   error_at (input_location,
+ "exporting namespace with internal linkage");
+   }
   if (module_purview_p ())
DECL_MODULE_PURVIEW_P (ns) = true;
 
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index aefbffe8330..a2bc6f69000 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -560,6 +560,8 @@ cp_debug_parser (FILE *file, cp_parser *parser)
   & THIS_FORBIDDEN));
   cp_debug_print_flag (file, "In unbraced linkage specification",
  parser->in_unbraced_linkage_specification_p);
+  cp_debug_print_flag (file, "In unbraced export declaration",
+ parser->in_unbraced_export_declaration_p);
   cp_debug_print_flag (file, "Parsing a declarator",
  parser->in_declarator_p);
   cp_debug_print_flag (file, "In template argument list",
@@ -4425,6 +4427,9 @@ cp_parser_new (cp_lexer *lexer)
   /* We are not processing an `extern "C"' declaration.  */
   parser->in_unbraced_linkage_specification_p = false;
 
+  /* We aren't parsing an export-declara

[gcc r15-59] c++: Fix instantiation of imported temploid friends [PR114275]

2024-04-29 Thread Nathaniel Shead via Gcc-cvs
https://gcc.gnu.org/g:b5f6a56940e70838a07e885de03a92e2bd64674a

commit r15-59-gb5f6a56940e70838a07e885de03a92e2bd64674a
Author: Nathaniel Shead 
Date:   Mon Apr 29 17:00:13 2024 +1000

c++: Fix instantiation of imported temploid friends [PR114275]

This patch fixes a number of issues with the handling of temploid friend
declarations.

The primary issue is that instantiations of friend declarations should
attach the declaration to the same module as the befriending class, by
[module.unit] p7.1 and [temp.friend] p2; this could be a different
module from the current TU, and so needs special handling.

The other main issue here is that we can't assume that just because name
lookup didn't find a definition for a hidden class template, that it
doesn't exist at all: it could be a non-exported entity that we've
nevertheless streamed in from an imported module.  We need to ensure
that when instantiating template friend classes that we return the same
TEMPLATE_DECL that we got from our imports, otherwise we will get later
issues with 'duplicate_decls' (rightfully) complaining that they're
different when trying to merge.

This doesn't appear necessary for function templates due to the existing
name lookup handling already finding these hidden declarations.

PR c++/105320
PR c++/114275

gcc/cp/ChangeLog:

* cp-tree.h (propagate_defining_module): Declare.
(lookup_imported_hidden_friend): Declare.
* decl.cc (duplicate_decls): Also check if hidden decls can be
redeclared in this module.
* module.cc (imported_temploid_friends): New.
(init_modules): Initialize it.
(trees_out::decl_value): Write it; don't consider imported
temploid friends as attached to a module.
(trees_in::decl_value): Read it.
(get_originating_module_decl): Follow the owning decl for an
imported temploid friend.
(propagate_defining_module): New.
* name-lookup.cc (get_mergeable_namespace_binding): New.
(lookup_imported_hidden_friend): New.
* pt.cc (tsubst_friend_function): Propagate defining module for
new friend functions.
(tsubst_friend_class): Lookup imported hidden friends.  Check
for valid module attachment of existing names.  Propagate
defining module for new classes.

gcc/testsuite/ChangeLog:

* g++.dg/modules/tpl-friend-10_a.C: New test.
* g++.dg/modules/tpl-friend-10_b.C: New test.
* g++.dg/modules/tpl-friend-10_c.C: New test.
* g++.dg/modules/tpl-friend-10_d.C: New test.
* g++.dg/modules/tpl-friend-11_a.C: New test.
* g++.dg/modules/tpl-friend-11_b.C: New test.
* g++.dg/modules/tpl-friend-12_a.C: New test.
* g++.dg/modules/tpl-friend-12_b.C: New test.
* g++.dg/modules/tpl-friend-12_c.C: New test.
* g++.dg/modules/tpl-friend-12_d.C: New test.
* g++.dg/modules/tpl-friend-12_e.C: New test.
* g++.dg/modules/tpl-friend-12_f.C: New test.
* g++.dg/modules/tpl-friend-13_a.C: New test.
* g++.dg/modules/tpl-friend-13_b.C: New test.
* g++.dg/modules/tpl-friend-13_c.C: New test.
* g++.dg/modules/tpl-friend-13_d.C: New test.
* g++.dg/modules/tpl-friend-13_e.C: New test.
* g++.dg/modules/tpl-friend-13_f.C: New test.
* g++.dg/modules/tpl-friend-13_g.C: New test.
* g++.dg/modules/tpl-friend-14_a.C: New test.
* g++.dg/modules/tpl-friend-14_b.C: New test.
* g++.dg/modules/tpl-friend-14_c.C: New test.
* g++.dg/modules/tpl-friend-14_d.C: New test.
* g++.dg/modules/tpl-friend-9.C: New test.

Signed-off-by: Nathaniel Shead 
Reviewed-by: Jason Merrill 

Diff:
---
 gcc/cp/cp-tree.h   |  2 +
 gcc/cp/decl.cc | 37 ---
 gcc/cp/module.cc   | 62 ++
 gcc/cp/name-lookup.cc  | 53 ++
 gcc/cp/pt.cc   | 29 +++-
 gcc/testsuite/g++.dg/modules/tpl-friend-10_a.C | 15 +++
 gcc/testsuite/g++.dg/modules/tpl-friend-10_b.C |  5 +++
 gcc/testsuite/g++.dg/modules/tpl-friend-10_c.C |  7 +++
 gcc/testsuite/g++.dg/modules/tpl-friend-10_d.C |  8 
 gcc/testsuite/g++.dg/modules/tpl-friend-11_a.C | 14 ++
 gcc/testsuite/g++.dg/modules/tpl-friend-11_b.C |  5 +++
 gcc/testsuite/g++.dg/modules/tpl-friend-12_a.C | 10 +
 gcc/testsuite/g++.dg/modules/tpl-friend-12_b.C |  9 
 gcc/testsuite/g++.dg/modules/tpl-friend-12_c.C | 10 +
 gcc/testsuite/g++.dg/modules/tpl-friend-12_d.C |  8 
 gcc/testsuite/g++.dg/modules/tpl-friend-1

[gcc r15-58] c++: Standardise errors for module_may_redeclare

2024-04-29 Thread Nathaniel Shead via Gcc-cvs
https://gcc.gnu.org/g:2faf040335f9b49c33ba6d40cf317920f27ce431

commit r15-58-g2faf040335f9b49c33ba6d40cf317920f27ce431
Author: Nathaniel Shead 
Date:   Sun Apr 14 23:03:11 2024 +1000

c++: Standardise errors for module_may_redeclare

Currently different places calling 'module_may_redeclare' all emit very
similar but slightly different error messages, and handle different
kinds of declarations differently.  This patch makes the function
perform its own error messages so that they're all in one place, and
prepares it for use with temploid friends.

gcc/cp/ChangeLog:

* cp-tree.h (module_may_redeclare): Add default parameter.
* decl.cc (duplicate_decls): Don't emit errors for failed
module_may_redeclare.
(xref_tag): Likewise.
(start_enum): Likewise.
* semantics.cc (begin_class_definition): Likewise.
* module.cc (module_may_redeclare): Clean up logic. Emit error
messages on failure.

gcc/testsuite/ChangeLog:

* g++.dg/modules/enum-12.C: Update error message.
* g++.dg/modules/friend-5_b.C: Likewise.
* g++.dg/modules/shadow-1_b.C: Likewise.

Signed-off-by: Nathaniel Shead 
Reviewed-by: Jason Merrill 

Diff:
---
 gcc/cp/cp-tree.h  |   2 +-
 gcc/cp/decl.cc|  28 +--
 gcc/cp/module.cc  | 120 --
 gcc/cp/semantics.cc   |   6 +-
 gcc/testsuite/g++.dg/modules/enum-12.C|   2 +-
 gcc/testsuite/g++.dg/modules/friend-5_b.C |   2 +-
 gcc/testsuite/g++.dg/modules/shadow-1_b.C |   5 +-
 7 files changed, 89 insertions(+), 76 deletions(-)

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index bafdf63dc63..4ac8cf69869 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -7401,7 +7401,7 @@ inline bool module_exporting_p ()
 
 extern module_state *get_module (tree name, module_state *parent = NULL,
 bool partition = false);
-extern bool module_may_redeclare (tree decl);
+extern bool module_may_redeclare (tree olddecl, tree newdecl = NULL);
 
 extern bool module_global_init_needed ();
 extern bool module_determine_import_inits ();
diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index 2af026d255d..91268ff631d 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -2279,18 +2279,8 @@ duplicate_decls (tree newdecl, tree olddecl, bool 
hiding, bool was_hidden)
   && TREE_CODE (olddecl) != NAMESPACE_DECL
   && !hiding)
 {
-  if (!module_may_redeclare (olddecl))
-   {
- if (DECL_ARTIFICIAL (olddecl))
-   error ("declaration %qD conflicts with builtin", newdecl);
- else
-   {
- error ("declaration %qD conflicts with import", newdecl);
- inform (olddecl_loc, "import declared %q#D here", olddecl);
-   }
-
- return error_mark_node;
-   }
+  if (!module_may_redeclare (olddecl, newdecl))
+   return error_mark_node;
 
   tree not_tmpl = STRIP_TEMPLATE (olddecl);
   if (DECL_LANG_SPECIFIC (not_tmpl)
@@ -16626,12 +16616,7 @@ xref_tag (enum tag_types tag_code, tree name,
{
  tree decl = TYPE_NAME (t);
  if (!module_may_redeclare (decl))
-   {
- auto_diagnostic_group d;
- error ("cannot declare %qD in a different module", decl);
- inform (DECL_SOURCE_LOCATION (decl), "previously declared here");
- return error_mark_node;
-   }
+   return error_mark_node;
 
  tree not_tmpl = STRIP_TEMPLATE (decl);
  if (DECL_LANG_SPECIFIC (not_tmpl)
@@ -16979,12 +16964,7 @@ start_enum (tree name, tree enumtype, tree 
underlying_type,
{
  tree decl = TYPE_NAME (enumtype);
  if (!module_may_redeclare (decl))
-   {
- auto_diagnostic_group d;
- error ("cannot declare %qD in different module", decl);
- inform (DECL_SOURCE_LOCATION (decl), "previously declared here");
- enumtype = error_mark_node;
-   }
+   enumtype = error_mark_node;
  else
set_instantiating_module (decl);
}
diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index 3bf863e15d4..c2f077d6fd8 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -19003,11 +19003,15 @@ get_importing_module (tree decl, bool flexible)
   return module->mod;
 }
 
-/* Is it permissible to redeclare DECL.  */
+/* Is it permissible to redeclare OLDDECL with NEWDECL.
+
+   If NEWDECL is NULL, assumes that OLDDECL will be redeclared using
+   the current scope's module and attachment.  */
 
 bool
-module_may_redeclare (tree decl)
+module_may_redeclare (tree olddecl, tree newdecl)
 {
+  tree decl = olddecl;
   for (;;)
 {
   tree ctx = CP_DECL_CONTEXT (decl);
@@ -19021,58 +19025,94 @@ module_may_redeclare (tree decl)
   decl = TYP

[gcc r14-10100] c++: Fix ICE with xobj parms and maybe incomplete decl-specifiers

2024-04-23 Thread Nathaniel Shead via Gcc-cvs
https://gcc.gnu.org/g:7318f1a389769ab540f414fcba743e90051d466b

commit r14-10100-g7318f1a389769ab540f414fcba743e90051d466b
Author: Nathaniel Shead 
Date:   Sat Apr 20 14:44:11 2024 +1000

c++: Fix ICE with xobj parms and maybe incomplete decl-specifiers

This fixes a null dereference issue when decl_specifiers.type is not yet
provided.

gcc/cp/ChangeLog:

* parser.cc (cp_parser_parameter_declaration): Check if
decl_specifiers.type is null.

gcc/testsuite/ChangeLog:

* g++.dg/cpp23/explicit-obj-basic7.C: New test.

Signed-off-by: Nathaniel Shead 

Diff:
---
 gcc/cp/parser.cc | 5 +++--
 gcc/testsuite/g++.dg/cpp23/explicit-obj-basic7.C | 9 +
 2 files changed, 12 insertions(+), 2 deletions(-)

diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index c23758cf5cf..598380dda08 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -25780,8 +25780,9 @@ cp_parser_parameter_declaration (cp_parser *parser,
 }
 
   if (xobj_param_p
-  && (declarator ? declarator->parameter_pack_p
-: PACK_EXPANSION_P (decl_specifiers.type)))
+  && ((declarator && declarator->parameter_pack_p)
+ || (decl_specifiers.type
+ && PACK_EXPANSION_P (decl_specifiers.type
 {
   location_t xobj_param
= make_location (decl_specifiers.locations[ds_this],
diff --git a/gcc/testsuite/g++.dg/cpp23/explicit-obj-basic7.C 
b/gcc/testsuite/g++.dg/cpp23/explicit-obj-basic7.C
new file mode 100644
index 000..a474e97fc18
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp23/explicit-obj-basic7.C
@@ -0,0 +1,9 @@
+// { dg-do compile { target c++23 } }
+
+// Shouldn't ICE
+struct S {
+  void a(this long);
+  void b(this const long);
+  void c(this long unsigned);
+  void c(this signed);
+};


[gcc r14-10085] c++: Check if allocation functions are xobj members [PR114078]

2024-04-22 Thread Nathaniel Shead via Gcc-cvs
https://gcc.gnu.org/g:cf51fe706ea0219beb5bb85e81606d372ca9635e

commit r14-10085-gcf51fe706ea0219beb5bb85e81606d372ca9635e
Author: Nathaniel Shead 
Date:   Sat Apr 20 15:08:02 2024 +1000

c++: Check if allocation functions are xobj members [PR114078]

A class allocation member function is implicitly 'static' by
[class.free] p3, so cannot have an explicit object parameter.

PR c++/114078

gcc/cp/ChangeLog:

* decl.cc (grokdeclarator): Check allocation functions for xobj
parameters.

gcc/testsuite/ChangeLog:

* g++.dg/cpp23/explicit-obj-ops-alloc.C: New test.

Signed-off-by: Nathaniel Shead 

Diff:
---
 gcc/cp/decl.cc  |  6 ++
 gcc/testsuite/g++.dg/cpp23/explicit-obj-ops-alloc.C | 11 +++
 2 files changed, 17 insertions(+)

diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index 65ab64885ff..2af026d255d 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -13728,6 +13728,12 @@ grokdeclarator (const cp_declarator *declarator,
inform (DECL_SOURCE_LOCATION (xobj_parm),
"explicit object parameter declared here");
  }
+   if (unqualified_id
+   && identifier_p (unqualified_id)
+   && IDENTIFIER_NEWDEL_OP_P (unqualified_id))
+ error_at (DECL_SOURCE_LOCATION (xobj_parm),
+   "%qD cannot be an explicit object member "
+   "function", unqualified_id);
  }
  }
tree pushed_scope = NULL_TREE;
diff --git a/gcc/testsuite/g++.dg/cpp23/explicit-obj-ops-alloc.C 
b/gcc/testsuite/g++.dg/cpp23/explicit-obj-ops-alloc.C
new file mode 100644
index 000..8a277db7ef5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp23/explicit-obj-ops-alloc.C
@@ -0,0 +1,11 @@
+// PR c++/114078
+// { dg-do compile { target c++23 } }
+
+using size_t = decltype(sizeof(0));
+
+struct S {
+  void* operator new(this size_t);  // { dg-error "explicit object" }
+  void* operator new[](this size_t);  // { dg-error "explicit object" }
+  void operator delete(this void*);  // { dg-error "explicit object" }
+  void operator delete[](this void*);  // { dg-error "explicit object" }
+};


[gcc r14-9961] c++: Only emit exported GMF usings [PR114600]

2024-04-15 Thread Nathaniel Shead via Gcc-cvs
https://gcc.gnu.org/g:3878e9aeb30cb192f769997c52743daf8190744c

commit r14-9961-g3878e9aeb30cb192f769997c52743daf8190744c
Author: Nathaniel Shead 
Date:   Mon Apr 8 23:34:42 2024 +1000

c++: Only emit exported GMF usings [PR114600]

A typo in r14-6978 made us emit too many things. This ensures that we
don't emit using-declarations from the GMF that we don't need to.

PR c++/114600

gcc/cp/ChangeLog:

* module.cc (depset::hash::add_binding_entity): Require both
WMB_Using and WMB_Export for GMF entities.

gcc/testsuite/ChangeLog:

* g++.dg/modules/using-14.C: New test.

Signed-off-by: Nathaniel Shead 
Co-authored-by: Patrick Palka 

Diff:
---
 gcc/cp/module.cc|  2 +-
 gcc/testsuite/g++.dg/modules/using-14.C | 14 ++
 2 files changed, 15 insertions(+), 1 deletion(-)

diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index 001430a4a8f..d94d8ff4df9 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -13090,7 +13090,7 @@ 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 | WMB_Export)))
+ && !((flags & WMB_Using) && (flags & WMB_Export)))
/* Ignore global module fragment entities unless explicitly
   exported with a using declaration.  */
return false;
diff --git a/gcc/testsuite/g++.dg/modules/using-14.C 
b/gcc/testsuite/g++.dg/modules/using-14.C
new file mode 100644
index 000..0e15a952de5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/using-14.C
@@ -0,0 +1,14 @@
+// PR c++/114600
+// { dg-additional-options "-fmodules-ts -Wno-global-module 
-fdump-lang-module" }
+// { dg-module-cmi M }
+
+module;
+namespace std {
+  template struct A { int n; };
+  template A f();
+  namespace __swappable_details { using std::f; }
+}
+export module M;
+
+// The whole GMF should be discarded here
+// { dg-final { scan-lang-dump "Wrote 0 clusters" module } }


[gcc r14-9959] c++: Setup aliases imported from modules [PR106820]

2024-04-14 Thread Nathaniel Shead via Gcc-cvs
https://gcc.gnu.org/g:62a0ef0d02cbb74cd865c1db2ecb7ca1b11f87cd

commit r14-9959-g62a0ef0d02cbb74cd865c1db2ecb7ca1b11f87cd
Author: Nathaniel Shead 
Date:   Sat Feb 17 23:10:49 2024 +1100

c++: Setup aliases imported from modules [PR106820]

I wonder if more generally we need to be doing more work when importing
definitions from header units especially to handle all the work that
'make_rtl_for_nonlocal_decl' and 'rest_of_decl_compilation' would have
been performing. But this patch fixes at least one missing step.

PR c++/106820

gcc/cp/ChangeLog:

* module.cc (trees_in::decl_value): Assemble alias when needed.

gcc/testsuite/ChangeLog:

* g++.dg/modules/pr106820_a.H: New test.
* g++.dg/modules/pr106820_b.C: New test.

Signed-off-by: Nathaniel Shead 

Diff:
---
 gcc/cp/module.cc  | 9 +
 gcc/testsuite/g++.dg/modules/pr106820_a.H | 5 +
 gcc/testsuite/g++.dg/modules/pr106820_b.C | 8 
 3 files changed, 22 insertions(+)

diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index c6f71e11515..001430a4a8f 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -219,6 +219,7 @@ Classes used:
 #include "dumpfile.h"
 #include "bitmap.h"
 #include "cgraph.h"
+#include "varasm.h"
 #include "tree-iterator.h"
 #include "cpplib.h"
 #include "mkdeps.h"
@@ -8414,6 +8415,14 @@ trees_in::decl_value ()
   if (state->is_header ()
  && decl_tls_wrapper_p (decl))
note_vague_linkage_fn (decl);
+
+  /* Setup aliases for the declaration.  */
+  if (tree alias = lookup_attribute ("alias", DECL_ATTRIBUTES (decl)))
+   {
+ alias = TREE_VALUE (TREE_VALUE (alias));
+ alias = get_identifier (TREE_STRING_POINTER (alias));
+ assemble_alias (decl, alias);
+   }
 }
   else
 {
diff --git a/gcc/testsuite/g++.dg/modules/pr106820_a.H 
b/gcc/testsuite/g++.dg/modules/pr106820_a.H
new file mode 100644
index 000..7d32d4e5fc3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/pr106820_a.H
@@ -0,0 +1,5 @@
+// PR c++/106820
+// { dg-additional-options "-fmodules-ts" }
+// { dg-module-cmi {} }
+
+static int __gthrw___pthread_key_create() __attribute__((__weakref__("foo")));
diff --git a/gcc/testsuite/g++.dg/modules/pr106820_b.C 
b/gcc/testsuite/g++.dg/modules/pr106820_b.C
new file mode 100644
index 000..247fe26e778
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/pr106820_b.C
@@ -0,0 +1,8 @@
+// PR c++/106820
+// { dg-additional-options "-fmodules-ts" }
+
+import "pr106820_a.H";
+
+int main() {
+  __gthrw___pthread_key_create();
+}


[gcc r14-9883] c++: Keep DECL_SAVED_TREE of cdtor instantiations in modules [PR104040]

2024-04-09 Thread Nathaniel Shead via Gcc-cvs
https://gcc.gnu.org/g:0774240b4df9a9bc48ce33a9625788e402498f5a

commit r14-9883-g0774240b4df9a9bc48ce33a9625788e402498f5a
Author: Nathaniel Shead 
Date:   Fri Mar 29 13:53:54 2024 +1100

c++: Keep DECL_SAVED_TREE of cdtor instantiations in modules [PR104040]

A template instantiation still needs to have its DECL_SAVED_TREE so that
its definition is emitted into the CMI. This way it can be emitted in
the object file of any importers that use it, in case it doesn't end up
getting emitted in this TU.

This is true even for maybe-in-charge functions, because we don't
currently stream the clones directly but instead regenerate them from
this function.

PR c++/104040

gcc/cp/ChangeLog:

* semantics.cc (expand_or_defer_fn_1): Keep DECL_SAVED_TREE for
all vague linkage cdtors with modules.

gcc/testsuite/ChangeLog:

* g++.dg/modules/pr104040_a.C: New test.
* g++.dg/modules/pr104040_b.C: New test.

Signed-off-by: Nathaniel Shead 
Reviewed-by: Jason Merrill 

Diff:
---
 gcc/cp/semantics.cc   |  8 ++--
 gcc/testsuite/g++.dg/modules/pr104040_a.C | 14 ++
 gcc/testsuite/g++.dg/modules/pr104040_b.C |  8 
 3 files changed, 28 insertions(+), 2 deletions(-)

diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index a43ff6e2ab2..329c524a509 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -5029,9 +5029,13 @@ expand_or_defer_fn_1 (tree fn)
   /* We don't want to process FN again, so pretend we've written
 it out, even though we haven't.  */
   TREE_ASM_WRITTEN (fn) = 1;
-  /* If this is a constexpr function, keep DECL_SAVED_TREE.  */
+  /* If this is a constexpr function we still need the body to be
+able to evaluate it.  Similarly, with modules we only stream
+the maybe-in-charge cdtor and regenerate the clones from it on
+demand, so we also need to keep the body.  Otherwise we don't
+need it anymore.  */
   if (!DECL_DECLARED_CONSTEXPR_P (fn)
- && !(modules_p () && DECL_DECLARED_INLINE_P (fn)))
+ && !(modules_p () && vague_linkage_p (fn)))
DECL_SAVED_TREE (fn) = NULL_TREE;
   return false;
 }
diff --git a/gcc/testsuite/g++.dg/modules/pr104040_a.C 
b/gcc/testsuite/g++.dg/modules/pr104040_a.C
new file mode 100644
index 000..ea36ce0a798
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/pr104040_a.C
@@ -0,0 +1,14 @@
+// PR c++/104040
+// { dg-additional-options "-fmodules-ts" }
+// { dg-module-cmi test }
+
+export module test;
+
+export template 
+struct test {
+  ~test() {}
+};
+
+test use() {
+  return {};
+}
diff --git a/gcc/testsuite/g++.dg/modules/pr104040_b.C 
b/gcc/testsuite/g++.dg/modules/pr104040_b.C
new file mode 100644
index 000..efe014673fb
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/pr104040_b.C
@@ -0,0 +1,8 @@
+// PR c++/104040
+// { dg-additional-options "-fmodules-ts" }
+
+import test;
+
+int main() {
+  test t{};
+}


[gcc r14-9881] c++: Track declarations imported from partitions [PR99377]

2024-04-09 Thread Nathaniel Shead via Gcc-cvs
https://gcc.gnu.org/g:77c0b5b23f91404004a9bf710981f6d615b63f57

commit r14-9881-g77c0b5b23f91404004a9bf710981f6d615b63f57
Author: Nathaniel Shead 
Date:   Thu Apr 4 23:16:08 2024 +1100

c++: Track declarations imported from partitions [PR99377]

The testcase in comment 15 of the linked PR is caused because the
following assumption in depset::hash::make_dependency doesn't hold:

  if (DECL_LANG_SPECIFIC (not_tmpl)
  && DECL_MODULE_IMPORT_P (not_tmpl))
{
  /* Store the module number and index in cluster/section,
 so we don't have to look them up again.  */
  unsigned index = import_entity_index (decl);
  module_state *from = import_entity_module (index);
  /* Remap will be zero for imports from partitions, which
 we want to treat as-if declared in this TU.  */
  if (from->remap)
{
  dep->cluster = index - from->entity_lwm;
  dep->section = from->remap;
  dep->set_flag_bit ();
}
}

This is because at least for template specialisations, we first see the
declaration in the header unit imported from the partition, and then the
instantiation provided by the partition itself.  This means that the
'import_entity_index' lookup doesn't report that the specialisation was
declared in the partition and thus should be considered as-if it was
part of the TU, and get emitted into the CMI.

We always need to emit definitions from module partitions into the
primary module interface's CMI, as unlike with other kinds of transitive
imports the built CMIs for module partitions are not visible to
importers.

To fix this, this patch allows, as a special case for installing an
entity from a partition, to overwrite the entity_map entry with the
(later) index into the partition so that this assumption holds again.

We only do this for the first time we override with a partition, so that
entities are at least still reported as originating from the first
imported partition that declares them (rather than the last); existing
tests check for this and this seems to be a friendlier approach to go
for, albeit slightly more expensive.

PR c++/99377

gcc/cp/ChangeLog:

* module.cc (trees_in::install_entity): Overwrite entity map
index if installing from a partition.

gcc/testsuite/ChangeLog:

* g++.dg/modules/pr99377-3_a.H: New test.
* g++.dg/modules/pr99377-3_b.C: New test.
* g++.dg/modules/pr99377-3_c.C: New test.
* g++.dg/modules/pr99377-3_d.C: New test.

Signed-off-by: Nathaniel Shead 

Diff:
---
 gcc/cp/module.cc   | 13 +
 gcc/testsuite/g++.dg/modules/pr99377-3_a.H | 17 +
 gcc/testsuite/g++.dg/modules/pr99377-3_b.C | 10 ++
 gcc/testsuite/g++.dg/modules/pr99377-3_c.C |  5 +
 gcc/testsuite/g++.dg/modules/pr99377-3_d.C |  8 
 5 files changed, 53 insertions(+)

diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index 8aab9ea0bae..4e91fa6e052 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -7649,6 +7649,19 @@ trees_in::install_entity (tree decl)
   gcc_checking_assert (!existed);
   slot = ident;
 }
+  else if (state->is_partition ())
+{
+  /* The decl is already in the entity map, but we see it again now from a
+partition: we want to overwrite if the original decl wasn't also from
+a (possibly different) partition.  Otherwise, for things like template
+instantiations, make_dependency might not realise that this is also
+provided from a partition and should be considered part of this module
+(and thus always emitted into the primary interface's CMI).  */
+  unsigned *slot = entity_map->get (DECL_UID (decl));
+  module_state *imp = import_entity_module (*slot);
+  if (!imp->is_partition ())
+   *slot = ident;
+}
 
   return true;
 }
diff --git a/gcc/testsuite/g++.dg/modules/pr99377-3_a.H 
b/gcc/testsuite/g++.dg/modules/pr99377-3_a.H
new file mode 100644
index 000..580a7631ae1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/pr99377-3_a.H
@@ -0,0 +1,17 @@
+// { dg-additional-options "-fmodule-header" }
+// { dg-module-cmi {} }
+
+template
+struct Widget
+{
+  Widget (int) { }
+
+  bool First() const { return true; }
+
+  bool Second () const { return true;}
+};
+
+inline void Frob (const Widget& w) noexcept
+{
+  w.First ();
+}
diff --git a/gcc/testsuite/g++.dg/modules/pr99377-3_b.C 
b/gcc/testsuite/g++.dg/modules/pr99377-3_b.C
new file mode 100644
index 000..5cbce7b3544
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/pr99377-3_b.C
@@ -0,0 +1,10 @@
+// { dg-additional-options "-fmodules-ts" }
+// { dg-module-cmi Foo:check }
+
+export module Foo:check;
+import "pr99377-3_a.H";
+
+export inline bool Ch

[gcc r14-9530] c++: Fix handling of no-linkage decls for modules

2024-03-18 Thread Nathaniel Shead via Gcc-cvs
https://gcc.gnu.org/g:c4845edfeaf44756ad9672e8d143f1c8f5c4c0f6

commit r14-9530-gc4845edfeaf44756ad9672e8d143f1c8f5c4c0f6
Author: Nathaniel Shead 
Date:   Sat Mar 16 22:00:29 2024 +1100

c++: Fix handling of no-linkage decls for modules

When testing the changes for PR c++/112631 we discovered that currently
we don't emit definitions of block-scope function declarations if
they're not used in the module interface TU, which causes issues if they
are used by importers.

This patch fixes the handling of no-linkage declarations for C++20. In
particular, a type declared in a function with vague linkage or declared
in a module CMI could potentially be accessible outside its defining TU,
and as such we can't assume that function declarations using that type
can never be defined in another TU.

A complication with handling this is that we're only strictly interested
in declarations with a module CMI, but when parsing the global module
fragment we don't yet know whether or not this module will have a CMI
until we reach the "export module" line (or not). Since this case is
IFNDR anyway (by [basic.def.odr] p11) we just tentatively assume while
parsing the GMF that this module will have a CMI; once we see (or don't
see) an 'export module' declaration we can commit to that knowledge for
future declarations.

gcc/cp/ChangeLog:

* cp-tree.h (module_maybe_has_cmi_p): New function.
* decl.cc (grokfndecl): Mark block-scope functions as public if
they could be visible in other TUs.
* decl2.cc (no_linkage_error): Don't error for declarations that
could be defined in other TUs since C++20. Suppress duplicate
errors from 'check_global_declaration'.
* tree.cc (no_linkage_check): In relaxed mode, don't consider
types in a module CMI to have no linkage.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/linkage-1.C: New test.
* g++.dg/modules/block-decl-3.h: New test.
* g++.dg/modules/block-decl-3_a.C: New test.
* g++.dg/modules/block-decl-3_b.C: New test.
* g++.dg/modules/block-decl-3_c.C: New test.
* g++.dg/modules/linkage-1_a.C: New test.
* g++.dg/modules/linkage-1_b.C: New test.
* g++.dg/modules/linkage-1_c.C: New test.
* g++.dg/modules/linkage-2.C: New test.

Signed-off-by: Nathaniel Shead 
Reviewed-by: Jason Merrill 

Diff:
---
 gcc/cp/cp-tree.h  |   6 +
 gcc/cp/decl.cc|  10 +-
 gcc/cp/decl2.cc   |  39 ++-
 gcc/cp/tree.cc|  21 +++-
 gcc/testsuite/g++.dg/cpp2a/linkage-1.C|  18 +++
 gcc/testsuite/g++.dg/modules/block-decl-3.h   |  39 +++
 gcc/testsuite/g++.dg/modules/block-decl-3_a.C | 157 ++
 gcc/testsuite/g++.dg/modules/block-decl-3_b.C |   8 ++
 gcc/testsuite/g++.dg/modules/block-decl-3_c.C |  30 +
 gcc/testsuite/g++.dg/modules/linkage-1_a.C|  15 +++
 gcc/testsuite/g++.dg/modules/linkage-1_b.C|   6 +
 gcc/testsuite/g++.dg/modules/linkage-1_c.C|   9 ++
 gcc/testsuite/g++.dg/modules/linkage-2.C  |  26 +
 13 files changed, 372 insertions(+), 12 deletions(-)

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 05913861e06..52d53589e51 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -7384,6 +7384,12 @@ inline bool named_module_purview_p ()
 inline bool named_module_attach_p ()
 { return named_module_p () && module_attach_p (); }
 
+/* We don't know if this TU will have a CMI while parsing the GMF,
+   so tentatively assume that it might, for the purpose of determining
+   whether no-linkage decls could be used by an importer.  */
+inline bool module_maybe_has_cmi_p ()
+{ return module_has_cmi_p () || (named_module_p () && !module_purview_p ()); }
+
 /* We're currently exporting declarations.  */
 inline bool module_exporting_p ()
 { return module_kind & MK_EXPORTING; }
diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index 7a97b867199..65ab64885ff 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -10756,9 +10756,15 @@ grokfndecl (tree ctype,
 
   /* Members of anonymous types and local classes have no linkage; make
  them internal.  If a typedef is made later, this will be changed.  */
-  if (ctype && (!TREE_PUBLIC (TYPE_MAIN_DECL (ctype))
-   || decl_function_context (TYPE_MAIN_DECL (ctype
+  if (ctype && !TREE_PUBLIC (TYPE_MAIN_DECL (ctype)))
 publicp = 0;
+  else if (ctype && decl_function_context (TYPE_MAIN_DECL (ctype)))
+/* But members of local classes in a module CMI should have their
+   definitions exported, in case they are (directly or indirectly)
+   used by an importer.  We don't just use module_has_cmi_p here
+   because for entities in the GMF we don't yet know whether this
+ 

[gcc r14-9517] testsuite: Fix excess errors for new modules testcases on powerpc [PR114320]

2024-03-18 Thread Nathaniel Shead via Gcc-cvs
https://gcc.gnu.org/g:6cb5ef37c2fac240b68d8ee438aba4885956269f

commit r14-9517-g6cb5ef37c2fac240b68d8ee438aba4885956269f
Author: Nathaniel Shead 
Date:   Sat Mar 16 00:11:25 2024 +1100

testsuite: Fix excess errors for new modules testcases on powerpc [PR114320]

On some configurations, PowerPC emits -Wpsabi warnings when using IEEE
long doubles on a machine configured with IBM long double by default.
This patch suppresses these warnings for this testcase.

PR testsuite/114320

gcc/testsuite/ChangeLog:

* g++.dg/modules/target-powerpc-1_a.C: Suppress -Wpsabi.
* g++.dg/modules/target-powerpc-1_b.C: Likewise.

Signed-off-by: Nathaniel Shead 

Diff:
---
 gcc/testsuite/g++.dg/modules/target-powerpc-1_a.C | 2 +-
 gcc/testsuite/g++.dg/modules/target-powerpc-1_b.C | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/gcc/testsuite/g++.dg/modules/target-powerpc-1_a.C 
b/gcc/testsuite/g++.dg/modules/target-powerpc-1_a.C
index 693ed101ed5..01709e0eac0 100644
--- a/gcc/testsuite/g++.dg/modules/target-powerpc-1_a.C
+++ b/gcc/testsuite/g++.dg/modules/target-powerpc-1_a.C
@@ -1,7 +1,7 @@
 // PR c++/98645
 // { dg-do compile { target powerpc*-*-* } }
 // { dg-require-effective-target ppc_float128_sw }
-// { dg-additional-options "-fmodules-ts -mfloat128 -mabi=ieeelongdouble" }
+// { dg-additional-options "-fmodules-ts -mfloat128 -mabi=ieeelongdouble 
-Wno-psabi" }
 
 export module M;
 export __ibm128 i = 0.0;
diff --git a/gcc/testsuite/g++.dg/modules/target-powerpc-1_b.C 
b/gcc/testsuite/g++.dg/modules/target-powerpc-1_b.C
index d6b684b556d..b4209bc1550 100644
--- a/gcc/testsuite/g++.dg/modules/target-powerpc-1_b.C
+++ b/gcc/testsuite/g++.dg/modules/target-powerpc-1_b.C
@@ -1,7 +1,7 @@
 // PR c++/98645
 // { dg-module-do compile { target powerpc*-*-* } }
 // { dg-require-effective-target ppc_float128_sw }
-// { dg-additional-options "-fmodules-ts -mfloat128 -mabi=ieeelongdouble" }
+// { dg-additional-options "-fmodules-ts -mfloat128 -mabi=ieeelongdouble 
-Wno-psabi" }
 
 import M;


[gcc r14-9501] c++: Check module attachment instead of just purview when necessary [PR112631]

2024-03-16 Thread Nathaniel Shead via Gcc-cvs
https://gcc.gnu.org/g:ead3075406ece9daaad65a01ae539150aee43f5a

commit r14-9501-gead3075406ece9daaad65a01ae539150aee43f5a
Author: Nathaniel Shead 
Date:   Tue Mar 12 23:24:27 2024 +1100

c++: Check module attachment instead of just purview when necessary 
[PR112631]

Block-scope declarations of functions or extern values are not allowed
when attached to a named module. Similarly, class member functions are
not inline if attached to a named module. However, in both these cases
we currently only check if the declaration is within the module purview;
it is possible for such a declaration to occur within the module purview
but not be attached to a named module (e.g. in an 'extern "C++"' block).
This patch makes the required adjustments.

PR c++/112631

gcc/cp/ChangeLog:

* cp-tree.h (named_module_attach_p): New function.
* decl.cc (start_decl): Check for attachment not purview.
(grokmethod): Likewise.

gcc/testsuite/ChangeLog:

* g++.dg/modules/block-decl-1_a.C: New test.
* g++.dg/modules/block-decl-1_b.C: New test.
* g++.dg/modules/block-decl-2.C: New test.

Signed-off-by: Nathaniel Shead 

Diff:
---
 gcc/cp/cp-tree.h  |  2 ++
 gcc/cp/decl.cc| 10 +-
 gcc/testsuite/g++.dg/modules/block-decl-1_a.C |  9 +
 gcc/testsuite/g++.dg/modules/block-decl-1_b.C | 10 ++
 gcc/testsuite/g++.dg/modules/block-decl-2.C   | 21 +
 5 files changed, 47 insertions(+), 5 deletions(-)

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 14895bc6585..05913861e06 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -7381,6 +7381,8 @@ inline bool module_attach_p ()
 
 inline bool named_module_purview_p ()
 { return named_module_p () && module_purview_p (); }
+inline bool named_module_attach_p ()
+{ return named_module_p () && module_attach_p (); }
 
 /* We're currently exporting declarations.  */
 inline bool module_exporting_p ()
diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index dbc3df24e77..7a97b867199 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -6092,10 +6092,10 @@ start_decl (const cp_declarator *declarator,
 {
   /* A function-scope decl of some namespace-scope decl.  */
   DECL_LOCAL_DECL_P (decl) = true;
-  if (named_module_purview_p ())
+  if (named_module_attach_p ())
error_at (declarator->id_loc,
- "block-scope extern declaration %q#D not permitted"
- " in module purview", decl);
+ "block-scope extern declaration %q#D must not be"
+ " attached to a named module", decl);
 }
 
   /* Enter this declaration into the symbol table.  Don't push the plain
@@ -18907,10 +18907,10 @@ grokmethod (cp_decl_specifier_seq *declspecs,
   check_template_shadow (fndecl);
 
   /* p1779 ABI-Isolation makes inline not a default for in-class
- definitions in named module purview.  If the user explicitly
+ definitions attached to a named module.  If the user explicitly
  made it inline, grokdeclarator will already have done the right
  things.  */
-  if ((!named_module_purview_p ()
+  if ((!named_module_attach_p ()
|| flag_module_implicit_inline
   /* Lambda's operator function remains inline.  */
|| LAMBDA_TYPE_P (DECL_CONTEXT (fndecl)))
diff --git a/gcc/testsuite/g++.dg/modules/block-decl-1_a.C 
b/gcc/testsuite/g++.dg/modules/block-decl-1_a.C
new file mode 100644
index 000..e7ffc629192
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/block-decl-1_a.C
@@ -0,0 +1,9 @@
+// { dg-additional-options "-fmodules-ts" }
+// { dg-module-cmi bla }
+
+export module bla;
+
+export extern "C++" inline void fun() {
+  void oops();  // { dg-bogus "block-scope extern declaration" }
+  oops();
+}
diff --git a/gcc/testsuite/g++.dg/modules/block-decl-1_b.C 
b/gcc/testsuite/g++.dg/modules/block-decl-1_b.C
new file mode 100644
index 000..c0d724f25ac
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/block-decl-1_b.C
@@ -0,0 +1,10 @@
+// { dg-module-do link }
+// { dg-additional-options "-fmodules-ts" }
+
+import bla;
+
+void oops() {}
+
+int main() {
+  fun();
+}
diff --git a/gcc/testsuite/g++.dg/modules/block-decl-2.C 
b/gcc/testsuite/g++.dg/modules/block-decl-2.C
new file mode 100644
index 000..974e26f9b7a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/block-decl-2.C
@@ -0,0 +1,21 @@
+// { dg-additional-options "-fmodules-ts" }
+// { dg-module-cmi !mod }
+
+export module mod;
+
+namespace {
+  void internal() {}
+}
+
+export extern "C++" auto foo() {
+  struct X {
+// `foo` is not attached to a named module, and as such
+// `X::f` should be implicitly `inline` here
+void f() {  // { dg-error "references internal linkage entity" }
+  internal();
+}
+  };
+  return X{};
+}
+
+// { dg-prune-output "failed to write compiled module"

[gcc r14-9439] c++: Support target-specific nodes when streaming modules [PR111224]

2024-03-12 Thread Nathaniel Shead via Gcc-cvs
https://gcc.gnu.org/g:4aa87b856067d4911de8fb66b3a27659dc75ca6d

commit r14-9439-g4aa87b856067d4911de8fb66b3a27659dc75ca6d
Author: Nathaniel Shead 
Date:   Sun Mar 10 22:06:18 2024 +1100

c++: Support target-specific nodes when streaming modules [PR111224]

Some targets make use of POLY_INT_CSTs and other custom builtin types,
which currently violate some assumptions when streaming. This patch adds
support for them, such as types like Aarch64 __fp16, PowerPC __ibm128,
and vector types thereof.

This patch doesn't provide "full" support of AArch64 SVE, however, since
for that we would need to support 'target' nodes (tracked in PR108080).

Adding the new builtin types means that on Aarch64 we now have 217
global trees created on initialisation (up from 191), so this patch also
slightly bumps the initial size of the fixed_trees allocation to 250.

PR c++/98645
PR c++/98688
PR c++/111224

gcc/cp/ChangeLog:

* module.cc (enum tree_tag): Add new tag for builtin types.
(trees_out::start): POLY_INT_CSTs can be emitted.
(trees_in::start): Likewise.
(trees_out::core_vals): Stream POLY_INT_CSTs.
(trees_in::core_vals): Likewise.
(trees_out::type_node): Handle vectors with multiple coeffs.
(trees_in::tree_node): Likewise.
(init_modules): Register target-specific builtin types. Bump
initial capacity slightly.

gcc/testsuite/ChangeLog:

* g++.dg/modules/target-aarch64-1_a.C: New test.
* g++.dg/modules/target-aarch64-1_b.C: New test.
* g++.dg/modules/target-powerpc-1_a.C: New test.
* g++.dg/modules/target-powerpc-1_b.C: New test.
* g++.dg/modules/target-powerpc-2_a.C: New test.
* g++.dg/modules/target-powerpc-2_b.C: New test.

Signed-off-by: Nathaniel Shead 
Reviewed-by: Patrick Palka 

Diff:
---
 gcc/cp/module.cc  | 32 ---
 gcc/testsuite/g++.dg/modules/target-aarch64-1_a.C | 17 
 gcc/testsuite/g++.dg/modules/target-aarch64-1_b.C | 13 +
 gcc/testsuite/g++.dg/modules/target-powerpc-1_a.C |  7 +
 gcc/testsuite/g++.dg/modules/target-powerpc-1_b.C | 10 +++
 gcc/testsuite/g++.dg/modules/target-powerpc-2_a.C | 20 ++
 gcc/testsuite/g++.dg/modules/target-powerpc-2_b.C | 12 +
 7 files changed, 101 insertions(+), 10 deletions(-)

diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index 99055523d91..8aab9ea0bae 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -5173,7 +5173,6 @@ trees_out::start (tree t, bool code_streamed)
   break;
 
 case FIXED_CST:
-case POLY_INT_CST:
   gcc_unreachable (); /* Not supported in C++.  */
   break;
 
@@ -5259,7 +5258,6 @@ trees_in::start (unsigned code)
 
 case FIXED_CST:
 case IDENTIFIER_NODE:
-case POLY_INT_CST:
 case SSA_NAME:
 case TARGET_MEM_REF:
 case TRANSLATION_UNIT_DECL:
@@ -6106,7 +6104,10 @@ trees_out::core_vals (tree t)
   break;
 
 case POLY_INT_CST:
-  gcc_unreachable (); /* Not supported in C++.  */
+  if (streaming_p ())
+   for (unsigned ix = 0; ix != NUM_POLY_INT_COEFFS; ix++)
+ WT (POLY_INT_CST_COEFF (t, ix));
+  break;
 
 case REAL_CST:
   if (streaming_p ())
@@ -6615,8 +6616,9 @@ trees_in::core_vals (tree t)
   break;
 
 case POLY_INT_CST:
-  /* Not suported in C++.  */
-  return false;
+  for (unsigned ix = 0; ix != NUM_POLY_INT_COEFFS; ix++)
+   RT (POLY_INT_CST_COEFF (t, ix));
+  break;
 
 case REAL_CST:
   if (const void *bytes = buf (sizeof (real_value)))
@@ -9068,8 +9070,8 @@ trees_out::type_node (tree type)
   if (streaming_p ())
{
  poly_uint64 nunits = TYPE_VECTOR_SUBPARTS (type);
- /* to_constant asserts that only coeff[0] is of interest.  */
- wu (static_cast (nunits.to_constant ()));
+ for (unsigned ix = 0; ix != NUM_POLY_INT_COEFFS; ix++)
+   wu (nunits.coeffs[ix]);
}
   break;
 }
@@ -9630,9 +9632,11 @@ trees_in::tree_node (bool is_use)
 
  case VECTOR_TYPE:
{
- unsigned HOST_WIDE_INT nunits = wu ();
+ poly_uint64 nunits;
+ for (unsigned ix = 0; ix != NUM_POLY_INT_COEFFS; ix++)
+   nunits.coeffs[ix] = wu ();
  if (!get_overrun ())
-   res = build_vector_type (res, static_cast (nunits));
+   res = build_vector_type (res, nunits);
}
break;
  }
@@ -20151,7 +20155,7 @@ init_modules (cpp_reader *reader)
  some global trees are lazily created and we don't want that to
  mess with our syndrome of fixed trees.  */
   unsigned crc = 0;
-  vec_alloc (fixed_trees, 200);
+  vec_alloc (fixed_trees, 250);
 
   dump () && dump ("+Creating globals");
 

[gcc r14-9375] c++: Redetermine whether to write vtables on stream-in [PR114229]

2024-03-07 Thread Nathaniel Shead via Gcc-cvs
https://gcc.gnu.org/g:9ccd03dee4c35a24c6699a58a7251a5277a91cf5

commit r14-9375-g9ccd03dee4c35a24c6699a58a7251a5277a91cf5
Author: Nathaniel Shead 
Date:   Thu Mar 7 23:09:03 2024 +1100

c++: Redetermine whether to write vtables on stream-in [PR114229]

We currently always stream DECL_INTERFACE_KNOWN, which is needed since
many kinds of declarations already have their interface determined at
parse time.  But for vtables and type-info declarations we need to
re-evaluate on stream-in as whether they need to be emitted or not
changes in each TU, so this patch clears DECL_INTERFACE_KNOWN on these
kinds of declarations so that they can go through 'import_export_decl'
again.

Note that the precise details of the virt-2 tests will need to change
when we implement the resolution of [1], for now I just updated the test
to not fail with the new (current) semantics.

[1]: https://github.com/itanium-cxx-abi/cxx-abi/pull/171

PR c++/114229

gcc/cp/ChangeLog:

* module.cc (trees_out::core_bools): Redetermine
DECL_INTERFACE_KNOWN on stream-in for vtables and tinfo.
* decl2.cc (import_export_decl): Add fixme for ABI changes with
module vtables and tinfo.

gcc/testsuite/ChangeLog:

* g++.dg/modules/virt-2_b.C: Update test to acknowledge that we
now emit vtables here too.
* g++.dg/modules/virt-3_a.C: New test.
* g++.dg/modules/virt-3_b.C: New test.
* g++.dg/modules/virt-3_c.C: New test.
* g++.dg/modules/virt-3_d.C: New test.

Signed-off-by: Nathaniel Shead 

Diff:
---
 gcc/cp/decl2.cc |  4 
 gcc/cp/module.cc| 12 +++-
 gcc/testsuite/g++.dg/modules/virt-2_b.C |  5 ++---
 gcc/testsuite/g++.dg/modules/virt-3_a.C |  9 +
 gcc/testsuite/g++.dg/modules/virt-3_b.C |  6 ++
 gcc/testsuite/g++.dg/modules/virt-3_c.C |  3 +++
 gcc/testsuite/g++.dg/modules/virt-3_d.C |  7 +++
 7 files changed, 42 insertions(+), 4 deletions(-)

diff --git a/gcc/cp/decl2.cc b/gcc/cp/decl2.cc
index 1dddbaab38b..6c9fd415d40 100644
--- a/gcc/cp/decl2.cc
+++ b/gcc/cp/decl2.cc
@@ -3398,6 +3398,10 @@ import_export_decl (tree decl)
  unit.  */
   import_p = false;
 
+  /* FIXME: Since https://github.com/itanium-cxx-abi/cxx-abi/pull/171,
+ the ABI specifies that classes attached to named modules should
+ have their vtables uniquely emitted in the object for the module
+ unit in which it is defined.  And similarly for RTTI structures.  */
   if (VAR_P (decl) && DECL_VTABLE_OR_VTT_P (decl))
 {
   class_type = DECL_CONTEXT (decl);
diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index 53104753737..99055523d91 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -5376,7 +5376,17 @@ trees_out::core_bools (tree t)
   WB (t->decl_common.lang_flag_2);
   WB (t->decl_common.lang_flag_3);
   WB (t->decl_common.lang_flag_4);
-  WB (t->decl_common.lang_flag_5);
+
+  {
+   /* This is DECL_INTERFACE_KNOWN: We should redetermine whether
+  we need to import or export any vtables or typeinfo objects
+  on stream-in.  */
+   bool interface_known = t->decl_common.lang_flag_5;
+   if (VAR_P (t) && (DECL_VTABLE_OR_VTT_P (t) || DECL_TINFO_P (t)))
+ interface_known = false;
+   WB (interface_known);
+  }
+
   WB (t->decl_common.lang_flag_6);
   WB (t->decl_common.lang_flag_7);
   WB (t->decl_common.lang_flag_8);
diff --git a/gcc/testsuite/g++.dg/modules/virt-2_b.C 
b/gcc/testsuite/g++.dg/modules/virt-2_b.C
index e041f0721f9..2bc5eced013 100644
--- a/gcc/testsuite/g++.dg/modules/virt-2_b.C
+++ b/gcc/testsuite/g++.dg/modules/virt-2_b.C
@@ -21,8 +21,7 @@ int main ()
   return !(Visit (&me) == 1);
 }
 
-// We do not emit Visitor vtable
-// but we do emit rtti here
-// { dg-final { scan-assembler-not {_ZTVW3foo7Visitor:} } }
+// Again, we emit Visitor vtable and rtti here
+// { dg-final { scan-assembler {_ZTVW3foo7Visitor:} } }
 // { dg-final { scan-assembler {_ZTIW3foo7Visitor:} } }
 // { dg-final { scan-assembler {_ZTSW3foo7Visitor:} } }
diff --git a/gcc/testsuite/g++.dg/modules/virt-3_a.C 
b/gcc/testsuite/g++.dg/modules/virt-3_a.C
new file mode 100644
index 000..a7eae7f9d35
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/virt-3_a.C
@@ -0,0 +1,9 @@
+// PR c++/114229
+// { dg-additional-options "-fmodules-ts -Wno-global-module" }
+// { dg-module-cmi modA }
+
+module;
+template struct basic_streambuf { virtual void overflow() { } };
+extern template struct basic_streambuf;
+export module modA;
+export basic_streambuf *p;
diff --git a/gcc/testsuite/g++.dg/modules/virt-3_b.C 
b/gcc/testsuite/g++.dg/modules/virt-3_b.C
new file mode 100644
index 000..4d87b965bbf
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/virt-3_b.C
@@ -0,0 +1,6 @@
+// PR c++/114229
+// { dg-additional-option

[gcc r14-9357] c++: Fix ICE diagnosing incomplete type of overloaded function set [PR98356]

2024-03-07 Thread Nathaniel Shead via Gcc-cvs
https://gcc.gnu.org/g:940586a63586941a9f2b973491afc8a15a96c98b

commit r14-9357-g940586a63586941a9f2b973491afc8a15a96c98b
Author: Nathaniel Shead 
Date:   Tue Mar 5 01:59:41 2024 +1100

c++: Fix ICE diagnosing incomplete type of overloaded function set [PR98356]

In the linked PR the result of 'get_first_fn' is a USING_DECL against
the template parameter, to be filled in on instantiation. But we don't
actually need to get the first set of the member functions: it's enough
to know that we have a (possibly overloaded) member function at all.

PR c++/98356

gcc/cp/ChangeLog:

* typeck2.cc (cxx_incomplete_type_diagnostic): Don't assume
'member' will be a FUNCTION_DECL (or something like it).

gcc/testsuite/ChangeLog:

* g++.dg/pr98356.C: New test.

Signed-off-by: Nathaniel Shead 

Diff:
---
 gcc/cp/typeck2.cc  | 11 +--
 gcc/testsuite/g++.dg/pr98356.C |  9 +
 2 files changed, 14 insertions(+), 6 deletions(-)

diff --git a/gcc/cp/typeck2.cc b/gcc/cp/typeck2.cc
index 9608bdccd8b..31198b2f9f5 100644
--- a/gcc/cp/typeck2.cc
+++ b/gcc/cp/typeck2.cc
@@ -350,16 +350,15 @@ cxx_incomplete_type_diagnostic (location_t loc, 
const_tree value,
 bad_member:
   {
tree member = TREE_OPERAND (value, 1);
-   if (is_overloaded_fn (member))
- member = get_first_fn (member);
-
-   if (DECL_FUNCTION_MEMBER_P (member)
-   && ! flag_ms_extensions)
+   if (is_overloaded_fn (member) && !flag_ms_extensions)
  {
gcc_rich_location richloc (loc);
/* If "member" has no arguments (other than "this"), then
   add a fix-it hint.  */
-   if (type_num_arguments (TREE_TYPE (member)) == 1)
+   member = MAYBE_BASELINK_FUNCTIONS (member);
+   if (TREE_CODE (member) == FUNCTION_DECL
+   && DECL_OBJECT_MEMBER_FUNCTION_P (member)
+   && type_num_arguments (TREE_TYPE (member)) == 1)
  richloc.add_fixit_insert_after ("()");
complained = emit_diagnostic (diag_kind, &richloc, 0,
 "invalid use of member function %qD "
diff --git a/gcc/testsuite/g++.dg/pr98356.C b/gcc/testsuite/g++.dg/pr98356.C
new file mode 100644
index 000..acea238593b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/pr98356.C
@@ -0,0 +1,9 @@
+// PR c++/98356
+// { dg-do compile { target c++11 } }
+
+template  class T> struct S {
+  using A = T;
+  using A::foo;
+  void foo ();
+  void bar () {foo.}  // { dg-error "invalid use of member function" }
+};


[gcc r14-9356] c++: Stream DECL_CONTEXT for template template parms [PR98881]

2024-03-07 Thread Nathaniel Shead via Gcc-cvs
https://gcc.gnu.org/g:2f8a3da8ea30066d2201f8148714a8e89da5

commit r14-9356-g2f8a3da8ea30066d2201f8148714a8e89da5
Author: Nathaniel Shead 
Date:   Tue Mar 5 15:17:09 2024 +1100

c++: Stream DECL_CONTEXT for template template parms [PR98881]

When streaming in a nested template-template parameter as in the
attached testcase, we end up reaching the containing template-template
parameter in 'tpl_parms_fini'. We should not set the DECL_CONTEXT to
this (nested) template-template parameter, as it should already be the
struct that the outer template-template parameter is declared on.

The precise logic for what DECL_CONTEXT should be for a template
template parameter in various situations seems rather obscure. Rather
than trying to determine the assumptions that need to hold, it seems
simpler to just always re-stream the DECL_CONTEXT as needed for now.

PR c++/98881

gcc/cp/ChangeLog:

* module.cc (trees_out::tpl_parms_fini): Stream out DECL_CONTEXT
for template template parameters.
(trees_in::tpl_parms_fini): Read it.

gcc/testsuite/ChangeLog:

* g++.dg/modules/tpl-tpl-parm-3.h: New test.
* g++.dg/modules/tpl-tpl-parm-3_a.H: New test.
* g++.dg/modules/tpl-tpl-parm-3_b.C: New test.
* g++.dg/modules/tpl-tpl-parm-3_c.C: New test.

Signed-off-by: Nathaniel Shead 
Reviewed-by: Patrick Palka 
Reviewed-by: Jason Merrill 

Diff:
---
 gcc/cp/module.cc| 41 ++---
 gcc/testsuite/g++.dg/modules/tpl-tpl-parm-3.h   | 12 
 gcc/testsuite/g++.dg/modules/tpl-tpl-parm-3_a.H |  5 +++
 gcc/testsuite/g++.dg/modules/tpl-tpl-parm-3_b.C |  5 +++
 gcc/testsuite/g++.dg/modules/tpl-tpl-parm-3_c.C | 15 +
 5 files changed, 47 insertions(+), 31 deletions(-)

diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index 80b63a70a62..f7e8b357fc2 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -10126,23 +10126,12 @@ trees_out::tpl_parms_fini (tree tmpl, unsigned 
tpl_levels)
  tree dflt = TREE_PURPOSE (parm);
  tree_node (dflt);
 
- if (streaming_p ())
-   {
- tree decl = TREE_VALUE (parm);
- if (TREE_CODE (decl) == TEMPLATE_DECL)
-   {
- tree ctx = DECL_CONTEXT (decl);
- tree inner = DECL_TEMPLATE_RESULT (decl);
- tree tpi = (TREE_CODE (inner) == TYPE_DECL
- ? TEMPLATE_TYPE_PARM_INDEX (TREE_TYPE (decl))
- : DECL_INITIAL (inner));
- bool original = (TEMPLATE_PARM_LEVEL (tpi)
-  == TEMPLATE_PARM_ORIG_LEVEL (tpi));
- /* Original template template parms have a context
-of their owning template.  Reduced ones do not.  */
- gcc_checking_assert (original ? ctx == tmpl : !ctx);
-   }
-   }
+ /* Template template parameters need a context of their owning
+template. This is quite tricky to infer correctly on stream-in
+(see PR c++/98881) so we'll just provide it directly.  */
+ tree decl = TREE_VALUE (parm);
+ if (TREE_CODE (decl) == TEMPLATE_DECL)
+   tree_node (DECL_CONTEXT (decl));
}
 }
 }
@@ -10160,24 +10149,14 @@ trees_in::tpl_parms_fini (tree tmpl, unsigned 
tpl_levels)
{
  tree parm = TREE_VEC_ELT (vec, ix);
  tree dflt = tree_node ();
- if (get_overrun ())
-   return false;
  TREE_PURPOSE (parm) = dflt;
 
  tree decl = TREE_VALUE (parm);
  if (TREE_CODE (decl) == TEMPLATE_DECL)
-   {
- tree inner = DECL_TEMPLATE_RESULT (decl);
- tree tpi = (TREE_CODE (inner) == TYPE_DECL
- ? TEMPLATE_TYPE_PARM_INDEX (TREE_TYPE (decl))
- : DECL_INITIAL (inner));
- bool original = (TEMPLATE_PARM_LEVEL (tpi)
-  == TEMPLATE_PARM_ORIG_LEVEL (tpi));
- /* Original template template parms have a context
-of their owning template.  Reduced ones do not.  */
- if (original)
-   DECL_CONTEXT (decl) = tmpl;
-   }
+   DECL_CONTEXT (decl) = tree_node ();
+
+ if (get_overrun ())
+   return false;
}
 }
   return true;
diff --git a/gcc/testsuite/g++.dg/modules/tpl-tpl-parm-3.h 
b/gcc/testsuite/g++.dg/modules/tpl-tpl-parm-3.h
new file mode 100644
index 000..b0dcf353c23
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/tpl-tpl-parm-3.h
@@ -0,0 +1,12 @@
+// PR c++/98881
+
+template  struct X {};
+
+template typename TT>
+struct X> {
+  template typename UU>
+  void f (X>&);
+};
+
+template class TT> struct Y;
+template class UU> struct Y { };
diff --git a/gcc/testsuite/g++.dg/modules/tpl-tp

[gcc r14-9332] c++: Fix template deduction for conversion operators with xobj parameters [PR113629]

2024-03-06 Thread Nathaniel Shead via Gcc-cvs
https://gcc.gnu.org/g:49d83e963aa453600088380aebd507e172eb80ad

commit r14-9332-g49d83e963aa453600088380aebd507e172eb80ad
Author: Nathaniel Shead 
Date:   Wed Mar 6 00:43:22 2024 +1100

c++: Fix template deduction for conversion operators with xobj parameters 
[PR113629]

Unification for conversion operators (DEDUCE_CONV) doesn't perform
transformations like handling forwarding references. This is correct in
general, but not for xobj parameters, which should be handled "normally"
for the purposes of deduction: [temp.deduct.conv] only applies to the
return type of the conversion function.

PR c++/113629

gcc/cp/ChangeLog:

* pt.cc (type_unification_real): Only use DEDUCE_CONV for the
return type of a conversion function.

gcc/testsuite/ChangeLog:

* g++.dg/cpp23/explicit-obj-conv-op.C: New test.

Signed-off-by: Nathaniel Shead 
Reviewed-by: Jason Merrill 

Diff:
---
 gcc/cp/pt.cc  | 12 +-
 gcc/testsuite/g++.dg/cpp23/explicit-obj-conv-op.C | 49 +++
 2 files changed, 60 insertions(+), 1 deletion(-)

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index c4bc54a8fdb..a6e6c804130 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -23312,10 +23312,18 @@ type_unification_real (tree tparms,
   parameter pack is a non-deduced context.  */
continue;
 
+  /* [temp.deduct.conv] only applies to the deduction of the return
+type, which is always the first argument here.  Other arguments
+(notably, explicit object parameters) should undergo normal
+call-like unification.  */
+  unification_kind_t kind = strict;
+  if (strict == DEDUCE_CONV && ia > 0)
+   kind = DEDUCE_CALL;
+
   arg = args[ia];
   ++ia;
 
-  if (unify_one_argument (tparms, full_targs, parm, arg, subr, strict,
+  if (unify_one_argument (tparms, full_targs, parm, arg, subr, kind,
  explain_p))
return 1;
 }
@@ -23324,6 +23332,8 @@ type_unification_real (tree tparms,
   && parms != void_list_node
   && TREE_CODE (TREE_VALUE (parms)) == TYPE_PACK_EXPANSION)
 {
+  gcc_assert (strict != DEDUCE_CONV);
+
   /* Unify the remaining arguments with the pack expansion type.  */
   tree argvec;
   tree parmvec = make_tree_vec (1);
diff --git a/gcc/testsuite/g++.dg/cpp23/explicit-obj-conv-op.C 
b/gcc/testsuite/g++.dg/cpp23/explicit-obj-conv-op.C
new file mode 100644
index 000..a6ae4ea1dda
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp23/explicit-obj-conv-op.C
@@ -0,0 +1,49 @@
+// PR c++/113629
+// { dg-do compile { target c++23 } }
+
+template  constexpr bool is_lvalue = false;
+template  constexpr bool is_lvalue = true;
+
+struct A {
+  constexpr operator bool(this auto&& self) {
+return is_lvalue;
+  }
+};
+
+constexpr A a;
+static_assert(static_cast(a));
+static_assert((bool)a);
+static_assert(!static_cast(A{}));
+static_assert(!(bool)A{});
+
+struct B : A {};
+
+constexpr B b;
+static_assert(static_cast(b));
+static_assert((bool)b);
+static_assert(!static_cast(B{}));
+static_assert(!(bool)B{});
+
+struct C {
+  template 
+  explicit constexpr operator R(this T&&) {
+return is_lvalue;
+  }
+};
+
+constexpr C c;
+static_assert(static_cast(c));
+static_assert((bool)c);
+static_assert(!static_cast(C{}));
+static_assert(!(bool)C{});
+
+struct D {
+  explicit constexpr operator bool(this const D&) { return true; }
+  explicit constexpr operator bool(this const D&&) { return false; }
+};
+
+constexpr D d;
+static_assert(static_cast(d));
+static_assert((bool)d);
+static_assert(!static_cast(D{}));
+static_assert(!(bool)D{});