From b510b83aad52adf94d52a6ae3a3b332946e947a1 Mon Sep 17 00:00:00 2001 From: Patrick Palka <ppalka@redhat.com> Date: Tue, 19 Sep 2023 08:29:39 -0400 Subject: [PATCH] c++: overeager type completion in convert_to_void [PR111419] 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>: 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 | 9 ++++++--- .../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(+), 3 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 c6b52f070508..96abfae7725e 100644 --- a/gcc/cp/cvt.cc +++ b/gcc/cp/cvt.cc @@ -1252,7 +1252,9 @@ convert_to_void (tree expr, impl_conv_void implicit, tsubst_flags_t complain) tree type = TREE_TYPE (expr); int is_reference = TYPE_REF_P (TREE_TYPE (TREE_OPERAND (expr, 0))); 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 +1414,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 000000000000..8d3a4fcd2aa2 --- /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 000000000000..c0c22e9e95bf --- /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 000000000000..1c4dff4553e3 --- /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" } +} -- GitLab