Commit 5c44cef5 by Nathan Sidwell

[C++ PATCH] Merge some using-decl handling

https://gcc.gnu.org/ml/gcc-patches/2019-11/msg00971.html
	gcc/cp/
	* name-lookup.c (lookup_using_decl): New function, merged from ...
	(do_class_using_decl): ... here.  Call it.  And ...
	(finish_nonmember_using_decl): ... here.  Call it.

	gcc/testsuite/
	* g++.dg/cpp0x/using-enum-2.C: Adjust expected error text.
	* g++.dg/cpp0x/using-enum-3.C: Likewise.
	* g++.dg/lookup/using4.C: Likewise.
	* g++.dg/lookup/using7.C: Likewise.
	* g++.dg/template/using12.C: Likewise.
	* g++.dg/template/using18.C: Likewise.
	* g++.dg/template/using22.C: Likewise.

From-SVN: r278106
parent 3c72b04b
2019-11-12 Nathan Sidwell <nathan@acm.org>
* name-lookup.c (lookup_using_decl): New function, merged from ...
(do_class_using_decl): ... here. Call it. And ...
(finish_nonmember_using_decl): ... here. Call it.
2019-11-12 Martin Liska <mliska@suse.cz> 2019-11-12 Martin Liska <mliska@suse.cz>
* name-lookup.c: Do not include params.h. * name-lookup.c: Do not include params.h.
...@@ -5,9 +11,9 @@ ...@@ -5,9 +11,9 @@
2019-11-12 Martin Liska <mliska@suse.cz> 2019-11-12 Martin Liska <mliska@suse.cz>
* name-lookup.c (namespace_hints::namespace_hints): Replace old parameter syntax * name-lookup.c (namespace_hints::namespace_hints): Replace old
with the new one, include opts.h if needed. Use SET_OPTION_IF_UNSET parameter syntax with the new one, include opts.h if needed. Use
macro. SET_OPTION_IF_UNSET macro.
* typeck.c (comptypes): Likewise. * typeck.c (comptypes): Likewise.
2019-11-12 Maciej W. Rozycki <macro@codesourcery.com> 2019-11-12 Maciej W. Rozycki <macro@codesourcery.com>
......
...@@ -4584,102 +4584,166 @@ push_class_level_binding (tree name, tree x) ...@@ -4584,102 +4584,166 @@ push_class_level_binding (tree name, tree x)
return ret; return ret;
} }
/* Process "using SCOPE::NAME" in a class scope. Return the /* Process and lookup a using decl SCOPE::lookup.name, filling in
USING_DECL created. */ lookup.values & lookup.type. Return true if ok. */
tree static bool
do_class_using_decl (tree scope, tree name) lookup_using_decl (tree scope, name_lookup &lookup)
{ {
if (name == error_mark_node) tree current = current_scope ();
return NULL_TREE; bool dependent_p = false;
if (!scope || !TYPE_P (scope)) if (TREE_CODE (scope) == NAMESPACE_DECL)
{ {
error ("using-declaration for non-member at class scope"); /* Naming a namespace member. */
return NULL_TREE; if (TYPE_P (current))
} {
error ("using-declaration for non-member at class scope");
return false;
}
/* Make sure the name is not invalid */ qualified_namespace_lookup (scope, &lookup);
if (TREE_CODE (name) == BIT_NOT_EXPR)
{
error ("%<%T::%D%> names destructor", scope, name);
return NULL_TREE;
} }
else if (TREE_CODE (scope) == ENUMERAL_TYPE)
/* Using T::T declares inheriting ctors, even if T is a typedef. */
if (MAYBE_CLASS_TYPE_P (scope)
&& (name == TYPE_IDENTIFIER (scope)
|| constructor_name_p (name, scope)))
{ {
maybe_warn_cpp0x (CPP0X_INHERITING_CTORS); error ("using-declaration may not name enumerator %<%E::%D%>",
name = ctor_identifier; scope, lookup.name);
CLASSTYPE_NON_AGGREGATE (current_class_type) = true; return false;
TYPE_HAS_USER_CONSTRUCTOR (current_class_type) = true;
} }
else
/* Cannot introduce a constructor name. */
if (constructor_name_p (name, current_class_type))
{ {
error ("%<%T::%D%> names constructor in %qT", /* Naming a class member. */
scope, name, current_class_type); if (!TYPE_P (current))
return NULL_TREE; {
} error ("using-declaration for member at non-class scope");
return false;
}
/* From [namespace.udecl]: /* Make sure the name is not invalid */
if (TREE_CODE (lookup.name) == BIT_NOT_EXPR)
{
error ("%<%T::%D%> names destructor", scope, lookup.name);
return false;
}
A using-declaration used as a member-declaration shall refer to a /* Using T::T declares inheriting ctors, even if T is a typedef. */
member of a base class of the class being defined. if (MAYBE_CLASS_TYPE_P (scope)
&& (lookup.name == TYPE_IDENTIFIER (scope)
|| constructor_name_p (lookup.name, scope)))
{
maybe_warn_cpp0x (CPP0X_INHERITING_CTORS);
lookup.name = ctor_identifier;
CLASSTYPE_NON_AGGREGATE (current) = true;
TYPE_HAS_USER_CONSTRUCTOR (current) = true;
}
/* Cannot introduce a constructor name. */
if (constructor_name_p (lookup.name, current))
{
error ("%<%T::%D%> names constructor in %qT",
scope, lookup.name, current);
return false;
}
In general, we cannot check this constraint in a template because /* Member using decls finish processing when completing the
we do not know the entire set of base classes of the current class. */
class type. Morover, if SCOPE is dependent, it might match a /* From [namespace.udecl]:
non-dependent base. */
tree decl = NULL_TREE; A using-declaration used as a member-declaration shall refer
if (!dependent_scope_p (scope)) to a member of a base class of the class being defined.
{
base_kind b_kind; In general, we cannot check this constraint in a template
tree binfo = lookup_base (current_class_type, scope, ba_any, &b_kind, because we do not know the entire set of base classes of the
tf_warning_or_error); current class type. Morover, if SCOPE is dependent, it might
if (b_kind < bk_proper_base) match a non-dependent base. */
dependent_p = dependent_scope_p (scope);
if (!dependent_p)
{ {
/* If there are dependent bases, scope might resolve at base_kind b_kind;
instantiation time, even if it isn't exactly one of the tree binfo = lookup_base (current, scope, ba_any, &b_kind,
dependent bases. */ tf_warning_or_error);
if (b_kind == bk_same_type || !any_dependent_bases_p ()) if (b_kind < bk_proper_base)
{
/* If there are dependent bases, scope might resolve at
instantiation time, even if it isn't exactly one of
the dependent bases. */
if (b_kind == bk_same_type || !any_dependent_bases_p ())
{
error_not_base_type (scope, current);
return false;
}
/* Treat as-if dependent. */
dependent_p = true;
}
else if (lookup.name == ctor_identifier && !binfo_direct_p (binfo))
{ {
error_not_base_type (scope, current_class_type); error ("cannot inherit constructors from indirect base %qT",
return NULL_TREE; scope);
return false;
} }
else if (IDENTIFIER_CONV_OP_P (lookup.name)
&& dependent_type_p (TREE_TYPE (lookup.name)))
dependent_p = true;
else
lookup.value = lookup_member (binfo, lookup.name, 0,
false, tf_warning_or_error);
} }
else if (name == ctor_identifier && !binfo_direct_p (binfo)) }
if (!dependent_p)
{
if (!lookup.value)
{ {
error ("cannot inherit constructors from indirect base %qT", scope); error ("%qD has not been declared in %qE", lookup.name, scope);
return NULL_TREE; return false;
} }
else if (!IDENTIFIER_CONV_OP_P (name)
|| !dependent_type_p (TREE_TYPE (name))) if (TREE_CODE (lookup.value) == TREE_LIST
/* We can (independently) have ambiguous implicit typedefs. */
|| (lookup.type && TREE_CODE (lookup.type) == TREE_LIST))
{ {
decl = lookup_member (binfo, name, 0, false, tf_warning_or_error); error ("reference to %qD is ambiguous", lookup.name);
if (!decl) print_candidates (TREE_CODE (lookup.value) == TREE_LIST
{ ? lookup.value : lookup.type);
error ("no members matching %<%T::%D%> in %q#T", scope, name, return false;
scope); }
return NULL_TREE;
}
/* The binfo from which the functions came does not matter. */ if (TREE_CODE (lookup.value) == NAMESPACE_DECL)
if (BASELINK_P (decl)) {
decl = BASELINK_FUNCTIONS (decl); error ("using-declaration may not name namespace %qD", lookup.value);
return false;
} }
} }
tree value = build_lang_decl (USING_DECL, name, NULL_TREE); return true;
USING_DECL_DECLS (value) = decl; }
USING_DECL_SCOPE (value) = scope;
DECL_DEPENDENT_P (value) = !decl; /* Process "using SCOPE::NAME" in a class scope. Return the
USING_DECL created. */
tree
do_class_using_decl (tree scope, tree name)
{
if (name == error_mark_node
|| scope == error_mark_node)
return NULL_TREE;
name_lookup lookup (name, 0);
if (!lookup_using_decl (scope, lookup))
return NULL_TREE;
tree found = lookup.value;
if (found && BASELINK_P (found))
/* The binfo from which the functions came does not matter. */
found = BASELINK_FUNCTIONS (found);
tree using_decl = build_lang_decl (USING_DECL, lookup.name, NULL_TREE);
USING_DECL_SCOPE (using_decl) = scope;
USING_DECL_DECLS (using_decl) = found;
DECL_DEPENDENT_P (using_decl) = !found;
return value; return using_decl;
} }
...@@ -5046,39 +5110,14 @@ void ...@@ -5046,39 +5110,14 @@ void
finish_nonmember_using_decl (tree scope, tree name) finish_nonmember_using_decl (tree scope, tree name)
{ {
gcc_checking_assert (current_binding_level->kind != sk_class); gcc_checking_assert (current_binding_level->kind != sk_class);
gcc_checking_assert (identifier_p (name));
name_lookup lookup (name, 0); if (scope == error_mark_node || name == error_mark_node)
return;
if (TREE_CODE (scope) != NAMESPACE_DECL)
{
error ("%qE is not a namespace or unscoped enum", scope);
return;
}
qualified_namespace_lookup (scope, &lookup);
if (!lookup.value)
{
error ("%qD has not been declared in %qE", name, scope);
return;
}
if (TREE_CODE (lookup.value) == TREE_LIST name_lookup lookup (name, 0);
/* But we can (independently) have ambiguous implicit typedefs. */
|| (lookup.type && TREE_CODE (lookup.type) == TREE_LIST))
{
error ("reference to %qD is ambiguous", name);
print_candidates (TREE_CODE (lookup.value) == TREE_LIST
? lookup.value : lookup.type);
return;
}
if (TREE_CODE (lookup.value) == NAMESPACE_DECL) if (!lookup_using_decl (scope, lookup))
{ return;
error ("using-declaration may not name namespace %qD", lookup.value);
return;
}
/* Emit debug info. */ /* Emit debug info. */
if (!processing_template_decl) if (!processing_template_decl)
...@@ -5106,7 +5145,7 @@ finish_nonmember_using_decl (tree scope, tree name) ...@@ -5106,7 +5145,7 @@ finish_nonmember_using_decl (tree scope, tree name)
} }
else else
{ {
tree using_decl = build_lang_decl (USING_DECL, name, NULL_TREE); tree using_decl = build_lang_decl (USING_DECL, lookup.name, NULL_TREE);
USING_DECL_SCOPE (using_decl) = scope; USING_DECL_SCOPE (using_decl) = scope;
add_decl_expr (using_decl); add_decl_expr (using_decl);
...@@ -5147,7 +5186,6 @@ finish_nonmember_using_decl (tree scope, tree name) ...@@ -5147,7 +5186,6 @@ finish_nonmember_using_decl (tree scope, tree name)
set_identifier_type_value (name, type); set_identifier_type_value (name, type);
} }
} }
} }
/* Return the declarations that are members of the namespace NS. */ /* Return the declarations that are members of the namespace NS. */
......
2019-11-12 Nathan Sidwell <nathan@acm.org>
* g++.dg/cpp0x/using-enum-2.C: Adjust expected error text.
* g++.dg/cpp0x/using-enum-3.C: Likewise.
* g++.dg/lookup/using4.C: Likewise.
* g++.dg/lookup/using7.C: Likewise.
* g++.dg/template/using12.C: Likewise.
* g++.dg/template/using18.C: Likewise.
* g++.dg/template/using22.C: Likewise.
2019-11-12 Segher Boessenkool <segher@kernel.crashing.org> 2019-11-12 Segher Boessenkool <segher@kernel.crashing.org>
PR target/92449 PR target/92449
......
...@@ -5,16 +5,16 @@ namespace A ...@@ -5,16 +5,16 @@ namespace A
{ {
enum class E { V }; enum class E { V };
using E::V; // { dg-error "not a namespace or unscoped enum" } using E::V; // { dg-error "name enumerator" }
} }
void foo() void foo()
{ {
using A::E::V; // { dg-error "not a namespace or unscoped enum" } using A::E::V; // { dg-error "name enumerator" }
} }
using A::E::V; // { dg-error "not a namespace or unscoped enum" } using A::E::V; // { dg-error "name enumerator" }
enum class F { U }; enum class F { U };
using F::U; // { dg-error "not a namespace or unscoped enum" } using F::U; // { dg-error "name enumerator" }
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
void f () void f ()
{ {
enum e { a }; enum e { a };
using e::a; // { dg-error "not a namespace or unscoped enum" } using e::a; // { dg-error "name enumerator" }
} }
struct S { struct S {
......
...@@ -10,6 +10,6 @@ template <class T> ...@@ -10,6 +10,6 @@ template <class T>
struct Bar : public Foo<T> { struct Bar : public Foo<T> {
void foo() void foo()
{ {
using Foo<T>::i; // { dg-error "not a namespace" } using Foo<T>::i; // { dg-error "member at non-class scope" }
} }
}; };
...@@ -6,7 +6,6 @@ template <typename T, bool=T::X> struct A ...@@ -6,7 +6,6 @@ template <typename T, bool=T::X> struct A
template <typename T> struct B : A<T> // { dg-error "incomplete" } template <typename T> struct B : A<T> // { dg-error "incomplete" }
{ {
using A<T>::i; // { dg-error "incomplete" "incomplete" } using A<T>::i; // { dg-error "incomplete" "incomplete" }
// { dg-error "using" "using" { target *-*-* } .-1 }
}; };
B<void> b; // { dg-message "required" } B<void> b; // { dg-message "required" }
...@@ -3,5 +3,5 @@ struct A { ...@@ -3,5 +3,5 @@ struct A {
template <typename T> template <typename T>
struct S : public A { struct S : public A {
using A::operator(); // { dg-error "no member" } using A::operator(); // { dg-error "has not been declared" }
}; };
...@@ -25,7 +25,7 @@ template <class T> struct B2 {}; ...@@ -25,7 +25,7 @@ template <class T> struct B2 {};
template <class T> template <class T>
struct C : B1, B2<T> struct C : B1, B2<T>
{ {
using B1::x; // { dg-error "no member" } using B1::x; // { dg-error "has not been declared" }
using B2<T>::y; using B2<T>::y;
using typename B2<T>::type; using typename B2<T>::type;
}; };
...@@ -16,25 +16,25 @@ struct A ...@@ -16,25 +16,25 @@ struct A
template <class T> template <class T>
struct A<T>::B : A<T> struct A<T>::B : A<T>
{ {
using A::nonexist; // { dg-error "no members matching" } using A::nonexist; // { dg-error "has not been declared" }
}; };
template <class T> template <class T>
struct A<T>::C : A struct A<T>::C : A
{ {
using A::nonexist; // { dg-error "no members matching" } using A::nonexist; // { dg-error "has not been declared" }
}; };
template <class T> template <class T>
struct A<T>::D : A<T> struct A<T>::D : A<T>
{ {
using A<T>::nonexist; // { dg-error "no members matching" } using A<T>::nonexist; // { dg-error "has not been declared" }
}; };
template <class T> template <class T>
struct A<T>::E : A struct A<T>::E : A
{ {
using A<T>::nonexist; // { dg-error "no members matching" } using A<T>::nonexist; // { dg-error "has not been declared" }
}; };
template <class T> template <class T>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment