c++: Allow parm of empty class type in constexpr.
authorJason Merrill <jason@redhat.com>
Mon, 3 Feb 2020 16:11:55 +0000 (11:11 -0500)
committerJason Merrill <jason@redhat.com>
Mon, 3 Feb 2020 22:50:36 +0000 (17:50 -0500)
Since copying a class object is defined in terms of the copy constructor,
copying an empty class is OK even if it would otherwise not be usable in a
constant expression.  Relatedly, using a parameter as an lvalue is no more
problematic than a local variable, and calling a member function uses the
object as an lvalue.

PR c++/91953
* constexpr.c (potential_constant_expression_1) [PARM_DECL]: Allow
empty class type.
[COMPONENT_REF]: A member function reference doesn't use the object
as an rvalue.

gcc/cp/ChangeLog
gcc/cp/constexpr.c
gcc/testsuite/g++.dg/cpp0x/constexpr-empty14.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1z/constexpr-if12.C

index 2429b1f164282171153bcb4cf4b0927b1f41a768..a8af79c77a7d4cc6ff8d56c2f734e90549590f66 100644 (file)
@@ -1,3 +1,11 @@
+2020-02-03  Jason Merrill  <jason@redhat.com>
+
+       PR c++/91953
+       * constexpr.c (potential_constant_expression_1) [PARM_DECL]: Allow
+       empty class type.
+       [COMPONENT_REF]: A member function reference doesn't use the object
+       as an rvalue.
+
 2020-02-03  Iain Sandoe  <iain@sandoe.co.uk>
 
        PR c++/93458
index 577022e9b9a6a7ab5ee1a257ee9cef4571612afb..a39ba413d687bfa388306949575e2a1de4bc818c 100644 (file)
@@ -7013,8 +7013,13 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
       return true;
 
     case PARM_DECL:
-      if (now)
+      if (now && want_rval)
        {
+         tree type = TREE_TYPE (t);
+         if (dependent_type_p (type)
+             || is_really_empty_class (type, /*ignore_vptr*/false))
+           /* An empty class has no data to read.  */
+           return true;
          if (flags & tf_error)
            error ("%qE is not a constant expression", t);
          return false;
@@ -7270,10 +7275,7 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
 #endif
       return RECUR (t, any);
 
-    case REALPART_EXPR:
-    case IMAGPART_EXPR:
     case COMPONENT_REF:
-    case BIT_FIELD_REF:
     case ARROW_EXPR:
     case OFFSET_REF:
       /* -- a class member access unless its postfix-expression is
@@ -7282,6 +7284,15 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
         postfix-expression being a potential constant expression.  */
       if (type_unknown_p (t))
        return true;
+      if (is_overloaded_fn (t))
+       /* In a template, a COMPONENT_REF of a function expresses ob.fn(),
+          which uses ob as an lvalue.  */
+       want_rval = false;
+      gcc_fallthrough ();
+
+    case REALPART_EXPR:
+    case IMAGPART_EXPR:
+    case BIT_FIELD_REF:
       return RECUR (TREE_OPERAND (t, 0), want_rval);
 
     case EXPR_PACK_EXPANSION:
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-empty14.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-empty14.C
new file mode 100644 (file)
index 0000000..ca4f9a5
--- /dev/null
@@ -0,0 +1,10 @@
+// PR c++/91953
+// { dg-do compile { target c++11 } }
+
+struct S {};
+
+template <class T> void
+foo (S s)
+{
+  constexpr S x = s;
+}
index f21a9896ff288f7569c5d1f9f3242989cbf93936..005aa80fc093adf6394013c9122182094bcdbb9d 100644 (file)
@@ -2,12 +2,13 @@
 // { dg-do compile { target c++17 } }
 
 struct T {
+  int i;
   constexpr auto foo() { return false; }
 };
 
 template <class MustBeTemplate>
 constexpr auto bf(T t) {
-    if constexpr(t.foo()) {    // { dg-error "constant expression" }
+    if constexpr(t.foo()) {
         return false;
     }
     return true;