SOURCES: compat-gcc-34-cxxabi.patch (NEW), compat-gcc-34-pr-rh.patch (NEW) ...
arekm
arekm at pld-linux.org
Tue Aug 5 00:59:28 CEST 2008
Author: arekm Date: Mon Aug 4 22:59:28 2008 GMT
Module: SOURCES Tag: HEAD
---- Log message:
- bunch of upstream/rh fixes (taken from rh)
---- Files affected:
SOURCES:
compat-gcc-34-cxxabi.patch (NONE -> 1.1) (NEW), compat-gcc-34-pr-rh.patch (NONE -> 1.1) (NEW)
---- Diffs:
================================================================
Index: SOURCES/compat-gcc-34-cxxabi.patch
diff -u /dev/null SOURCES/compat-gcc-34-cxxabi.patch:1.1
--- /dev/null Tue Aug 5 00:59:28 2008
+++ SOURCES/compat-gcc-34-cxxabi.patch Tue Aug 5 00:59:22 2008
@@ -0,0 +1,47 @@
+2005-02-18 Richard Henderson <rth at redhat.com>
+
+ PR libstdc++/10606
+ * config/linker-map.gnu (CXXABI_1.3.1): Add __cxa_get_exception_ptr.
+ * libsupc++/eh_catch.cc (__cxa_get_exception_ptr): New.
+ * libsupc++/unwind-cxx.h (__cxa_get_exception_ptr): Declare.
+
+--- libstdc++-v3/config/linker-map.gnu (revision 94498)
++++ libstdc++-v3/config/linker-map.gnu (revision 95705)
+@@ -406,3 +410,9 @@ CXXABI_1.3 {
+ local:
+ *;
+ };
++
++CXXABI_1.3.1 {
++
++ __cxa_get_exception_ptr;
++
++} CXXABI_1.3;
+--- libstdc++-v3/libsupc++/unwind-cxx.h (revision 94498)
++++ libstdc++-v3/libsupc++/unwind-cxx.h (revision 95705)
+@@ -107,6 +107,7 @@ extern "C" void __cxa_throw (void *throw
+ __attribute__((noreturn));
+
+ // Used to implement exception handlers.
++extern "C" void *__cxa_get_exception_ptr (void *) throw();
+ extern "C" void *__cxa_begin_catch (void *) throw();
+ extern "C" void __cxa_end_catch ();
+ extern "C" void __cxa_rethrow () __attribute__((noreturn));
+--- libstdc++-v3/libsupc++/eh_catch.cc (revision 94498)
++++ libstdc++-v3/libsupc++/eh_catch.cc (revision 95705)
+@@ -33,6 +33,15 @@
+
+ using namespace __cxxabiv1;
+
++extern "C" void *
++__cxxabiv1::__cxa_get_exception_ptr(void *exc_obj_in) throw()
++{
++ _Unwind_Exception *exceptionObject
++ = reinterpret_cast <_Unwind_Exception *>(exc_obj_in);
++ __cxa_exception *header = __get_exception_header_from_ue (exceptionObject);
++
++ return header->adjustedPtr;
++}
+
+ extern "C" void *
+ __cxxabiv1::__cxa_begin_catch (void *exc_obj_in) throw()
================================================================
Index: SOURCES/compat-gcc-34-pr-rh.patch
diff -u /dev/null SOURCES/compat-gcc-34-pr-rh.patch:1.1
--- /dev/null Tue Aug 5 00:59:29 2008
+++ SOURCES/compat-gcc-34-pr-rh.patch Tue Aug 5 00:59:22 2008
@@ -0,0 +1,3127 @@
+2006-02-17 Jakub Jelinek <jakub at redhat.com>
+
+ PR libstdc++/11953
+ * gthr-posix.h (_REENTRANT): Only define if __osf__ is defined.
+
+ * config/ia64/linux.h (CPP_SPEC): Define.
+ * config/s390/linux.h (CPP_SPEC): Define.
+
+--- gcc/gthr-posix.h (revision 111211)
++++ gcc/gthr-posix.h (revision 111212)
+@@ -36,7 +36,7 @@ Software Foundation, 51 Franklin Street,
+ #define __GTHREADS 1
+
+ /* Some implementations of <pthread.h> require this to be defined. */
+-#ifndef _REENTRANT
++#if !defined(_REENTRANT) && defined(__osf__)
+ #define _REENTRANT 1
+ #endif
+
+--- gcc/config/s390/linux.h (revision 111211)
++++ gcc/config/s390/linux.h (revision 111212)
+@@ -89,6 +89,7 @@ Software Foundation, 51 Franklin Street,
+ %{m31:-dynamic-linker /lib/ld.so.1} \
+ %{m64:-dynamic-linker /lib64/ld64.so.1}}}}"
+
++#define CPP_SPEC "%{posix:-D_POSIX_SOURCE} %{pthread:-D_REENTRANT}"
+
+ #define TARGET_ASM_FILE_END file_end_indicate_exec_stack
+
+--- gcc/config/ia64/linux.h (revision 111211)
++++ gcc/config/ia64/linux.h (revision 111212)
+@@ -48,6 +48,7 @@ do { \
+ %{!dynamic-linker:-dynamic-linker /lib/ld-linux-ia64.so.2}} \
+ %{static:-static}}"
+
++#define CPP_SPEC "%{posix:-D_POSIX_SOURCE} %{pthread:-D_REENTRANT}"
+
+ #define JMP_BUF_SIZE 76
+
+2004-05-27 Josef Zlomek <zlomekj at suse.cz>
+
+ PR middle-end/14084
+ * emit-rtl.c (gen_rtx_REG_offset): Adjust the offset according
+ to size of decl.
+
+--- gcc/emit-rtl.c 25 May 2004 12:04:15 -0000 1.391
++++ gcc/emit-rtl.c 27 May 2004 04:28:12 -0000 1.392
+@@ -746,13 +746,96 @@ gen_reg_rtx (enum machine_mode mode)
+ return val;
+ }
+
+-/* Generate a register with same attributes as REG,
+- but offsetted by OFFSET. */
++/* Generate a register with same attributes as REG, but offsetted by OFFSET.
++ Do the big endian correction if needed. */
+
+ rtx
+ gen_rtx_REG_offset (rtx reg, enum machine_mode mode, unsigned int regno, int offset)
+ {
+ rtx new = gen_rtx_REG (mode, regno);
++ tree decl;
++ HOST_WIDE_INT var_size;
++
++ /* PR middle-end/14084
++ The problem appears when a variable is stored in a larger register
++ and later it is used in the original mode or some mode in between
++ or some part of variable is accessed.
++
++ On little endian machines there is no problem because
++ the REG_OFFSET of the start of the variable is the same when
++ accessed in any mode (it is 0).
++
++ However, this is not true on big endian machines.
++ The offset of the start of the variable is different when accessed
++ in different modes.
++ When we are taking a part of the REG we have to change the OFFSET
++ from offset WRT size of mode of REG to offset WRT size of variable.
++
++ If we would not do the big endian correction the resulting REG_OFFSET
++ would be larger than the size of the DECL.
++
++ Examples of correction, for BYTES_BIG_ENDIAN WORDS_BIG_ENDIAN machine:
++
++ REG.mode MODE DECL size old offset new offset description
++ DI SI 4 4 0 int32 in SImode
++ DI SI 1 4 0 char in SImode
++ DI QI 1 7 0 char in QImode
++ DI QI 4 5 1 1st element in QImode
++ of char[4]
++ DI HI 4 6 2 1st element in HImode
++ of int16[2]
++
++ If the size of DECL is equal or greater than the size of REG
++ we can't do this correction because the register holds the
++ whole variable or a part of the variable and thus the REG_OFFSET
++ is already correct. */
++
++ decl = REG_EXPR (reg);
++ if ((BYTES_BIG_ENDIAN || WORDS_BIG_ENDIAN)
++ && decl != NULL
++ && offset > 0
++ && GET_MODE_SIZE (GET_MODE (reg)) > GET_MODE_SIZE (mode)
++ && ((var_size = int_size_in_bytes (TREE_TYPE (decl))) > 0
++ && var_size < GET_MODE_SIZE (GET_MODE (reg))))
++ {
++ int offset_le;
++
++ /* Convert machine endian to little endian WRT size of mode of REG. */
++ if (WORDS_BIG_ENDIAN)
++ offset_le = ((GET_MODE_SIZE (GET_MODE (reg)) - 1 - offset)
++ / UNITS_PER_WORD) * UNITS_PER_WORD;
++ else
++ offset_le = (offset / UNITS_PER_WORD) * UNITS_PER_WORD;
++
++ if (BYTES_BIG_ENDIAN)
++ offset_le += ((GET_MODE_SIZE (GET_MODE (reg)) - 1 - offset)
++ % UNITS_PER_WORD);
++ else
++ offset_le += offset % UNITS_PER_WORD;
++
++ if (offset_le >= var_size)
++ {
++ /* MODE is wider than the variable so the new reg will cover
++ the whole variable so the resulting OFFSET should be 0. */
++ offset = 0;
++ }
++ else
++ {
++ /* Convert little endian to machine endian WRT size of variable. */
++ if (WORDS_BIG_ENDIAN)
++ offset = ((var_size - 1 - offset_le)
++ / UNITS_PER_WORD) * UNITS_PER_WORD;
++ else
++ offset = (offset_le / UNITS_PER_WORD) * UNITS_PER_WORD;
++
++ if (BYTES_BIG_ENDIAN)
++ offset += ((var_size - 1 - offset_le)
++ % UNITS_PER_WORD);
++ else
++ offset += offset_le % UNITS_PER_WORD;
++ }
++ }
++
+ REG_ATTRS (new) = get_reg_attrs (REG_EXPR (reg),
+ REG_OFFSET (reg) + offset);
+ return new;
+2005-01-13 Jakub Jelinek <jakub at redhat.com>
+
+ PR rtl-optimization/16104
+ * expr.c (convert_move): Handle vector from resp. to if mode
+ sizes differ.
+
+ * gcc.c-torture/execute/20050113-1.c: New test.
+
+--- gcc/expr.c.jj 2004-12-27 21:31:08.000000000 +0100
++++ gcc/expr.c 2005-01-13 15:56:31.229253647 +0100
+@@ -590,7 +590,26 @@ convert_move (rtx to, rtx from, int unsi
+ if (VECTOR_MODE_P (to_mode) || VECTOR_MODE_P (from_mode))
+ {
+ if (GET_MODE_BITSIZE (from_mode) != GET_MODE_BITSIZE (to_mode))
+- abort ();
++ {
++ if (VECTOR_MODE_P (from_mode))
++ {
++ enum machine_mode new_mode;
++
++ new_mode = mode_for_size (GET_MODE_BITSIZE (from_mode),
++ MODE_INT, 0);
++ from = simplify_gen_subreg (new_mode, from, from_mode, 0);
++ }
++ if (VECTOR_MODE_P (to_mode))
++ {
++ enum machine_mode new_mode;
++
++ new_mode = mode_for_size (GET_MODE_BITSIZE (to_mode),
++ MODE_INT, 0);
++ to = simplify_gen_subreg (new_mode, to, to_mode, 0);
++ }
++ convert_move (to, from, unsignedp);
++ return;
++ }
+
+ if (VECTOR_MODE_P (to_mode))
+ from = simplify_gen_subreg (to_mode, from, GET_MODE (from), 0);
+--- gcc/testsuite/gcc.c-torture/execute/20050113-1.c.jj 2005-01-13 15:51:09.194383356 +0100
++++ gcc/testsuite/gcc.c-torture/execute/20050113-1.c 2005-01-13 15:37:22.000000000 +0100
+@@ -0,0 +1,56 @@
++/* PR rtl-optimization/16104 */
++
++extern void abort (void);
++
++typedef int V2SI __attribute__ ((vector_size (8)));
++typedef short V2HI __attribute__ ((vector_size (4)));
++
++int
++test1 (void)
++{
++ return (long long) (V2SI) 0LL;
++}
++
++int
++test2 (V2SI x)
++{
++ return (long long) x;
++}
++
++V2SI
++test3 (void)
++{
++ return (V2SI) (long long) (int) (V2HI) 0;
++}
++
++V2SI
++test4 (V2HI x)
++{
++ return (V2SI) (long long) (int) x;
++}
++
++int
++main (void)
++{
++ if (sizeof (short) != 2 || sizeof (int) != 4 || sizeof (long long) != 8)
++ return 0;
++
++ if (test1 () != 0)
++ abort ();
++
++ V2SI x = { 2, 2 };
++ if (test2 (x) != 2)
++ abort ();
++
++ union { V2SI x; int y[2]; } u;
++ u.x = test3 ();
++ if (u.y[0] != 0 || u.y[1] != 0)
++ abort ();
++
++ V2HI y = { 4, 4 };
++ union { V2SI x; long long y; } v;
++ v.x = test4 (y);
++ if (v.y != 0x40004)
++ abort ();
++ return 0;
++}
+2005-09-07 Jakub Jelinek <jakub at redhat.com>
+
+ PR target/18300
+ * config/i386/i386.c (classify_argument): Only use different
+ iterators for nested loops if nested loops sharing the same
+ iterator would hang.
+
+2004-11-13 Zak Kipling <zak at transversal.com>
+
+ PR target/18300
+ * config/i386/i386.c (classify_argument): Fix infinite loop when
+ passing object with 3 or more base classes by value.
+
+--- gcc/config/i386/i386.c.jj 2005-07-21 11:01:36.000000000 +0200
++++ gcc/config/i386/i386.c 2005-09-07 14:22:19.000000000 +0200
+@@ -2028,8 +2028,17 @@ classify_argument (enum machine_mode mod
+ {
+ tree bases = TYPE_BINFO_BASETYPES (type);
+ int n_bases = TREE_VEC_LENGTH (bases);
+- int i;
+-
++ int i, basenum;
++ enum x86_64_reg_class saveclasses[MAX_CLASSES];
++ bool seen[MAX_CLASSES];
++
++ /* PR target/18300: The following code mistakenly uses the same
++ iterator variable in both nested for loops. But to preserve
++ binary compatibility, do whatever this code used to do before
++ unless old GCC would hang in an infinite loop. In that case
++ use whatever GCC 4.0+ does. */
++ memset (seen, 0, sizeof (seen));
++ memcpy (saveclasses, classes, sizeof (saveclasses));
+ for (i = 0; i < n_bases; ++i)
+ {
+ tree binfo = TREE_VEC_ELT (bases, i);
+@@ -2037,6 +2046,12 @@ classify_argument (enum machine_mode mod
+ int offset = tree_low_cst (BINFO_OFFSET (binfo), 0) * 8;
+ tree type = BINFO_TYPE (binfo);
+
++ if (i < MAX_CLASSES)
++ {
++ if (seen[i])
++ break;
++ seen[i] = true;
++ }
+ num = classify_argument (TYPE_MODE (type),
+ type, subclasses,
+ (offset + bit_offset) % 256);
+@@ -2049,6 +2064,32 @@ classify_argument (enum machine_mode mod
+ merge_classes (subclasses[i], classes[i + pos]);
+ }
+ }
++ if (i < n_bases)
++ {
++ /* Older GCC 3.[0-4].x would hang in the above loop, so
++ don't worry about backwards compatibility and
++ just DTRT. */
++ memcpy (classes, saveclasses, sizeof (saveclasses));
++ for (basenum = 0; basenum < n_bases; ++basenum)
++ {
++ tree binfo = TREE_VEC_ELT (bases, basenum);
++ int num;
++ int offset = tree_low_cst (BINFO_OFFSET (binfo), 0) * 8;
++ tree type = BINFO_TYPE (binfo);
++
++ num = classify_argument (TYPE_MODE (type),
++ type, subclasses,
++ (offset + bit_offset) % 256);
++ if (!num)
++ return 0;
++ for (i = 0; i < num; i++)
++ {
++ int pos = (offset + (bit_offset % 64)) / 8 / 8;
++ classes[i + pos] =
++ merge_classes (subclasses[i], classes[i + pos]);
++ }
++ }
++ }
+ }
+ /* And now merge the fields of structure. */
+ for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
+@@ -2116,8 +2157,17 @@ classify_argument (enum machine_mode mod
+ {
+ tree bases = TYPE_BINFO_BASETYPES (type);
+ int n_bases = TREE_VEC_LENGTH (bases);
+- int i;
+-
++ int i, basenum;
++ enum x86_64_reg_class saveclasses[MAX_CLASSES];
++ bool seen[MAX_CLASSES];
++
++ /* PR target/18300: The following code mistakenly uses the same
++ iterator variable in both nested for loops. But to preserve
++ binary compatibility, do whatever this code used to do before
++ unless old GCC would hang in an infinite loop. In that case
++ use whatever GCC 4.0+ does. */
++ memset (seen, 0, sizeof (seen));
++ memcpy (saveclasses, classes, sizeof (saveclasses));
+ for (i = 0; i < n_bases; ++i)
+ {
+ tree binfo = TREE_VEC_ELT (bases, i);
+@@ -2125,6 +2175,12 @@ classify_argument (enum machine_mode mod
+ int offset = tree_low_cst (BINFO_OFFSET (binfo), 0) * 8;
+ tree type = BINFO_TYPE (binfo);
+
++ if (i < MAX_CLASSES)
++ {
++ if (seen[i])
++ break;
++ seen[i] = true;
++ }
+ num = classify_argument (TYPE_MODE (type),
+ type, subclasses,
+ (offset + (bit_offset % 64)) % 256);
+@@ -2137,6 +2193,32 @@ classify_argument (enum machine_mode mod
+ merge_classes (subclasses[i], classes[i + pos]);
+ }
+ }
++ if (i < n_bases)
++ {
++ /* Older GCC 3.[0-4].x would hang in the above loop, so
++ don't worry about backwards compatibility and
++ just DTRT. */
++ memcpy (classes, saveclasses, sizeof (saveclasses));
++ for (basenum = 0; basenum < n_bases; ++basenum)
++ {
++ tree binfo = TREE_VEC_ELT (bases, basenum);
++ int num;
++ int offset = tree_low_cst (BINFO_OFFSET (binfo), 0) * 8;
++ tree type = BINFO_TYPE (binfo);
++
++ num = classify_argument (TYPE_MODE (type),
++ type, subclasses,
++ (offset + (bit_offset % 64)) % 256);
++ if (!num)
++ return 0;
++ for (i = 0; i < num; i++)
++ {
++ int pos = (offset + (bit_offset % 64)) / 8 / 8;
++ classes[i + pos] =
++ merge_classes (subclasses[i], classes[i + pos]);
++ }
++ }
++ }
+ }
+ for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
+ {
+--- gcc/testsuite/g++.dg/other/infloop-1.C 1 Jan 1970 00:00:00 -0000
++++ gcc/testsuite/g++.dg/other/infloop-1.C 13 Nov 2004 23:09:08 -0000 1.1
+@@ -0,0 +1,16 @@
++// PR 18300: This sends old compilers into an infinite loop on x86_64
++// Testcase and patch contributed by Zak Kipling <zak at transversal.com>
++
++struct base1 { };
++struct base2 { };
++struct base3 { };
++
++struct derived : base1, base2, base3 { };
++
++void foo(derived);
++
++int main()
++{
++ foo(derived());
++}
++
+2004-12-13 Mark Mitchell <mark at codesourcery.com>
+
+ PR c++/18925
+ * class.c (layout_class_type): Determine the visibility of static
+ data members.
+
+ * g++.dg/ext/visibility/staticdatamem.C: New test.
+
+--- gcc/cp/class.c 8 Dec 2004 08:35:33 -0000 1.692
++++ gcc/cp/class.c 14 Dec 2004 02:21:46 -0000 1.693
+@@ -4553,7 +4553,13 @@ layout_class_type (tree t, tree *virtual
+ At this point, finish_record_layout will be called, but
+ S1 is still incomplete.) */
+ if (TREE_CODE (field) == VAR_DECL)
+- maybe_register_incomplete_var (field);
++ {
++ maybe_register_incomplete_var (field);
++ /* The visibility of static data members is determined
++ at their point of declaration, not their point of
++ definition. */
++ determine_visibility (field);
++ }
+ continue;
+ }
+
+--- gcc/testsuite/g++.dg/ext/visibility/staticdatamem.C 1 Jan 1970 00:00:00 -0000
++++ gcc/testsuite/g++.dg/ext/visibility/staticdatamem.C 14 Dec 2004 02:15:55 -0000 1.1
+@@ -0,0 +1,20 @@
++// PR c++/18925
++// { dg-do compile { target ia64-*-linux* } }
++// { dg-options "-fPIC -fvisibility=hidden" }
++// { dg-final { scan-assembler-not "gprel" } }
++
++class __attribute__ ((visibility("default"))) Type
++{
++ private:
++ static long _staticTypeCount;
++ public:
++ Type() { _staticTypeCount++; }
++ ~Type();
++};
++
++long Type::_staticTypeCount = 0;
++
++Type::~Type()
++{
++ _staticTypeCount--;
++}
+2005-05-07 Richard Henderson <rth at redhat.com>
+
+ PR target/21412
+ * config/rs6000/rs6000.c (rs6000_emit_move): Look for tls addresses
+ with constant offsets.
+
+2004-07-11 Ulrich Weigand <uweigand at de.ibm.com>
+
+ * config/s390/s390.c (legitimize_tls_address): Handle constant offsets
+ added to TLS symbol addresses.
+
+2004-07-06 Richard Henderson <rth at redhat.com>
+
+ * config/i386/i386.c (legitimize_address): Handle CONST with TLS
+ operand.
+ (ix86_expand_move): Don't call legitimize_pic_address directly.
+
+2006-05-05 Jakub Jelinek <jakub at redhat.com>
+
+ * gcc.dg/tls/opt-12.c: New test.
+
+--- gcc/config/s390/s390.c (revision 84404)
++++ gcc/config/s390/s390.c (revision 84535)
+@@ -2913,6 +2913,18 @@ legitimize_tls_address (rtx addr, rtx re
+ }
+ }
+
++ else if (GET_CODE (addr) == CONST && GET_CODE (XEXP (addr, 0)) == PLUS
++ && GET_CODE (XEXP (XEXP (addr, 0), 1)) == CONST_INT)
++ {
++ new = XEXP (XEXP (addr, 0), 0);
++ if (GET_CODE (new) != SYMBOL_REF)
++ new = gen_rtx_CONST (Pmode, new);
++
++ new = legitimize_tls_address (new, reg);
++ new = plus_constant (new, INTVAL (XEXP (XEXP (addr, 0), 1)));
++ new = force_operand (new, 0);
++ }
++
+ else
+ abort (); /* for now ... */
+
+--- gcc/config/i386/i386.c 2005-11-21 14:56:49.000000000 +0100
++++ gcc/config/i386/i386.c 2006-05-05 11:21:54.000000000 +0200
+@@ -6604,6 +6604,13 @@ legitimize_address (rtx x, rtx oldx ATTR
+ log = tls_symbolic_operand (x, mode);
+ if (log)
+ return legitimize_tls_address (x, log, false);
++ if (GET_CODE (x) == CONST
++ && GET_CODE (XEXP (x, 0)) == PLUS
++ && (log = tls_symbolic_operand (XEXP (XEXP (x, 0), 0), Pmode)))
++ {
++ rtx t = legitimize_tls_address (XEXP (XEXP (x, 0), 0), log, false);
++ return gen_rtx_PLUS (Pmode, t, XEXP (XEXP (x, 0), 1));
++ }
+
+ if (flag_pic && SYMBOLIC_CONST (x))
+ return legitimize_pic_address (x, 0);
+@@ -8395,6 +8402,10 @@ ix86_expand_move (enum machine_mode mode
+ #else
+ if (GET_CODE (op0) == MEM)
+ op1 = force_reg (Pmode, op1);
++ else if (GET_CODE (op1) == CONST
++ && GET_CODE (XEXP (op1, 0)) == PLUS
++ && tls_symbolic_operand (XEXP (XEXP (op1, 0), 0), Pmode))
++ op1 = legitimize_address (op1, op1, Pmode);
+ else
+ {
+ rtx temp = op0;
+--- gcc/config/rs6000/rs6000.c (revision 99334)
++++ gcc/config/rs6000/rs6000.c (revision 99367)
+@@ -4436,11 +4436,31 @@ rs6000_emit_move (rtx dest, rtx source,
+
+ /* Recognize the case where operand[1] is a reference to thread-local
+ data and load its address to a register. */
+- if (GET_CODE (operands[1]) == SYMBOL_REF)
++ if (rs6000_tls_referenced_p (operands[1]))
+ {
+- enum tls_model model = SYMBOL_REF_TLS_MODEL (operands[1]);
+- if (model != 0)
+- operands[1] = rs6000_legitimize_tls_address (operands[1], model);
<<Diff was trimmed, longer than 597 lines>>
More information about the pld-cvs-commit
mailing list