diff mbox series

[2/3] c++/modules: Propagate using decls from partitions

Message ID 66188303.170a0220.8de00.5a7c@mx.google.com
State New
Headers show
Series c++/modules: Fix some small issues with exported using-decls | expand

Commit Message

Nathaniel Shead April 12, 2024, 12:40 a.m. UTC
Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk?

-- >8 --

The modules code currently neglects to set OVL_USING_P on the dependency
created for a using-decl, which causes it not to remember that the
OVL_EXPORT_P flag had been set on it when emitted from the primary
interface unit. This patch ensures that it occurs.

gcc/cp/ChangeLog:

	* module.cc (depset::hash::add_binding_entity): Propagate
	OVL_USING_P for using-declarations.

gcc/testsuite/ChangeLog:

	* g++.dg/modules/using-15_a.C: New test.
	* g++.dg/modules/using-15_b.C: New test.
	* g++.dg/modules/using-15_c.C: New test.

Signed-off-by: Nathaniel Shead <nathanieloshead@gmail.com>
---
 gcc/cp/module.cc                          |  4 ++++
 gcc/testsuite/g++.dg/modules/using-15_a.C | 13 +++++++++++++
 gcc/testsuite/g++.dg/modules/using-15_b.C |  5 +++++
 gcc/testsuite/g++.dg/modules/using-15_c.C |  7 +++++++
 4 files changed, 29 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/modules/using-15_a.C
 create mode 100644 gcc/testsuite/g++.dg/modules/using-15_b.C
 create mode 100644 gcc/testsuite/g++.dg/modules/using-15_c.C

Comments

