@@ -6677,6 +6677,7 @@ extern tree build_vfn_ref (tree, tree);
extern tree get_vtable_decl (tree, int);
extern bool add_method (tree, tree, bool);
extern tree declared_access (tree);
+extern bool maybe_push_used_methods (tree);
extern tree currently_open_class (tree);
extern tree currently_open_derived_class (tree);
extern tree outermost_open_class (void);
@@ -8241,6 +8242,7 @@ extern tree fold_builtin_source_location (location_t);
/* in name-lookup.cc */
extern tree strip_using_decl (tree);
+extern void diagnose_name_conflict (tree, tree);
/* Tell the binding oracle what kind of binding we are looking for. */
@@ -1049,7 +1049,12 @@ add_method (tree type, tree method, bool via_using)
if (via_using && iter.using_p ()
/* Except handle inherited constructors specially. */
&& ! DECL_CONSTRUCTOR_P (fn))
- continue;
+ {
+ if (fn == method)
+ /* Don't add the same one twice. */
+ return false;
+ continue;
+ }
/* [over.load] Member function declarations with the
same name and the same parameter types cannot be
@@ -1212,10 +1217,11 @@ add_method (tree type, tree method, bool via_using)
if (via_using)
/* Defer to the local function. */
return false;
- else if (flag_new_inheriting_ctors
- && DECL_INHERITED_CTOR (fn))
+ else if (iter.using_p ()
+ || (flag_new_inheriting_ctors
+ && DECL_INHERITED_CTOR (fn)))
{
- /* Remove the inherited constructor. */
+ /* Remove the inherited function. */
current_fns = iter.remove_node (current_fns);
continue;
}
@@ -1299,21 +1305,65 @@ declared_access (tree decl)
: access_public_node);
}
+/* If DECL is a non-dependent using of non-ctor function members, push them
+ and return true, otherwise return false. Called from
+ finish_member_declaration. */
+
+bool
+maybe_push_used_methods (tree decl)
+{
+ if (TREE_CODE (decl) != USING_DECL)
+ return false;
+ tree used = strip_using_decl (decl);
+ if (!used || !is_overloaded_fn (used))
+ return false;
+
+ /* Add the functions to CLASSTYPE_MEMBER_VEC so that overload resolution
+ works within the class body. */
+ for (tree f : ovl_range (used))
+ {
+ if (DECL_CONSTRUCTOR_P (f))
+ /* Inheriting constructors are handled separately. */
+ return false;
+
+ bool added = add_method (current_class_type, f, true);
+
+ if (added)
+ alter_access (current_class_type, f, current_access_specifier);
+
+ /* If add_method returns false because f was already declared, look
+ for a duplicate using-declaration. */
+ else
+ for (tree d = TYPE_FIELDS (current_class_type); d; d = DECL_CHAIN (d))
+ if (TREE_CODE (d) == USING_DECL
+ && DECL_NAME (d) == DECL_NAME (decl)
+ && same_type_p (USING_DECL_SCOPE (d), USING_DECL_SCOPE (decl)))
+ {
+ diagnose_name_conflict (decl, d);
+ break;
+ }
+ }
+ return true;
+}
+
/* Process the USING_DECL, which is a member of T. */
static void
handle_using_decl (tree using_decl, tree t)
{
tree decl = USING_DECL_DECLS (using_decl);
- tree name = DECL_NAME (using_decl);
- tree access = declared_access (using_decl);
- tree flist = NULL_TREE;
- tree old_value;
gcc_assert (!processing_template_decl && decl);
- old_value = lookup_member (t, name, /*protect=*/0, /*want_type=*/false,
- tf_warning_or_error);
+ cp_emit_debug_info_for_using (decl, t);
+
+ if (is_overloaded_fn (decl))
+ /* Handled in maybe_push_used_methods. */
+ return;
+
+ tree name = DECL_NAME (using_decl);
+ tree old_value = lookup_member (t, name, /*protect=*/0, /*want_type=*/false,
+ tf_warning_or_error);
if (old_value)
{
old_value = OVL_FIRST (old_value);
@@ -1324,27 +1374,16 @@ handle_using_decl (tree using_decl, tree t)
old_value = NULL_TREE;
}
- cp_emit_debug_info_for_using (decl, t);
-
- if (is_overloaded_fn (decl))
- flist = decl;
-
if (! old_value)
;
else if (is_overloaded_fn (old_value))
{
- if (flist)
- /* It's OK to use functions from a base when there are functions with
- the same name already present in the current class. */;
- else
- {
- error_at (DECL_SOURCE_LOCATION (using_decl), "%qD invalid in %q#T "
- "because of local method %q#D with same name",
- using_decl, t, old_value);
- inform (DECL_SOURCE_LOCATION (old_value),
- "local method %q#D declared here", old_value);
- return;
- }
+ error_at (DECL_SOURCE_LOCATION (using_decl), "%qD invalid in %q#T "
+ "because of local method %q#D with same name",
+ using_decl, t, old_value);
+ inform (DECL_SOURCE_LOCATION (old_value),
+ "local method %q#D declared here", old_value);
+ return;
}
else if (!DECL_ARTIFICIAL (old_value))
{
@@ -1357,23 +1396,17 @@ handle_using_decl (tree using_decl, tree t)
}
iloc_sentinel ils (DECL_SOURCE_LOCATION (using_decl));
+ tree access = declared_access (using_decl);
/* Make type T see field decl FDECL with access ACCESS. */
- if (flist)
- for (tree f : ovl_range (flist))
- {
- add_method (t, f, true);
- alter_access (t, f, access);
- }
- else if (USING_DECL_UNRELATED_P (using_decl))
+ if (USING_DECL_UNRELATED_P (using_decl))
{
/* C++20 using enum can import non-inherited enumerators into class
scope. We implement that by making a copy of the CONST_DECL for which
CONST_DECL_USING_P is true. */
gcc_assert (TREE_CODE (decl) == CONST_DECL);
- auto cas = make_temp_override (current_access_specifier);
- set_current_access_from_decl (using_decl);
+ auto cas = make_temp_override (current_access_specifier, access);
tree copy = copy_decl (decl);
DECL_CONTEXT (copy) = t;
DECL_ARTIFICIAL (copy) = true;
@@ -7672,18 +7705,8 @@ finish_struct (tree t, tree attributes)
{
tree x;
- /* We need to add the target functions of USING_DECLS, so that
- they can be found when the using declaration is not
- instantiated yet. */
for (x = TYPE_FIELDS (t); x; x = DECL_CHAIN (x))
- if (TREE_CODE (x) == USING_DECL)
- {
- tree fn = strip_using_decl (x);
- if (OVL_P (fn))
- for (lkp_iterator iter (fn); iter; ++iter)
- add_method (t, *iter, true);
- }
- else if (DECL_DECLARES_FUNCTION_P (x))
+ if (DECL_DECLARES_FUNCTION_P (x))
{
DECL_IN_AGGR_P (x) = false;
if (DECL_VIRTUAL_P (x))
@@ -7700,14 +7723,17 @@ finish_struct (tree t, tree attributes)
lookup not to fail or recurse into bases. This isn't added
to the template decl list so we drop this at instantiation
time. */
- tree ass_op = build_lang_decl (USING_DECL, assign_op_identifier,
- NULL_TREE);
- DECL_CONTEXT (ass_op) = t;
- USING_DECL_SCOPE (ass_op) = t;
- DECL_DEPENDENT_P (ass_op) = true;
- DECL_ARTIFICIAL (ass_op) = true;
- DECL_CHAIN (ass_op) = TYPE_FIELDS (t);
- TYPE_FIELDS (t) = ass_op;
+ if (!get_class_binding_direct (t, assign_op_identifier, false))
+ {
+ tree ass_op = build_lang_decl (USING_DECL, assign_op_identifier,
+ NULL_TREE);
+ DECL_CONTEXT (ass_op) = t;
+ USING_DECL_SCOPE (ass_op) = t;
+ DECL_DEPENDENT_P (ass_op) = true;
+ DECL_ARTIFICIAL (ass_op) = true;
+ DECL_CHAIN (ass_op) = TYPE_FIELDS (t);
+ TYPE_FIELDS (t) = ass_op;
+ }
TYPE_SIZE (t) = bitsize_zero_node;
TYPE_SIZE_UNIT (t) = size_zero_node;
@@ -1715,7 +1715,6 @@ static void consider_binding_level (tree name,
cp_binding_level *lvl,
bool look_within_fields,
enum lookup_name_fuzzy_kind kind);
-static void diagnose_name_conflict (tree, tree);
/* ADL lookup of NAME. FNS is the result of regular lookup, and we
don't add duplicates to it. ARGS is the vector of call
@@ -2711,9 +2710,13 @@ supplement_binding (cxx_binding *binding, tree decl)
return ok;
}
-/* Diagnose a name conflict between DECL and BVAL. */
+/* Diagnose a name conflict between DECL and BVAL.
-static void
+ This is non-static so maybe_push_used_methods can use it and avoid changing
+ the diagnostic for inherit/using4.C; otherwise it should not be used from
+ outside this file. */
+
+void
diagnose_name_conflict (tree decl, tree bval)
{
if (TREE_CODE (decl) == TREE_CODE (bval)
@@ -5480,13 +5483,18 @@ push_class_level_binding (tree name, tree x)
&& DECL_DEPENDENT_P (bval))
return true;
else if (TREE_CODE (decl) == USING_DECL
+ && DECL_DEPENDENT_P (decl)
&& OVL_P (target_bval))
+ /* The new dependent using beats an old overload. */
old_decl = bval;
else if (TREE_CODE (bval) == USING_DECL
+ && DECL_DEPENDENT_P (bval)
&& OVL_P (target_decl))
- old_decl = bval;
+ /* The old dependent using beats a new overload. */
+ return true;
else if (OVL_P (target_decl)
&& OVL_P (target_bval))
+ /* The new overload set contains the old one. */
old_decl = bval;
if (old_decl && binding->scope == class_binding_level)
@@ -3549,8 +3549,8 @@ finish_member_declaration (tree decl)
}
if (TREE_CODE (decl) == USING_DECL)
- /* For now, ignore class-scope USING_DECLS, so that debugging
- backends do not see them. */
+ /* Avoid debug info for class-scope USING_DECLS for now, we'll
+ call cp_emit_debug_info_for_using later. */
DECL_IGNORED_P (decl) = 1;
/* Check for bare parameter packs in the non-static data member
@@ -3578,6 +3578,7 @@ finish_member_declaration (tree decl)
/* Enter the DECL into the scope of the class, if the class
isn't a closure (whose fields are supposed to be unnamed). */
else if (CLASSTYPE_LAMBDA_EXPR (current_class_type)
+ || maybe_push_used_methods (decl)
|| pushdecl_class_level (decl))
add = true;
@@ -4,10 +4,10 @@ struct A;
struct B
{
- constexpr A & operator= (const A &); // { dg-warning "used" "" { target c++14 } }
+ constexpr A & operator= (const A &);
};
-struct A : B // { dg-error "cannot be overloaded" "" { target c++14 } }
+struct A : B
{
using B::operator=;
} a { a = a };
new file mode 100644
@@ -0,0 +1,22 @@
+// PR c++/92918
+// { dg-do compile { target c++11 } }
+
+struct Base03
+{
+ static void impl();
+};
+
+struct ThisDoesNotCompileOnGCC : Base03
+{
+ using Base03::impl;
+ static int impl(char const *);
+
+ auto f(const char *t) const
+ -> decltype(impl(t))
+ {
+ return impl(t);
+ }
+};
+
+ThisDoesNotCompileOnGCC t;
+int i = t.f("42");
new file mode 100644
@@ -0,0 +1,20 @@
+// PR c++/104476
+// { dg-do compile { target c++11 } }
+
+struct A {
+ static void f();
+ static void f2();
+};
+
+struct B : A
+{
+ static void f(int);
+ using A::f;
+ auto g() -> decltype(f());
+ auto ga() -> decltype(f(2));
+
+ using A::f2;
+ static void f2(int);
+ auto g2() -> decltype(f2());
+ auto g2a() -> decltype(f2(2));
+};