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)
{
/* Naming a namespace member. */
if (TYPE_P (current))
{ {
error ("using-declaration for non-member at class scope"); error ("using-declaration for non-member at class scope");
return NULL_TREE; return false;
}
qualified_namespace_lookup (scope, &lookup);
}
else if (TREE_CODE (scope) == ENUMERAL_TYPE)
{
error ("using-declaration may not name enumerator %<%E::%D%>",
scope, lookup.name);
return false;
}
else
{
/* Naming a class member. */
if (!TYPE_P (current))
{
error ("using-declaration for member at non-class scope");
return false;
} }
/* Make sure the name is not invalid */ /* Make sure the name is not invalid */
if (TREE_CODE (name) == BIT_NOT_EXPR) if (TREE_CODE (lookup.name) == BIT_NOT_EXPR)
{ {
error ("%<%T::%D%> names destructor", scope, name); error ("%<%T::%D%> names destructor", scope, lookup.name);
return NULL_TREE; return false;
} }
/* Using T::T declares inheriting ctors, even if T is a typedef. */ /* Using T::T declares inheriting ctors, even if T is a typedef. */
if (MAYBE_CLASS_TYPE_P (scope) if (MAYBE_CLASS_TYPE_P (scope)
&& (name == TYPE_IDENTIFIER (scope) && (lookup.name == TYPE_IDENTIFIER (scope)
|| constructor_name_p (name, scope))) || constructor_name_p (lookup.name, scope)))
{ {
maybe_warn_cpp0x (CPP0X_INHERITING_CTORS); maybe_warn_cpp0x (CPP0X_INHERITING_CTORS);
name = ctor_identifier; lookup.name = ctor_identifier;
CLASSTYPE_NON_AGGREGATE (current_class_type) = true; CLASSTYPE_NON_AGGREGATE (current) = true;
TYPE_HAS_USER_CONSTRUCTOR (current_class_type) = true; TYPE_HAS_USER_CONSTRUCTOR (current) = true;
} }
/* Cannot introduce a constructor name. */ /* Cannot introduce a constructor name. */
if (constructor_name_p (name, current_class_type)) if (constructor_name_p (lookup.name, current))
{ {
error ("%<%T::%D%> names constructor in %qT", error ("%<%T::%D%> names constructor in %qT",
scope, name, current_class_type); scope, lookup.name, current);
return NULL_TREE; return false;
} }
/* Member using decls finish processing when completing the
class. */
/* From [namespace.udecl]: /* From [namespace.udecl]:
A using-declaration used as a member-declaration shall refer to a A using-declaration used as a member-declaration shall refer
member of a base class of the class being defined. to a member of a base class of the class being defined.
In general, we cannot check this constraint in a template because In general, we cannot check this constraint in a template
we do not know the entire set of base classes of the current because we do not know the entire set of base classes of the
class type. Morover, if SCOPE is dependent, it might match a current class type. Morover, if SCOPE is dependent, it might
non-dependent base. */ match a non-dependent base. */
tree decl = NULL_TREE; dependent_p = dependent_scope_p (scope);
if (!dependent_scope_p (scope)) if (!dependent_p)
{ {
base_kind b_kind; base_kind b_kind;
tree binfo = lookup_base (current_class_type, scope, ba_any, &b_kind, tree binfo = lookup_base (current, scope, ba_any, &b_kind,
tf_warning_or_error); tf_warning_or_error);
if (b_kind < bk_proper_base) if (b_kind < bk_proper_base)
{ {
/* If there are dependent bases, scope might resolve at /* If there are dependent bases, scope might resolve at
instantiation time, even if it isn't exactly one of the instantiation time, even if it isn't exactly one of
dependent bases. */ the dependent bases. */
if (b_kind == bk_same_type || !any_dependent_bases_p ()) if (b_kind == bk_same_type || !any_dependent_bases_p ())
{ {
error_not_base_type (scope, current_class_type); error_not_base_type (scope, current);
return NULL_TREE; return false;
} }
/* Treat as-if dependent. */
dependent_p = true;
} }
else if (name == ctor_identifier && !binfo_direct_p (binfo)) else if (lookup.name == ctor_identifier && !binfo_direct_p (binfo))
{ {
error ("cannot inherit constructors from indirect base %qT", scope); 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 (!IDENTIFIER_CONV_OP_P (name) }
|| !dependent_type_p (TREE_TYPE (name)))
if (!dependent_p)
{ {
decl = lookup_member (binfo, name, 0, false, tf_warning_or_error); if (!lookup.value)
if (!decl)
{ {
error ("no members matching %<%T::%D%> in %q#T", scope, name, error ("%qD has not been declared in %qE", lookup.name, scope);
scope); return false;
return NULL_TREE;
} }
/* The binfo from which the functions came does not matter. */ if (TREE_CODE (lookup.value) == TREE_LIST
if (BASELINK_P (decl)) /* We can (independently) have ambiguous implicit typedefs. */
decl = BASELINK_FUNCTIONS (decl); || (lookup.type && TREE_CODE (lookup.type) == TREE_LIST))
{
error ("reference to %qD is ambiguous", lookup.name);
print_candidates (TREE_CODE (lookup.value) == TREE_LIST
? lookup.value : lookup.type);
return false;
}
if (TREE_CODE (lookup.value) == NAMESPACE_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 (TREE_CODE (scope) != NAMESPACE_DECL) if (scope == error_mark_node || name == error_mark_node)
{
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; 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))
{
error ("using-declaration may not name namespace %qD", lookup.value);
return; 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