2019-11-12 Nathan Sidwell <nathan@acm.org>
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.
===================================================================
@@ -4585,100 +4585,164 @@ push_class_level_binding (tree name, tre
}
-/* Process "using SCOPE::NAME" in a class scope. Return the
- USING_DECL created. */
+/* Process and lookup a using decl SCOPE::lookup.name, filling in
+ lookup.values & lookup.type. Return true if ok. */
-tree
-do_class_using_decl (tree scope, tree name)
+static bool
+lookup_using_decl (tree scope, name_lookup &lookup)
{
- if (name == error_mark_node)
- return NULL_TREE;
+ tree current = current_scope ();
+ bool dependent_p = false;
- if (!scope || !TYPE_P (scope))
+ if (TREE_CODE (scope) == NAMESPACE_DECL)
{
- error ("using-declaration for non-member at class scope");
- return NULL_TREE;
- }
+ /* Naming a namespace member. */
+ if (TYPE_P (current))
+ {
+ error ("using-declaration for non-member at class scope");
+ return false;
+ }
- /* Make sure the name is not invalid */
- if (TREE_CODE (name) == BIT_NOT_EXPR)
- {
- error ("%<%T::%D%> names destructor", scope, name);
- return NULL_TREE;
+ qualified_namespace_lookup (scope, &lookup);
}
-
- /* 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)))
+ else if (TREE_CODE (scope) == ENUMERAL_TYPE)
{
- maybe_warn_cpp0x (CPP0X_INHERITING_CTORS);
- name = ctor_identifier;
- CLASSTYPE_NON_AGGREGATE (current_class_type) = true;
- TYPE_HAS_USER_CONSTRUCTOR (current_class_type) = true;
+ error ("using-declaration may not name enumerator %<%E::%D%>",
+ scope, lookup.name);
+ return false;
}
-
- /* Cannot introduce a constructor name. */
- if (constructor_name_p (name, current_class_type))
+ else
{
- error ("%<%T::%D%> names constructor in %qT",
- scope, name, current_class_type);
- return NULL_TREE;
- }
+ /* 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 */
+ if (TREE_CODE (lookup.name) == BIT_NOT_EXPR)
+ {
+ error ("%<%T::%D%> names destructor", scope, lookup.name);
+ return false;
+ }
- /* From [namespace.udecl]:
+ /* Using T::T declares inheriting ctors, even if T is a typedef. */
+ 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;
+ }
- A using-declaration used as a member-declaration shall refer to a
- member of a base class of the class being defined.
+ /* 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
- we do not know the entire set of base classes of the current
- class type. Morover, if SCOPE is dependent, it might match a
- non-dependent base. */
+ /* Member using decls finish processing when completing the
+ class. */
+ /* From [namespace.udecl]:
- tree decl = NULL_TREE;
- if (!dependent_scope_p (scope))
- {
- base_kind b_kind;
- tree binfo = lookup_base (current_class_type, scope, ba_any, &b_kind,
- tf_warning_or_error);
- if (b_kind < bk_proper_base)
+ A using-declaration used as a member-declaration shall refer
+ to a member of a base class of the class being defined.
+
+ In general, we cannot check this constraint in a template
+ because we do not know the entire set of base classes of the
+ current class type. Morover, if SCOPE is dependent, it might
+ match a non-dependent base. */
+
+ dependent_p = dependent_scope_p (scope);
+ if (!dependent_p)
{
- /* 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 ())
+ base_kind b_kind;
+ tree binfo = lookup_base (current, scope, ba_any, &b_kind,
+ tf_warning_or_error);
+ if (b_kind < bk_proper_base)
{
- error_not_base_type (scope, current_class_type);
- return NULL_TREE;
+ /* 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 ("cannot inherit constructors from indirect base %qT",
+ 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);
- return NULL_TREE;
+ error ("%qD has not been declared in %qE", lookup.name, scope);
+ 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);
- if (!decl)
- {
- error ("no members matching %<%T::%D%> in %q#T", scope, name,
- scope);
- return NULL_TREE;
- }
+ error ("reference to %qD is ambiguous", lookup.name);
+ print_candidates (TREE_CODE (lookup.value) == TREE_LIST
+ ? lookup.value : lookup.type);
+ return false;
+ }
- /* The binfo from which the functions came does not matter. */
- if (BASELINK_P (decl))
- decl = BASELINK_FUNCTIONS (decl);
+ 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);
- USING_DECL_DECLS (value) = decl;
- USING_DECL_SCOPE (value) = scope;
- DECL_DEPENDENT_P (value) = !decl;
+ return true;
+}
- return value;
+/* 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 using_decl;
}
@@ -5047,37 +5111,12 @@ finish_nonmember_using_decl (tree scope,
{
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)
- {
- 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 (scope == error_mark_node || name == error_mark_node)
+ return;
- if (TREE_CODE (lookup.value) == TREE_LIST
- /* 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;
- }
+ name_lookup lookup (name, 0);
- if (TREE_CODE (lookup.value) == NAMESPACE_DECL)
- {
- error ("using-declaration may not name namespace %qD", lookup.value);
- return;
- }
+ if (!lookup_using_decl (scope, lookup))
+ return;
/* Emit debug info. */
@@ -5107,5 +5146,5 @@ finish_nonmember_using_decl (tree scope,
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;
add_decl_expr (using_decl);
@@ -5148,5 +5187,4 @@ finish_nonmember_using_decl (tree scope,
}
}
-
}
===================================================================
@@ -6,15 +6,15 @@ namespace A
enum class E { V };
- using E::V; // { dg-error "not a namespace or unscoped enum" }
+ using E::V; // { dg-error "name enumerator" }
}
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 };
-using F::U; // { dg-error "not a namespace or unscoped enum" }
+using F::U; // { dg-error "name enumerator" }
===================================================================
@@ -5,5 +5,5 @@ void f ()
{
enum e { a };
- using e::a; // { dg-error "not a namespace or unscoped enum" }
+ using e::a; // { dg-error "name enumerator" }
}
===================================================================
@@ -11,5 +11,5 @@ struct Bar : public Foo<T> {
void foo()
{
- using Foo<T>::i; // { dg-error "not a namespace" }
+ using Foo<T>::i; // { dg-error "member at non-class scope" }
}
};
===================================================================
@@ -7,5 +7,4 @@ template <typename T> struct B : A<T> //
{
using A<T>::i; // { dg-error "incomplete" "incomplete" }
- // { dg-error "using" "using" { target *-*-* } .-1 }
};
===================================================================
@@ -4,4 +4,4 @@ struct A {
template <typename T>
struct S : public A {
- using A::operator(); // { dg-error "no member" }
+ using A::operator(); // { dg-error "has not been declared" }
};
===================================================================
@@ -26,5 +26,5 @@ template <class 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 typename B2<T>::type;
===================================================================
@@ -17,5 +17,5 @@ template <class T>
struct A<T>::B : A<T>
{
- using A::nonexist; // { dg-error "no members matching" }
+ using A::nonexist; // { dg-error "has not been declared" }
};
@@ -23,5 +23,5 @@ template <class T>
struct A<T>::C : A
{
- using A::nonexist; // { dg-error "no members matching" }
+ using A::nonexist; // { dg-error "has not been declared" }
};
@@ -29,5 +29,5 @@ template <class 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" }
};
@@ -35,5 +35,5 @@ template <class T>
struct A<T>::E : A
{
- using A<T>::nonexist; // { dg-error "no members matching" }
+ using A<T>::nonexist; // { dg-error "has not been declared" }
};