aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorFabien Chêne <fabien@gcc.gnu.org>2011-11-14 18:55:57 +0100
committerJason Merrill <jason@gcc.gnu.org>2011-11-14 12:55:57 -0500
commit557831a91df947b447fc9fd94ecad02470a3c86a (patch)
treef07e77967d125d0ff0d7a38837f5d8b94e0bf38f /gcc
parentac99ebf5ae4e852bf4aa158d7d8cc2a14c73c7e8 (diff)
downloadgcc-557831a91df947b447fc9fd94ecad02470a3c86a.zip
gcc-557831a91df947b447fc9fd94ecad02470a3c86a.tar.gz
gcc-557831a91df947b447fc9fd94ecad02470a3c86a.tar.bz2
re PR c++/6936 (member "using" binds wrong)
PR c++/6936 PR c++/25994 PR c++/26256 PR c++/30195 * search.c (lookup_field_1): Look through USING_DECL. (lookup_field_r): Call lookup_fnfields_slot instead of lookup_fnfields_1. * semantics.c (finish_member_declaration): Remove the check that prevents USING_DECLs from being verified by pushdecl_class_level. Call add_method for using declarations that designates functions if the using declaration is in a template class. Set DECL_IGNORED_P on class-scope using declarations. * typeck.c (build_class_member_access_expr): Handle USING_DECLs. * class.c (check_field_decls): Keep using declarations. (add_method): Remove two diagnostics about conflicting using declarations. * parser.c (cp_parser_nonclass_name): Handle USING_DECLs. * decl.c (start_enum): Call xref_tag whenever possible. * cp-tree.h (strip_using_decl): Declare, and reident the previous function. * name-lookup.c (strip_using_decl): New function. (supplement_binding_1): Call strip_using_decl on decl and bval. Perform most of the checks with USING_DECLs stripped. Also check that the target decl and the target bval does not refer to the same declaration. Allow pushing an enum multiple times in a template class. Adjustment to diagnose using redeclarations. Call diagnose_name_conflict. (push_class_level_binding): Call strip_using_decl on decl and bval. Perform most of the checks with USING_DECLs stripped. Return true if both decl and bval refer to USING_DECLs and are dependent. (diagnose_name_conflict): New function. From-SVN: r181359
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/ChangeLog34
-rw-r--r--gcc/cp/class.c12
-rw-r--r--gcc/cp/cp-tree.h3
-rw-r--r--gcc/cp/decl.c18
-rw-r--r--gcc/cp/name-lookup.c139
-rw-r--r--gcc/cp/parser.c3
-rw-r--r--gcc/cp/search.c34
-rw-r--r--gcc/cp/semantics.c24
-rw-r--r--gcc/cp/typeck.c6
-rw-r--r--gcc/testsuite/ChangeLog47
-rw-r--r--gcc/testsuite/g++.dg/abi/mangle41.C5
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/forw_enum10.C31
-rw-r--r--gcc/testsuite/g++.dg/debug/using4.C24
-rw-r--r--gcc/testsuite/g++.dg/debug/using5.C23
-rw-r--r--gcc/testsuite/g++.dg/inherit/using4.C4
-rw-r--r--gcc/testsuite/g++.dg/lookup/name-clash9.C4
-rw-r--r--gcc/testsuite/g++.dg/lookup/pr6936.C23
-rw-r--r--gcc/testsuite/g++.dg/lookup/using24.C12
-rw-r--r--gcc/testsuite/g++.dg/lookup/using25.C28
-rw-r--r--gcc/testsuite/g++.dg/lookup/using26.C27
-rw-r--r--gcc/testsuite/g++.dg/lookup/using27.C48
-rw-r--r--gcc/testsuite/g++.dg/lookup/using28.C11
-rw-r--r--gcc/testsuite/g++.dg/lookup/using29.C81
-rw-r--r--gcc/testsuite/g++.dg/lookup/using30.C8
-rw-r--r--gcc/testsuite/g++.dg/lookup/using31.C8
-rw-r--r--gcc/testsuite/g++.dg/lookup/using32.C9
-rw-r--r--gcc/testsuite/g++.dg/lookup/using33.C26
-rw-r--r--gcc/testsuite/g++.dg/lookup/using34.C10
-rw-r--r--gcc/testsuite/g++.dg/lookup/using35.C11
-rw-r--r--gcc/testsuite/g++.dg/lookup/using36.C31
-rw-r--r--gcc/testsuite/g++.dg/lookup/using37.C22
-rw-r--r--gcc/testsuite/g++.dg/lookup/using38.C23
-rw-r--r--gcc/testsuite/g++.dg/lookup/using39.C63
-rw-r--r--gcc/testsuite/g++.dg/lookup/using40.C28
-rw-r--r--gcc/testsuite/g++.dg/lookup/using41.C21
-rw-r--r--gcc/testsuite/g++.dg/lookup/using42.C26
-rw-r--r--gcc/testsuite/g++.dg/lookup/using44.C28
-rw-r--r--gcc/testsuite/g++.dg/lookup/using45.C33
-rw-r--r--gcc/testsuite/g++.dg/parse/ctor5.C2
-rw-r--r--gcc/testsuite/g++.dg/template/static4.C2
-rw-r--r--gcc/testsuite/g++.dg/template/typedef1.C2
-rw-r--r--gcc/testsuite/g++.dg/template/using2.C15
-rw-r--r--gcc/testsuite/g++.old-deja/g++.brendan/misc14.C4
-rw-r--r--gcc/testsuite/g++.old-deja/g++.bugs/900127_02.C4
-rw-r--r--gcc/testsuite/g++.old-deja/g++.jason/scoping16.C2
-rw-r--r--gcc/testsuite/g++.old-deja/g++.other/anon7.C6
-rw-r--r--gcc/testsuite/g++.old-deja/g++.other/redecl1.C2
-rw-r--r--gcc/testsuite/g++.old-deja/g++.other/typedef7.C4
-rw-r--r--gcc/testsuite/g++.old-deja/g++.other/using1.C6
49 files changed, 931 insertions, 106 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index a33332c..e9a7330 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,37 @@
+2011-11-14 Fabien Chêne <fabien@gcc.gnu.org>
+
+ PR c++/6936
+ PR c++/25994
+ PR c++/26256
+ PR c++/30195
+ * search.c (lookup_field_1): Look through USING_DECL.
+ (lookup_field_r): Call lookup_fnfields_slot instead of
+ lookup_fnfields_1.
+ * semantics.c (finish_member_declaration): Remove the check that
+ prevents USING_DECLs from being verified by
+ pushdecl_class_level. Call add_method for using declarations that
+ designates functions if the using declaration is in a template
+ class. Set DECL_IGNORED_P on class-scope using declarations.
+ * typeck.c (build_class_member_access_expr): Handle USING_DECLs.
+ * class.c (check_field_decls): Keep using declarations.
+ (add_method): Remove two diagnostics about conflicting using
+ declarations.
+ * parser.c (cp_parser_nonclass_name): Handle USING_DECLs.
+ * decl.c (start_enum): Call xref_tag whenever possible.
+ * cp-tree.h (strip_using_decl): Declare, and reident the previous
+ function.
+ * name-lookup.c (strip_using_decl): New function.
+ (supplement_binding_1): Call strip_using_decl on decl and
+ bval. Perform most of the checks with USING_DECLs stripped. Also
+ check that the target decl and the target bval does not refer to
+ the same declaration. Allow pushing an enum multiple times in a
+ template class. Adjustment to diagnose using redeclarations. Call
+ diagnose_name_conflict.
+ (push_class_level_binding): Call strip_using_decl on decl and
+ bval. Perform most of the checks with USING_DECLs stripped. Return
+ true if both decl and bval refer to USING_DECLs and are dependent.
+ (diagnose_name_conflict): New function.
+
2011-11-12 Jason Merrill <jason@redhat.com>
PR c++/986
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index d2cf63c..4a291ac 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -1058,11 +1058,6 @@ add_method (tree type, tree method, tree using_decl)
if (DECL_CONTEXT (fn) == type)
/* Defer to the local function. */
return false;
- if (DECL_CONTEXT (fn) == DECL_CONTEXT (method))
- error ("repeated using declaration %q+D", using_decl);
- else
- error ("using declaration %q+D conflicts with a previous using declaration",
- using_decl);
}
else
{
@@ -3039,15 +3034,8 @@ check_field_decls (tree t, tree *access_decls,
if (TREE_CODE (x) == USING_DECL)
{
- /* Prune the access declaration from the list of fields. */
- *field = DECL_CHAIN (x);
-
/* Save the access declarations for our caller. */
*access_decls = tree_cons (NULL_TREE, x, *access_decls);
-
- /* Since we've reset *FIELD there's no reason to skip to the
- next field. */
- next = field;
continue;
}
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index b306976..fe50e34 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5886,7 +5886,8 @@ extern void cxx_omp_finish_clause (tree);
extern bool cxx_omp_privatize_by_reference (const_tree);
/* in name-lookup.c */
-extern void suggest_alternatives_for (location_t, tree);
+extern void suggest_alternatives_for (location_t, tree);
+extern tree strip_using_decl (tree);
/* -- end of C++ */
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 1c46adf..d744da8 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -11988,8 +11988,22 @@ start_enum (tree name, tree enumtype, tree underlying_type,
*is_new = true;
}
prevtype = enumtype;
- enumtype = cxx_make_type (ENUMERAL_TYPE);
- enumtype = pushtag (name, enumtype, /*tag_scope=*/ts_current);
+
+ /* Do not push the decl more than once, unless we need to
+ compare underlying types at instantiation time */
+ if (!enumtype
+ || (underlying_type
+ && dependent_type_p (underlying_type))
+ || (ENUM_UNDERLYING_TYPE (enumtype)
+ && dependent_type_p (ENUM_UNDERLYING_TYPE (enumtype))))
+ {
+ enumtype = cxx_make_type (ENUMERAL_TYPE);
+ enumtype = pushtag (name, enumtype, /*tag_scope=*/ts_current);
+ }
+ else
+ enumtype = xref_tag (enum_type, name, /*tag_scope=*/ts_current,
+ false);
+
if (enumtype == error_mark_node)
return error_mark_node;
diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
index 044a97f..7f6b8cd 100644
--- a/gcc/cp/name-lookup.c
+++ b/gcc/cp/name-lookup.c
@@ -53,6 +53,7 @@ static bool qualified_lookup_using_namespace (tree, tree,
static tree lookup_type_current_level (tree);
static tree push_using_directive (tree);
static tree lookup_extern_c_fun_in_all_ns (tree);
+static void diagnose_name_conflict (tree, tree);
/* The :: namespace. */
@@ -394,6 +395,16 @@ pop_binding (tree id, tree decl)
}
}
+/* Strip non dependent using declarations. */
+
+tree
+strip_using_decl (tree decl)
+{
+ while (TREE_CODE (decl) == USING_DECL && !DECL_DEPENDENT_P (decl))
+ decl = USING_DECL_DECLS (decl);
+ return decl;
+}
+
/* BINDING records an existing declaration for a name in the current scope.
But, DECL is another declaration for that same identifier in the
same scope. This is the `struct stat' hack whereby a non-typedef
@@ -417,29 +428,46 @@ supplement_binding_1 (cxx_binding *binding, tree decl)
{
tree bval = binding->value;
bool ok = true;
-
- if (TREE_CODE (decl) == TYPE_DECL && DECL_ARTIFICIAL (decl))
+ tree target_bval = strip_using_decl (bval);
+ tree target_decl = strip_using_decl (decl);
+
+ if (TREE_CODE (target_decl) == TYPE_DECL && DECL_ARTIFICIAL (target_decl)
+ && target_decl != target_bval
+ && (TREE_CODE (target_bval) != TYPE_DECL
+ /* We allow pushing an enum multiple times in a class
+ template in order to handle late matching of underlying
+ type on an opaque-enum-declaration followed by an
+ enum-specifier. */
+ || (TREE_CODE (TREE_TYPE (target_decl)) == ENUMERAL_TYPE
+ && TREE_CODE (TREE_TYPE (target_bval)) == ENUMERAL_TYPE
+ && (dependent_type_p (ENUM_UNDERLYING_TYPE
+ (TREE_TYPE (target_decl)))
+ || dependent_type_p (ENUM_UNDERLYING_TYPE
+ (TREE_TYPE (target_bval)))))))
/* The new name is the type name. */
binding->type = decl;
- else if (/* BVAL is null when push_class_level_binding moves an
- inherited type-binding out of the way to make room for a
- new value binding. */
- !bval
- /* BVAL is error_mark_node when DECL's name has been used
- in a non-class scope prior declaration. In that case,
- we should have already issued a diagnostic; for graceful
- error recovery purpose, pretend this was the intended
- declaration for that name. */
- || bval == error_mark_node
- /* If BVAL is anticipated but has not yet been declared,
- pretend it is not there at all. */
- || (TREE_CODE (bval) == FUNCTION_DECL
- && DECL_ANTICIPATED (bval)
- && !DECL_HIDDEN_FRIEND_P (bval)))
+ else if (/* TARGET_BVAL is null when push_class_level_binding moves
+ an inherited type-binding out of the way to make room
+ for a new value binding. */
+ !target_bval
+ /* TARGET_BVAL is error_mark_node when TARGET_DECL's name
+ has been used in a non-class scope prior declaration.
+ In that case, we should have already issued a
+ diagnostic; for graceful error recovery purpose, pretend
+ this was the intended declaration for that name. */
+ || target_bval == error_mark_node
+ /* If TARGET_BVAL is anticipated but has not yet been
+ declared, pretend it is not there at all. */
+ || (TREE_CODE (target_bval) == FUNCTION_DECL
+ && DECL_ANTICIPATED (target_bval)
+ && !DECL_HIDDEN_FRIEND_P (target_bval)))
binding->value = decl;
- else if (TREE_CODE (bval) == TYPE_DECL && DECL_ARTIFICIAL (bval)
- && (TREE_CODE (decl) != TYPE_DECL
- || same_type_p (TREE_TYPE (decl), TREE_TYPE (bval))))
+ else if (TREE_CODE (target_bval) == TYPE_DECL
+ && DECL_ARTIFICIAL (target_bval)
+ && target_decl != target_bval
+ && (TREE_CODE (target_decl) != TYPE_DECL
+ || same_type_p (TREE_TYPE (target_decl),
+ TREE_TYPE (target_bval))))
{
/* The old binding was a type name. It was placed in
VALUE field because it was thought, at the point it was
@@ -450,15 +478,15 @@ supplement_binding_1 (cxx_binding *binding, tree decl)
binding->value = decl;
binding->value_is_inherited = false;
}
- else if (TREE_CODE (bval) == TYPE_DECL
- && TREE_CODE (decl) == TYPE_DECL
- && DECL_NAME (decl) == DECL_NAME (bval)
+ else if (TREE_CODE (target_bval) == TYPE_DECL
+ && TREE_CODE (target_decl) == TYPE_DECL
+ && DECL_NAME (target_decl) == DECL_NAME (target_bval)
&& binding->scope->kind != sk_class
- && (same_type_p (TREE_TYPE (decl), TREE_TYPE (bval))
+ && (same_type_p (TREE_TYPE (target_decl), TREE_TYPE (target_bval))
/* If either type involves template parameters, we must
wait until instantiation. */
- || uses_template_parms (TREE_TYPE (decl))
- || uses_template_parms (TREE_TYPE (bval))))
+ || uses_template_parms (TREE_TYPE (target_decl))
+ || uses_template_parms (TREE_TYPE (target_bval))))
/* We have two typedef-names, both naming the same type to have
the same name. In general, this is OK because of:
@@ -480,9 +508,10 @@ supplement_binding_1 (cxx_binding *binding, tree decl)
A member shall not be declared twice in the
member-specification. */
- else if (TREE_CODE (decl) == VAR_DECL && TREE_CODE (bval) == VAR_DECL
- && DECL_EXTERNAL (decl) && DECL_EXTERNAL (bval)
- && !DECL_CLASS_SCOPE_P (decl))
+ else if (TREE_CODE (target_decl) == VAR_DECL
+ && TREE_CODE (target_bval) == VAR_DECL
+ && DECL_EXTERNAL (target_decl) && DECL_EXTERNAL (target_bval)
+ && !DECL_CLASS_SCOPE_P (target_decl))
{
duplicate_decls (decl, binding->value, /*newdecl_is_friend=*/false);
ok = false;
@@ -501,14 +530,30 @@ supplement_binding_1 (cxx_binding *binding, tree decl)
ok = false;
else
{
- error ("declaration of %q#D", decl);
- error ("conflicts with previous declaration %q+#D", bval);
+ diagnose_name_conflict (decl, bval);
ok = false;
}
return ok;
}
+/* Diagnose a name conflict between DECL and BVAL. */
+
+static void
+diagnose_name_conflict (tree decl, tree bval)
+{
+ if (TREE_CODE (decl) == TREE_CODE (bval)
+ && (TREE_CODE (decl) != TYPE_DECL
+ || (DECL_ARTIFICIAL (decl) && DECL_ARTIFICIAL (bval))
+ || (!DECL_ARTIFICIAL (decl) && !DECL_ARTIFICIAL (bval)))
+ && !is_overloaded_fn (decl))
+ error ("redeclaration of %q#D", decl);
+ else
+ error ("%q#D conflicts with a previous declaration", decl);
+
+ inform (input_location, "previous declaration %q+#D", bval);
+}
+
/* Wrapper for supplement_binding_1. */
static bool
@@ -3028,6 +3073,8 @@ push_class_level_binding_1 (tree name, tree x)
{
tree bval = binding->value;
tree old_decl = NULL_TREE;
+ tree target_decl = strip_using_decl (decl);
+ tree target_bval = strip_using_decl (bval);
if (INHERITED_VALUE_BINDING_P (binding))
{
@@ -3035,8 +3082,10 @@ push_class_level_binding_1 (tree name, tree x)
tag name, slide it over to make room for the new binding.
The old binding is still visible if explicitly qualified
with a class-key. */
- if (TREE_CODE (bval) == TYPE_DECL && DECL_ARTIFICIAL (bval)
- && !(TREE_CODE (x) == TYPE_DECL && DECL_ARTIFICIAL (x)))
+ if (TREE_CODE (target_bval) == TYPE_DECL
+ && DECL_ARTIFICIAL (target_bval)
+ && !(TREE_CODE (target_decl) == TYPE_DECL
+ && DECL_ARTIFICIAL (target_decl)))
{
old_decl = binding->type;
binding->type = bval;
@@ -3048,17 +3097,31 @@ push_class_level_binding_1 (tree name, tree x)
old_decl = bval;
/* Any inherited type declaration is hidden by the type
declaration in the derived class. */
- if (TREE_CODE (x) == TYPE_DECL && DECL_ARTIFICIAL (x))
+ if (TREE_CODE (target_decl) == TYPE_DECL
+ && DECL_ARTIFICIAL (target_decl))
binding->type = NULL_TREE;
}
}
- else if (TREE_CODE (x) == OVERLOAD && is_overloaded_fn (bval))
+ else if (TREE_CODE (target_decl) == OVERLOAD
+ && is_overloaded_fn (target_bval))
old_decl = bval;
- else if (TREE_CODE (x) == USING_DECL && TREE_CODE (bval) == USING_DECL)
+ else if (TREE_CODE (decl) == USING_DECL
+ && TREE_CODE (bval) == USING_DECL
+ && same_type_p (USING_DECL_SCOPE (decl),
+ USING_DECL_SCOPE (bval)))
+ /* This is a using redeclaration that will be diagnosed later
+ in supplement_binding */
+ ;
+ else if (TREE_CODE (decl) == USING_DECL
+ && TREE_CODE (bval) == USING_DECL
+ && DECL_DEPENDENT_P (decl)
+ && DECL_DEPENDENT_P (bval))
return true;
- else if (TREE_CODE (x) == USING_DECL && is_overloaded_fn (bval))
+ else if (TREE_CODE (decl) == USING_DECL
+ && is_overloaded_fn (target_bval))
old_decl = bval;
- else if (TREE_CODE (bval) == USING_DECL && is_overloaded_fn (x))
+ else if (TREE_CODE (bval) == USING_DECL
+ && is_overloaded_fn (target_decl))
return true;
if (old_decl && binding->scope == class_binding_level)
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index fc8f3c8..23885b8 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -13758,6 +13758,9 @@ cp_parser_nonclass_name (cp_parser* parser)
/* Look up the type-name. */
type_decl = cp_parser_lookup_name_simple (parser, identifier, token->location);
+ /* If it is a using decl, use its underlying decl. */
+ type_decl = strip_using_decl (type_decl);
+
if (TREE_CODE (type_decl) != TYPE_DECL
&& (objc_is_id (identifier) || objc_is_class_name (identifier)))
{
diff --git a/gcc/cp/search.c b/gcc/cp/search.c
index 7d9551c..9f308e2 100644
--- a/gcc/cp/search.c
+++ b/gcc/cp/search.c
@@ -1,7 +1,7 @@
/* Breadth-first and depth-first routines for
searching multiple-inheritance lattice for GNU C++.
Copyright (C) 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010
+ 1999, 2000, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010, 2011
Free Software Foundation, Inc.
Contributed by Michael Tiemann (tiemann@cygnus.com)
@@ -449,6 +449,8 @@ lookup_field_1 (tree type, tree name, bool want_type)
#endif /* GATHER_STATISTICS */
for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
{
+ tree decl = field;
+
#ifdef GATHER_STATISTICS
n_fields_searched++;
#endif /* GATHER_STATISTICS */
@@ -460,26 +462,20 @@ lookup_field_1 (tree type, tree name, bool want_type)
if (temp)
return temp;
}
- if (TREE_CODE (field) == USING_DECL)
+
+ if (TREE_CODE (decl) == USING_DECL
+ && DECL_NAME (decl) == name)
{
- /* We generally treat class-scope using-declarations as
- ARM-style access specifications, because support for the
- ISO semantics has not been implemented. So, in general,
- there's no reason to return a USING_DECL, and the rest of
- the compiler cannot handle that. Once the class is
- defined, USING_DECLs are purged from TYPE_FIELDS; see
- handle_using_decl. However, we make special efforts to
- make using-declarations in class templates and class
- template partial specializations work correctly. */
- if (!DECL_DEPENDENT_P (field))
+ decl = strip_using_decl (decl);
+ if (is_overloaded_fn (decl))
continue;
}
- if (DECL_NAME (field) == name
+ if (DECL_NAME (decl) == name
&& (!want_type
- || TREE_CODE (field) == TYPE_DECL
- || DECL_TYPE_TEMPLATE_P (field)))
- return field;
+ || TREE_CODE (decl) == TYPE_DECL
+ || DECL_TYPE_TEMPLATE_P (decl)))
+ return decl;
}
/* Not found. */
if (name == vptr_identifier)
@@ -1028,11 +1024,7 @@ lookup_field_r (tree binfo, void *data)
member with the same name, and if there's a function and a type
with the same name, the type is hidden by the function. */
if (!lfi->want_type)
- {
- int idx = lookup_fnfields_1 (type, lfi->name);
- if (idx >= 0)
- nval = VEC_index (tree, CLASSTYPE_METHOD_VEC (type), idx);
- }
+ nval = lookup_fnfields_slot (type, lfi->name);
if (!nval)
/* Look for a data member or type. */
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index e9da381..f70bdb3 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -2658,9 +2658,29 @@ finish_member_declaration (tree decl)
}
}
/* Enter the DECL into the scope of the class. */
- else if ((TREE_CODE (decl) == USING_DECL && !DECL_DEPENDENT_P (decl))
- || pushdecl_class_level (decl))
+ else if (pushdecl_class_level (decl))
{
+ if (TREE_CODE (decl) == USING_DECL)
+ {
+ /* We need to add the target functions to the
+ CLASSTYPE_METHOD_VEC if an enclosing scope is a template
+ class, so that this function be found by lookup_fnfields_1
+ when the using declaration is not instantiated yet. */
+
+ tree target_decl = strip_using_decl (decl);
+ if (dependent_type_p (current_class_type)
+ && is_overloaded_fn (target_decl))
+ {
+ tree t = target_decl;
+ for (; t; t = OVL_NEXT (t))
+ add_method (current_class_type, OVL_CURRENT (t), decl);
+ }
+
+ /* For now, ignore class-scope USING_DECLS, so that
+ debugging backends do not see them. */
+ DECL_IGNORED_P (decl) = 1;
+ }
+
/* All TYPE_DECLs go at the end of TYPE_FIELDS. Ordinary fields
go at the beginning. The reason is that lookup_field_1
searches the list in order, and we want a field name to
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 722cec5..f08877c 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -2115,6 +2115,7 @@ build_class_member_access_expr (tree object, tree member,
tree object_type;
tree member_scope;
tree result = NULL_TREE;
+ tree using_decl = NULL_TREE;
if (error_operand_p (object) || error_operand_p (member))
return error_mark_node;
@@ -2343,6 +2344,11 @@ build_class_member_access_expr (tree object, tree member,
result = build2 (COMPOUND_EXPR, TREE_TYPE (result),
object, result);
}
+ else if ((using_decl = strip_using_decl (member)) != member)
+ result = build_class_member_access_expr (object,
+ using_decl,
+ access_path, preserve_reference,
+ complain);
else
{
if (complain & tf_error)
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 57e5eb5..7a7445e 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,50 @@
+2011-11-14 Fabien Chêne <fabien@gcc.gnu.org>
+
+ PR c++/6936
+ PR c++/25994
+ PR c++/26256
+ PR c++/30195
+ * g++.old-deja/g++.brendan/misc14.C: Adjust.
+ * g++.old-deja/g++.jason/scoping16.C: Likewise.
+ * g++.old-deja/g++.other/anon7.C: Likewise.
+ * g++.old-deja/g++.other/using1.C: Likewise.
+ * g++.old-deja/g++.other/redecl1.C: Likewise.
+ * g++.old-deja/g++.other/typedef7.C: Likewise.
+ * g++.old-deja/g++.bugs/900127_02.C: Likewise.
+ * g++.dg/template/using2.C: Likewise.
+ * g++.dg/template/static4.C: Likewise.
+ * g++.dg/template/typedef1.C: Likewise.
+ * g++.dg/lookup/name-clash9.C: Likewise.
+ * g++.dg/abi/mangle41.C: Likewise.
+ * g++.dg/parse/ctor5.C: Likewise.
+ * g++.dg/inherit/using4.C: Likewise.
+ * g++.dg/lookup/using24.C: New.
+ * g++.dg/lookup/using25.C: New.
+ * g++.dg/lookup/using26.C: New.
+ * g++.dg/lookup/using27.C: New.
+ * g++.dg/lookup/using28.C: New.
+ * g++.dg/lookup/using29.C: New.
+ * g++.dg/lookup/using30.C: New.
+ * g++.dg/lookup/using31.C: New.
+ * g++.dg/lookup/using32.C: New.
+ * g++.dg/lookup/using33.C: New.
+ * g++.dg/lookup/using34.C: New.
+ * g++.dg/lookup/using35.C: New.
+ * g++.dg/lookup/using36.C: New.
+ * g++.dg/lookup/using37.C: New.
+ * g++.dg/lookup/using38.C: New.
+ * g++.dg/lookup/using39.C: New.
+ * g++.dg/lookup/using40.C: New.
+ * g++.dg/lookup/using41.C: New.
+ * g++.dg/lookup/using42.C: New.
+ * g++.dg/lookup/using43.C: New.
+ * g++.dg/lookup/using44.C: New.
+ * g++.dg/lookup/using45.C: New.
+ * g++.dg/lookup/pr6936.C: New.
+ * g++.dg/debug/using4.C: New.
+ * g++.dg/debug/using5.C: New.
+ * g++.dg/cpp0x/forw_enum10.C: New.
+
2011-11-14 Zolotukhin Michael <michael.v.zolotukhin@gmail.com>
Jan Hubicka <jh@suse.cz>
diff --git a/gcc/testsuite/g++.dg/abi/mangle41.C b/gcc/testsuite/g++.dg/abi/mangle41.C
index 3a9c04f..4c0d003 100644
--- a/gcc/testsuite/g++.dg/abi/mangle41.C
+++ b/gcc/testsuite/g++.dg/abi/mangle41.C
@@ -3,5 +3,6 @@
// { dg-options "-mavx -fabi-version=2" }
#include <x86intrin.h>
-void f(__m128) { } // { dg-error "previous" }
-void f(__m256) { } // { dg-message "declaration|mangling" }
+void f(__m128) { } // { dg-message "previous declaration" }
+void f(__m256) { } // { dg-error "conflicts" }
+// { dg-message "mangling" "" { target *-*-* } 7 }
diff --git a/gcc/testsuite/g++.dg/cpp0x/forw_enum10.C b/gcc/testsuite/g++.dg/cpp0x/forw_enum10.C
new file mode 100644
index 0000000..a57c0a9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/forw_enum10.C
@@ -0,0 +1,31 @@
+// { dg-do compile }
+// { dg-options "-std=c++0x" }
+
+//This error is diagnosed at instantiation time
+template<typename T> struct S1
+{
+ enum E : T; // { dg-error "previous definition" }
+ enum E : int; // { dg-error "different underlying type" }
+};
+template struct S1<short>; // { dg-message "required from here" }
+
+template<typename T> struct S2
+{
+ enum E : T;
+ enum E : T;
+};
+template struct S2<short>;
+
+template<typename T1, typename T2> struct S3
+{
+ enum E : T1;
+ enum E : T2;
+};
+template struct S3<short,short>;
+
+template<typename T1, typename T2> struct S4
+{
+ enum E : T1; // { dg-error "previous definition" }
+ enum E : T2; // { dg-error "different underlying type" }
+};
+template struct S4<short,char>; // { dg-message "required from here" }
diff --git a/gcc/testsuite/g++.dg/debug/using4.C b/gcc/testsuite/g++.dg/debug/using4.C
new file mode 100644
index 0000000..8a61626
--- /dev/null
+++ b/gcc/testsuite/g++.dg/debug/using4.C
@@ -0,0 +1,24 @@
+// PR c++/26256
+// { dg-do compile }
+
+struct A
+{
+ typedef char type;
+};
+
+struct B
+{
+ typedef int type;
+};
+
+struct C : A, B
+{
+ using A::type;
+ type f (type);
+};
+
+C::type C::f( type )
+{
+ type c = 'e';
+ return c;
+}
diff --git a/gcc/testsuite/g++.dg/debug/using5.C b/gcc/testsuite/g++.dg/debug/using5.C
new file mode 100644
index 0000000..3f2de9b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/debug/using5.C
@@ -0,0 +1,23 @@
+// PR c++/26256
+// { dg-do compile }
+
+struct A
+{
+ int i;
+};
+
+struct B
+{
+ int i;
+};
+
+struct C : A, B
+{
+ using B::i;
+ int f ();
+};
+
+int C::f()
+{
+ return i;
+}
diff --git a/gcc/testsuite/g++.dg/inherit/using4.C b/gcc/testsuite/g++.dg/inherit/using4.C
index a0b3873..4b7a28f 100644
--- a/gcc/testsuite/g++.dg/inherit/using4.C
+++ b/gcc/testsuite/g++.dg/inherit/using4.C
@@ -9,6 +9,6 @@ struct B {
};
struct D : B {
- using B::f;
- using B::f; // { dg-error "repeated" }
+ using B::f; // { dg-message "previous declaration" }
+ using B::f; // { dg-error "redeclaration" }
};
diff --git a/gcc/testsuite/g++.dg/lookup/name-clash9.C b/gcc/testsuite/g++.dg/lookup/name-clash9.C
index 4167f47..1e04faf 100644
--- a/gcc/testsuite/g++.dg/lookup/name-clash9.C
+++ b/gcc/testsuite/g++.dg/lookup/name-clash9.C
@@ -3,6 +3,6 @@
struct A
{
- struct type {}; // { dg-error "conflicts with previous" }
- typedef int type; // { dg-error "declaration" }
+ struct type {}; // { dg-message "previous" }
+ typedef int type; // { dg-error "conflicts" }
};
diff --git a/gcc/testsuite/g++.dg/lookup/pr6936.C b/gcc/testsuite/g++.dg/lookup/pr6936.C
new file mode 100644
index 0000000..377fbcc
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lookup/pr6936.C
@@ -0,0 +1,23 @@
+// { dg-do compile }
+// PR c++/6936
+
+struct Baser
+{
+ enum { j, i }; // { dg-error "inaccessible" }
+};
+
+struct Base : Baser
+{
+ static void j();
+ static void i();
+};
+
+struct Derv : Base
+{
+ using Baser::j;
+private:
+ using Baser::i;
+};
+
+int k = Derv::j;
+int l = Derv::i; // { dg-error "context" }
diff --git a/gcc/testsuite/g++.dg/lookup/using24.C b/gcc/testsuite/g++.dg/lookup/using24.C
new file mode 100644
index 0000000..4413be1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lookup/using24.C
@@ -0,0 +1,12 @@
+// PR c++/26256
+// { dg-do compile }
+
+struct A { int next; };
+struct B { int next; };
+struct C : B { using B::next; };
+
+struct D : A, C
+{
+ using C::next;
+ void f() { next = 1; }
+};
diff --git a/gcc/testsuite/g++.dg/lookup/using25.C b/gcc/testsuite/g++.dg/lookup/using25.C
new file mode 100644
index 0000000..eb60570
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lookup/using25.C
@@ -0,0 +1,28 @@
+// PR c++/26256
+// { dg-do run }
+
+struct A
+{
+ int next;
+};
+
+struct B
+{
+ int next;
+};
+
+struct C : public A, public B
+{
+ using A::next;
+};
+
+void foo(C& c) { c.next = 42; }
+
+int main()
+{
+ C c;
+ foo (c);
+ c.B::next = 12;
+ if (c.next != 42 || c.A::next != 42 || c.B::next != 12)
+ __builtin_abort();
+}
diff --git a/gcc/testsuite/g++.dg/lookup/using26.C b/gcc/testsuite/g++.dg/lookup/using26.C
new file mode 100644
index 0000000..141d145
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lookup/using26.C
@@ -0,0 +1,27 @@
+// PR c++/26256
+// { dg-do compile }
+
+struct A
+{
+ double next;
+};
+
+struct B
+{
+private:
+ int next; // { dg-error "private" }
+};
+
+struct C
+{
+ int next;
+};
+
+struct D : A, B, C // { dg-error "context" }
+{
+ using B::next;
+ void f()
+ {
+ next = 12;
+ }
+};
diff --git a/gcc/testsuite/g++.dg/lookup/using27.C b/gcc/testsuite/g++.dg/lookup/using27.C
new file mode 100644
index 0000000..c94cf6e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lookup/using27.C
@@ -0,0 +1,48 @@
+// PR c++/26256
+// { dg-do run }
+
+struct A
+{
+ typedef int type;
+};
+
+struct B
+{
+ typedef double type;
+};
+
+struct C : A, B
+{
+ using A::type;
+ type d;
+
+ void f()
+ {
+ type e;
+ if (sizeof (type) != sizeof (A::type))
+ __builtin_abort();
+ }
+
+ void g();
+};
+
+void C::g()
+{
+ type x;
+ if (sizeof (type) != sizeof (A::type))
+ __builtin_abort();
+}
+
+int main ()
+{
+ if (sizeof (C::type) != sizeof (A::type))
+ __builtin_abort();
+
+ if (sizeof (C::d) != sizeof (A::type))
+ __builtin_abort();
+
+ C::type x;
+ C c;
+ c.f();
+ c.g();
+}
diff --git a/gcc/testsuite/g++.dg/lookup/using28.C b/gcc/testsuite/g++.dg/lookup/using28.C
new file mode 100644
index 0000000..ae4067a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lookup/using28.C
@@ -0,0 +1,11 @@
+// PR c++/26256
+// { dg-do compile }
+
+struct A { int f; };
+struct B { int f; };
+struct C : A, B { using B::f; };
+
+struct D : C
+{
+ void g() { f = 1; }
+};
diff --git a/gcc/testsuite/g++.dg/lookup/using29.C b/gcc/testsuite/g++.dg/lookup/using29.C
new file mode 100644
index 0000000..428021c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lookup/using29.C
@@ -0,0 +1,81 @@
+// { dg-do compile }
+
+struct A
+{
+ int i;
+};
+
+struct B
+{
+ int i;
+};
+
+struct C : A, B
+{
+ using A::i; // { dg-message "previous" }
+ using B::i; // { dg-error "redeclaration" }
+};
+
+struct E
+{
+ typedef int type;
+};
+
+struct F
+{
+ typedef int type;
+};
+
+struct G : E, F
+{
+ using E::type; // { dg-message "previous" }
+ using F::type; // { dg-error "redeclaration" }
+};
+
+struct H
+{
+ typedef int type;
+};
+
+struct I : H
+{
+ typedef int type; // { dg-message "previous" }
+ using H::type; // { dg-error "conflicts" }
+};
+
+struct I2 : H
+{
+ using H::type; // { dg-message "previous" }
+ typedef int type; // { dg-error "conflicts" }
+};
+
+struct J
+{
+ struct type {};
+};
+
+struct K : J
+{
+ struct type {}; // { dg-message "previous" }
+ using J::type; // { dg-error "conflicts" }
+};
+
+struct L : J
+{
+ using J::type; // { dg-message "previous" }
+ struct type {}; // { dg-error "conflicts" }
+};
+
+struct M
+{
+ typedef int type;
+ struct type2 {};
+};
+
+struct N : M
+{
+ using M::type; // { dg-message "previous" }
+ using M::type; // { dg-error "redeclaration" }
+ using M::type2; // { dg-message "previous" }
+ using M::type2; // { dg-error "redeclaration" }
+};
diff --git a/gcc/testsuite/g++.dg/lookup/using30.C b/gcc/testsuite/g++.dg/lookup/using30.C
new file mode 100644
index 0000000..3fbe96c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lookup/using30.C
@@ -0,0 +1,8 @@
+// { dg-do compile }
+
+struct H { typedef int type; };
+struct J : H
+{
+ struct type {}; // { dg-message "previous" }
+ using H::type; // { dg-error "conflicts" }
+};
diff --git a/gcc/testsuite/g++.dg/lookup/using31.C b/gcc/testsuite/g++.dg/lookup/using31.C
new file mode 100644
index 0000000..3b1f6e9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lookup/using31.C
@@ -0,0 +1,8 @@
+// { dg-do compile }
+
+struct H2 { int f (); };
+struct J2 : H2
+{
+ struct f {};
+ using H2::f;
+};
diff --git a/gcc/testsuite/g++.dg/lookup/using32.C b/gcc/testsuite/g++.dg/lookup/using32.C
new file mode 100644
index 0000000..cc0e96c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lookup/using32.C
@@ -0,0 +1,9 @@
+// { dg-do compile }
+
+struct T { struct type {}; };
+struct T2 : T { using T::type; };
+struct T3 : T2
+{
+ struct type {};
+ type t;
+};
diff --git a/gcc/testsuite/g++.dg/lookup/using33.C b/gcc/testsuite/g++.dg/lookup/using33.C
new file mode 100644
index 0000000..a80be03
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lookup/using33.C
@@ -0,0 +1,26 @@
+// { dg-do run }
+
+template <class T>
+struct Foo
+{
+ int k (float) {return 0;}
+};
+
+template <class T>
+struct Baz
+{
+ int k (int) {return 1;}
+};
+
+template <class T>
+struct Bar : Foo<T> , Baz<T>
+{
+ using Foo<T>::k;
+ using Baz<T>::k;
+};
+
+int main()
+{
+ Bar<int> bar;
+ return bar.k( 1.0f );
+}
diff --git a/gcc/testsuite/g++.dg/lookup/using34.C b/gcc/testsuite/g++.dg/lookup/using34.C
new file mode 100644
index 0000000..79c019d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lookup/using34.C
@@ -0,0 +1,10 @@
+// { dg-do compile }
+
+struct A { int f (); };
+struct B : A
+{
+ using A::f;
+ struct f {};
+ void g() { f(); struct f ff; }
+ struct f ff;
+};
diff --git a/gcc/testsuite/g++.dg/lookup/using35.C b/gcc/testsuite/g++.dg/lookup/using35.C
new file mode 100644
index 0000000..e7e8274
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lookup/using35.C
@@ -0,0 +1,11 @@
+// { dg-do compile }
+
+struct A { typedef int type; };
+struct B { typedef int type; };
+struct C : B { using B::type; };
+
+struct D : A, C
+{
+ using C::type;
+ void f() { type t = 0;}
+};
diff --git a/gcc/testsuite/g++.dg/lookup/using36.C b/gcc/testsuite/g++.dg/lookup/using36.C
new file mode 100644
index 0000000..966c60b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lookup/using36.C
@@ -0,0 +1,31 @@
+// PR c++/25994
+// { dg-do run }
+
+struct B1
+{
+ void f (char) {}
+ void f (double) { __builtin_abort(); }
+};
+
+struct B2
+{
+ void f (double) { __builtin_abort(); }
+ void f (int) {}
+};
+
+struct D : public B1, public B2
+{
+ using B1::f;
+ using B2::f;
+ void g ()
+ {
+ f ('a'); // should call B1::f(char)
+ f (33); // should call B2::f(int)
+ }
+};
+
+int main()
+{
+ D d;
+ d.g();
+}
diff --git a/gcc/testsuite/g++.dg/lookup/using37.C b/gcc/testsuite/g++.dg/lookup/using37.C
new file mode 100644
index 0000000..a71206e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lookup/using37.C
@@ -0,0 +1,22 @@
+// PR c++/30195
+// { dg-do run }
+
+template<class T> struct B
+{
+ void foo(T) {}
+};
+
+template<class T>
+struct D : B<int>, B<double>
+{
+ using B<int>::foo;
+ using B<double>::foo;
+ void bar() { foo(3); }
+};
+
+int main()
+{
+ D<int> x;
+ x.bar();
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/lookup/using38.C b/gcc/testsuite/g++.dg/lookup/using38.C
new file mode 100644
index 0000000..377fbcc
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lookup/using38.C
@@ -0,0 +1,23 @@
+// { dg-do compile }
+// PR c++/6936
+
+struct Baser
+{
+ enum { j, i }; // { dg-error "inaccessible" }
+};
+
+struct Base : Baser
+{
+ static void j();
+ static void i();
+};
+
+struct Derv : Base
+{
+ using Baser::j;
+private:
+ using Baser::i;
+};
+
+int k = Derv::j;
+int l = Derv::i; // { dg-error "context" }
diff --git a/gcc/testsuite/g++.dg/lookup/using39.C b/gcc/testsuite/g++.dg/lookup/using39.C
new file mode 100644
index 0000000..56ae89a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lookup/using39.C
@@ -0,0 +1,63 @@
+// { dg-do run }
+
+template <class T>
+struct A
+{
+ int f() { return 1; }
+};
+
+template <class T>
+struct B : A<T>
+{
+ int f() { return 2; }
+
+ using A<T>::f;
+ void g()
+ {
+ if (A<T>::f() != 1 )
+ __builtin_abort();
+
+ if( B<T>::f() != 2 )
+ __builtin_abort();
+
+ if( this->f() != 2 )
+ __builtin_abort();
+ }
+};
+
+template <class T>
+struct C
+{
+ int h( int i ) { return 1; }
+ int h( double d ) { return 2; }
+};
+
+template <class T>
+struct D : private C<T>
+{
+ using C<T>::h;
+ int h( char c ) { return 0; }
+ int h() { return 3; }
+};
+
+int main()
+{
+ B<int> b;
+ b.g();
+ b.f();
+ b.A<int>::f();
+ b.B<int>::f();
+
+ D<int> d;
+ if( d.h( 'a' ) != 0 )
+ __builtin_abort();
+
+ if( d.h( 3 ) != 1 )
+ __builtin_abort();
+
+ if( d.h( 3.14 ) != 2 )
+ __builtin_abort();
+
+ if( d.h() != 3 )
+ __builtin_abort();
+}
diff --git a/gcc/testsuite/g++.dg/lookup/using40.C b/gcc/testsuite/g++.dg/lookup/using40.C
new file mode 100644
index 0000000..1bcdd0d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lookup/using40.C
@@ -0,0 +1,28 @@
+// { dg-do compile }
+
+struct Base
+{
+ void f();
+ typedef int type;
+ struct Type {};
+ int i;
+ static int j;
+};
+
+struct A : Base
+{
+ using Base::f; // { dg-message "previous declaration" }
+ using Base::f; // { dg-error "redeclaration" }
+
+ using Base::type; // { dg-message "previous declaration" }
+ using Base::type; // { dg-error "redeclaration" }
+
+ using Base::Type; // { dg-message "previous declaration" }
+ using Base::Type; // { dg-error "redeclaration" }
+
+ using Base::i; // { dg-message "previous declaration" }
+ using Base::i; // { dg-error "redeclaration" }
+
+ using Base::j; // { dg-message "previous declaration" }
+ using Base::j; // { dg-error "redeclaration" }
+};
diff --git a/gcc/testsuite/g++.dg/lookup/using41.C b/gcc/testsuite/g++.dg/lookup/using41.C
new file mode 100644
index 0000000..dcc618b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lookup/using41.C
@@ -0,0 +1,21 @@
+// { dg-do compile }
+
+template <class T>
+struct Base
+{
+ void f();
+};
+
+template <class T>
+struct A : Base<T>
+{
+ using Base<T>::f; // { dg-message "previous declaration" }
+ using Base<T>::f; // { dg-error "redeclaration" }
+};
+
+template <class T, class U>
+struct B : Base<T>, Base<U>
+{
+ using Base<T>::f;
+ using Base<U>::f;
+};
diff --git a/gcc/testsuite/g++.dg/lookup/using42.C b/gcc/testsuite/g++.dg/lookup/using42.C
new file mode 100644
index 0000000..bca65ac
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lookup/using42.C
@@ -0,0 +1,26 @@
+// PR c++/30195
+// { dg-do run }
+
+template <class T>
+struct B
+{
+ void foo(T) {}
+};
+
+template<class T>
+struct Out
+{
+ struct D : B<T>, B<double>
+ {
+ using B<T>::foo;
+ using B<double>::foo;
+ void bar() { foo(3); }
+ };
+};
+
+int main()
+{
+ Out<int>::D x;
+ x.bar();
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/lookup/using44.C b/gcc/testsuite/g++.dg/lookup/using44.C
new file mode 100644
index 0000000..d754bef
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lookup/using44.C
@@ -0,0 +1,28 @@
+// PR c++/30195
+// { dg-do run }
+
+template <class T>
+struct B
+{
+ void foo(char) { __builtin_abort(); }
+ void foo(short) { __builtin_abort(); }
+ void foo(T) {}
+};
+
+template<class T>
+struct Out
+{
+ struct D : B<T>, B<double>
+ {
+ using B<T>::foo;
+ using B<double>::foo;
+ void bar() { foo(3); }
+ };
+};
+
+int main()
+{
+ Out<int>::D x;
+ x.bar();
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/lookup/using45.C b/gcc/testsuite/g++.dg/lookup/using45.C
new file mode 100644
index 0000000..c92b794
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lookup/using45.C
@@ -0,0 +1,33 @@
+// PR c++/30195
+// { dg-do run }
+
+template <class T>
+struct A
+{
+ int f(int) { return 0; }
+ int f(double) { return 1; }
+ int f(char) { return 2; }
+};
+
+template <class T>
+struct B : A<T>
+{
+ using A<T>::f;
+ int f(int) { return 3; }
+};
+
+int main()
+{
+ B<int> b;
+ if( b.f( 42 ) != 3 )
+ __builtin_abort();
+
+ if( b.f( 3.14 ) != 1 )
+ __builtin_abort();
+
+ if( b.f( 'a' ) != 2 )
+ __builtin_abort();
+
+ if( b.A<int>::f( 42 ) != 0 )
+ __builtin_abort();
+}
diff --git a/gcc/testsuite/g++.dg/parse/ctor5.C b/gcc/testsuite/g++.dg/parse/ctor5.C
index 3ea2354..f980b4a 100644
--- a/gcc/testsuite/g++.dg/parse/ctor5.C
+++ b/gcc/testsuite/g++.dg/parse/ctor5.C
@@ -2,7 +2,7 @@
struct A
{
- int i; // { dg-error "conflicts" }
+ int i; // { dg-message "previous" }
A() i() {} // { dg-error "declaration" }
};
diff --git a/gcc/testsuite/g++.dg/template/static4.C b/gcc/testsuite/g++.dg/template/static4.C
index c548632..526ced6 100644
--- a/gcc/testsuite/g++.dg/template/static4.C
+++ b/gcc/testsuite/g++.dg/template/static4.C
@@ -1,6 +1,6 @@
template <class R>
struct A {
- static int _test; // { dg-error "" }
+ static int _test; // { dg-message "" }
static int _test; // { dg-error "" }
};
template <class R> int A<R>::_test = 0;
diff --git a/gcc/testsuite/g++.dg/template/typedef1.C b/gcc/testsuite/g++.dg/template/typedef1.C
index 75b00e0..270adcd 100644
--- a/gcc/testsuite/g++.dg/template/typedef1.C
+++ b/gcc/testsuite/g++.dg/template/typedef1.C
@@ -12,7 +12,7 @@ template <typename T> struct A
template <typename T> struct B
{
- typedef int xxx; // { dg-error "" }
+ typedef int xxx; // { dg-message "" }
typedef T xxx; // { dg-error "" }
typedef typename A<T>::type xxx; // { dg-error "" }
typedef A<int>::type xxx; // { dg-error "" }
diff --git a/gcc/testsuite/g++.dg/template/using2.C b/gcc/testsuite/g++.dg/template/using2.C
index 6dd9ef4..5987254 100644
--- a/gcc/testsuite/g++.dg/template/using2.C
+++ b/gcc/testsuite/g++.dg/template/using2.C
@@ -7,24 +7,25 @@
template <class T>
struct Foo {
- int i; // { dg-error "Foo" }
+ int i;
};
struct Baz
{
- int i; // { dg-error "Baz" }
+ int i;
};
template <class T>
-struct Bar : public Foo<T>, Baz {
- using Foo<T>::i;
- using Baz::i;
+struct Bar : public Foo<T>, Baz
+{
+ using Foo<T>::i; // { dg-message "previous declaration" }
+ using Baz::i; // { dg-error "redeclaration" }
- int foo () { return i; } // { dg-error "request for member" }
+ int foo () { return i; }
};
void foo (Bar<int> &bar)
{
- bar.foo(); // { dg-message "required" }
+ bar.foo();
}
diff --git a/gcc/testsuite/g++.old-deja/g++.brendan/misc14.C b/gcc/testsuite/g++.old-deja/g++.brendan/misc14.C
index d2e4909..ea6ce4c 100644
--- a/gcc/testsuite/g++.old-deja/g++.brendan/misc14.C
+++ b/gcc/testsuite/g++.old-deja/g++.brendan/misc14.C
@@ -3,11 +3,11 @@
class X {
public:
enum e {
- New // { dg-error "conflicts with previous" }
+ New // { dg-message "previous" }
, // { dg-error "comma at end" "" { target c++98 } }
};
- static int New(int); // { dg-error "declaration of" }
+ static int New(int); // { dg-error "conflicts with a previous" }
};
int main() {}
diff --git a/gcc/testsuite/g++.old-deja/g++.bugs/900127_02.C b/gcc/testsuite/g++.old-deja/g++.bugs/900127_02.C
index 0ae2388..12ae64a 100644
--- a/gcc/testsuite/g++.old-deja/g++.bugs/900127_02.C
+++ b/gcc/testsuite/g++.old-deja/g++.bugs/900127_02.C
@@ -23,12 +23,12 @@ int global1 (); // { dg-error "" } xref for below
int global1; // { dg-error "" } caught
struct struct_0 {
- int class_local (); // { dg-error "" }
+ int class_local (); // { dg-message "" }
int class_local; // { dg-error "" }
};
struct struct_1 {
- int class_local; // { dg-error "" }
+ int class_local; // { dg-message "" }
int class_local (); // { dg-error "" }
};
diff --git a/gcc/testsuite/g++.old-deja/g++.jason/scoping16.C b/gcc/testsuite/g++.old-deja/g++.jason/scoping16.C
index 9b9d915..1c225c7 100644
--- a/gcc/testsuite/g++.old-deja/g++.jason/scoping16.C
+++ b/gcc/testsuite/g++.old-deja/g++.jason/scoping16.C
@@ -1,5 +1,5 @@
// { dg-do assemble }
struct A {
- int a(); // { dg-error "" }
+ int a(); // { dg-message "" }
int a; // { dg-error "" }
};
diff --git a/gcc/testsuite/g++.old-deja/g++.other/anon7.C b/gcc/testsuite/g++.old-deja/g++.other/anon7.C
index ebc3780..6a951a9 100644
--- a/gcc/testsuite/g++.old-deja/g++.other/anon7.C
+++ b/gcc/testsuite/g++.old-deja/g++.other/anon7.C
@@ -2,13 +2,13 @@
struct A {
union {
- int a; // { dg-error "" } conflicts with previous declaration
+ int a; // { dg-message "" } conflicts with previous declaration
};
int a; // { dg-error "" }
};
struct B {
- int b; // { dg-error "" } conflicts with previous declaration
+ int b; // { dg-message "" } conflicts with previous declaration
union {
int b; // { dg-error "" } duplicate member
};
@@ -16,7 +16,7 @@ struct B {
struct C {
union {
- int c; // { dg-error "" } conflicts with previous declaration
+ int c; // { dg-message "" } conflicts with previous declaration
};
union {
int c; // { dg-error "" } duplicate member
diff --git a/gcc/testsuite/g++.old-deja/g++.other/redecl1.C b/gcc/testsuite/g++.old-deja/g++.other/redecl1.C
index bd6382e..d979786 100644
--- a/gcc/testsuite/g++.old-deja/g++.other/redecl1.C
+++ b/gcc/testsuite/g++.old-deja/g++.other/redecl1.C
@@ -1,6 +1,6 @@
// { dg-do assemble }
struct X{
void i();
- void i(int); // { dg-error "" }
+ void i(int); // { dg-message "" }
int i; // { dg-error "" } conflict
};
diff --git a/gcc/testsuite/g++.old-deja/g++.other/typedef7.C b/gcc/testsuite/g++.old-deja/g++.other/typedef7.C
index 42cf4f1..93784c0 100644
--- a/gcc/testsuite/g++.old-deja/g++.other/typedef7.C
+++ b/gcc/testsuite/g++.old-deja/g++.other/typedef7.C
@@ -8,13 +8,13 @@ typedef int I;
// invalid.
struct A {
- typedef int I; // { dg-error "" }
+ typedef int I; // { dg-message "" }
typedef int I; // { dg-error "" }
};
template <class T>
struct S {
- typedef int I; // { dg-error "" }
+ typedef int I; // { dg-message "" }
typedef int I; // { dg-error "" }
};
diff --git a/gcc/testsuite/g++.old-deja/g++.other/using1.C b/gcc/testsuite/g++.old-deja/g++.other/using1.C
index d734576..48c29f7 100644
--- a/gcc/testsuite/g++.old-deja/g++.other/using1.C
+++ b/gcc/testsuite/g++.old-deja/g++.other/using1.C
@@ -16,12 +16,12 @@ public:
using B::b;
};
-class D2 : public B { // { dg-error "" } conflicting access specifications
+class D2 : public B {
public:
using B::a;
- using B::b;
+ using B::b; // { dg-message "" } conflicting declaration
private:
- using B::b;
+ using B::b; // { dg-error "" } conflicts
};