public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] Fix ICE with mangling aliases (PR c++/67354)
@ 2015-11-18  8:52 Jakub Jelinek
  2015-11-18 21:22 ` Jason Merrill
  0 siblings, 1 reply; 5+ messages in thread
From: Jakub Jelinek @ 2015-11-18  8:52 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches

Hi!

This is an attempt to fix an ICE on the following testcase.
Normally (when !at_eof), note_mangling_alias just queues up the mangling
aliases in a vector, but when maybe_thunk_body is called at_eof,
it calls cdtor_comdat_group which mangles first the names of both the
fns to determine the name of the comdat group, and as it is at_eof,
it emits the mangling aliases right away.  That means the base ctor is
put into one same_comdat_group (together with its mangling alias),
and comp ctor into a different same_comdat_group.  Then a few lines later
we want to put the base ctor as same body alias with the comp ctor, but ICE,
because the two are already having non-NULL same_comdat_group.
The patch in this case temporarily queues up the mangling aliases in the
vector and only after putting the two ctors into the same comdat group
adds the mangling aliases.
If changing at_eof for this is too big hack, perhaps we could have a
different bool just to affect the mangling aliases (and set it to true
in generate_mangling_aliases or so).

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk/5.3?

2015-11-18  Jakub Jelinek  <jakub@redhat.com>

	PR c++/67354
	* cp-tree.h (generate_mangling_aliases): New prototype.
	* decl2.c (generate_mangling_aliases): No longer static.
	* optimize.c (maybe_thunk_body): Defer emitting mangling aliases
	if at_eof until the fns are put into the same comdat group.

	* g++.dg/abi/mangle67.C: New test.

--- gcc/cp/cp-tree.h.jj	2015-11-14 19:35:53.000000000 +0100
+++ gcc/cp/cp-tree.h	2015-11-16 15:58:44.143844060 +0100
@@ -5772,6 +5772,7 @@ extern tree cxx_maybe_build_cleanup		(tr
 
 /* in decl2.c */
 extern void note_mangling_alias			(tree, tree);
+extern void generate_mangling_aliases		(void);
 extern bool check_java_method			(tree);
 extern tree build_memfn_type			(tree, tree, cp_cv_quals, cp_ref_qualifier);
 extern tree build_pointer_ptrmemfn_type	(tree);
--- gcc/cp/decl2.c.jj	2015-11-14 19:35:53.000000000 +0100
+++ gcc/cp/decl2.c	2015-11-16 15:58:09.944330046 +0100
@@ -4399,7 +4399,7 @@ note_mangling_alias (tree decl ATTRIBUTE
 #endif
 }
 
-static void
+void
 generate_mangling_aliases ()
 {
   while (!vec_safe_is_empty (mangling_aliases))
--- gcc/cp/optimize.c.jj	2015-11-14 19:35:53.000000000 +0100
+++ gcc/cp/optimize.c	2015-11-16 16:01:56.467111088 +0100
@@ -270,7 +270,11 @@ maybe_thunk_body (tree fn, bool force)
     }
   else if (HAVE_COMDAT_GROUP)
     {
+      /* Avoid creating mangling aliases if at_eof.  */
+      int save_at_eof = at_eof;
+      at_eof = 0;
       tree comdat_group = cdtor_comdat_group (fns[1], fns[0]);
+      at_eof = save_at_eof;
       cgraph_node::get_create (fns[0])->set_comdat_group (comdat_group);
       cgraph_node::get_create (fns[1])->add_to_same_comdat_group
 	(cgraph_node::get_create (fns[0]));
@@ -281,6 +285,9 @@ maybe_thunk_body (tree fn, bool force)
 	   virtual, it goes into the same comdat group as well.  */
 	cgraph_node::get_create (fns[2])->add_to_same_comdat_group
 	  (symtab_node::get (fns[0]));
+      /* Emit them now that the thunks are same comdat group aliases.  */
+      if (save_at_eof)
+	generate_mangling_aliases ();
       TREE_PUBLIC (fn) = false;
       DECL_EXTERNAL (fn) = false;
       DECL_INTERFACE_KNOWN (fn) = true;
--- gcc/testsuite/g++.dg/abi/mangle67.C.jj	2015-11-16 16:07:05.614620070 +0100
+++ gcc/testsuite/g++.dg/abi/mangle67.C	2015-11-16 16:06:35.000000000 +0100
@@ -0,0 +1,21 @@
+// PR c++/67354
+// { dg-do compile { target c++11 } }
+// { dg-options "-fabi-version=5 -Os" }
+
+class A
+{
+};
+
+template <typename T>
+void
+foo ()
+{
+  T ();
+}
+
+struct B : virtual A
+{
+  template <typename...> B () {}
+};
+
+auto f = foo<B>;

	Jakub

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] Fix ICE with mangling aliases (PR c++/67354)
  2015-11-18  8:52 [PATCH] Fix ICE with mangling aliases (PR c++/67354) Jakub Jelinek
@ 2015-11-18 21:22 ` Jason Merrill
  2015-11-19 12:40   ` [PATCH] Fix ICE with mangling aliases (PR c++/67354, take 2) Jakub Jelinek
  0 siblings, 1 reply; 5+ messages in thread
From: Jason Merrill @ 2015-11-18 21:22 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: gcc-patches

On 11/18/2015 03:52 AM, Jakub Jelinek wrote:
> If changing at_eof for this is too big hack, perhaps we could have a
> different bool just to affect the mangling aliases (and set it to true
> in generate_mangling_aliases or so).

Let's do that.

Jason

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH] Fix ICE with mangling aliases (PR c++/67354, take 2)
  2015-11-18 21:22 ` Jason Merrill
