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
This commit is contained in:
Fabien Chêne 2011-11-14 18:55:57 +01:00 committed by Jason Merrill
parent ac99ebf5ae
commit 557831a91d
49 changed files with 930 additions and 105 deletions

View File

@ -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

View File

@ -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;
}

View File

@ -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++ */

View File

@ -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;

View File

@ -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;
tree target_bval = strip_using_decl (bval);
tree target_decl = strip_using_decl (decl);
if (TREE_CODE (decl) == TYPE_DECL && DECL_ARTIFICIAL (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)

View File

@ -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)))
{

View File

@ -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. */

View File

@ -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

View File

@ -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)

View File

@ -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>

View File

@ -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 }

View File

@ -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" }

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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" }
};

View File

@ -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" }
};

View File

@ -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" }

View File

@ -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; }
};

View File

@ -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();
}

View File

@ -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;
}
};

View File

@ -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();
}

View File

@ -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; }
};

View File

@ -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" }
};

View File

@ -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" }
};

View File

@ -0,0 +1,8 @@
// { dg-do compile }
struct H2 { int f (); };
struct J2 : H2
{
struct f {};
using H2::f;
};

View File

@ -0,0 +1,9 @@
// { dg-do compile }
struct T { struct type {}; };
struct T2 : T { using T::type; };
struct T3 : T2
{
struct type {};
type t;
};

View File

@ -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 );
}

View File

@ -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;
};

View File

@ -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;}
};

View File

@ -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();
}

View File

@ -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;
}

View File

@ -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" }

View File

@ -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();
}

View File

@ -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" }
};

View File

@ -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;
};

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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();
}

View File

@ -2,7 +2,7 @@
struct A
{
int i; // { dg-error "conflicts" }
int i; // { dg-message "previous" }
A() i() {} // { dg-error "declaration" }
};

View File

@ -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;

View File

@ -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 "" }

View File

@ -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();
}

View File

@ -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() {}

View File

@ -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 "" }
};

View File

@ -1,5 +1,5 @@
// { dg-do assemble }
struct A {
int a(); // { dg-error "" }
int a(); // { dg-message "" }
int a; // { dg-error "" }
};

View File

@ -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

View File

@ -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
};

View File

@ -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 "" }
};

View File

@ -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
};