* [PATCH 1/2] c++: potentiality of templated memfn call [PR109480]
@ 2023-05-01 19:59 Patrick Palka
2023-05-01 19:59 ` [PATCH 2/2] c++: non-dep init folding and access checking [PR109480] Patrick Palka
2023-05-02 18:34 ` [PATCH 1/2] c++: potentiality of templated memfn call [PR109480] Jason Merrill
0 siblings, 2 replies; 12+ messages in thread
From: Patrick Palka @ 2023-05-01 19:59 UTC (permalink / raw)
To: gcc-patches; +Cc: jason, Patrick Palka
Here we're incorrectly deeming the templated call a.g() inside b's
initializer as potentially constant, despite g being non-constexpr,
which leads to us wastefully instantiating the initializer ahead of time
and triggering a bug in access checking deferral (which will get fixed
in the subsequent patch).
This patch fixes this by calling get_fns earlier during potentiality
checking so that we also handle the templated form of a member function
call (whose overall callee is a COMPONENT_REF) when checking if the called
function is constexpr etc.
PR c++/109480
gcc/cp/ChangeLog:
* constexpr.cc (potential_constant_expression_1) <case CALL_EXPR>:
Reorganize to call get_fns sooner. Remove dead store to 'fun'.
gcc/testsuite/ChangeLog:
* g++.dg/cpp0x/noexcept59.C: Make e() constexpr so that the
expected "without object" diagnostic isn't replaced by a
"call to non-constexpr function" diagnostic.
* g++.dg/template/non-dependent25.C: New test.
---
gcc/cp/constexpr.cc | 16 ++++++++--------
gcc/testsuite/g++.dg/cpp0x/noexcept59.C | 2 +-
gcc/testsuite/g++.dg/template/non-dependent25.C | 14 ++++++++++++++
3 files changed, 23 insertions(+), 9 deletions(-)
create mode 100644 gcc/testsuite/g++.dg/template/non-dependent25.C
diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index d1097764b10..29d872d0a5e 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -9132,6 +9132,10 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
if (fun && is_overloaded_fn (fun))
{
+ if (!RECUR (fun, true))
+ return false;
+ fun = get_fns (fun);
+
if (TREE_CODE (fun) == FUNCTION_DECL)
{
if (builtin_valid_in_constant_expr_p (fun))
@@ -9167,7 +9171,8 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
expression the address will be folded away, so look
through it now. */
if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fun)
- && !DECL_CONSTRUCTOR_P (fun))
+ && !DECL_CONSTRUCTOR_P (fun)
+ && !processing_template_decl)
{
tree x = get_nth_callarg (t, 0);
if (is_this_parameter (x))
@@ -9182,16 +9187,11 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
i = 1;
}
}
- else
- {
- if (!RECUR (fun, true))
- return false;
- fun = get_first_fn (fun);
- }
+
+ fun = OVL_FIRST (fun);
/* Skip initial arguments to base constructors. */
if (DECL_BASE_CONSTRUCTOR_P (fun))
i = num_artificial_parms_for (fun);
- fun = DECL_ORIGIN (fun);
}
else if (fun)
{
diff --git a/gcc/testsuite/g++.dg/cpp0x/noexcept59.C b/gcc/testsuite/g++.dg/cpp0x/noexcept59.C
index c752601ba09..1dc826d3111 100644
--- a/gcc/testsuite/g++.dg/cpp0x/noexcept59.C
+++ b/gcc/testsuite/g++.dg/cpp0x/noexcept59.C
@@ -3,7 +3,7 @@
template <class ...Ts> class A
{
- void e ();
+ constexpr bool e () { return true; };
bool f (int() noexcept(this->e())); // { dg-error "this" }
bool g (int() noexcept(e())); // { dg-error "without object" }
};
diff --git a/gcc/testsuite/g++.dg/template/non-dependent25.C b/gcc/testsuite/g++.dg/template/non-dependent25.C
new file mode 100644
index 00000000000..a2f9801e11f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/non-dependent25.C
@@ -0,0 +1,14 @@
+// PR c++/109480
+
+template<class T>
+struct A {
+ void f() {
+ A<int> a;
+ const bool b = a.g();
+ }
+
+private:
+ bool g() const;
+};
+
+template struct A<int>;
--
2.40.1.459.g48d89b51b3
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH 2/2] c++: non-dep init folding and access checking [PR109480]
2023-05-01 19:59 [PATCH 1/2] c++: potentiality of templated memfn call [PR109480] Patrick Palka
@ 2023-05-01 19:59 ` Patrick Palka
2023-05-02 18:35 ` Jason Merrill
2023-05-02 18:34 ` [PATCH 1/2] c++: potentiality of templated memfn call [PR109480] Jason Merrill
1 sibling, 1 reply; 12+ messages in thread
From: Patrick Palka @ 2023-05-01 19:59 UTC (permalink / raw)
To: gcc-patches; +Cc: jason, Patrick Palka
enforce_access currently inspects processing_template_decl to determine
whether to defer the given access check until instantiation time. But
using this flag is unreliable because it gets cleared during e.g.
non-dependent initializer folding, and can lead to premature access
check failures as in the below testcase. It seems better to inspect
current_template_parms instead.
Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK
for trunk?
PR c++/109480
gcc/cp/ChangeLog:
* semantics.cc (enforce_access): Check current_template_parms
instead of processing_template_decl when determining whether
to defer the access check.
gcc/testsuite/ChangeLog:
* g++.dg/template/non-dependent25a.C: New test.
---
gcc/cp/semantics.cc | 2 +-
.../g++.dg/template/non-dependent25a.C | 17 +++++++++++++++++
2 files changed, 18 insertions(+), 1 deletion(-)
create mode 100644 gcc/testsuite/g++.dg/template/non-dependent25a.C
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 9ba316ab3be..474da71bff6 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -346,7 +346,7 @@ enforce_access (tree basetype_path, tree decl, tree diag_decl,
}
tree cs = current_scope ();
- if (processing_template_decl
+ if (current_template_parms
&& (CLASS_TYPE_P (cs) || TREE_CODE (cs) == FUNCTION_DECL))
if (tree template_info = get_template_info (cs))
{
diff --git a/gcc/testsuite/g++.dg/template/non-dependent25a.C b/gcc/testsuite/g++.dg/template/non-dependent25a.C
new file mode 100644
index 00000000000..902e537ec09
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/non-dependent25a.C
@@ -0,0 +1,17 @@
+// PR c++/109480
+// A version of non-dependent25.C where b's initializer is a constant
+// expression.
+// { dg-do compile { target c++11 } }
+
+template<class T>
+struct A {
+ void f() {
+ constexpr A<int> a;
+ const bool b = a.g(); // { dg-bogus "private" }
+ }
+
+private:
+ constexpr bool g() const { return true; }
+};
+
+template struct A<int>;
--
2.40.1.459.g48d89b51b3
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 1/2] c++: potentiality of templated memfn call [PR109480]
2023-05-01 19:59 [PATCH 1/2] c++: potentiality of templated memfn call [PR109480] Patrick Palka
2023-05-01 19:59 ` [PATCH 2/2] c++: non-dep init folding and access checking [PR109480] Patrick Palka
@ 2023-05-02 18:34 ` Jason Merrill
2023-05-02 19:35 ` Patrick Palka
1 sibling, 1 reply; 12+ messages in thread
From: Jason Merrill @ 2023-05-02 18:34 UTC (permalink / raw)
To: Patrick Palka, gcc-patches
On 5/1/23 15:59, Patrick Palka wrote:
> Here we're incorrectly deeming the templated call a.g() inside b's
> initializer as potentially constant, despite g being non-constexpr,
> which leads to us wastefully instantiating the initializer ahead of time
> and triggering a bug in access checking deferral (which will get fixed
> in the subsequent patch).
>
> This patch fixes this by calling get_fns earlier during potentiality
> checking so that we also handle the templated form of a member function
> call (whose overall callee is a COMPONENT_REF) when checking if the called
> function is constexpr etc.
>
> PR c++/109480
>
> gcc/cp/ChangeLog:
>
> * constexpr.cc (potential_constant_expression_1) <case CALL_EXPR>:
> Reorganize to call get_fns sooner. Remove dead store to 'fun'.
>
> gcc/testsuite/ChangeLog:
>
> * g++.dg/cpp0x/noexcept59.C: Make e() constexpr so that the
> expected "without object" diagnostic isn't replaced by a
> "call to non-constexpr function" diagnostic.
> * g++.dg/template/non-dependent25.C: New test.
> ---
> gcc/cp/constexpr.cc | 16 ++++++++--------
> gcc/testsuite/g++.dg/cpp0x/noexcept59.C | 2 +-
> gcc/testsuite/g++.dg/template/non-dependent25.C | 14 ++++++++++++++
> 3 files changed, 23 insertions(+), 9 deletions(-)
> create mode 100644 gcc/testsuite/g++.dg/template/non-dependent25.C
>
> diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
> index d1097764b10..29d872d0a5e 100644
> --- a/gcc/cp/constexpr.cc
> +++ b/gcc/cp/constexpr.cc
> @@ -9132,6 +9132,10 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
>
> if (fun && is_overloaded_fn (fun))
> {
> + if (!RECUR (fun, true))
> + return false;
> + fun = get_fns (fun);
> +
> if (TREE_CODE (fun) == FUNCTION_DECL)
> {
> if (builtin_valid_in_constant_expr_p (fun))
> @@ -9167,7 +9171,8 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
> expression the address will be folded away, so look
> through it now. */
> if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fun)
> - && !DECL_CONSTRUCTOR_P (fun))
> + && !DECL_CONSTRUCTOR_P (fun)
> + && !processing_template_decl)
I don't see any rationale for this hunk?
> {
> tree x = get_nth_callarg (t, 0);
> if (is_this_parameter (x))
> @@ -9182,16 +9187,11 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
> i = 1;
> }
> }
> - else
> - {
> - if (!RECUR (fun, true))
> - return false;
> - fun = get_first_fn (fun);
> - }
> +
> + fun = OVL_FIRST (fun);
> /* Skip initial arguments to base constructors. */
> if (DECL_BASE_CONSTRUCTOR_P (fun))
> i = num_artificial_parms_for (fun);
> - fun = DECL_ORIGIN (fun);
> }
> else if (fun)
> {
> diff --git a/gcc/testsuite/g++.dg/cpp0x/noexcept59.C b/gcc/testsuite/g++.dg/cpp0x/noexcept59.C
> index c752601ba09..1dc826d3111 100644
> --- a/gcc/testsuite/g++.dg/cpp0x/noexcept59.C
> +++ b/gcc/testsuite/g++.dg/cpp0x/noexcept59.C
> @@ -3,7 +3,7 @@
>
> template <class ...Ts> class A
> {
> - void e ();
> + constexpr bool e () { return true; };
> bool f (int() noexcept(this->e())); // { dg-error "this" }
> bool g (int() noexcept(e())); // { dg-error "without object" }
> };
> diff --git a/gcc/testsuite/g++.dg/template/non-dependent25.C b/gcc/testsuite/g++.dg/template/non-dependent25.C
> new file mode 100644
> index 00000000000..a2f9801e11f
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/template/non-dependent25.C
> @@ -0,0 +1,14 @@
> +// PR c++/109480
> +
> +template<class T>
> +struct A {
> + void f() {
> + A<int> a;
> + const bool b = a.g();
> + }
> +
> +private:
> + bool g() const;
> +};
> +
> +template struct A<int>;
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 2/2] c++: non-dep init folding and access checking [PR109480]
2023-05-01 19:59 ` [PATCH 2/2] c++: non-dep init folding and access checking [PR109480] Patrick Palka
@ 2023-05-02 18:35 ` Jason Merrill
0 siblings, 0 replies; 12+ messages in thread
From: Jason Merrill @ 2023-05-02 18:35 UTC (permalink / raw)
To: Patrick Palka, gcc-patches
On 5/1/23 15:59, Patrick Palka wrote:
> enforce_access currently inspects processing_template_decl to determine
> whether to defer the given access check until instantiation time. But
> using this flag is unreliable because it gets cleared during e.g.
> non-dependent initializer folding, and can lead to premature access
> check failures as in the below testcase. It seems better to inspect
> current_template_parms instead.
>
> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK
> for trunk?
OK.
> PR c++/109480
>
> gcc/cp/ChangeLog:
>
> * semantics.cc (enforce_access): Check current_template_parms
> instead of processing_template_decl when determining whether
> to defer the access check.
>
> gcc/testsuite/ChangeLog:
>
> * g++.dg/template/non-dependent25a.C: New test.
> ---
> gcc/cp/semantics.cc | 2 +-
> .../g++.dg/template/non-dependent25a.C | 17 +++++++++++++++++
> 2 files changed, 18 insertions(+), 1 deletion(-)
> create mode 100644 gcc/testsuite/g++.dg/template/non-dependent25a.C
>
> diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
> index 9ba316ab3be..474da71bff6 100644
> --- a/gcc/cp/semantics.cc
> +++ b/gcc/cp/semantics.cc
> @@ -346,7 +346,7 @@ enforce_access (tree basetype_path, tree decl, tree diag_decl,
> }
>
> tree cs = current_scope ();
> - if (processing_template_decl
> + if (current_template_parms
> && (CLASS_TYPE_P (cs) || TREE_CODE (cs) == FUNCTION_DECL))
> if (tree template_info = get_template_info (cs))
> {
> diff --git a/gcc/testsuite/g++.dg/template/non-dependent25a.C b/gcc/testsuite/g++.dg/template/non-dependent25a.C
> new file mode 100644
> index 00000000000..902e537ec09
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/template/non-dependent25a.C
> @@ -0,0 +1,17 @@
> +// PR c++/109480
> +// A version of non-dependent25.C where b's initializer is a constant
> +// expression.
> +// { dg-do compile { target c++11 } }
> +
> +template<class T>
> +struct A {
> + void f() {
> + constexpr A<int> a;
> + const bool b = a.g(); // { dg-bogus "private" }
> + }
> +
> +private:
> + constexpr bool g() const { return true; }
> +};
> +
> +template struct A<int>;
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 1/2] c++: potentiality of templated memfn call [PR109480]
2023-05-02 18:34 ` [PATCH 1/2] c++: potentiality of templated memfn call [PR109480] Jason Merrill
@ 2023-05-02 19:35 ` Patrick Palka
2023-05-02 19:53 ` Patrick Palka
0 siblings, 1 reply; 12+ messages in thread
From: Patrick Palka @ 2023-05-02 19:35 UTC (permalink / raw)
To: Jason Merrill; +Cc: Patrick Palka, gcc-patches
On Tue, 2 May 2023, Jason Merrill wrote:
> On 5/1/23 15:59, Patrick Palka wrote:
> > Here we're incorrectly deeming the templated call a.g() inside b's
> > initializer as potentially constant, despite g being non-constexpr,
> > which leads to us wastefully instantiating the initializer ahead of time
> > and triggering a bug in access checking deferral (which will get fixed
> > in the subsequent patch).
> >
> > This patch fixes this by calling get_fns earlier during potentiality
> > checking so that we also handle the templated form of a member function
> > call (whose overall callee is a COMPONENT_REF) when checking if the called
> > function is constexpr etc.
> >
> > PR c++/109480
> >
> > gcc/cp/ChangeLog:
> >
> > * constexpr.cc (potential_constant_expression_1) <case CALL_EXPR>:
> > Reorganize to call get_fns sooner. Remove dead store to 'fun'.
> >
> > gcc/testsuite/ChangeLog:
> >
> > * g++.dg/cpp0x/noexcept59.C: Make e() constexpr so that the
> > expected "without object" diagnostic isn't replaced by a
> > "call to non-constexpr function" diagnostic.
> > * g++.dg/template/non-dependent25.C: New test.
> > ---
> > gcc/cp/constexpr.cc | 16 ++++++++--------
> > gcc/testsuite/g++.dg/cpp0x/noexcept59.C | 2 +-
> > gcc/testsuite/g++.dg/template/non-dependent25.C | 14 ++++++++++++++
> > 3 files changed, 23 insertions(+), 9 deletions(-)
> > create mode 100644 gcc/testsuite/g++.dg/template/non-dependent25.C
> >
> > diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
> > index d1097764b10..29d872d0a5e 100644
> > --- a/gcc/cp/constexpr.cc
> > +++ b/gcc/cp/constexpr.cc
> > @@ -9132,6 +9132,10 @@ potential_constant_expression_1 (tree t, bool
> > want_rval, bool strict, bool now,
> > if (fun && is_overloaded_fn (fun))
> > {
> > + if (!RECUR (fun, true))
> > + return false;
> > + fun = get_fns (fun);
> > +
> > if (TREE_CODE (fun) == FUNCTION_DECL)
> > {
> > if (builtin_valid_in_constant_expr_p (fun))
> > @@ -9167,7 +9171,8 @@ potential_constant_expression_1 (tree t, bool
> > want_rval, bool strict, bool now,
> > expression the address will be folded away, so look
> > through it now. */
> > if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fun)
> > - && !DECL_CONSTRUCTOR_P (fun))
> > + && !DECL_CONSTRUCTOR_P (fun)
> > + && !processing_template_decl)
>
> I don't see any rationale for this hunk?
Now that we call get_fns earlier, we can reach this code path with a
templated non-static memfn call, but the code that follows assumes
non-templated form.
I tried teaching it to handle the templated form too, but there's
apparently two different templated forms for non-static memfn calls,
one with a COMPONENT_REF callee and one with an ordinary BASELINK
callee (without a implicit object argument). In the former the implict
object argument is inside the COMPONENT_REF (and is a reference instead
of a pointer), and in the latter we don't even have an implicit object
argument to inspect.
FWIW I think which form we use depends on whether we know if the called
function is a member of the current instantiation, e.g
struct A { void f(); };
template<class T> struct B;
template<class T>
struct C : B<T> {
void g();
void h() {
A::f(); // templated form has BASELINK callee, no object arg
C::g(); // templated form has COMPONENT_REF callee
}
};
So it seemed best to punt on templated non-static memfn calls here for
now and treat that as a separate enhancement.
>
> > {
> > tree x = get_nth_callarg (t, 0);
> > if (is_this_parameter (x))
> > @@ -9182,16 +9187,11 @@ potential_constant_expression_1 (tree t, bool
> > want_rval, bool strict, bool now,
> > i = 1;
> > }
> > }
> > - else
> > - {
> > - if (!RECUR (fun, true))
> > - return false;
> > - fun = get_first_fn (fun);
> > - }
> > +
> > + fun = OVL_FIRST (fun);
> > /* Skip initial arguments to base constructors. */
> > if (DECL_BASE_CONSTRUCTOR_P (fun))
> > i = num_artificial_parms_for (fun);
> > - fun = DECL_ORIGIN (fun);
> > }
> > else if (fun)
> > {
> > diff --git a/gcc/testsuite/g++.dg/cpp0x/noexcept59.C
> > b/gcc/testsuite/g++.dg/cpp0x/noexcept59.C
> > index c752601ba09..1dc826d3111 100644
> > --- a/gcc/testsuite/g++.dg/cpp0x/noexcept59.C
> > +++ b/gcc/testsuite/g++.dg/cpp0x/noexcept59.C
> > @@ -3,7 +3,7 @@
> > template <class ...Ts> class A
> > {
> > - void e ();
> > + constexpr bool e () { return true; };
> > bool f (int() noexcept(this->e())); // { dg-error "this" }
> > bool g (int() noexcept(e())); // { dg-error "without object" }
> > };
> > diff --git a/gcc/testsuite/g++.dg/template/non-dependent25.C
> > b/gcc/testsuite/g++.dg/template/non-dependent25.C
> > new file mode 100644
> > index 00000000000..a2f9801e11f
> > --- /dev/null
> > +++ b/gcc/testsuite/g++.dg/template/non-dependent25.C
> > @@ -0,0 +1,14 @@
> > +// PR c++/109480
> > +
> > +template<class T>
> > +struct A {
> > + void f() {
> > + A<int> a;
> > + const bool b = a.g();
> > + }
> > +
> > +private:
> > + bool g() const;
> > +};
> > +
> > +template struct A<int>;
>
>
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 1/2] c++: potentiality of templated memfn call [PR109480]
2023-05-02 19:35 ` Patrick Palka
@ 2023-05-02 19:53 ` Patrick Palka
2023-05-03 19:55 ` Jason Merrill
0 siblings, 1 reply; 12+ messages in thread
From: Patrick Palka @ 2023-05-02 19:53 UTC (permalink / raw)
To: Patrick Palka; +Cc: Jason Merrill, gcc-patches
on Tue, 2 May 2023, Patrick Palka wrote:
> On Tue, 2 May 2023, Jason Merrill wrote:
>
> > On 5/1/23 15:59, Patrick Palka wrote:
> > > Here we're incorrectly deeming the templated call a.g() inside b's
> > > initializer as potentially constant, despite g being non-constexpr,
> > > which leads to us wastefully instantiating the initializer ahead of time
> > > and triggering a bug in access checking deferral (which will get fixed
> > > in the subsequent patch).
> > >
> > > This patch fixes this by calling get_fns earlier during potentiality
> > > checking so that we also handle the templated form of a member function
> > > call (whose overall callee is a COMPONENT_REF) when checking if the called
> > > function is constexpr etc.
> > >
> > > PR c++/109480
> > >
> > > gcc/cp/ChangeLog:
> > >
> > > * constexpr.cc (potential_constant_expression_1) <case CALL_EXPR>:
> > > Reorganize to call get_fns sooner. Remove dead store to 'fun'.
> > >
> > > gcc/testsuite/ChangeLog:
> > >
> > > * g++.dg/cpp0x/noexcept59.C: Make e() constexpr so that the
> > > expected "without object" diagnostic isn't replaced by a
> > > "call to non-constexpr function" diagnostic.
> > > * g++.dg/template/non-dependent25.C: New test.
> > > ---
> > > gcc/cp/constexpr.cc | 16 ++++++++--------
> > > gcc/testsuite/g++.dg/cpp0x/noexcept59.C | 2 +-
> > > gcc/testsuite/g++.dg/template/non-dependent25.C | 14 ++++++++++++++
> > > 3 files changed, 23 insertions(+), 9 deletions(-)
> > > create mode 100644 gcc/testsuite/g++.dg/template/non-dependent25.C
> > >
> > > diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
> > > index d1097764b10..29d872d0a5e 100644
> > > --- a/gcc/cp/constexpr.cc
> > > +++ b/gcc/cp/constexpr.cc
> > > @@ -9132,6 +9132,10 @@ potential_constant_expression_1 (tree t, bool
> > > want_rval, bool strict, bool now,
> > > if (fun && is_overloaded_fn (fun))
> > > {
> > > + if (!RECUR (fun, true))
> > > + return false;
> > > + fun = get_fns (fun);
> > > +
> > > if (TREE_CODE (fun) == FUNCTION_DECL)
> > > {
> > > if (builtin_valid_in_constant_expr_p (fun))
> > > @@ -9167,7 +9171,8 @@ potential_constant_expression_1 (tree t, bool
> > > want_rval, bool strict, bool now,
> > > expression the address will be folded away, so look
> > > through it now. */
> > > if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fun)
> > > - && !DECL_CONSTRUCTOR_P (fun))
> > > + && !DECL_CONSTRUCTOR_P (fun)
> > > + && !processing_template_decl)
> >
> > I don't see any rationale for this hunk?
>
> Now that we call get_fns earlier, we can reach this code path with a
> templated non-static memfn call, but the code that follows assumes
> non-templated form.
>
> I tried teaching it to handle the templated form too, but there's
> apparently two different templated forms for non-static memfn calls,
> one with a COMPONENT_REF callee and one with an ordinary BASELINK
> callee (without a implicit object argument). In the former the implict
> object argument is inside the COMPONENT_REF (and is a reference instead
> of a pointer), and in the latter we don't even have an implicit object
> argument to inspect.
>
> FWIW I think which form we use depends on whether we know if the called
> function is a member of the current instantiation, e.g
>
> struct A { void f(); };
>
> template<class T> struct B;
>
> template<class T>
> struct C : B<T> {
> void g();
>
> void h() {
> A::f(); // templated form has BASELINK callee, no object arg
> C::g(); // templated form has COMPONENT_REF callee
> }
> };
>
> So it seemed best to punt on templated non-static memfn calls here for
> now and treat that as a separate enhancement.
And I'm not even sure if the code path in question is necessary at all
anymore: disabling it outright doesn't cause any regressions in the testsuite.
It seems effectively equivalent to the body of the loop over the args a few
lines later:
for (; i < nargs; ++i)
{
tree x = get_nth_callarg (t, i);
/* In a template, reference arguments haven't been converted to
REFERENCE_TYPE and we might not even know if the parameter
is a reference, so accept lvalue constants too. */
bool rv = processing_template_decl ? any : rval;
/* Don't require an immediately constant value, as constexpr
substitution might not use the value of the argument. */
bool sub_now = false;
if (!potential_constant_expression_1 (x, rv, strict,
sub_now, fundef_p, flags,
jump_target))
return false;
}
>
> >
> > > {
> > > tree x = get_nth_callarg (t, 0);
> > > if (is_this_parameter (x))
> > > @@ -9182,16 +9187,11 @@ potential_constant_expression_1 (tree t, bool
> > > want_rval, bool strict, bool now,
> > > i = 1;
> > > }
> > > }
> > > - else
> > > - {
> > > - if (!RECUR (fun, true))
> > > - return false;
> > > - fun = get_first_fn (fun);
> > > - }
> > > +
> > > + fun = OVL_FIRST (fun);
> > > /* Skip initial arguments to base constructors. */
> > > if (DECL_BASE_CONSTRUCTOR_P (fun))
> > > i = num_artificial_parms_for (fun);
> > > - fun = DECL_ORIGIN (fun);
> > > }
> > > else if (fun)
> > > {
> > > diff --git a/gcc/testsuite/g++.dg/cpp0x/noexcept59.C
> > > b/gcc/testsuite/g++.dg/cpp0x/noexcept59.C
> > > index c752601ba09..1dc826d3111 100644
> > > --- a/gcc/testsuite/g++.dg/cpp0x/noexcept59.C
> > > +++ b/gcc/testsuite/g++.dg/cpp0x/noexcept59.C
> > > @@ -3,7 +3,7 @@
> > > template <class ...Ts> class A
> > > {
> > > - void e ();
> > > + constexpr bool e () { return true; };
> > > bool f (int() noexcept(this->e())); // { dg-error "this" }
> > > bool g (int() noexcept(e())); // { dg-error "without object" }
> > > };
> > > diff --git a/gcc/testsuite/g++.dg/template/non-dependent25.C
> > > b/gcc/testsuite/g++.dg/template/non-dependent25.C
> > > new file mode 100644
> > > index 00000000000..a2f9801e11f
> > > --- /dev/null
> > > +++ b/gcc/testsuite/g++.dg/template/non-dependent25.C
> > > @@ -0,0 +1,14 @@
> > > +// PR c++/109480
> > > +
> > > +template<class T>
> > > +struct A {
> > > + void f() {
> > > + A<int> a;
> > > + const bool b = a.g();
> > > + }
> > > +
> > > +private:
> > > + bool g() const;
> > > +};
> > > +
> > > +template struct A<int>;
> >
> >
>
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 1/2] c++: potentiality of templated memfn call [PR109480]
2023-05-02 19:53 ` Patrick Palka
@ 2023-05-03 19:55 ` Jason Merrill
2023-05-03 20:50 ` Patrick Palka
0 siblings, 1 reply; 12+ messages in thread
From: Jason Merrill @ 2023-05-03 19:55 UTC (permalink / raw)
To: Patrick Palka; +Cc: gcc-patches
On 5/2/23 15:53, Patrick Palka wrote:
> on Tue, 2 May 2023, Patrick Palka wrote:
>
>> On Tue, 2 May 2023, Jason Merrill wrote:
>>
>>> On 5/1/23 15:59, Patrick Palka wrote:
>>>> Here we're incorrectly deeming the templated call a.g() inside b's
>>>> initializer as potentially constant, despite g being non-constexpr,
>>>> which leads to us wastefully instantiating the initializer ahead of time
>>>> and triggering a bug in access checking deferral (which will get fixed
>>>> in the subsequent patch).
>>>>
>>>> This patch fixes this by calling get_fns earlier during potentiality
>>>> checking so that we also handle the templated form of a member function
>>>> call (whose overall callee is a COMPONENT_REF) when checking if the called
>>>> function is constexpr etc.
>>>>
>>>> PR c++/109480
>>>>
>>>> gcc/cp/ChangeLog:
>>>>
>>>> * constexpr.cc (potential_constant_expression_1) <case CALL_EXPR>:
>>>> Reorganize to call get_fns sooner. Remove dead store to 'fun'.
>>>>
>>>> gcc/testsuite/ChangeLog:
>>>>
>>>> * g++.dg/cpp0x/noexcept59.C: Make e() constexpr so that the
>>>> expected "without object" diagnostic isn't replaced by a
>>>> "call to non-constexpr function" diagnostic.
>>>> * g++.dg/template/non-dependent25.C: New test.
>>>> ---
>>>> gcc/cp/constexpr.cc | 16 ++++++++--------
>>>> gcc/testsuite/g++.dg/cpp0x/noexcept59.C | 2 +-
>>>> gcc/testsuite/g++.dg/template/non-dependent25.C | 14 ++++++++++++++
>>>> 3 files changed, 23 insertions(+), 9 deletions(-)
>>>> create mode 100644 gcc/testsuite/g++.dg/template/non-dependent25.C
>>>>
>>>> diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
>>>> index d1097764b10..29d872d0a5e 100644
>>>> --- a/gcc/cp/constexpr.cc
>>>> +++ b/gcc/cp/constexpr.cc
>>>> @@ -9132,6 +9132,10 @@ potential_constant_expression_1 (tree t, bool
>>>> want_rval, bool strict, bool now,
>>>> if (fun && is_overloaded_fn (fun))
>>>> {
>>>> + if (!RECUR (fun, true))
>>>> + return false;
>>>> + fun = get_fns (fun);
>>>> +
>>>> if (TREE_CODE (fun) == FUNCTION_DECL)
>>>> {
>>>> if (builtin_valid_in_constant_expr_p (fun))
>>>> @@ -9167,7 +9171,8 @@ potential_constant_expression_1 (tree t, bool
>>>> want_rval, bool strict, bool now,
>>>> expression the address will be folded away, so look
>>>> through it now. */
>>>> if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fun)
>>>> - && !DECL_CONSTRUCTOR_P (fun))
>>>> + && !DECL_CONSTRUCTOR_P (fun)
>>>> + && !processing_template_decl)
>>>
>>> I don't see any rationale for this hunk?
>>
>> Now that we call get_fns earlier, we can reach this code path with a
>> templated non-static memfn call, but the code that follows assumes
>> non-templated form.
>>
>> I tried teaching it to handle the templated form too, but there's
>> apparently two different templated forms for non-static memfn calls,
>> one with a COMPONENT_REF callee and one with an ordinary BASELINK
>> callee (without a implicit object argument). In the former the implict
>> object argument is inside the COMPONENT_REF (and is a reference instead
>> of a pointer), and in the latter we don't even have an implicit object
>> argument to inspect.
>>
>> FWIW I think which form we use depends on whether we know if the called
>> function is a member of the current instantiation, e.g
>>
>> struct A { void f(); };
>>
>> template<class T> struct B;
>>
>> template<class T>
>> struct C : B<T> {
>> void g();
>>
>> void h() {
>> A::f(); // templated form has BASELINK callee, no object arg
>> C::g(); // templated form has COMPONENT_REF callee
>> }
>> };
>>
>> So it seemed best to punt on templated non-static memfn calls here for
>> now and treat that as a separate enhancement.
>
> And I'm not even sure if the code path in question is necessary at all
> anymore: disabling it outright doesn't cause any regressions in the testsuite.
> It seems effectively equivalent to the body of the loop over the args a few
> lines later:
If removing that hunk doesn't regress anything, let's do it. Probably
that should have happened in r13-55-ge9d2adc17d0dbe
> for (; i < nargs; ++i)
> {
> tree x = get_nth_callarg (t, i);
> /* In a template, reference arguments haven't been converted to
> REFERENCE_TYPE and we might not even know if the parameter
> is a reference, so accept lvalue constants too. */
> bool rv = processing_template_decl ? any : rval;
> /* Don't require an immediately constant value, as constexpr
> substitution might not use the value of the argument. */
> bool sub_now = false;
> if (!potential_constant_expression_1 (x, rv, strict,
> sub_now, fundef_p, flags,
> jump_target))
> return false;
> }
>
>>
>>>
>>>> {
>>>> tree x = get_nth_callarg (t, 0);
>>>> if (is_this_parameter (x))
>>>> @@ -9182,16 +9187,11 @@ potential_constant_expression_1 (tree t, bool
>>>> want_rval, bool strict, bool now,
>>>> i = 1;
>>>> }
>>>> }
>>>> - else
>>>> - {
>>>> - if (!RECUR (fun, true))
>>>> - return false;
>>>> - fun = get_first_fn (fun);
>>>> - }
>>>> +
>>>> + fun = OVL_FIRST (fun);
>>>> /* Skip initial arguments to base constructors. */
>>>> if (DECL_BASE_CONSTRUCTOR_P (fun))
>>>> i = num_artificial_parms_for (fun);
>>>> - fun = DECL_ORIGIN (fun);
>>>> }
>>>> else if (fun)
>>>> {
>>>> diff --git a/gcc/testsuite/g++.dg/cpp0x/noexcept59.C
>>>> b/gcc/testsuite/g++.dg/cpp0x/noexcept59.C
>>>> index c752601ba09..1dc826d3111 100644
>>>> --- a/gcc/testsuite/g++.dg/cpp0x/noexcept59.C
>>>> +++ b/gcc/testsuite/g++.dg/cpp0x/noexcept59.C
>>>> @@ -3,7 +3,7 @@
>>>> template <class ...Ts> class A
>>>> {
>>>> - void e ();
>>>> + constexpr bool e () { return true; };
>>>> bool f (int() noexcept(this->e())); // { dg-error "this" }
>>>> bool g (int() noexcept(e())); // { dg-error "without object" }
>>>> };
>>>> diff --git a/gcc/testsuite/g++.dg/template/non-dependent25.C
>>>> b/gcc/testsuite/g++.dg/template/non-dependent25.C
>>>> new file mode 100644
>>>> index 00000000000..a2f9801e11f
>>>> --- /dev/null
>>>> +++ b/gcc/testsuite/g++.dg/template/non-dependent25.C
>>>> @@ -0,0 +1,14 @@
>>>> +// PR c++/109480
>>>> +
>>>> +template<class T>
>>>> +struct A {
>>>> + void f() {
>>>> + A<int> a;
>>>> + const bool b = a.g();
>>>> + }
>>>> +
>>>> +private:
>>>> + bool g() const;
>>>> +};
>>>> +
>>>> +template struct A<int>;
>>>
>>>
>>
>
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 1/2] c++: potentiality of templated memfn call [PR109480]
2023-05-03 19:55 ` Jason Merrill
@ 2023-05-03 20:50 ` Patrick Palka
2023-05-04 13:56 ` Jason Merrill
2023-05-12 16:12 ` Martin Jambor
0 siblings, 2 replies; 12+ messages in thread
From: Patrick Palka @ 2023-05-03 20:50 UTC (permalink / raw)
To: Jason Merrill; +Cc: Patrick Palka, gcc-patches
On Wed, 3 May 2023, Jason Merrill wrote:
> On 5/2/23 15:53, Patrick Palka wrote:
> > on Tue, 2 May 2023, Patrick Palka wrote:
> >
> > > On Tue, 2 May 2023, Jason Merrill wrote:
> > >
> > > > On 5/1/23 15:59, Patrick Palka wrote:
> > > > > Here we're incorrectly deeming the templated call a.g() inside b's
> > > > > initializer as potentially constant, despite g being non-constexpr,
> > > > > which leads to us wastefully instantiating the initializer ahead of
> > > > > time
> > > > > and triggering a bug in access checking deferral (which will get fixed
> > > > > in the subsequent patch).
> > > > >
> > > > > This patch fixes this by calling get_fns earlier during potentiality
> > > > > checking so that we also handle the templated form of a member
> > > > > function
> > > > > call (whose overall callee is a COMPONENT_REF) when checking if the
> > > > > called
> > > > > function is constexpr etc.
> > > > >
> > > > > PR c++/109480
> > > > >
> > > > > gcc/cp/ChangeLog:
> > > > >
> > > > > * constexpr.cc (potential_constant_expression_1) <case
> > > > > CALL_EXPR>:
> > > > > Reorganize to call get_fns sooner. Remove dead store to
> > > > > 'fun'.
> > > > >
> > > > > gcc/testsuite/ChangeLog:
> > > > >
> > > > > * g++.dg/cpp0x/noexcept59.C: Make e() constexpr so that the
> > > > > expected "without object" diagnostic isn't replaced by a
> > > > > "call to non-constexpr function" diagnostic.
> > > > > * g++.dg/template/non-dependent25.C: New test.
> > > > > ---
> > > > > gcc/cp/constexpr.cc | 16
> > > > > ++++++++--------
> > > > > gcc/testsuite/g++.dg/cpp0x/noexcept59.C | 2 +-
> > > > > gcc/testsuite/g++.dg/template/non-dependent25.C | 14 ++++++++++++++
> > > > > 3 files changed, 23 insertions(+), 9 deletions(-)
> > > > > create mode 100644 gcc/testsuite/g++.dg/template/non-dependent25.C
> > > > >
> > > > > diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
> > > > > index d1097764b10..29d872d0a5e 100644
> > > > > --- a/gcc/cp/constexpr.cc
> > > > > +++ b/gcc/cp/constexpr.cc
> > > > > @@ -9132,6 +9132,10 @@ potential_constant_expression_1 (tree t, bool
> > > > > want_rval, bool strict, bool now,
> > > > > if (fun && is_overloaded_fn (fun))
> > > > > {
> > > > > + if (!RECUR (fun, true))
> > > > > + return false;
> > > > > + fun = get_fns (fun);
> > > > > +
> > > > > if (TREE_CODE (fun) == FUNCTION_DECL)
> > > > > {
> > > > > if (builtin_valid_in_constant_expr_p (fun))
> > > > > @@ -9167,7 +9171,8 @@ potential_constant_expression_1 (tree t, bool
> > > > > want_rval, bool strict, bool now,
> > > > > expression the address will be folded away, so look
> > > > > through it now. */
> > > > > if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fun)
> > > > > - && !DECL_CONSTRUCTOR_P (fun))
> > > > > + && !DECL_CONSTRUCTOR_P (fun)
> > > > > + && !processing_template_decl)
> > > >
> > > > I don't see any rationale for this hunk?
> > >
> > > Now that we call get_fns earlier, we can reach this code path with a
> > > templated non-static memfn call, but the code that follows assumes
> > > non-templated form.
> > >
> > > I tried teaching it to handle the templated form too, but there's
> > > apparently two different templated forms for non-static memfn calls,
> > > one with a COMPONENT_REF callee and one with an ordinary BASELINK
> > > callee (without a implicit object argument). In the former the implict
> > > object argument is inside the COMPONENT_REF (and is a reference instead
> > > of a pointer), and in the latter we don't even have an implicit object
> > > argument to inspect.
> > >
> > > FWIW I think which form we use depends on whether we know if the called
> > > function is a member of the current instantiation, e.g
> > >
> > > struct A { void f(); };
> > >
> > > template<class T> struct B;
> > >
> > > template<class T>
> > > struct C : B<T> {
> > > void g();
> > >
> > > void h() {
> > > A::f(); // templated form has BASELINK callee, no object arg
> > > C::g(); // templated form has COMPONENT_REF callee
> > > }
> > > };
> > >
> > > So it seemed best to punt on templated non-static memfn calls here for
> > > now and treat that as a separate enhancement.
> >
> > And I'm not even sure if the code path in question is necessary at all
> > anymore: disabling it outright doesn't cause any regressions in the
> > testsuite.
> > It seems effectively equivalent to the body of the loop over the args a few
> > lines later:
>
> If removing that hunk doesn't regress anything, let's do it. Probably that
> should have happened in r13-55-ge9d2adc17d0dbe
Sounds good, here's the combined patch which I'm bootstrapping for good
measure. Does it look OK for trunk if bootstrap+regtest succeeds?
-- >8 --
Subject: [PATCH] c++: potentiality of templated memfn call [PR109480]
Here we're incorrectly deeming the templated call a.g() inside b's
initializer as potentially constant, despite g being non-constexpr,
which leads to us wastefully instantiating the initializer ahead of time,
which incidentally tiggers a bug in access checking deferral (to be
fixed by the subsequent patch).
This patch fixes this by calling get_fns earlier during CALL_EXPR
potentiality checking so that we're able to extract a FUNCTION_DECL out
of a templated member function call (whose overall is typically a
COMPONENT_REF) and to the usual checking if the called function is
constexpr etc.
In passing, I noticed potential_constant_expression_1's special handling
of the object argument of a non-static member function call is effectively
the same as the generic argument handling a few lines later. So this
patch just gets rid of this special handling; otherwise we'd have to adapt
it to handle templated versions of such calls.
PR c++/109480
gcc/cp/ChangeLog:
* constexpr.cc (potential_constant_expression_1) <case CALL_EXPR>:
Reorganize to call get_fns sooner. Remove special handling of
the object argument of a non-static member function call. Remove
dead store to 'fun'.
gcc/testsuite/ChangeLog:
* g++.dg/cpp0x/noexcept59.C: Make e() constexpr so that the
expected "without object" diagnostic isn't replaced by a
"call to non-constexpr function" diagnostic.
* g++.dg/template/non-dependent25.C: New test.
---
gcc/cp/constexpr.cc | 32 ++++---------------
gcc/testsuite/g++.dg/cpp0x/noexcept59.C | 2 +-
.../g++.dg/template/non-dependent25.C | 14 ++++++++
3 files changed, 21 insertions(+), 27 deletions(-)
create mode 100644 gcc/testsuite/g++.dg/template/non-dependent25.C
diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index d1097764b10..075339f7f62 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -9132,6 +9132,10 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
if (fun && is_overloaded_fn (fun))
{
+ if (!RECUR (fun, true))
+ return false;
+ fun = get_fns (fun);
+
if (TREE_CODE (fun) == FUNCTION_DECL)
{
if (builtin_valid_in_constant_expr_p (fun))
@@ -9162,36 +9166,12 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
explain_invalid_constexpr_fn (fun);
return false;
}
- /* A call to a non-static member function takes the address
- of the object as the first argument. But in a constant
- expression the address will be folded away, so look
- through it now. */
- if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fun)
- && !DECL_CONSTRUCTOR_P (fun))
- {
- tree x = get_nth_callarg (t, 0);
- if (is_this_parameter (x))
- return true;
- /* Don't require an immediately constant value, as
- constexpr substitution might not use the value. */
- bool sub_now = false;
- if (!potential_constant_expression_1 (x, rval, strict,
- sub_now, fundef_p,
- flags, jump_target))
- return false;
- i = 1;
- }
- }
- else
- {
- if (!RECUR (fun, true))
- return false;
- fun = get_first_fn (fun);
}
+
+ fun = OVL_FIRST (fun);
/* Skip initial arguments to base constructors. */
if (DECL_BASE_CONSTRUCTOR_P (fun))
i = num_artificial_parms_for (fun);
- fun = DECL_ORIGIN (fun);
}
else if (fun)
{
diff --git a/gcc/testsuite/g++.dg/cpp0x/noexcept59.C b/gcc/testsuite/g++.dg/cpp0x/noexcept59.C
index c752601ba09..1dc826d3111 100644
--- a/gcc/testsuite/g++.dg/cpp0x/noexcept59.C
+++ b/gcc/testsuite/g++.dg/cpp0x/noexcept59.C
@@ -3,7 +3,7 @@
template <class ...Ts> class A
{
- void e ();
+ constexpr bool e () { return true; };
bool f (int() noexcept(this->e())); // { dg-error "this" }
bool g (int() noexcept(e())); // { dg-error "without object" }
};
diff --git a/gcc/testsuite/g++.dg/template/non-dependent25.C b/gcc/testsuite/g++.dg/template/non-dependent25.C
new file mode 100644
index 00000000000..c00e44532b0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/non-dependent25.C
@@ -0,0 +1,14 @@
+// PR c++/109480
+
+template<class T>
+struct A {
+ void f() {
+ A<int> a;
+ const bool b = a.g(); // { dg-bogus "private" }
+ }
+
+private:
+ bool g() const;
+};
+
+template struct A<int>;
--
2.40.1.476.g69c786637d
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 1/2] c++: potentiality of templated memfn call [PR109480]
2023-05-03 20:50 ` Patrick Palka
@ 2023-05-04 13:56 ` Jason Merrill
2023-05-12 16:12 ` Martin Jambor
1 sibling, 0 replies; 12+ messages in thread
From: Jason Merrill @ 2023-05-04 13:56 UTC (permalink / raw)
To: Patrick Palka; +Cc: gcc-patches
On 5/3/23 16:50, Patrick Palka wrote:
> On Wed, 3 May 2023, Jason Merrill wrote:
>
>> On 5/2/23 15:53, Patrick Palka wrote:
>>> on Tue, 2 May 2023, Patrick Palka wrote:
>>>
>>>> On Tue, 2 May 2023, Jason Merrill wrote:
>>>>
>>>>> On 5/1/23 15:59, Patrick Palka wrote:
>>>>>> Here we're incorrectly deeming the templated call a.g() inside b's
>>>>>> initializer as potentially constant, despite g being non-constexpr,
>>>>>> which leads to us wastefully instantiating the initializer ahead of
>>>>>> time
>>>>>> and triggering a bug in access checking deferral (which will get fixed
>>>>>> in the subsequent patch).
>>>>>>
>>>>>> This patch fixes this by calling get_fns earlier during potentiality
>>>>>> checking so that we also handle the templated form of a member
>>>>>> function
>>>>>> call (whose overall callee is a COMPONENT_REF) when checking if the
>>>>>> called
>>>>>> function is constexpr etc.
>>>>>>
>>>>>> PR c++/109480
>>>>>>
>>>>>> gcc/cp/ChangeLog:
>>>>>>
>>>>>> * constexpr.cc (potential_constant_expression_1) <case
>>>>>> CALL_EXPR>:
>>>>>> Reorganize to call get_fns sooner. Remove dead store to
>>>>>> 'fun'.
>>>>>>
>>>>>> gcc/testsuite/ChangeLog:
>>>>>>
>>>>>> * g++.dg/cpp0x/noexcept59.C: Make e() constexpr so that the
>>>>>> expected "without object" diagnostic isn't replaced by a
>>>>>> "call to non-constexpr function" diagnostic.
>>>>>> * g++.dg/template/non-dependent25.C: New test.
>>>>>> ---
>>>>>> gcc/cp/constexpr.cc | 16
>>>>>> ++++++++--------
>>>>>> gcc/testsuite/g++.dg/cpp0x/noexcept59.C | 2 +-
>>>>>> gcc/testsuite/g++.dg/template/non-dependent25.C | 14 ++++++++++++++
>>>>>> 3 files changed, 23 insertions(+), 9 deletions(-)
>>>>>> create mode 100644 gcc/testsuite/g++.dg/template/non-dependent25.C
>>>>>>
>>>>>> diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
>>>>>> index d1097764b10..29d872d0a5e 100644
>>>>>> --- a/gcc/cp/constexpr.cc
>>>>>> +++ b/gcc/cp/constexpr.cc
>>>>>> @@ -9132,6 +9132,10 @@ potential_constant_expression_1 (tree t, bool
>>>>>> want_rval, bool strict, bool now,
>>>>>> if (fun && is_overloaded_fn (fun))
>>>>>> {
>>>>>> + if (!RECUR (fun, true))
>>>>>> + return false;
>>>>>> + fun = get_fns (fun);
>>>>>> +
>>>>>> if (TREE_CODE (fun) == FUNCTION_DECL)
>>>>>> {
>>>>>> if (builtin_valid_in_constant_expr_p (fun))
>>>>>> @@ -9167,7 +9171,8 @@ potential_constant_expression_1 (tree t, bool
>>>>>> want_rval, bool strict, bool now,
>>>>>> expression the address will be folded away, so look
>>>>>> through it now. */
>>>>>> if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fun)
>>>>>> - && !DECL_CONSTRUCTOR_P (fun))
>>>>>> + && !DECL_CONSTRUCTOR_P (fun)
>>>>>> + && !processing_template_decl)
>>>>>
>>>>> I don't see any rationale for this hunk?
>>>>
>>>> Now that we call get_fns earlier, we can reach this code path with a
>>>> templated non-static memfn call, but the code that follows assumes
>>>> non-templated form.
>>>>
>>>> I tried teaching it to handle the templated form too, but there's
>>>> apparently two different templated forms for non-static memfn calls,
>>>> one with a COMPONENT_REF callee and one with an ordinary BASELINK
>>>> callee (without a implicit object argument). In the former the implict
>>>> object argument is inside the COMPONENT_REF (and is a reference instead
>>>> of a pointer), and in the latter we don't even have an implicit object
>>>> argument to inspect.
>>>>
>>>> FWIW I think which form we use depends on whether we know if the called
>>>> function is a member of the current instantiation, e.g
>>>>
>>>> struct A { void f(); };
>>>>
>>>> template<class T> struct B;
>>>>
>>>> template<class T>
>>>> struct C : B<T> {
>>>> void g();
>>>>
>>>> void h() {
>>>> A::f(); // templated form has BASELINK callee, no object arg
>>>> C::g(); // templated form has COMPONENT_REF callee
>>>> }
>>>> };
>>>>
>>>> So it seemed best to punt on templated non-static memfn calls here for
>>>> now and treat that as a separate enhancement.
>>>
>>> And I'm not even sure if the code path in question is necessary at all
>>> anymore: disabling it outright doesn't cause any regressions in the
>>> testsuite.
>>> It seems effectively equivalent to the body of the loop over the args a few
>>> lines later:
>>
>> If removing that hunk doesn't regress anything, let's do it. Probably that
>> should have happened in r13-55-ge9d2adc17d0dbe
>
> Sounds good, here's the combined patch which I'm bootstrapping for good
> measure. Does it look OK for trunk if bootstrap+regtest succeeds?
OK.
> -- >8 --
>
> Subject: [PATCH] c++: potentiality of templated memfn call [PR109480]
>
> Here we're incorrectly deeming the templated call a.g() inside b's
> initializer as potentially constant, despite g being non-constexpr,
> which leads to us wastefully instantiating the initializer ahead of time,
> which incidentally tiggers a bug in access checking deferral (to be
> fixed by the subsequent patch).
>
> This patch fixes this by calling get_fns earlier during CALL_EXPR
> potentiality checking so that we're able to extract a FUNCTION_DECL out
> of a templated member function call (whose overall is typically a
> COMPONENT_REF) and to the usual checking if the called function is
> constexpr etc.
>
> In passing, I noticed potential_constant_expression_1's special handling
> of the object argument of a non-static member function call is effectively
> the same as the generic argument handling a few lines later. So this
> patch just gets rid of this special handling; otherwise we'd have to adapt
> it to handle templated versions of such calls.
>
> PR c++/109480
>
> gcc/cp/ChangeLog:
>
> * constexpr.cc (potential_constant_expression_1) <case CALL_EXPR>:
> Reorganize to call get_fns sooner. Remove special handling of
> the object argument of a non-static member function call. Remove
> dead store to 'fun'.
>
> gcc/testsuite/ChangeLog:
>
> * g++.dg/cpp0x/noexcept59.C: Make e() constexpr so that the
> expected "without object" diagnostic isn't replaced by a
> "call to non-constexpr function" diagnostic.
> * g++.dg/template/non-dependent25.C: New test.
> ---
> gcc/cp/constexpr.cc | 32 ++++---------------
> gcc/testsuite/g++.dg/cpp0x/noexcept59.C | 2 +-
> .../g++.dg/template/non-dependent25.C | 14 ++++++++
> 3 files changed, 21 insertions(+), 27 deletions(-)
> create mode 100644 gcc/testsuite/g++.dg/template/non-dependent25.C
>
> diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
> index d1097764b10..075339f7f62 100644
> --- a/gcc/cp/constexpr.cc
> +++ b/gcc/cp/constexpr.cc
> @@ -9132,6 +9132,10 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
>
> if (fun && is_overloaded_fn (fun))
> {
> + if (!RECUR (fun, true))
> + return false;
> + fun = get_fns (fun);
> +
> if (TREE_CODE (fun) == FUNCTION_DECL)
> {
> if (builtin_valid_in_constant_expr_p (fun))
> @@ -9162,36 +9166,12 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
> explain_invalid_constexpr_fn (fun);
> return false;
> }
> - /* A call to a non-static member function takes the address
> - of the object as the first argument. But in a constant
> - expression the address will be folded away, so look
> - through it now. */
> - if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fun)
> - && !DECL_CONSTRUCTOR_P (fun))
> - {
> - tree x = get_nth_callarg (t, 0);
> - if (is_this_parameter (x))
> - return true;
> - /* Don't require an immediately constant value, as
> - constexpr substitution might not use the value. */
> - bool sub_now = false;
> - if (!potential_constant_expression_1 (x, rval, strict,
> - sub_now, fundef_p,
> - flags, jump_target))
> - return false;
> - i = 1;
> - }
> - }
> - else
> - {
> - if (!RECUR (fun, true))
> - return false;
> - fun = get_first_fn (fun);
> }
> +
> + fun = OVL_FIRST (fun);
> /* Skip initial arguments to base constructors. */
> if (DECL_BASE_CONSTRUCTOR_P (fun))
> i = num_artificial_parms_for (fun);
> - fun = DECL_ORIGIN (fun);
> }
> else if (fun)
> {
> diff --git a/gcc/testsuite/g++.dg/cpp0x/noexcept59.C b/gcc/testsuite/g++.dg/cpp0x/noexcept59.C
> index c752601ba09..1dc826d3111 100644
> --- a/gcc/testsuite/g++.dg/cpp0x/noexcept59.C
> +++ b/gcc/testsuite/g++.dg/cpp0x/noexcept59.C
> @@ -3,7 +3,7 @@
>
> template <class ...Ts> class A
> {
> - void e ();
> + constexpr bool e () { return true; };
> bool f (int() noexcept(this->e())); // { dg-error "this" }
> bool g (int() noexcept(e())); // { dg-error "without object" }
> };
> diff --git a/gcc/testsuite/g++.dg/template/non-dependent25.C b/gcc/testsuite/g++.dg/template/non-dependent25.C
> new file mode 100644
> index 00000000000..c00e44532b0
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/template/non-dependent25.C
> @@ -0,0 +1,14 @@
> +// PR c++/109480
> +
> +template<class T>
> +struct A {
> + void f() {
> + A<int> a;
> + const bool b = a.g(); // { dg-bogus "private" }
> + }
> +
> +private:
> + bool g() const;
> +};
> +
> +template struct A<int>;
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 1/2] c++: potentiality of templated memfn call [PR109480]
2023-05-03 20:50 ` Patrick Palka
2023-05-04 13:56 ` Jason Merrill
@ 2023-05-12 16:12 ` Martin Jambor
2023-05-12 17:02 ` Patrick Palka
1 sibling, 1 reply; 12+ messages in thread
From: Martin Jambor @ 2023-05-12 16:12 UTC (permalink / raw)
To: Patrick Palka; +Cc: gcc-patches, Jason Merrill
Hello Patrick,
On Wed, May 03 2023, Patrick Palka via Gcc-patches wrote:
>
[...]
>
> Subject: [PATCH] c++: potentiality of templated memfn call [PR109480]
>
> Here we're incorrectly deeming the templated call a.g() inside b's
> initializer as potentially constant, despite g being non-constexpr,
> which leads to us wastefully instantiating the initializer ahead of time,
> which incidentally tiggers a bug in access checking deferral (to be
> fixed by the subsequent patch).
>
> This patch fixes this by calling get_fns earlier during CALL_EXPR
> potentiality checking so that we're able to extract a FUNCTION_DECL out
> of a templated member function call (whose overall is typically a
> COMPONENT_REF) and to the usual checking if the called function is
> constexpr etc.
>
> In passing, I noticed potential_constant_expression_1's special handling
> of the object argument of a non-static member function call is effectively
> the same as the generic argument handling a few lines later. So this
> patch just gets rid of this special handling; otherwise we'd have to adapt
> it to handle templated versions of such calls.
>
> PR c++/109480
>
> gcc/cp/ChangeLog:
>
> * constexpr.cc (potential_constant_expression_1) <case CALL_EXPR>:
> Reorganize to call get_fns sooner. Remove special handling of
> the object argument of a non-static member function call. Remove
> dead store to 'fun'.
>
This patch makes g++ no longer accept the following, complaining that
get_subsys is non-constexpr (with just -std=c++17 -S), which is of
course auto-reduced from a much larger source file from Ceph:
----------------------------------- 8< -----------------------------------
struct {
void get_subsys();
} PriorSet_dpp;
struct PriorSet {
template <typename> PriorSet();
};
template <typename> PriorSet::PriorSet() {
[](auto cctX) { cctX.template should_gather<PriorSet_dpp.get_subsys()>; };
}
----------------------------------- 8< -----------------------------------
I assume that is intentional and am actually somewhat surprised it was
accepted before, but can you please confirm?
Thanks,
Martin
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 1/2] c++: potentiality of templated memfn call [PR109480]
2023-05-12 16:12 ` Martin Jambor
@ 2023-05-12 17:02 ` Patrick Palka
2023-05-12 17:13 ` Jason Merrill
0 siblings, 1 reply; 12+ messages in thread
From: Patrick Palka @ 2023-05-12 17:02 UTC (permalink / raw)
To: Martin Jambor; +Cc: gcc-patches, Jason Merrill
Hi Martin,
On Fri, May 12, 2023 at 12:13 PM Martin Jambor <mjambor@suse.cz> wrote:
>
> Hello Patrick,
>
> On Wed, May 03 2023, Patrick Palka via Gcc-patches wrote:
> >
> [...]
> >
> > Subject: [PATCH] c++: potentiality of templated memfn call [PR109480]
> >
> > Here we're incorrectly deeming the templated call a.g() inside b's
> > initializer as potentially constant, despite g being non-constexpr,
> > which leads to us wastefully instantiating the initializer ahead of time,
> > which incidentally tiggers a bug in access checking deferral (to be
> > fixed by the subsequent patch).
> >
> > This patch fixes this by calling get_fns earlier during CALL_EXPR
> > potentiality checking so that we're able to extract a FUNCTION_DECL out
> > of a templated member function call (whose overall is typically a
> > COMPONENT_REF) and to the usual checking if the called function is
> > constexpr etc.
> >
> > In passing, I noticed potential_constant_expression_1's special handling
> > of the object argument of a non-static member function call is effectively
> > the same as the generic argument handling a few lines later. So this
> > patch just gets rid of this special handling; otherwise we'd have to adapt
> > it to handle templated versions of such calls.
> >
> > PR c++/109480
> >
> > gcc/cp/ChangeLog:
> >
> > * constexpr.cc (potential_constant_expression_1) <case CALL_EXPR>:
> > Reorganize to call get_fns sooner. Remove special handling of
> > the object argument of a non-static member function call. Remove
> > dead store to 'fun'.
> >
>
> This patch makes g++ no longer accept the following, complaining that
> get_subsys is non-constexpr (with just -std=c++17 -S), which is of
> course auto-reduced from a much larger source file from Ceph:
>
> ----------------------------------- 8< -----------------------------------
> struct {
> void get_subsys();
> } PriorSet_dpp;
> struct PriorSet {
> template <typename> PriorSet();
> };
> template <typename> PriorSet::PriorSet() {
> [](auto cctX) { cctX.template should_gather<PriorSet_dpp.get_subsys()>; };
> }
> ----------------------------------- 8< -----------------------------------
>
> I assume that is intentional and am actually somewhat surprised it was
> accepted before, but can you please confirm?
Yes, this seems correct/intentional to me-- no instantiation of the
template would be valid because it's trying to use a non-constant
expression (which we now correctly identify as such) as a template
argument, so this snippet is IFNDR.
I don't think we have testsuite coverage for this QoI diagnostic, I'll add one.
>
> Thanks,
>
> Martin
>
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 1/2] c++: potentiality of templated memfn call [PR109480]
2023-05-12 17:02 ` Patrick Palka
@ 2023-05-12 17:13 ` Jason Merrill
0 siblings, 0 replies; 12+ messages in thread
From: Jason Merrill @ 2023-05-12 17:13 UTC (permalink / raw)
To: Patrick Palka, Martin Jambor; +Cc: gcc-patches
On 5/12/23 13:02, Patrick Palka wrote:
> Hi Martin,
>
> On Fri, May 12, 2023 at 12:13 PM Martin Jambor <mjambor@suse.cz> wrote:
>>
>> Hello Patrick,
>>
>> On Wed, May 03 2023, Patrick Palka via Gcc-patches wrote:
>>>
>> [...]
>>>
>>> Subject: [PATCH] c++: potentiality of templated memfn call [PR109480]
>>>
>>> Here we're incorrectly deeming the templated call a.g() inside b's
>>> initializer as potentially constant, despite g being non-constexpr,
>>> which leads to us wastefully instantiating the initializer ahead of time,
>>> which incidentally tiggers a bug in access checking deferral (to be
>>> fixed by the subsequent patch).
>>>
>>> This patch fixes this by calling get_fns earlier during CALL_EXPR
>>> potentiality checking so that we're able to extract a FUNCTION_DECL out
>>> of a templated member function call (whose overall is typically a
>>> COMPONENT_REF) and to the usual checking if the called function is
>>> constexpr etc.
>>>
>>> In passing, I noticed potential_constant_expression_1's special handling
>>> of the object argument of a non-static member function call is effectively
>>> the same as the generic argument handling a few lines later. So this
>>> patch just gets rid of this special handling; otherwise we'd have to adapt
>>> it to handle templated versions of such calls.
>>>
>>> PR c++/109480
>>>
>>> gcc/cp/ChangeLog:
>>>
>>> * constexpr.cc (potential_constant_expression_1) <case CALL_EXPR>:
>>> Reorganize to call get_fns sooner. Remove special handling of
>>> the object argument of a non-static member function call. Remove
>>> dead store to 'fun'.
>>>
>>
>> This patch makes g++ no longer accept the following, complaining that
>> get_subsys is non-constexpr (with just -std=c++17 -S), which is of
>> course auto-reduced from a much larger source file from Ceph:
>>
>> ----------------------------------- 8< -----------------------------------
>> struct {
>> void get_subsys();
>> } PriorSet_dpp;
>> struct PriorSet {
>> template <typename> PriorSet();
>> };
>> template <typename> PriorSet::PriorSet() {
>> [](auto cctX) { cctX.template should_gather<PriorSet_dpp.get_subsys()>; };
>> }
>> ----------------------------------- 8< -----------------------------------
>>
>> I assume that is intentional and am actually somewhat surprised it was
>> accepted before, but can you please confirm?
>
> Yes, this seems correct/intentional to me-- no instantiation of the
> template would be valid because it's trying to use a non-constant
> expression (which we now correctly identify as such) as a template
> argument, so this snippet is IFNDR.
>
> I don't think we have testsuite coverage for this QoI diagnostic, I'll add one.
Incidentally, I wonder about trying to make IFNDR diags in general
permerrors or default-error pedwarns, but that doesn't need to happen now.
Jason
^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2023-05-12 17:13 UTC | newest]
Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-05-01 19:59 [PATCH 1/2] c++: potentiality of templated memfn call [PR109480] Patrick Palka
2023-05-01 19:59 ` [PATCH 2/2] c++: non-dep init folding and access checking [PR109480] Patrick Palka
2023-05-02 18:35 ` Jason Merrill
2023-05-02 18:34 ` [PATCH 1/2] c++: potentiality of templated memfn call [PR109480] Jason Merrill
2023-05-02 19:35 ` Patrick Palka
2023-05-02 19:53 ` Patrick Palka
2023-05-03 19:55 ` Jason Merrill
2023-05-03 20:50 ` Patrick Palka
2023-05-04 13:56 ` Jason Merrill
2023-05-12 16:12 ` Martin Jambor
2023-05-12 17:02 ` Patrick Palka
2023-05-12 17:13 ` Jason Merrill
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).