@ 2015-11-19 12:40   ` Jakub Jelinek
  2015-11-19 20:04     ` Jason Merrill
  0 siblings, 1 reply; 5+ messages in thread
From: Jakub Jelinek @ 2015-11-19 12:40 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches

On Wed, Nov 18, 2015 at 04:22:21PM -0500, Jason Merrill wrote:
> On 11/18/2015 03:52 AM, Jakub Jelinek wrote:
> >If changing at_eof for this is too big hack, perhaps we could have a
> >different bool just to affect the mangling aliases (and set it to true
> >in generate_mangling_aliases or so).
> 
> Let's do that.

Here it is.  Bootstrapped/regtested on x86_64-linux and i686-linux, ok for
trunk/5.3?

2015-11-19  Jakub Jelinek  <jakub@redhat.com>

	PR c++/67354
	* cp-tree.h (defer_mangling_aliases): Declare.
	(generate_mangling_aliases): New prototype.
	* decl2.c (defer_mangling_aliases): New variable.
	(note_mangling_alias): Use !defer_mangling_aliases
	instead of at_eof.
	(generate_mangling_aliases): No longer static.
	(c_parse_final_cleanups): Clear defer_mangling_aliases.
	* optimize.c (maybe_thunk_body): Defer emitting mangling aliases
	if !defer_mangling_aliases until the fns are put into the same
	comdat group.

	* g++.dg/abi/mangle67.C: New test.

--- gcc/cp/cp-tree.h.jj	2015-11-18 11:19:20.956770209 +0100
+++ gcc/cp/cp-tree.h	2015-11-19 09:58:00.355009161 +0100
@@ -4842,6 +4842,11 @@ extern GTY(()) vec<tree, va_gc> *local_c
 
 extern int at_eof;
 
+/* True if note_mangling_alias should enqueue mangling aliases for
+   later generation, rather than emitting them right away.  */
+
+extern bool defer_mangling_aliases;
+
 /* A list of namespace-scope objects which have constructors or
    destructors which reside in the global scope.  The decl is stored
    in the TREE_VALUE slot and the initializer is stored in the
@@ -5768,6 +5773,7 @@ extern tree cxx_maybe_build_cleanup		(tr
 
 /* in decl2.c */
 extern void note_mangling_alias			(tree, tree);
+extern void generate_mangling_aliases		(void);
 extern bool check_java_method			(tree);
 extern tree build_memfn_type			(tree, tree, cp_cv_quals, cp_ref_qualifier);
 extern tree build_pointer_ptrmemfn_type	(tree);
