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 INDIRECT_REF or
VAR_DECL 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 accordingly.

        PR c++/111419

gcc/cp/ChangeLog:

        * cvt.cc (convert_to_void) <case INDIRECT_REF>: Only call
        complete_type if the type is volatile and the INDIRECT_REF
        isn't an implicit one.
        <case VAR_DECL>: Only call complete_type if the type is
        volatile.

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                                    | 11 +++++++----
 gcc/testsuite/g++.dg/cpp2a/concepts-requires36.C | 16 ++++++++++++++++
 gcc/testsuite/g++.dg/expr/discarded1.C           | 15 +++++++++++++++
 gcc/testsuite/g++.dg/expr/discarded1a.C          | 16 ++++++++++++++++
 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..5e2c01476e3 100644
--- a/gcc/cp/cvt.cc
+++ b/gcc/cp/cvt.cc
@@ -1252,10 +1252,12 @@ 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 && !is_reference)
+         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)
+       if (is_volatile && !is_reference && !is_complete)
           {
             if (complain & tf_warning)
              switch (implicit)
@@ -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 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..5516ff46fe9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/expr/discarded1a.C
@@ -0,0 +1,16 @@
+// 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-warning "implicit dereference will not access object" }
+     // { dg-bogus "required from here" "" { target *-*-* } .-1 }
+  *c; // { dg-message "required from here" }
+}
-- 
2.42.0.158.g94e83dcf5b

Reply via email to