This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.
Index Nav: | [Date Index] [Subject Index] [Author Index] [Thread Index] | |
---|---|---|
Message Nav: | [Date Prev] [Date Next] | [Thread Prev] [Thread Next] |
Other format: | [Raw text] |
This patch for mainline CVS fixes C++ PRs 19076 and 6628 and implements the resolution to DR 195 (unless -pedantic is specified, in which case it warns first). It obsoletes my prior attempt at http://gcc.gnu.org/ml/gcc-patches/2005-01/msg01341.html. Tested on i686-pc-linux-gnu: no new regressions, the two new tests pass, and two existing xfail'd tests now pass. All of the examples from the two PRs this fixes (including Giovanni's test case from yesterday) work properly. The patch is split into two parts: the C++ front end changes (-cp) and the testsuite changes (-testsuite), with separate changelogs. There are several places in the front end where it is assumed that function types cannot have qualifiers. This is wrong: function types can have qualifiers, but there are only a few ways in which these qualifiers can be added: - cv-qualifier function types can be created with a typedef of a function, e.g., typedef int foo(float) const; - cv-qualified function types can come from unifying a member pointer to a pointer to cv-qualified member function, e.g., template<typename> struct X; template<typename T, typename Class> struct X<T Class::*> {}; struct Y {}; X<int (Y::*)(float, double) const>; // T = int(float, double) const However, one cannot add qualifiers to a function type. For instance, the second line of the following code does not add qualifiers to "foo": typedef int foo(float) const; typedef volatile foo foo_v; // #2 In C++98, the line marked #2 is an error. However, DR 295 makes this code legal but drops the qualifiers, so "foo_v" will be the same type as "foo". The patch therefore warns only when -pedantic is provided. This is a largish patch with several parts, because there are several intertwined changes: 1) Remove all of the incorrect errors/warnings about qualifiers. 2) Add errors/warnings where qualified function types cannot be used or where they will be dropped. 3) Transfer qualifiers between the function type of a member pointer and the implicit object type of a member function pointer. 4) Unify member pointers to member function pointers. 5) Print out qualifiers on function types (they are already mangled properly). Doug Gregor dgregor@cs.indiana.edu
Attachment:
ChangeLog-cp
Description: Text document
Attachment:
ChangeLog-testsuite
Description: Text document
Index: cp-tree.h =================================================================== RCS file: /cvsroot/gcc/gcc/gcc/cp/cp-tree.h,v retrieving revision 1.1097 diff -c -3 -p -b -r1.1097 cp-tree.h *** cp-tree.h 20 Jan 2005 07:12:49 -0000 1.1097 --- cp-tree.h 22 Jan 2005 21:02:28 -0000 *************** extern tree build_ptrmemfunc (tree, tr *** 4306,4311 **** --- 4306,4312 ---- extern int cp_type_quals (tree); extern bool cp_has_mutable_p (tree); extern bool at_least_as_qualified_p (tree, tree); + extern void cp_apply_type_quals_to_decl (int, tree); extern tree build_ptrmemfunc1 (tree, tree, tree); extern void expand_ptrmemfunc_cst (tree, tree *, tree *); extern tree pfn_from_ptrmemfunc (tree); Index: decl.c =================================================================== RCS file: /cvsroot/gcc/gcc/gcc/cp/decl.c,v retrieving revision 1.1354 diff -c -3 -p -b -r1.1354 decl.c *** decl.c 18 Jan 2005 23:49:35 -0000 1.1354 --- decl.c 22 Jan 2005 21:02:31 -0000 *************** grokdeclarator (const cp_declarator *dec *** 6900,6905 **** --- 6900,6919 ---- error ("qualifiers are not allowed on declaration of %<operator %T%>", ctor_return_type); + if (TREE_CODE (type) == FUNCTION_TYPE + && type_quals != TYPE_UNQUALIFIED) + { + /* This was an error in C++98 (cv-qualifiers cannot be added to + a function type), but DR 295 makes the code well-formed by + dropping the extra qualifiers. */ + if (pedantic) + { + tree bad_type = build_qualified_type (type, type_quals); + pedwarn ("ignoring %qV qualifiers added to function type %qT", + bad_type, type); + } + type_quals = TYPE_UNQUALIFIED; + } type_quals |= cp_type_quals (type); type = cp_build_qualified_type_real (type, type_quals, ((typedef_decl && !DECL_ARTIFICIAL (typedef_decl) *************** grokdeclarator (const cp_declarator *dec *** 7261,7266 **** --- 7275,7281 ---- } type = build_function_type (type, arg_types); + type = cp_build_qualified_type (type, quals); } break; *************** grokdeclarator (const cp_declarator *dec *** 7293,7298 **** --- 7308,7319 ---- && (TREE_CODE (type) == FUNCTION_TYPE || (quals && TREE_CODE (type) == METHOD_TYPE))) { + /* If the type is a FUNCTION_TYPE, pick up the + qualifiers from that function type. No other + qualifiers may be supplied. */ + if (TREE_CODE (type) == FUNCTION_TYPE) + quals = cp_type_quals (type); + tree dummy = build_decl (TYPE_DECL, NULL_TREE, type); grok_method_quals (declarator->u.pointer.class_type, dummy, quals); *************** grokdeclarator (const cp_declarator *dec *** 7587,7597 **** { if (ctype == NULL_TREE) { ! if (TREE_CODE (type) != METHOD_TYPE) ! error ("%Jinvalid type qualifier for non-member function type", ! decl); ! else ctype = TYPE_METHOD_BASETYPE (type); } if (ctype != NULL_TREE) grok_method_quals (ctype, decl, quals); --- 7608,7619 ---- { if (ctype == NULL_TREE) { ! if (TREE_CODE (type) == METHOD_TYPE) ctype = TYPE_METHOD_BASETYPE (type); + /* Any qualifiers on a function type typedef have + already been dealt with. */ + else if (TREE_CODE (type) == FUNCTION_TYPE) + quals = TYPE_UNQUALIFIED; } if (ctype != NULL_TREE) grok_method_quals (ctype, decl, quals); *************** grokdeclarator (const cp_declarator *dec *** 7634,7639 **** --- 7656,7678 ---- } parms = nreverse (decls); + + if (decl_context != TYPENAME) + { + /* A cv-qualifier-seq shall only be part of the function type + for a non-static member function. [8.3.5/4 dcl.fct] */ + if (cp_type_quals (type) != TYPE_UNQUALIFIED + && (current_class_type == NULL_TREE || staticp) ) + { + error ("qualified function types cannot be used to declare %s functions", + (staticp? "static member" : "free")); + type = TYPE_MAIN_VARIANT (type); + } + + /* The qualifiers on the function type become the qualifiers on + the non-static member function. */ + quals |= cp_type_quals (type); + } } /* If this is a type name (such as, in a cast or sizeof), *************** grokdeclarator (const cp_declarator *dec *** 8166,8172 **** when processing a template; we'll do this for the instantiated declaration based on the type of DECL. */ if (!processing_template_decl) ! c_apply_type_quals_to_decl (type_quals, decl); return decl; } --- 8205,8211 ---- when processing a template; we'll do this for the instantiated declaration based on the type of DECL. */ if (!processing_template_decl) ! cp_apply_type_quals_to_decl (type_quals, decl); return decl; } *************** start_preparsed_function (tree decl1, tr *** 9945,9951 **** DECL_IGNORED_P (resdecl) = 1; DECL_RESULT (decl1) = resdecl; ! c_apply_type_quals_to_decl (cp_type_quals (restype), resdecl); } /* Initialize RTL machinery. We cannot do this until --- 9984,9990 ---- DECL_IGNORED_P (resdecl) = 1; DECL_RESULT (decl1) = resdecl; ! cp_apply_type_quals_to_decl (cp_type_quals (restype), resdecl); } /* Initialize RTL machinery. We cannot do this until Index: decl2.c =================================================================== RCS file: /cvsroot/gcc/gcc/gcc/cp/decl2.c,v retrieving revision 1.764 diff -c -3 -p -b -r1.764 decl2.c *** decl2.c 5 Jan 2005 10:02:11 -0000 1.764 --- decl2.c 22 Jan 2005 21:02:32 -0000 *************** grokclassfn (tree ctype, tree function, *** 300,306 **** this_quals |= TYPE_QUAL_CONST; qual_type = cp_build_qualified_type (type, this_quals); parm = build_artificial_parm (this_identifier, qual_type); ! c_apply_type_quals_to_decl (this_quals, parm); TREE_CHAIN (parm) = DECL_ARGUMENTS (function); DECL_ARGUMENTS (function) = parm; } --- 300,306 ---- this_quals |= TYPE_QUAL_CONST; qual_type = cp_build_qualified_type (type, this_quals); parm = build_artificial_parm (this_identifier, qual_type); ! cp_apply_type_quals_to_decl (this_quals, parm); TREE_CHAIN (parm) = DECL_ARGUMENTS (function); DECL_ARGUMENTS (function) = parm; } Index: error.c =================================================================== RCS file: /cvsroot/gcc/gcc/gcc/cp/error.c,v retrieving revision 1.275 diff -c -3 -p -b -r1.275 error.c *** error.c 21 Dec 2004 17:54:23 -0000 1.275 --- error.c 22 Jan 2005 21:02:32 -0000 *************** dump_type_suffix (tree t, int flags) *** 613,618 **** --- 613,620 ---- if (TREE_CODE (t) == METHOD_TYPE) pp_cxx_cv_qualifier_seq (cxx_pp, TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (t)))); + else + pp_cxx_cv_qualifier_seq(cxx_pp, t); dump_exception_spec (TYPE_RAISES_EXCEPTIONS (t), flags); dump_type_suffix (TREE_TYPE (t), flags); break; Index: pt.c =================================================================== RCS file: /cvsroot/gcc/gcc/gcc/cp/pt.c,v retrieving revision 1.968 diff -c -3 -p -b -r1.968 pt.c *** pt.c 21 Jan 2005 02:27:09 -0000 1.968 --- pt.c 22 Jan 2005 21:02:34 -0000 *************** tsubst_decl (tree t, tree args, tsubst_f *** 6510,6516 **** type = tsubst (TREE_TYPE (t), args, complain, in_decl); TREE_TYPE (r) = type; ! c_apply_type_quals_to_decl (cp_type_quals (type), r); if (DECL_INITIAL (r)) { --- 6510,6516 ---- type = tsubst (TREE_TYPE (t), args, complain, in_decl); TREE_TYPE (r) = type; ! cp_apply_type_quals_to_decl (cp_type_quals (type), r); if (DECL_INITIAL (r)) { *************** tsubst_decl (tree t, tree args, tsubst_f *** 6540,6546 **** if (type == error_mark_node) return error_mark_node; TREE_TYPE (r) = type; ! c_apply_type_quals_to_decl (cp_type_quals (type), r); /* We don't have to set DECL_CONTEXT here; it is set by finish_member_declaration. */ --- 6540,6546 ---- if (type == error_mark_node) return error_mark_node; TREE_TYPE (r) = type; ! cp_apply_type_quals_to_decl (cp_type_quals (type), r); /* We don't have to set DECL_CONTEXT here; it is set by finish_member_declaration. */ *************** tsubst_decl (tree t, tree args, tsubst_f *** 6640,6646 **** else if (DECL_SELF_REFERENCE_P (t)) SET_DECL_SELF_REFERENCE_P (r); TREE_TYPE (r) = type; ! c_apply_type_quals_to_decl (cp_type_quals (type), r); DECL_CONTEXT (r) = ctx; /* Clear out the mangled name and RTL for the instantiation. */ SET_DECL_ASSEMBLER_NAME (r, NULL_TREE); --- 6640,6646 ---- else if (DECL_SELF_REFERENCE_P (t)) SET_DECL_SELF_REFERENCE_P (r); TREE_TYPE (r) = type; ! cp_apply_type_quals_to_decl (cp_type_quals (type), r); DECL_CONTEXT (r) = ctx; /* Clear out the mangled name and RTL for the instantiation. */ SET_DECL_ASSEMBLER_NAME (r, NULL_TREE); *************** tsubst (tree t, tree args, tsubst_flags_ *** 7259,7280 **** gcc_assert (TREE_CODE (type) != METHOD_TYPE); if (TREE_CODE (type) == FUNCTION_TYPE) { ! /* This is really a method type. The cv qualifiers of the ! this pointer should _not_ be determined by the cv ! qualifiers of the class type. They should be held ! somewhere in the FUNCTION_TYPE, but we don't do that at ! the moment. Consider ! typedef void (Func) () const; ! ! template <typename T1> void Foo (Func T1::*); ! ! */ tree method_type; ! ! method_type = build_method_type_directly (TYPE_MAIN_VARIANT (r), TREE_TYPE (type), TYPE_ARG_TYPES (type)); ! return build_ptrmemfunc_type (build_pointer_type (method_type)); } else return cp_build_qualified_type_real (build_ptrmem_type (r, type), --- 7259,7276 ---- gcc_assert (TREE_CODE (type) != METHOD_TYPE); if (TREE_CODE (type) == FUNCTION_TYPE) { ! /* The type of the implicit object parameter gets its ! cv-qualifiers from the FUNCTION_TYPE. */ tree method_type; ! tree this_type = cp_build_qualified_type (TYPE_MAIN_VARIANT (r), ! cp_type_quals (type)); ! tree memptr; ! method_type = build_method_type_directly (this_type, TREE_TYPE (type), TYPE_ARG_TYPES (type)); ! memptr = build_ptrmemfunc_type (build_pointer_type (method_type)); ! return cp_build_qualified_type_real (memptr, cp_type_quals (t), ! complain); } else return cp_build_qualified_type_real (build_ptrmem_type (r, type), *************** unify (tree tparms, tree targs, tree par *** 10287,10292 **** --- 10283,10319 ---- DEDUCE_EXACT, 0, -1); case OFFSET_TYPE: + /* Unify a pointer to member with a pointer to member function, which + deduces the type of the member as a function type. */ + if (TYPE_PTRMEMFUNC_P (arg)) + { + tree method_type; + tree fntype; + cp_cv_quals cv_quals; + + /* Check top-level cv qualifiers */ + if (!check_cv_quals_for_unify (UNIFY_ALLOW_NONE, arg, parm)) + return 1; + + if (unify (tparms, targs, TYPE_OFFSET_BASETYPE (parm), + TYPE_PTRMEMFUNC_OBJECT_TYPE (arg), UNIFY_ALLOW_NONE)) + return 1; + + /* Determine the type of the function we are unifying against. */ + method_type = TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (arg)); + fntype = + build_function_type (TREE_TYPE (method_type), + TREE_CHAIN (TYPE_ARG_TYPES (method_type))); + + /* Extract the cv-qualifiers of the member function from the + implicit object parameter and place them on the function + type to be restored later. */ + cv_quals = + cp_type_quals(TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (method_type)))); + fntype = build_qualified_type (fntype, cv_quals); + return unify (tparms, targs, TREE_TYPE (parm), fntype, strict); + } + if (TREE_CODE (arg) != OFFSET_TYPE) return 1; if (unify (tparms, targs, TYPE_OFFSET_BASETYPE (parm), Index: tree.c =================================================================== RCS file: /cvsroot/gcc/gcc/gcc/cp/tree.c,v retrieving revision 1.425 diff -c -3 -p -b -r1.425 tree.c *** tree.c 18 Jan 2005 23:51:26 -0000 1.425 --- tree.c 22 Jan 2005 21:02:35 -0000 *************** cp_build_qualified_type_real (tree type, *** 486,496 **** return build_ptrmemfunc_type (t); } ! /* A reference, function or method type shall not be cv qualified. [dcl.ref], [dct.fct] */ if (type_quals & (TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE) && (TREE_CODE (type) == REFERENCE_TYPE - || TREE_CODE (type) == FUNCTION_TYPE || TREE_CODE (type) == METHOD_TYPE)) { bad_quals |= type_quals & (TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE); --- 486,495 ---- return build_ptrmemfunc_type (t); } ! /* A reference or method type shall not be cv qualified. [dcl.ref], [dct.fct] */ if (type_quals & (TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE) && (TREE_CODE (type) == REFERENCE_TYPE || TREE_CODE (type) == METHOD_TYPE)) { bad_quals |= type_quals & (TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE); *************** cp_build_qualified_type_real (tree type, *** 498,507 **** } /* A restrict-qualified type must be a pointer (or reference) ! to object or incomplete type. */ if ((type_quals & TYPE_QUAL_RESTRICT) && TREE_CODE (type) != TEMPLATE_TYPE_PARM && TREE_CODE (type) != TYPENAME_TYPE && !POINTER_TYPE_P (type)) { bad_quals |= TYPE_QUAL_RESTRICT; --- 497,507 ---- } /* A restrict-qualified type must be a pointer (or reference) ! to object or incomplete type, or a function type. */ if ((type_quals & TYPE_QUAL_RESTRICT) && TREE_CODE (type) != TEMPLATE_TYPE_PARM && TREE_CODE (type) != TYPENAME_TYPE + && TREE_CODE (type) != FUNCTION_TYPE && !POINTER_TYPE_P (type)) { bad_quals |= TYPE_QUAL_RESTRICT; Index: typeck.c =================================================================== RCS file: /cvsroot/gcc/gcc/gcc/cp/typeck.c,v retrieving revision 1.608 diff -c -3 -p -b -r1.608 typeck.c *** typeck.c 20 Jan 2005 07:12:50 -0000 1.608 --- typeck.c 22 Jan 2005 21:02:36 -0000 *************** cp_has_mutable_p (tree type) *** 6440,6445 **** --- 6440,6474 ---- return CLASS_TYPE_P (type) && CLASSTYPE_HAS_MUTABLE (type); } + /* Apply the TYPE_QUALS to the new DECL. */ + void + cp_apply_type_quals_to_decl (int type_quals, tree decl) + { + tree type = TREE_TYPE (decl); + + if (type == error_mark_node) + return; + + if (TREE_CODE (type) == FUNCTION_TYPE + && type_quals != TYPE_UNQUALIFIED) + { + /* This was an error in C++98 (cv-qualifiers cannot be added to + a function type), but DR 295 makes the code well-formed by + dropping the extra qualifiers. */ + if (pedantic) + { + tree bad_type = build_qualified_type (type, type_quals); + pedwarn ("ignoring %qV qualifiers added to function type %qT", + bad_type, type); + } + + TREE_TYPE (decl) = TYPE_MAIN_VARIANT (type); + return; + } + + c_apply_type_quals_to_decl (type_quals, decl); + } + /* Subroutine of casts_away_constness. Make T1 and T2 point at exemplar types such that casting T1 to T2 is casting away constness if and only if there is no implicit conversion from T1 to T2. */
Index: g++.dg/other/cv_func.C =================================================================== RCS file: g++.dg/other/cv_func.C diff -N g++.dg/other/cv_func.C *** /dev/null 1 Jan 1970 00:00:00 -0000 --- g++.dg/other/cv_func.C 22 Jan 2005 17:10:30 -0000 *************** *** 0 **** --- 1,32 ---- + // { dg-do compile } + // { dg-options "-pedantic -pedantic-errors" } + typedef int FIC(int) const; + typedef int FI(int); + + FIC f; // { dg-error "qualified" } + // { dg-error "ignoring" "" { target *-*-* } 6 } + struct S { + FIC f; // OK + + const FI g; // { dg-error "qualifier" } + + int h(int) const; + + }; + FIC S::*pm = &S::f; + const FI S::*pm2 = &S::f; // { dg-error "qualifier" } + // { dg-error "cannot convert" "" { target *-*-* } 17 } + const FIC S::*pm3 = &S::f; // { dg-error "qualifier" } + + int S::f(int) const + { + return 17; + } + + + int foo(float) const // { dg-error "qualifier" } + { + return 0; + } + + int bar(float) volatile; // { dg-error "qualifier" } Index: g++.dg/template/mem_func_ptr.C =================================================================== RCS file: g++.dg/template/mem_func_ptr.C diff -N g++.dg/template/mem_func_ptr.C *** /dev/null 1 Jan 1970 00:00:00 -0000 --- g++.dg/template/mem_func_ptr.C 22 Jan 2005 17:10:30 -0000 *************** *** 0 **** --- 1,57 ---- + // { dg-do compile } + template<typename T> struct takes_member_ptr; + template<typename T, typename Class> struct takes_member_ptr<T Class::*> {}; + + template<typename T, typename Class> + void fun_takes_member_ptr(T Class::*) {} + + + template<typename T> struct order_member_ptrs; + template<typename T, typename Class> struct order_member_ptrs<T Class::*> {}; + template<typename R, typename T1, typename Class> + struct order_member_ptrs<R (Class::*)(T1)> + { + typedef int type; + }; + + template<typename R, typename T1, typename Class> + struct order_member_ptrs<R (Class::*)(T1) const> + { + typedef int c_type; + }; + + template<typename R, typename T1, typename Class> + struct order_member_ptrs<R (Class::*)(T1) volatile> + { + typedef int v_type; + }; + + template<typename R, typename T1, typename Class> + struct order_member_ptrs<R (Class::*)(T1) const volatile> + { + typedef int cv_type; + }; + + + struct X { + void bar(float) {} + void bar_c(float) const {} + void bar_v(float) volatile {} + void bar_cv(float) const volatile {} + }; + + void foo() + { + sizeof(takes_member_ptr<void (X::*)(float)>); + sizeof(takes_member_ptr<void (X::*)(float) const>); + sizeof(takes_member_ptr<void (X::*)(float) volatile>); + sizeof(takes_member_ptr<void (X::*)(float) const volatile>); + sizeof(order_member_ptrs<void (X::*)(float)>::type); + sizeof(order_member_ptrs<void (X::*)(float) const>::c_type); + sizeof(order_member_ptrs<void (X::*)(float) volatile>::v_type); + sizeof(order_member_ptrs<void (X::*)(float) const volatile>::cv_type); + fun_takes_member_ptr(&X::bar); + fun_takes_member_ptr(&X::bar_c); + fun_takes_member_ptr(&X::bar_v); + fun_takes_member_ptr(&X::bar_cv); + } Index: g++.dg/template/qualttp20.C =================================================================== RCS file: /cvsroot/gcc/gcc/gcc/testsuite/g++.dg/template/qualttp20.C,v retrieving revision 1.7 diff -c -3 -p -b -r1.7 qualttp20.C *** g++.dg/template/qualttp20.C 10 Oct 2004 21:36:41 -0000 1.7 --- g++.dg/template/qualttp20.C 22 Jan 2005 17:10:30 -0000 *************** *** 1,4 **** --- 1,5 ---- // { dg-do compile } + // { dg-options "-pedantic -pedantic-errors" } // Copyright (C) 2001 Free Software Foundation, Inc. // Contributed by Nathan Sidwell 15 Dec 2001 <nathan@codesourcery.com> *************** struct AS *** 16,22 **** template <typename T> struct B1 : T { typedef typename T::L __restrict__ r;// { dg-error "'__restrict__' qualifiers cannot" "" } ! typedef typename T::myT __restrict__ p;// { dg-warning "ignoring '__restrict__'" "" { xfail *-*-* } } // The following are DR 295 dependent typedef typename T::myT volatile *myvolatile; --- 17,23 ---- template <typename T> struct B1 : T { typedef typename T::L __restrict__ r;// { dg-error "'__restrict__' qualifiers cannot" "" } ! typedef typename T::myT __restrict__ p;// { dg-error "ignoring '__restrict__'" } // The following are DR 295 dependent typedef typename T::myT volatile *myvolatile; Index: g++.old-deja/g++.pt/ptrmem5.C =================================================================== RCS file: /cvsroot/gcc/gcc/gcc/testsuite/g++.old-deja/g++.pt/ptrmem5.C,v retrieving revision 1.3 diff -c -3 -p -b -r1.3 ptrmem5.C *** g++.old-deja/g++.pt/ptrmem5.C 1 May 2003 02:02:55 -0000 1.3 --- g++.old-deja/g++.pt/ptrmem5.C 22 Jan 2005 17:10:31 -0000 *************** struct Null { *** 14,17 **** int *pd = NULL; int (*pf)() = NULL; int Null::*pmd = NULL; ! int (Null::*pmf)() = NULL; // { dg-bogus "" "" { xfail *-*-* } } - cannot convert - --- 14,17 ---- int *pd = NULL; int (*pf)() = NULL; int Null::*pmd = NULL; ! int (Null::*pmf)() = NULL;
Index Nav: | [Date Index] [Subject Index] [Author Index] [Thread Index] | |
---|---|---|
Message Nav: | [Date Prev] [Date Next] | [Thread Prev] [Thread Next] |