Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?
-- >8 --
Now that r17-4860, r17-4232, and r17-4789 are all in, I can finally
fix the PR that prompted all of the above.
The problem here is that we are not detecting any of:
[namespace.udir]/1: The splice-specifier (if any) shall designate
a namespace that is not the global namespace. The nested-name-specifier,
namespace-name, and splice-specifier shall not be dependent.
Do so, then. And likewise for [namespace.alias]/2. Moreover,
using namespace [: ^^:: :]::N;
should work but currently doesn't. The problem is that when
global_namespace is created with void_type_node, void_type_node is
still a NULL_TREE; it only becomes a thing after
c_common_nodes_and_builtins. And since global_namespace's type is
null, it is wrongly considered dependent, and so the using above does
not work as expected. Since this is true for not just :: but also for
std::, I've adjusted type_dependent_expression_p instead.
PR c++/126653
gcc/cp/ChangeLog:
* cp-tree.h (check_namespace_splice): Declare.
* parser.cc (cp_parser_namespace_alias_definition): Call
check_namespace_splice.
(cp_parser_using_directive): Likewise. Give an error if the
nested-name-specifier, namespace-name, or splice-specifier is
dependent.
* pt.cc (type_dependent_expression_p): Return false for
NAMESPACE_DECL.
* reflect.cc (check_namespace_splice): New.
gcc/testsuite/ChangeLog:
* g++.dg/reflect/ns10.C: New test.
---
gcc/cp/cp-tree.h | 1 +
gcc/cp/parser.cc | 44 +++++++++++++++++++--
gcc/cp/pt.cc | 6 +++
gcc/cp/reflect.cc | 25 +++++++++++-
gcc/testsuite/g++.dg/reflect/ns10.C | 61 +++++++++++++++++++++++++++++
5 files changed, 132 insertions(+), 5 deletions(-)
create mode 100644 gcc/testsuite/g++.dg/reflect/ns10.C
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 947bf62ff98..3a88352b02c 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -9560,6 +9560,7 @@ extern bool dependent_splice_p (const_tree)
ATTRIBUTE_PURE;
extern tree reflection_mangle_prefix (tree, char [3]);
extern bool reflection_function_template_p (const_tree) ATTRIBUTE_PURE;
extern void dump_data_member_spec (pretty_printer *, tree);
+extern bool check_namespace_splice (cp_expr);
/* Inline bodies. */
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 3c84f6e335f..1ec5a13cfe0 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -24637,7 +24637,15 @@ cp_parser_namespace_alias_definition (cp_parser*
parser)
}
cp_parser_require (parser, CPP_EQ, RT_EQ);
if (cp_parser_nth_token_starts_splice_without_nns_p (parser, 1))
- namespace_specifier = cp_parser_splice_specifier (parser);
+ {
+ cp_expr splice = cp_parser_splice_specifier (parser);
+ /* [namespace.alias]/2: The splice-specifier (if any) shall designate
+ a namespace that is not the global namespace. */
+ if (check_namespace_splice (splice))
+ namespace_specifier = splice;
+ else
+ namespace_specifier = error_mark_node;
+ }
else
/* Look for the qualified-namespace-specifier. */
namespace_specifier = cp_parser_qualified_namespace_specifier (parser);
@@ -25125,8 +25133,18 @@ cp_parser_using_directive (cp_parser* parser)
cp_parser_require_keyword (parser, RID_USING, RT_USING);
/* And the `namespace' keyword. */
cp_parser_require_keyword (parser, RID_NAMESPACE, RT_NAMESPACE);
+ const location_t loc = cp_lexer_peek_token (parser->lexer)->location;
+ bool dep_error = false;
if (cp_parser_nth_token_starts_splice_without_nns_p (parser, 1))
- namespace_decl = cp_parser_splice_specifier (parser);
+ {
+ cp_expr splice = cp_parser_splice_specifier (parser);
+ /* [namespace.udir]/1: The splice-specifier (if any) shall designate
+ a namespace that is not the global namespace. */
+ if (check_namespace_splice (splice))
+ namespace_decl = splice;
+ else
+ namespace_decl = error_mark_node;
+ }
else
{
/* Look for the optional `::' operator. */
@@ -25137,8 +25155,26 @@ cp_parser_using_directive (cp_parser* parser)
/*check_dependency_p=*/true,
/*type_p=*/false,
/*is_declaration=*/true);
- /* Get the namespace being used. */
- namespace_decl = cp_parser_namespace_name (parser);
+ if (parser->scope
+ && parser->scope != error_mark_node
+ && (dependent_namespace_p (parser->scope)
+ || (TYPE_P (parser->scope) && dependent_type_p (parser->scope))))
+ {
+ /* Don't emit the "not a namespace-name" error. */
+ cp_parser_identifier (parser);
+ dep_error = true;
+ }
+ else
+ /* Get the namespace being used. */
+ namespace_decl = cp_parser_namespace_name (parser);
+ }
+ /* [namespace.udir]/1: The nested-name-specifier, namespace-name, and
+ splice-specifier shall not be dependent. */
+ if (dep_error || dependent_namespace_p (namespace_decl))
+ {
+ error_at (loc, "dependent namespaces cannot appear in a using "
+ "directive");
+ namespace_decl = error_mark_node;
}
cp_warn_deprecated_use_scopes (namespace_decl);
/* And any specified GNU attributes. */
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 2b68ceb0cd2..80148f78b03 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -30405,6 +30405,12 @@ type_dependent_expression_p (tree expression)
|| TREE_CODE (expression) == USING_DECL)
return true;
+ /* Most namespaces have void type and so wouldn't be considered
+ dependent, but some (::, std) have no type. They are still not
+ dependent, though. */
+ if (TREE_CODE (expression) == NAMESPACE_DECL)
+ return false;
+
/* A lambda-expression in template context is dependent. dependent_type_p is
true for a lambda in the scope of a class or function template, but that
doesn't cover all template contexts, like a default template argument. */
diff --git a/gcc/cp/reflect.cc b/gcc/cp/reflect.cc
index 8bf518df64f..ccf075b73c1 100644
--- a/gcc/cp/reflect.cc
+++ b/gcc/cp/reflect.cc
@@ -9253,7 +9253,7 @@ valid_splice_for_member_access_p (const_tree t, bool
decls_only_p/*=true*/)
splice is used in foo.[: bar :] or foo->[: bar :] context. TEMPLATE_P is
true if the splice-expression was preceded by 'template'. TARGS_P is true
if there were template arguments. COMPLAIN_P is true if any errors should
- be emitted. Returns true is no problems are found, false otherwise. */
+ be emitted. Returns true if no problems are found, false otherwise. */
bool
check_splice_expr (location_t loc, location_t start_loc, tree t,
@@ -9480,6 +9480,29 @@ dependent_splice_p (const_tree t)
&& TREE_CODE (TREE_OPERAND (t, 0)) == SPLICE_EXPR));
}
+/* Check if SPLICE is a valid namespace splice. Returns true if no problems
+ are found, false otherwise. */
+
+bool
+check_namespace_splice (cp_expr splice)
+{
+ if (TREE_CODE (splice) != NAMESPACE_DECL && !dependent_namespace_p (splice))
+ {
+ auto_diagnostic_group d;
+ error_at (splice.get_location (), "expected a reflection of "
+ "a namespace");
+ inform_tree_category (splice);
+ return false;
+ }
+ else if (splice == global_namespace)
+ {
+ error_at (splice.get_location (), "splice of the global namespace "
+ "can only appear in a nested-name-specifier");
+ return false;
+ }
+ return true;
+}
+
/* Annotation index for mangling. */
static GTY(()) int annotation_idx;
diff --git a/gcc/testsuite/g++.dg/reflect/ns10.C
b/gcc/testsuite/g++.dg/reflect/ns10.C
new file mode 100644
index 00000000000..c68d4e97a0c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/reflect/ns10.C
@@ -0,0 +1,61 @@
+// PR c++/126653
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+namespace std { }
+struct S { };
+namespace N { int foo; };
+
+namespace GS = [: ^^:: :]; // { dg-error "splice of the global namespace" }
+using namespace [: ^^GS :]; // { dg-error "declared|expected" }
+
+using namespace [: ^^int :]; // { dg-error "expected a reflection of a
namespace" }
+namespace X = [: ^^void :]; // { dg-error "expected a reflection of a
namespace" }
+
+using namespace S::T; // { dg-error ".T. is not a namespace-name" }
+
+template<auto ns>
+void
+bad ()
+{
+ using namespace [:ns:]; // { dg-error "dependent namespaces cannot
appear in a using directive" }
+ using namespace ::[:ns:]; // { dg-error "expected" }
+ using namespace N::[:ns:]; // { dg-error "expected" }
+ using namespace [:ns:]::N; // { dg-error "dependent namespaces cannot
appear in a using directive" }
+ using namespace [: ^^:: :]; // { dg-error "splice of the global namespace
can only appear in a nested-name-specifier" }
+ using namespace ::; // { dg-error "expected identifier before" }
+
+ namespace A = [:ns:];
+ using namespace A::N; // { dg-error "dependent namespaces
cannot appear in a using directive" }
+ using namespace A::N::M; // { dg-error "dependent namespaces cannot
appear in a using directive" }
+}
+
+template<typename T>
+void
+also_bad ()
+{
+ using namespace T::N; // { dg-error "dependent namespaces
cannot appear in a using directive" }
+}
+
+int
+ok ()
+{
+ using namespace [: ^^:: :]::N;
+ using namespace [: ^^N :];
+ using namespace [: ^^::N :];
+ using namespace ::N;
+ using namespace [: ^^std :];
+ namespace B = [: ^^N :];
+ using namespace B;
+ return foo;
+}
+
+template<typename>
+void
+also_ok ()
+{
+ namespace B = [: ^^N :];
+ using namespace B;
+ using namespace [: ^^N :];
+}
+template void also_ok<int> ();
base-commit: 962723b046ae6406c0c457bfdb76318b3652673f
--
2.55.0