Jason Merrill April 12, 2024, 5:50 p.m. UTC | #1
On 4/11/24 20:40, Nathaniel Shead wrote:
> Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk?
> 
> -- >8 --
> 
> The modules code currently neglects to set OVL_USING_P on the dependency
> created for a using-decl, which causes it not to remember that the
> OVL_EXPORT_P flag had been set on it when emitted from the primary
> interface unit. This patch ensures that it occurs.
> 
> gcc/cp/ChangeLog:
> 
> 	* module.cc (depset::hash::add_binding_entity): Propagate
> 	OVL_USING_P for using-declarations.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* g++.dg/modules/using-15_a.C: New test.
> 	* g++.dg/modules/using-15_b.C: New test.
> 	* g++.dg/modules/using-15_c.C: New test.
> 
> Signed-off-by: Nathaniel Shead <nathanieloshead@gmail.com>
> ---
>   gcc/cp/module.cc                          |  4 ++++
>   gcc/testsuite/g++.dg/modules/using-15_a.C | 13 +++++++++++++
>   gcc/testsuite/g++.dg/modules/using-15_b.C |  5 +++++
>   gcc/testsuite/g++.dg/modules/using-15_c.C |  7 +++++++
>   4 files changed, 29 insertions(+)
>   create mode 100644 gcc/testsuite/g++.dg/modules/using-15_a.C
>   create mode 100644 gcc/testsuite/g++.dg/modules/using-15_b.C
>   create mode 100644 gcc/testsuite/g++.dg/modules/using-15_c.C
> 
> diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
> index 9d054c4c792..527c9046c67 100644
> --- a/gcc/cp/module.cc
> +++ b/gcc/cp/module.cc
> @@ -12915,10 +12915,12 @@ depset::hash::add_binding_entity (tree decl, WMB_Flags flags, void *data_)
>   	/* Ignore NTTP objects.  */
>   	return false;
>   
> +      bool unscoped_enum_const_p = false;
>         if (!(flags & WMB_Using) && CP_DECL_CONTEXT (decl) != data->ns)
>   	{
>   	  /* A using that lost its wrapper or an unscoped enum
>   	     constant.  */
> +	  unscoped_enum_const_p = (TREE_CODE (decl) == CONST_DECL);

How does this interact with C++20 using enum?

>   	  flags = WMB_Flags (flags | WMB_Using);
>   	  if (DECL_MODULE_EXPORT_P (TREE_CODE (decl) == CONST_DECL
>   				    ? TYPE_NAME (TREE_TYPE (decl))
> @@ -12979,6 +12981,8 @@ depset::hash::add_binding_entity (tree decl, WMB_Flags flags, void *data_)
>         if (flags & WMB_Using)
>   	{
>   	  decl = ovl_make (decl, NULL_TREE);
> +	  if (!unscoped_enum_const_p)
> +	    OVL_USING_P (decl) = true;
>   	  if (flags & WMB_Export)
>   	    OVL_EXPORT_P (decl) = true;
>   	}
> diff --git a/gcc/testsuite/g++.dg/modules/using-15_a.C b/gcc/testsuite/g++.dg/modules/using-15_a.C
> new file mode 100644
> index 00000000000..23895bd8c4a
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/modules/using-15_a.C
> @@ -0,0 +1,13 @@
> +// { dg-additional-options "-fmodules-ts -Wno-global-module" }
> +// { dg-module-cmi M:a }
> +
> +module;
> +namespace foo {
> +  void a();
> +};
> +export module M:a;
> +
> +namespace bar {
> +  // propagate usings from partitions
> +  export using foo::a;
> +};
> diff --git a/gcc/testsuite/g++.dg/modules/using-15_b.C b/gcc/testsuite/g++.dg/modules/using-15_b.C
> new file mode 100644
> index 00000000000..a88f86af61f
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/modules/using-15_b.C
> @@ -0,0 +1,5 @@
> +// { dg-additional-options "-fmodules-ts" }
> +// { dg-module-cmi M }
> +
> +export module M;
> +export import :a;
> diff --git a/gcc/testsuite/g++.dg/modules/using-15_c.C b/gcc/testsuite/g++.dg/modules/using-15_c.C
> new file mode 100644
> index 00000000000..0651efffc91
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/modules/using-15_c.C
> @@ -0,0 +1,7 @@
> +// { dg-additional-options "-fmodules-ts" }
> +import M;
> +
> +int main() {
> +  bar::a();
> +  foo::a();  // { dg-error "not been declared" }
> +}
Nathaniel Shead April 13, 2024, 3:40 p.m. UTC | #2
On Fri, Apr 12, 2024 at 01:50:47PM -0400, Jason Merrill wrote:
> On 4/11/24 20:40, Nathaniel Shead wrote:
> > Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk?
> > 
> > -- >8 --
> > 
> > The modules code currently neglects to set OVL_USING_P on the dependency
> > created for a using-decl, which causes it not to remember that the
> > OVL_EXPORT_P flag had been set on it when emitted from the primary
> > interface unit. This patch ensures that it occurs.
> > 
> > gcc/cp/ChangeLog:
> > 
> > 	* module.cc (depset::hash::add_binding_entity): Propagate
> > 	OVL_USING_P for using-declarations.
> > 
> > gcc/testsuite/ChangeLog:
> > 
> > 	* g++.dg/modules/using-15_a.C: New test.
> > 	* g++.dg/modules/using-15_b.C: New test.
> > 	* g++.dg/modules/using-15_c.C: New test.
> > 
> > Signed-off-by: Nathaniel Shead <nathanieloshead@gmail.com>
> > ---
> >   gcc/cp/module.cc                          |  4 ++++
> >   gcc/testsuite/g++.dg/modules/using-15_a.C | 13 +++++++++++++
> >   gcc/testsuite/g++.dg/modules/using-15_b.C |  5 +++++
> >   gcc/testsuite/g++.dg/modules/using-15_c.C |  7 +++++++
> >   4 files changed, 29 insertions(+)
> >   create mode 100644 gcc/testsuite/g++.dg/modules/using-15_a.C
> >   create mode 100644 gcc/testsuite/g++.dg/modules/using-15_b.C
> >   create mode 100644 gcc/testsuite/g++.dg/modules/using-15_c.C
> > 
> > diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
> > index 9d054c4c792..527c9046c67 100644
> > --- a/gcc/cp/module.cc
> > +++ b/gcc/cp/module.cc
> > @@ -12915,10 +12915,12 @@ depset::hash::add_binding_entity (tree decl, WMB_Flags flags, void *data_)
> >   	/* Ignore NTTP objects.  */
> >   	return false;
> > +      bool unscoped_enum_const_p = false;
> >         if (!(flags & WMB_Using) && CP_DECL_CONTEXT (decl) != data->ns)
> >   	{
> >   	  /* A using that lost its wrapper or an unscoped enum
> >   	     constant.  */
> > +	  unscoped_enum_const_p = (TREE_CODE (decl) == CONST_DECL);
> 
> How does this interact with C++20 using enum?

Looks like it ignores those (so they still suffer from this error).  But
in general we don't handle usings of non-functions correctly anyway yet
(for the reasons I described in the cover letter); I just added this for
now to prevent regressing some test-cases caused by importing enum
consts wrapped in an OVERLOAD.

Otherwise happy to defer this patch until GCC 15 when I can look at
exploring what needs to be done to handle non-function using-decls
correctly, but I'll need to work out a new testcase for the followup
patch in this series (or just defer that one too, I suppose).

> >   	  flags = WMB_Flags (flags | WMB_Using);
> >   	  if (DECL_MODULE_EXPORT_P (TREE_CODE (decl) == CONST_DECL
> >   				    ? TYPE_NAME (TREE_TYPE (decl))
> > @@ -12979,6 +12981,8 @@ depset::hash::add_binding_entity (tree decl, WMB_Flags flags, void *data_)
> >         if (flags & WMB_Using)
> >   	{
> >   	  decl = ovl_make (decl, NULL_TREE);
> > +	  if (!unscoped_enum_const_p)
> > +	    OVL_USING_P (decl) = true;
> >   	  if (flags & WMB_Export)
> >   	    OVL_EXPORT_P (decl) = true;
> >   	}
> > diff --git a/gcc/testsuite/g++.dg/modules/using-15_a.C b/gcc/testsuite/g++.dg/modules/using-15_a.C
> > new file mode 100644
> > index 00000000000..23895bd8c4a
> > --- /dev/null
> > +++ b/gcc/testsuite/g++.dg/modules/using-15_a.C
> > @@ -0,0 +1,13 @@
> > +// { dg-additional-options "-fmodules-ts -Wno-global-module" }
> > +// { dg-module-cmi M:a }
> > +
> > +module;
> > +namespace foo {
> > +  void a();
> > +};
> > +export module M:a;
> > +
> > +namespace bar {
> > +  // propagate usings from partitions
> > +  export using foo::a;
> > +};
> > diff --git a/gcc/testsuite/g++.dg/modules/using-15_b.C b/gcc/testsuite/g++.dg/modules/using-15_b.C
> > new file mode 100644
> > index 00000000000..a88f86af61f
> > --- /dev/null
> > +++ b/gcc/testsuite/g++.dg/modules/using-15_b.C
> > @@ -0,0 +1,5 @@
> > +// { dg-additional-options "-fmodules-ts" }
> > +// { dg-module-cmi M }
> > +
> > +export module M;
> > +export import :a;
> > diff --git a/gcc/testsuite/g++.dg/modules/using-15_c.C b/gcc/testsuite/g++.dg/modules/using-15_c.C
> > new file mode 100644
> > index 00000000000..0651efffc91
> > --- /dev/null
> > +++ b/gcc/testsuite/g++.dg/modules/using-15_c.C
> > @@ -0,0 +1,7 @@
> > +// { dg-additional-options "-fmodules-ts" }
> > +import M;
> > +
> > +int main() {
> > +  bar::a();
> > +  foo::a();  // { dg-error "not been declared" }
> > +}
>
Nathaniel Shead April 30, 2024, 7:59 a.m. UTC | #3
On Sun, Apr 14, 2024 at 01:40:18AM +1000, Nathaniel Shead wrote:
> On Fri, Apr 12, 2024 at 01:50:47PM -0400, Jason Merrill wrote:
> > On 4/11/24 20:40, Nathaniel Shead wrote:
> > > Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk?
> > > 
> > > -- >8 --
> > > 
> > > The modules code currently neglects to set OVL_USING_P on the dependency
> > > created for a using-decl, which causes it not to remember that the
> > > OVL_EXPORT_P flag had been set on it when emitted from the primary
> > > interface unit. This patch ensures that it occurs.
> > > 
> > > gcc/cp/ChangeLog:
> > > 
> > > 	* module.cc (depset::hash::add_binding_entity): Propagate
> > > 	OVL_USING_P for using-declarations.
> > > 
> > > gcc/testsuite/ChangeLog:
> > > 
> > > 	* g++.dg/modules/using-15_a.C: New test.
> > > 	* g++.dg/modules/using-15_b.C: New test.
> > > 	* g++.dg/modules/using-15_c.C: New test.
> > > 
> > > Signed-off-by: Nathaniel Shead <nathanieloshead@gmail.com>
> > > ---
> > >   gcc/cp/module.cc                          |  4 ++++
> > >   gcc/testsuite/g++.dg/modules/using-15_a.C | 13 +++++++++++++
> > >   gcc/testsuite/g++.dg/modules/using-15_b.C |  5 +++++
> > >   gcc/testsuite/g++.dg/modules/using-15_c.C |  7 +++++++
> > >   4 files changed, 29 insertions(+)
> > >   create mode 100644 gcc/testsuite/g++.dg/modules/using-15_a.C
> > >   create mode 100644 gcc/testsuite/g++.dg/modules/using-15_b.C
> > >   create mode 100644 gcc/testsuite/g++.dg/modules/using-15_c.C
> > > 
> > > diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
> > > index 9d054c4c792..527c9046c67 100644
> > > --- a/gcc/cp/module.cc
> > > +++ b/gcc/cp/module.cc
> > > @@ -12915,10 +12915,12 @@ depset::hash::add_binding_entity (tree decl, WMB_Flags flags, void *data_)
> > >   	/* Ignore NTTP objects.  */
> > >   	return false;
> > > +      bool unscoped_enum_const_p = false;
> > >         if (!(flags & WMB_Using) && CP_DECL_CONTEXT (decl) != data->ns)
> > >   	{
> > >   	  /* A using that lost its wrapper or an unscoped enum
> > >   	     constant.  */
> > > +	  unscoped_enum_const_p = (TREE_CODE (decl) == CONST_DECL);
> > 
> > How does this interact with C++20 using enum?
> 
> Looks like it ignores those (so they still suffer from this error).  But
> in general we don't handle usings of non-functions correctly anyway yet
> (for the reasons I described in the cover letter); I just added this for
> now to prevent regressing some test-cases caused by importing enum
> consts wrapped in an OVERLOAD.
> 
> Otherwise happy to defer this patch until GCC 15 when I can look at
> exploring what needs to be done to handle non-function using-decls
> correctly, but I'll need to work out a new testcase for the followup
> patch in this series (or just defer that one too, I suppose).
> 

Ping.  Or should I just scrap this patch for now, find a new testcase
for the followup patch, and submit it again once we have a general
solution for using-decls of non-functions?

> > >   	  flags = WMB_Flags (flags | WMB_Using);
> > >   	  if (DECL_MODULE_EXPORT_P (TREE_CODE (decl) == CONST_DECL
> > >   				    ? TYPE_NAME (TREE_TYPE (decl))
> > > @@ -12979,6 +12981,8 @@ depset::hash::add_binding_entity (tree decl, WMB_Flags flags, void *data_)
> > >         if (flags & WMB_Using)
> > >   	{
> > >   	  decl = ovl_make (decl, NULL_TREE);
> > > +	  if (!unscoped_enum_const_p)
> > > +	    OVL_USING_P (decl) = true;
> > >   	  if (flags & WMB_Export)
> > >   	    OVL_EXPORT_P (decl) = true;
> > >   	}
> > > diff --git a/gcc/testsuite/g++.dg/modules/using-15_a.C b/gcc/testsuite/g++.dg/modules/using-15_a.C
> > > new file mode 100644
> > > index 00000000000..23895bd8c4a
> > > --- /dev/null
> > > +++ b/gcc/testsuite/g++.dg/modules/using-15_a.C
> > > @@ -0,0 +1,13 @@
> > > +// { dg-additional-options "-fmodules-ts -Wno-global-module" }
> > > +// { dg-module-cmi M:a }
> > > +
> > > +module;
> > > +namespace foo {
> > > +  void a();
> > > +};
> > > +export module M:a;
> > > +
> > > +namespace bar {
> > > +  // propagate usings from partitions
> > > +  export using foo::a;
> > > +};
> > > diff --git a/gcc/testsuite/g++.dg/modules/using-15_b.C b/gcc/testsuite/g++.dg/modules/using-15_b.C
> > > new file mode 100644
> > > index 00000000000..a88f86af61f
> > > --- /dev/null
> > > +++ b/gcc/testsuite/g++.dg/modules/using-15_b.C
> > > @@ -0,0 +1,5 @@
> > > +// { dg-additional-options "-fmodules-ts" }
> > > +// { dg-module-cmi M }
> > > +
> > > +export module M;
> > > +export import :a;
> > > diff --git a/gcc/testsuite/g++.dg/modules/using-15_c.C b/gcc/testsuite/g++.dg/modules/using-15_c.C
> > > new file mode 100644
> > > index 00000000000..0651efffc91
> > > --- /dev/null
> > > +++ b/gcc/testsuite/g++.dg/modules/using-15_c.C
> > > @@ -0,0 +1,7 @@
> > > +// { dg-additional-options "-fmodules-ts" }
> > > +import M;
> > > +
> > > +int main() {
> > > +  bar::a();
> > > +  foo::a();  // { dg-error "not been declared" }
> > > +}
> >
Jason Merrill April 30, 2024, 6:16 p.m. UTC | #4
On 4/30/24 00:59, Nathaniel Shead wrote:
> On Sun, Apr 14, 2024 at 01:40:18AM +1000, Nathaniel Shead wrote:
>> On Fri, Apr 12, 2024 at 01:50:47PM -0400, Jason Merrill wrote:
>>> On 4/11/24 20:40, Nathaniel Shead wrote:
>>>> Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk?
>>>>
>>>> -- >8 --
>>>>
>>>> The modules code currently neglects to set OVL_USING_P on the dependency
>>>> created for a using-decl, which causes it not to remember that the
>>>> OVL_EXPORT_P flag had been set on it when emitted from the primary
>>>> interface unit. This patch ensures that it occurs.
>>>>
>>>> gcc/cp/ChangeLog:
>>>>
>>>> 	* module.cc (depset::hash::add_binding_entity): Propagate
>>>> 	OVL_USING_P for using-declarations.
>>>>
>>>> gcc/testsuite/ChangeLog:
>>>>
>>>> 	* g++.dg/modules/using-15_a.C: New test.
>>>> 	* g++.dg/modules/using-15_b.C: New test.
>>>> 	* g++.dg/modules/using-15_c.C: New test.
>>>>
>>>> Signed-off-by: Nathaniel Shead <nathanieloshead@gmail.com>
>>>> ---
>>>>    gcc/cp/module.cc                          |  4 ++++
>>>>    gcc/testsuite/g++.dg/modules/using-15_a.C | 13 +++++++++++++
>>>>    gcc/testsuite/g++.dg/modules/using-15_b.C |  5 +++++
>>>>    gcc/testsuite/g++.dg/modules/using-15_c.C |  7 +++++++
>>>>    4 files changed, 29 insertions(+)
>>>>    create mode 100644 gcc/testsuite/g++.dg/modules/using-15_a.C
>>>>    create mode 100644 gcc/testsuite/g++.dg/modules/using-15_b.C
>>>>    create mode 100644 gcc/testsuite/g++.dg/modules/using-15_c.C
>>>>
>>>> diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
>>>> index 9d054c4c792..527c9046c67 100644
>>>> --- a/gcc/cp/module.cc
>>>> +++ b/gcc/cp/module.cc
>>>> @@ -12915,10 +12915,12 @@ depset::hash::add_binding_entity (tree decl, WMB_Flags flags, void *data_)
>>>>    	/* Ignore NTTP objects.  */
>>>>    	return false;
>>>> +      bool unscoped_enum_const_p = false;
>>>>          if (!(flags & WMB_Using) && CP_DECL_CONTEXT (decl) != data->ns)
>>>>    	{
>>>>    	  /* A using that lost its wrapper or an unscoped enum
>>>>    	     constant.  */
>>>> +	  unscoped_enum_const_p = (TREE_CODE (decl) == CONST_DECL);
>>>
>>> How does this interact with C++20 using enum?
>>
>> Looks like it ignores those (so they still suffer from this error).  But
>> in general we don't handle usings of non-functions correctly anyway yet
>> (for the reasons I described in the cover letter); I just added this for
>> now to prevent regressing some test-cases caused by importing enum
>> consts wrapped in an OVERLOAD.
>>
>> Otherwise happy to defer this patch until GCC 15 when I can look at
>> exploring what needs to be done to handle non-function using-decls
>> correctly, but I'll need to work out a new testcase for the followup
>> patch in this series (or just defer that one too, I suppose).
> 
> Ping.  Or should I just scrap this patch for now, find a new testcase
> for the followup patch, and submit it again once we have a general
> solution for using-decls of non-functions?

Please add a FIXME about using enum here and a using enum testcase to 
the appropriate PR; OK for trunk and 14.2 with that change.

Jason
diff mbox series

Patch

diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index 9d054c4c792..527c9046c67 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -12915,10 +12915,12 @@  depset::hash::add_binding_entity (tree decl, WMB_Flags flags, void *data_)
 	/* Ignore NTTP objects.  */
 	return false;
 
+      bool unscoped_enum_const_p = false;
       if (!(flags & WMB_Using) && CP_DECL_CONTEXT (decl) != data->ns)
 	{
 	  /* A using that lost its wrapper or an unscoped enum
 	     constant.  */
+	  unscoped_enum_const_p = (TREE_CODE (decl) == CONST_DECL);
 	  flags = WMB_Flags (flags | WMB_Using);
 	  if (DECL_MODULE_EXPORT_P (TREE_CODE (decl) == CONST_DECL
 				    ? TYPE_NAME (TREE_TYPE (decl))
@@ -12979,6 +12981,8 @@  depset::hash::add_binding_entity (tree decl, WMB_Flags flags, void *data_)
       if (flags & WMB_Using)
 	{
 	  decl = ovl_make (decl, NULL_TREE);
+	  if (!unscoped_enum_const_p)
+	    OVL_USING_P (decl) = true;
 	  if (flags & WMB_Export)
 	    OVL_EXPORT_P (decl) = true;
 	}
diff --git a/gcc/testsuite/g++.dg/modules/using-15_a.C b/gcc/testsuite/g++.dg/modules/using-15_a.C
new file mode 100644
index 00000000000..23895bd8c4a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/using-15_a.C
@@ -0,0 +1,13 @@ 
+// { dg-additional-options "-fmodules-ts -Wno-global-module" }
+// { dg-module-cmi M:a }
+
+module;
+namespace foo {
+  void a();
+};
+export module M:a;
+
+namespace bar {
+  // propagate usings from partitions
+  export using foo::a;
+};
diff --git a/gcc/testsuite/g++.dg/modules/using-15_b.C b/gcc/testsuite/g++.dg/modules/using-15_b.C
new file mode 100644
index 00000000000..a88f86af61f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/using-15_b.C
@@ -0,0 +1,5 @@ 
+// { dg-additional-options "-fmodules-ts" }
+// { dg-module-cmi M }
+
+export module M;
+export import :a;
diff --git a/gcc/testsuite/g++.dg/modules/using-15_c.C b/gcc/testsuite/g++.dg/modules/using-15_c.C
new file mode 100644
index 00000000000..0651efffc91
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/using-15_c.C
@@ -0,0 +1,7 @@ 
+// { dg-additional-options "-fmodules-ts" }
+import M;
+
+int main() {
+  bar::a();
+  foo::a();  // { dg-error "not been declared" }
+}