c++/reflection: bogus error with block-scope using [:ns:]::S [PR126654]

Message ID 20261002211934.1415422-1-polacek@redhat.com
State Committed
Commit 1801e9f042319e934045f3d4aaaa3ba40e22d017
Headers
Series c++/reflection: bogus error with block-scope using [:ns:]::S [PR126654] |

Commit Message

Marek Polacek Oct. 2, 2026, 9:19 p.m. UTC
  Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk/16?

-- >8 --
Here we emit error "'::' is not a class, namespace, or
enumeration" for

  using [:ns:]::S; // where ns=^^::

which is clearly wrong.  tsubst_stmt/DECL_EXPR has

    scope = tsubst (scope, args, complain, in_decl);
    if (!MAYBE_CLASS_TYPE_P (scope)
	&& TREE_CODE (scope) != ENUMERAL_TYPE)
      {
	if (complain & tf_error)
	  error_at (DECL_SOURCE_LOCATION (decl), "%qT is not a "
		    "class, namespace, or enumeration", scope);
	return error_mark_node;
      }

but it never checked for a NAMESPACE_DECL.  That was ok before P2996
which brought dependent namespaces but now we need to allow them.

As it so happens, I found another problem in this space, a failure
to propagate USING_DECL_TYPENAME_P (127707).

	PR c++/126654

gcc/cp/ChangeLog:

	* pt.cc (tsubst_stmt) <case DECL_EXPR>: If tsubst returns
	error_mark_node, return error_mark_node.  Allow NAMESPACE_DECL.

gcc/testsuite/ChangeLog:

	* g++.dg/reflect/ns11.C: New test.
---
 gcc/cp/pt.cc                        |  3 ++
 gcc/testsuite/g++.dg/reflect/ns11.C | 70 +++++++++++++++++++++++++++++
 2 files changed, 73 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/reflect/ns11.C


base-commit: d27e275b54ca0eb44ad136bc9f0488b846355e19
  

Comments

Jason Merrill Oct. 2, 2026, 11:33 p.m. UTC | #1
On 10/2/26 11:19 PM, Marek Polacek wrote:
> Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk/16?

