Fix empty class parameters with constexpr.
authorJason Merrill <jason@redhat.com>
Tue, 9 Aug 2016 04:33:42 +0000 (00:33 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Tue, 9 Aug 2016 04:33:42 +0000 (00:33 -0400)
PR c++/67131
* class.c (is_really_empty_class): Call complete_type.
* constexpr.c (cxx_eval_constant_expression): Check
is_really_empty_class.
(potential_constant_expression_1): Likewise.  Check for error type.

From-SVN: r239267

gcc/cp/ChangeLog
gcc/cp/class.c
gcc/cp/constexpr.c
gcc/testsuite/g++.dg/cpp0x/constexpr-empty12.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/constexpr-empty13.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1y/var-templ42.C

index bd036a8a6280b26159b80266b119b0fb7bc84d61..1ff70d4a8e748031d3a582c80321cf3771f39f3b 100644 (file)
@@ -1,3 +1,11 @@
+2016-08-08  Jason Merrill  <jason@redhat.com>
+
+       PR c++/67131
+       * class.c (is_really_empty_class): Call complete_type.
+       * constexpr.c (cxx_eval_constant_expression): Check
+       is_really_empty_class.
+       (potential_constant_expression_1): Likewise.  Check for error type.
+
 2016-08-08  Jakub Jelinek  <jakub@redhat.com>
 
        PR c++/58706
index f8349650fe6e4cf2a7eff0aed558887a4d113a37..d898c380057d2f64a8e8d1f47dc45c0faeb56ec0 100644 (file)
@@ -8419,7 +8419,7 @@ is_really_empty_class (tree type)
 
       /* CLASSTYPE_EMPTY_P isn't set properly until the class is actually laid
         out, but we'd like to be able to check this before then.  */
-      if (COMPLETE_TYPE_P (type) && is_empty_class (type))
+      if (COMPLETE_TYPE_P (complete_type (type)) && is_empty_class (type))
        return true;
 
       for (binfo = TYPE_BINFO (type), i = 0;
index e7b08c8a9bec0d286f2046fb7fc3c534b32b1f4b..2ced9c64e44cac6e90e73efe7dfe097ae7a61d98 100644 (file)
@@ -3670,7 +3670,13 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
         CONST_DECL for aggregate constants.  */
       if (lval)
        return t;
-      if (ctx->strict)
+      if (is_really_empty_class (TREE_TYPE (t)))
+       {
+         /* If the class is empty, we aren't actually loading anything.  */
+         r = build_constructor (TREE_TYPE (t), NULL);
+         TREE_CONSTANT (r) = true;
+       }
+      else if (ctx->strict)
        r = decl_really_constant_value (t);
       else
        r = decl_constant_value (t);
@@ -3705,7 +3711,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
        /* Defer in case this is only used for its type.  */;
       else if (TREE_CODE (TREE_TYPE (t)) == REFERENCE_TYPE)
        /* Defer, there's no lvalue->rvalue conversion.  */;
-      else if (is_empty_class (TREE_TYPE (t)))
+      else if (is_really_empty_class (TREE_TYPE (t)))
        {
          /* If the class is empty, we aren't actually loading anything.  */
          r = build_constructor (TREE_TYPE (t), NULL);
@@ -4736,6 +4742,9 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict,
     }
   if (CONSTANT_CLASS_P (t))
     return true;
+  if (CODE_CONTAINS_STRUCT (TREE_CODE (t), TS_TYPED)
+      && TREE_TYPE (t) == error_mark_node)
+    return false;
 
   switch (TREE_CODE (t))
     {
@@ -4891,12 +4900,14 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict,
 
     case VAR_DECL:
       if (want_rval
+         && !var_in_constexpr_fn (t)
+         && !type_dependent_expression_p (t)
          && !decl_constant_var_p (t)
          && (strict
              || !CP_TYPE_CONST_NON_VOLATILE_P (TREE_TYPE (t))
              || !DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (t))
-         && !var_in_constexpr_fn (t)
-         && !type_dependent_expression_p (t))
+         && COMPLETE_TYPE_P (TREE_TYPE (t))
+         && !is_really_empty_class (TREE_TYPE (t)))
         {
           if (flags & tf_error)
             non_const_var_error (t);
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-empty12.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-empty12.C
new file mode 100644 (file)
index 0000000..7463442
--- /dev/null
@@ -0,0 +1,5 @@
+// { dg-do compile { target c++11 } }
+
+struct A { } a;
+constexpr int f (A a) { return 42; }
+constexpr int i = f(a);
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-empty13.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-empty13.C
new file mode 100644 (file)
index 0000000..1896ead
--- /dev/null
@@ -0,0 +1,7 @@
+// { dg-do compile { target c++11 } }
+
+struct A {
+  struct B { } b;
+} a;
+constexpr int f (A a) { return 42; }
+constexpr int i = f(a);
index a43149d9b557dc4a789c13a440b2bed237b56356..de11b26a99f44bf7f0937f976d5cee9c4c9e3fb8 100644 (file)
@@ -14,4 +14,4 @@ template <template <typename...> class F> struct A {
 template <typename F> auto valid_call(F f) -> decltype(f());
 constexpr auto valid_call(...) { return 0; }
 template <typename> struct no_type;
-static_assert(!valid_call(metafunction<no_type>),""); // { dg-error "" }
+static_assert(!valid_call(metafunction<no_type>),"");