On Mon, 18 Sep 2023, Patrick Palka wrote: > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for > trunk? > > -- >8 -- > > Here convert_to_void always completes the type of an indirection or > id-expression, but according to [expr.context] an lvalue-to-rvalue > conversion is applied to a discarded-value expression only if "the > expression is a glvalue of volatile-qualified type". This patch > restricts convert_to_void's type completion to match. > > PR c++/111419 > > gcc/cp/ChangeLog: > > * cvt.cc (convert_to_void) <case INDIRECT_REF>: Only call > complete_type if the type is volatile. > <case VAR_DECL>: Only call complete_type if the type is volatile. > Likewise. > > gcc/testsuite/ChangeLog: > > * g++.dg/cpp2a/concepts-requires36.C: New test. > * g++.dg/expr/discarded1.C: New test. > * g++.dg/expr/discarded1a.C: New test. > --- > gcc/cp/cvt.cc | 10 ++++++---- > .../g++.dg/cpp2a/concepts-requires36.C | 16 ++++++++++++++++ > gcc/testsuite/g++.dg/expr/discarded1.C | 15 +++++++++++++++ > gcc/testsuite/g++.dg/expr/discarded1a.C | 17 +++++++++++++++++ > 4 files changed, 54 insertions(+), 4 deletions(-) > create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-requires36.C > create mode 100644 gcc/testsuite/g++.dg/expr/discarded1.C > create mode 100644 gcc/testsuite/g++.dg/expr/discarded1a.C > > diff --git a/gcc/cp/cvt.cc b/gcc/cp/cvt.cc > index c6b52f07050..4424670356c 100644 > --- a/gcc/cp/cvt.cc > +++ b/gcc/cp/cvt.cc > @@ -1250,9 +1250,10 @@ convert_to_void (tree expr, impl_conv_void implicit, > tsubst_flags_t complain) > case INDIRECT_REF: > { > tree type = TREE_TYPE (expr); > - int is_reference = TYPE_REF_P (TREE_TYPE (TREE_OPERAND (expr, 0)));
Oops, this removal of is_reference should happen in the follow-up patch instead, consider that fixed. > int is_volatile = TYPE_VOLATILE (type); > - int is_complete = COMPLETE_TYPE_P (complete_type (type)); > + if (is_volatile) > + complete_type (type); > + int is_complete = COMPLETE_TYPE_P (type); > > /* Can't load the value if we don't know the type. */ > if (is_volatile && !is_complete) > @@ -1412,9 +1413,10 @@ convert_to_void (tree expr, impl_conv_void implicit, > tsubst_flags_t complain) > { > /* External variables might be incomplete. */ > tree type = TREE_TYPE (expr); > - int is_complete = COMPLETE_TYPE_P (complete_type (type)); > > - if (TYPE_VOLATILE (type) && !is_complete && (complain & tf_warning)) > + if (TYPE_VOLATILE (type) > + && !COMPLETE_TYPE_P (complete_type (type)) > + && (complain & tf_warning)) > switch (implicit) > { > case ICV_CAST: > diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-requires36.C > b/gcc/testsuite/g++.dg/cpp2a/concepts-requires36.C > new file mode 100644 > index 00000000000..8d3a4fcd2aa > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-requires36.C > @@ -0,0 +1,16 @@ > +// PR c++/111419 > +// { dg-do compile { target c++20 } } > + > +template<class F> > +concept invocable = requires(F& f) { f(); }; > + > +template<class F> > +concept deref_invocable = requires(F& f) { *f(); }; > + > +struct Incomplete; > + > +template<class T> > +struct Holder { T t; }; > + > +static_assert(invocable<Holder<Incomplete>& ()>); > +static_assert(deref_invocable<Holder<Incomplete>* ()>); > diff --git a/gcc/testsuite/g++.dg/expr/discarded1.C > b/gcc/testsuite/g++.dg/expr/discarded1.C > new file mode 100644 > index 00000000000..c0c22e9e95b > --- /dev/null > +++ b/gcc/testsuite/g++.dg/expr/discarded1.C > @@ -0,0 +1,15 @@ > +// PR c++/111419 > + > +struct Incomplete; > + > +template<class T> struct Holder { T t; }; // { dg-bogus "incomplete" } > + > +extern Holder<Incomplete> a; > +extern Holder<Incomplete>& b; > +extern Holder<Incomplete>* c; > + > +int main() { > + a; > + b; > + *c; > +} > diff --git a/gcc/testsuite/g++.dg/expr/discarded1a.C > b/gcc/testsuite/g++.dg/expr/discarded1a.C > new file mode 100644 > index 00000000000..1c4dff4553e > --- /dev/null > +++ b/gcc/testsuite/g++.dg/expr/discarded1a.C > @@ -0,0 +1,17 @@ > +// A version of discarded1.C using volatile types. > +// PR c++/111419 > + > +struct Incomplete; > + > +template<class T, int> struct Holder { T t; }; // { dg-error "incomplete" } > + > +extern volatile Holder<Incomplete, 0> a; > +extern volatile Holder<Incomplete, 1>& b; > +extern volatile Holder<Incomplete, 2>* c; > + > +int main() { > + a; // { dg-message "required from here" } > + b; // { dg-message "required from here" } > + // { dg-warning "implicit dereference will not access object" "" { target > *-*-* } .-1 } > + *c; // { dg-message "required from here" } > +} > -- > 2.42.0.216.gbda494f404 > >