aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Palka <ppalka@redhat.com>2023-09-19 08:29:39 -0400
committerPatrick Palka <ppalka@redhat.com>2023-09-19 08:29:39 -0400
commitb510b83aad52adf94d52a6ae3a3b332946e947a1 (patch)
treeaa2d42e4248810ed711ac891df9173554e51bae2
parentddd064e3571c4a9e6258c75eba65585a07367712 (diff)
downloadgcc-b510b83aad52adf94d52a6ae3a3b332946e947a1.zip
gcc-b510b83aad52adf94d52a6ae3a3b332946e947a1.tar.gz
gcc-b510b83aad52adf94d52a6ae3a3b332946e947a1.tar.bz2
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.
-rw-r--r--gcc/cp/cvt.cc9
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-requires36.C16
-rw-r--r--gcc/testsuite/g++.dg/expr/discarded1.C15
-rw-r--r--gcc/testsuite/g++.dg/expr/discarded1a.C17
4 files changed, 54 insertions, 3 deletions
diff --git a/gcc/cp/cvt.cc b/gcc/cp/cvt.cc
index c6b52f0..96abfae 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 0000000..8d3a4fc
--- /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 0000000..c0c22e9
--- /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 0000000..1c4dff4
--- /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" }
+}