OK.
> -- >8 --
> Here we emit error "'::' is not a class, namespace, or
> enumeration" for
> 
>    using [:ns:]::S; // where ns=^^::
> 
> which is clearly wrong.  tsubst_stmt/DECL_EXPR has
> 
>      scope = tsubst (scope, args, complain, in_decl);
>      if (!MAYBE_CLASS_TYPE_P (scope)
> 	&& TREE_CODE (scope) != ENUMERAL_TYPE)
>        {
> 	if (complain & tf_error)
> 	  error_at (DECL_SOURCE_LOCATION (decl), "%qT is not a "
> 		    "class, namespace, or enumeration", scope);
> 	return error_mark_node;
>        }
> 
> but it never checked for a NAMESPACE_DECL.  That was ok before P2996
> which brought dependent namespaces but now we need to allow them.
> 
> As it so happens, I found another problem in this space, a failure
> to propagate USING_DECL_TYPENAME_P (127707).
> 
> 	PR c++/126654
> 
> gcc/cp/ChangeLog:
> 
> 	* pt.cc (tsubst_stmt) <case DECL_EXPR>: If tsubst returns
> 	error_mark_node, return error_mark_node.  Allow NAMESPACE_DECL.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* g++.dg/reflect/ns11.C: New test.
> ---
>   gcc/cp/pt.cc                        |  3 ++
>   gcc/testsuite/g++.dg/reflect/ns11.C | 70 +++++++++++++++++++++++++++++
>   2 files changed, 73 insertions(+)
>   create mode 100644 gcc/testsuite/g++.dg/reflect/ns11.C
> 
> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> index 6c8d0e2de71..2b68ceb0cd2 100644
> --- a/gcc/cp/pt.cc
> +++ b/gcc/cp/pt.cc
> @@ -19908,7 +19908,10 @@ tsubst_stmt (tree t, tree args, tsubst_flags_t complain, tree in_decl)
>   	    if (DECL_DEPENDENT_P (decl))
>   	      {
>   		scope = tsubst (scope, args, complain, in_decl);
> +		if (scope == error_mark_node)
> +		  return error_mark_node;
>   		if (!MAYBE_CLASS_TYPE_P (scope)
> +		    && TREE_CODE (scope) != NAMESPACE_DECL
>   		    && TREE_CODE (scope) != ENUMERAL_TYPE)
>   		  {
>   		    if (complain & tf_error)
> diff --git a/gcc/testsuite/g++.dg/reflect/ns11.C b/gcc/testsuite/g++.dg/reflect/ns11.C
> new file mode 100644
> index 00000000000..0bdd9131a1d
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/reflect/ns11.C
> @@ -0,0 +1,70 @@
> +// PR c++/126654
> +// { dg-do compile { target c++26 } }
> +// { dg-additional-options "-freflection" }
> +
> +int v;
> +
> +namespace N {
> +  struct S {};
> +  namespace M {
> +    struct S {};
> +    int v;
> +  }
> +  int v;
> +}
> +namespace A = N;
> +struct S {};
> +enum class E { S };
> +struct C { struct S {}; };
> +
> +template<auto ns>
> +void
> +f ()
> +{
> +  using [:ns:]::S;
> +  using [:ns:]::v;
> +  v = 42;
> +}
> +
> +template<auto ns>
> +void
> +fe ()
> +{
> +  using [:ns:]::S;
> +  auto e = S;
> +}
> +
> +template<auto ns>
> +void
> +f2 ()
> +{
> +  using [:ns:]::S; // { dg-error "expected a reflection of a class, namespace, or enumeration" }
> +// { dg-message "but .int. is a type" "" { target *-*-* } .-1 }
> +}
> +
> +template<auto ns>
> +void
> +f3 ()
> +{
> +  using [:ns:]::S;  // { dg-error "using-declaration for member at non-class scope" }
> +}
> +
> +template<typename T>
> +void
> +f4 ()
> +{
> +  using T::x;  // { dg-error "is not a class, namespace, or enumeration" }
> +}
> +
> +void
> +g ()
> +{
> +  f<^^::>();
> +  f<^^N>();
> +  f<^^A>();
> +  f<^^N::M>();
> +  fe<^^E>();
> +  f2<^^int>();
> +  f3<^^C>();
> +  f4<int>();
> +}
> 
> base-commit: d27e275b54ca0eb44ad136bc9f0488b846355e19
  

Patch

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 6c8d0e2de71..2b68ceb0cd2 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -19908,7 +19908,10 @@  tsubst_stmt (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 	    if (DECL_DEPENDENT_P (decl))
 	      {
 		scope = tsubst (scope, args, complain, in_decl);
+		if (scope == error_mark_node)
+		  return error_mark_node;
 		if (!MAYBE_CLASS_TYPE_P (scope)
+		    && TREE_CODE (scope) != NAMESPACE_DECL
 		    && TREE_CODE (scope) != ENUMERAL_TYPE)
 		  {
 		    if (complain & tf_error)
diff --git a/gcc/testsuite/g++.dg/reflect/ns11.C b/gcc/testsuite/g++.dg/reflect/ns11.C
new file mode 100644
index 00000000000..0bdd9131a1d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/reflect/ns11.C
@@ -0,0 +1,70 @@ 
+// PR c++/126654
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+int v;
+
+namespace N {
+  struct S {};
+  namespace M {
+    struct S {};
+    int v;
+  }
+  int v;
+}
+namespace A = N;
+struct S {};
+enum class E { S };
+struct C { struct S {}; };
+
+template<auto ns>
+void
+f ()
+{
+  using [:ns:]::S;
+  using [:ns:]::v;
+  v = 42;
+}
+
+template<auto ns>
+void
+fe ()
+{
+  using [:ns:]::S;
+  auto e = S;
+}
+
+template<auto ns>
+void
+f2 ()
+{
+  using [:ns:]::S; // { dg-error "expected a reflection of a class, namespace, or enumeration" }
+// { dg-message "but .int. is a type" "" { target *-*-* } .-1 }
+}
+
+template<auto ns>
+void
+f3 ()
+{
+  using [:ns:]::S;  // { dg-error "using-declaration for member at non-class scope" }
+}
+
+template<typename T>
+void
+f4 ()
+{
+  using T::x;  // { dg-error "is not a class, namespace, or enumeration" }
+}
+
+void
+g ()
+{
+  f<^^::>();
+  f<^^N>();
+  f<^^A>();
+  f<^^N::M>();
+  fe<^^E>();
+  f2<^^int>();
+  f3<^^C>();
+  f4<int>();
+}