--- gcc/cp/decl2.c.jj	2015-11-18 11:19:12.866884363 +0100
+++ gcc/cp/decl2.c	2015-11-19 10:12:24.423695746 +0100
@@ -102,6 +102,11 @@ static GTY(()) vec<tree, va_gc> *manglin
 /* Nonzero if we're done parsing and into end-of-file activities.  */
 
 int at_eof;
+
+/* True if note_mangling_alias should enqueue mangling aliases for
+   later generation, rather than emitting them right away.  */
+
+bool defer_mangling_aliases = true;
 \f
 
 /* Return a member function type (a METHOD_TYPE), given FNTYPE (a
@@ -4389,7 +4394,7 @@ void
 note_mangling_alias (tree decl ATTRIBUTE_UNUSED, tree id2 ATTRIBUTE_UNUSED)
 {
 #ifdef ASM_OUTPUT_DEF
-  if (at_eof)
+  if (!defer_mangling_aliases)
     generate_mangling_alias (decl, id2);
   else
     {
@@ -4399,7 +4404,9 @@ note_mangling_alias (tree decl ATTRIBUTE
 #endif
 }
 
-static void
+/* Emit all mangling aliases that were deferred up to this point.  */
+
+void
 generate_mangling_aliases ()
 {
   while (!vec_safe_is_empty (mangling_aliases))
@@ -4502,6 +4509,7 @@ c_parse_final_cleanups (void)
 
   locus_at_end_of_parsing = input_location;
   at_eof = 1;
+  defer_mangling_aliases = false;
 
   /* Bad parse errors.  Just forget about it.  */
   if (! global_bindings_p () || current_class_type
--- gcc/cp/optimize.c.jj	2015-11-18 11:19:12.935883389 +0100
+++ gcc/cp/optimize.c	2015-11-19 10:12:24.423695746 +0100
@@ -270,7 +270,11 @@ maybe_thunk_body (tree fn, bool force)
     }
   else if (HAVE_COMDAT_GROUP)
     {
+      /* At eof, defer creation of mangling aliases temporarily.  */
+      bool save_defer_mangling_aliases = defer_mangling_aliases;
+      defer_mangling_aliases = true;
       tree comdat_group = cdtor_comdat_group (fns[1], fns[0]);
+      defer_mangling_aliases = save_defer_mangling_aliases;
       cgraph_node::get_create (fns[0])->set_comdat_group (comdat_group);
       cgraph_node::get_create (fns[1])->add_to_same_comdat_group
 	(cgraph_node::get_create (fns[0]));
@@ -281,6 +285,9 @@ maybe_thunk_body (tree fn, bool force)
 	   virtual, it goes into the same comdat group as well.  */
 	cgraph_node::get_create (fns[2])->add_to_same_comdat_group
 	  (symtab_node::get (fns[0]));
+      /* Emit them now that the thunks are same comdat group aliases.  */
+      if (!save_defer_mangling_aliases)
+	generate_mangling_aliases ();
       TREE_PUBLIC (fn) = false;
       DECL_EXTERNAL (fn) = false;
       DECL_INTERFACE_KNOWN (fn) = true;
--- gcc/testsuite/g++.dg/abi/mangle67.C.jj	2015-11-19 09:54:51.644701162 +0100
+++ gcc/testsuite/g++.dg/abi/mangle67.C	2015-11-19 09:54:51.644701162 +0100
@@ -0,0 +1,21 @@
+// PR c++/67354
+// { dg-do compile { target c++11 } }
+// { dg-options "-fabi-version=5 -Os" }
+
+class A
+{
+};
+
+template <typename T>
+void
+foo ()
+{
+  T ();
+}
+
+struct B : virtual A
+{
+  template <typename...> B () {}
+};
+
+auto f = foo<B>;


	Jakub

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] Fix ICE with mangling aliases (PR c++/67354, take 2)
  2015-11-19 12:40   ` [PATCH] Fix ICE with mangling aliases (PR c++/67354, take 2) Jakub Jelinek
@ 2015-11-19 20:04     ` Jason Merrill
  2015-11-23 13:52       ` [5 PATCH] Fix ICE with mangling aliases (PR c++/67354) Jakub Jelinek
  0 siblings, 1 reply; 5+ messages in thread
From: Jason Merrill @ 2015-11-19 20:04 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: gcc-patches

On 11/19/2015 07:40 AM, Jakub Jelinek wrote:
> @@ -4502,6 +4509,7 @@ c_parse_final_cleanups (void)
>
>     locus_at_end_of_parsing = input_location;
>     at_eof = 1;
> +  defer_mangling_aliases = false;

Let's clear this in generate_mangling_aliases rather than here.  OK with 
that change.

Jason

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [5 PATCH] Fix ICE with mangling aliases (PR c++/67354)
  2015-11-19 20:04     ` Jason Merrill
@ 2015-11-23 13:52       ` Jakub Jelinek
  0 siblings, 0 replies; 5+ messages in thread
From: Jakub Jelinek @ 2015-11-23 13:52 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches

Hi!

On Thu, Nov 19, 2015 at 03:04:35PM -0500, Jason Merrill wrote:
> On 11/19/2015 07:40 AM, Jakub Jelinek wrote:
> >@@ -4502,6 +4509,7 @@ c_parse_final_cleanups (void)
> >
> >    locus_at_end_of_parsing = input_location;
> >    at_eof = 1;
> >+  defer_mangling_aliases = false;
> 
> Let's clear this in generate_mangling_aliases rather than here.  OK with
> that change.

Unfortunately, the GCC 5.3 backport of this is larger, because it relies
on the deferring of the mangling aliases that has been added during the
early debug efforts.  Still, it looks to me small enough.
Bootstrapped/regtested on GCC 5 branch on x86_64-linux and i686-linux, ok
for branch?

2015-11-23  Jakub Jelinek  <jakub@redhat.com>

	Backported from mainline
	2015-11-20  Jakub Jelinek  <jakub@redhat.com>

	PR c++/67354
	* cp-tree.h (defer_mangling_aliases): Declare.
	(generate_mangling_aliases): New prototype.
	* decl2.c (defer_mangling_aliases): New variable.
	(note_mangling_alias): Use !defer_mangling_aliases
	instead of at_eof.
	(generate_mangling_aliases): No longer static. Clear
	defer_mangling_aliases.
	* optimize.c (maybe_thunk_body): Defer emitting mangling aliases
	if !defer_mangling_aliases until the fns are put into the same
	comdat group.

	* g++.dg/abi/mangle67.C: New test.

	2015-05-09  Aldy Hernandez  <aldyh@redhat.com>

	PR bootstrap/66085
	* decl2.c (note_mangling_alias): Declare arguments as unused.

	2015-05-08  Jason Merrill  <jason@redhat.com>

	* decl2.c (mangling_aliases): New variable.
	(note_mangling_alias, generate_mangling_aliases): New.
	(cp_write_global_declarations): Call generate_mangling_aliases.
	(generate_mangling_alias): Split out from...
	* mangle.c (mangle_decl): ...here.
	* cp-tree.h: Declare note_mangling_alias.

--- gcc/cp/cp-tree.h.jj	2015-11-20 10:12:02.917358200 +0100
+++ gcc/cp/cp-tree.h	2015-11-23 10:42:12.707937270 +0100
@@ -4606,6 +4606,11 @@ extern GTY(()) vec<tree, va_gc> *local_c
 
 extern int at_eof;
 
+/* True if note_mangling_alias should enqueue mangling aliases for
+   later generation, rather than emitting them right away.  */
+
+extern bool defer_mangling_aliases;
+
 /* A list of namespace-scope objects which have constructors or
    destructors which reside in the global scope.  The decl is stored
    in the TREE_VALUE slot and the initializer is stored in the
@@ -5453,6 +5458,8 @@ extern tree finish_case_label			(locatio
 extern tree cxx_maybe_build_cleanup		(tree, tsubst_flags_t);
 
 /* in decl2.c */
+extern void note_mangling_alias			(tree, tree);
+extern void generate_mangling_aliases		(void);
 extern bool check_java_method			(tree);
 extern tree build_memfn_type			(tree, tree, cp_cv_quals, cp_ref_qualifier);
 extern tree build_pointer_ptrmemfn_type	(tree);
--- gcc/cp/mangle.c.jj	2015-09-04 20:33:01.456531377 +0200
+++ gcc/cp/mangle.c	2015-11-23 10:37:30.668926382 +0100
@@ -3584,30 +3584,7 @@ mangle_decl (const tree decl)
 		     flag_abi_compat_version, id2);
 	}
 
-#ifdef ASM_OUTPUT_DEF
-      /* If there's a declaration already using this mangled name,
-	 don't create a compatibility alias that conflicts.  */
-      if (IDENTIFIER_GLOBAL_VALUE (id2))
-	return;
-
-      struct cgraph_node *n = NULL;
-      if (TREE_CODE (decl) == FUNCTION_DECL
-	  && !(n = cgraph_node::get (decl)))
-	/* Don't create an alias to an unreferenced function.  */
-	return;
-
-      tree alias = make_alias_for (decl, id2);
-      SET_IDENTIFIER_GLOBAL_VALUE (id2, alias);
-      DECL_IGNORED_P (alias) = 1;
-      TREE_PUBLIC (alias) = TREE_PUBLIC (decl);
-      DECL_VISIBILITY (alias) = DECL_VISIBILITY (decl);
-      if (vague_linkage_p (decl))
-	DECL_WEAK (alias) = 1;
-      if (TREE_CODE (decl) == FUNCTION_DECL)
-	n->create_same_body_alias (alias, decl);
-      else
-	varpool_node::create_extra_name_alias (alias, decl);
-#endif
+      note_mangling_alias (decl, id2);
     }
 }
 
--- gcc/cp/optimize.c.jj	2015-11-20 10:12:02.941357861 +0100
+++ gcc/cp/optimize.c	2015-11-23 10:42:12.709937242 +0100
@@ -294,7 +294,11 @@ maybe_thunk_body (tree fn, bool force)
     }
   else if (HAVE_COMDAT_GROUP)
     {
+      /* At eof, defer creation of mangling aliases temporarily.  */
+      bool save_defer_mangling_aliases = defer_mangling_aliases;
+      defer_mangling_aliases = true;
       tree comdat_group = cdtor_comdat_group (fns[1], fns[0]);
+      defer_mangling_aliases = save_defer_mangling_aliases;
       cgraph_node::get_create (fns[0])->set_comdat_group (comdat_group);
       cgraph_node::get_create (fns[1])->add_to_same_comdat_group
 	(cgraph_node::get_create (fns[0]));
@@ -305,6 +309,9 @@ maybe_thunk_body (tree fn, bool force)
 	   virtual, it goes into the same comdat group as well.  */
 	cgraph_node::get_create (fns[2])->add_to_same_comdat_group
 	  (symtab_node::get (fns[0]));
+      /* Emit them now that the thunks are same comdat group aliases.  */
+      if (!save_defer_mangling_aliases)
+	generate_mangling_aliases ();
       TREE_PUBLIC (fn) = false;
       DECL_EXTERNAL (fn) = false;
       DECL_INTERFACE_KNOWN (fn) = true;
--- gcc/cp/decl2.c.jj	2015-11-20 10:12:02.926358073 +0100
+++ gcc/cp/decl2.c	2015-11-23 10:42:12.709937242 +0100
@@ -118,9 +118,18 @@ static GTY(()) vec<tree, va_gc> *deferre
    sure are defined.  */
 static GTY(()) vec<tree, va_gc> *no_linkage_decls;
 
+/* A vector of alternating decls and identifiers, where the latter
+   is to be an alias for the former if the former is defined.  */
+static GTY(()) vec<tree, va_gc> *mangling_aliases;
+
 /* Nonzero if we're done parsing and into end-of-file activities.  */
 
 int at_eof;
+
+/* True if note_mangling_alias should enqueue mangling aliases for
+   later generation, rather than emitting them right away.  */
+
+bool defer_mangling_aliases = true;
 \f
 
 /* Return a member function type (a METHOD_TYPE), given FNTYPE (a
@@ -4327,6 +4336,69 @@ handle_tls_init (void)
   expand_or_defer_fn (finish_function (0));
 }
 
+/* We're at the end of compilation, so generate any mangling aliases that
+   we've been saving up, if DECL is going to be output and ID2 isn't
+   already taken by another declaration.  */
+
+static void
+generate_mangling_alias (tree decl, tree id2)
+{
+  /* If there's a declaration already using this mangled name,
+     don't create a compatibility alias that conflicts.  */
+  if (IDENTIFIER_GLOBAL_VALUE (id2))
+    return;
+
+  struct cgraph_node *n = NULL;
+  if (TREE_CODE (decl) == FUNCTION_DECL
+      && !(n = cgraph_node::get (decl)))
+    /* Don't create an alias to an unreferenced function.  */
+    return;
+
+  tree alias = make_alias_for (decl, id2);
+  SET_IDENTIFIER_GLOBAL_VALUE (id2, alias);
+  DECL_IGNORED_P (alias) = 1;
+  TREE_PUBLIC (alias) = TREE_PUBLIC (decl);
+  DECL_VISIBILITY (alias) = DECL_VISIBILITY (decl);
+  if (vague_linkage_p (decl))
+    DECL_WEAK (alias) = 1;
+  if (TREE_CODE (decl) == FUNCTION_DECL)
+    n->create_same_body_alias (alias, decl);
+  else
+    varpool_node::create_extra_name_alias (alias, decl);
+}
+
+/* Note that we might want to emit an alias with the symbol ID2 for DECL at
+   the end of translation, for compatibility across bugs in the mangling
+   implementation.  */
+
+void
+note_mangling_alias (tree decl ATTRIBUTE_UNUSED, tree id2 ATTRIBUTE_UNUSED)
+{
+#ifdef ASM_OUTPUT_DEF
+  if (!defer_mangling_aliases)
+    generate_mangling_alias (decl, id2);
+  else
+    {
+      vec_safe_push (mangling_aliases, decl);
+      vec_safe_push (mangling_aliases, id2);
+    }
+#endif
+}
+
+/* Emit all mangling aliases that were deferred up to this point.  */
+
+void
+generate_mangling_aliases ()
+{
+  while (!vec_safe_is_empty (mangling_aliases))
+    {
+      tree id2 = mangling_aliases->pop();
+      tree decl = mangling_aliases->pop();
+      generate_mangling_alias (decl, id2);
+    }
+  defer_mangling_aliases = false;
+}
+
 /* The entire file is now complete.  If requested, dump everything
    to a file.  */
 
@@ -4688,6 +4760,8 @@ cp_write_global_declarations (void)
     }
   while (reconsider);
 
+  generate_mangling_aliases ();
+
   /* All used inline functions must have a definition at this point.  */
   FOR_EACH_VEC_SAFE_ELT (deferred_fns, i, decl)
     {
--- gcc/testsuite/g++.dg/abi/mangle67.C.jj	2015-11-23 10:42:21.936807654 +0100
+++ gcc/testsuite/g++.dg/abi/mangle67.C	2015-11-23 10:42:12.710937228 +0100
@@ -0,0 +1,21 @@
+// PR c++/67354
+// { dg-do compile { target c++11 } }
+// { dg-options "-fabi-version=5 -Os" }
+
+class A
+{
+};
+
+template <typename T>
+void
+foo ()
+{
+  T ();
+}
+
+struct B : virtual A
+{
+  template <typename...> B () {}
+};
+
+auto f = foo<B>;


	Jakub

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2015-11-23 13:47 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-11-18  8:52 [PATCH] Fix ICE with mangling aliases (PR c++/67354) Jakub Jelinek
2015-11-18 21:22 ` Jason Merrill
2015-11-19 12:40   ` [PATCH] Fix ICE with mangling aliases (PR c++/67354, take 2) Jakub Jelinek
2015-11-19 20:04     ` Jason Merrill
2015-11-23 13:52       ` [5 PATCH] Fix ICE with mangling aliases (PR c++/67354) Jakub Jelinek

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).